Powered By Blogger

2013年2月8日金曜日

AS5145開発断念

磁気式エンコーダIC「AS5145」はマイクロマウスで普及しつつある「AS5040」の後継機で、最大12bit分解能(AS5040は10bit)、精度改善などの特徴があるそうで、早速使ってみようとしたのですが、使い勝手がAS5040とは異なることが分かりました。

AS5145はレジスタ書き換え機能をもち、ユーザーに適した用途で使えるようにできるAS5145Hシリーズ、デフォルトでインクリメンタル出力可能に設定されたAS5145A(分解能10bit)、AS5145B(分解能12bit)シリーズがあり、基本的にAかBシリーズを使いたいのですが、DigikeyやMouserで入手可能なのはHシリーズのみという状況で仕方なくHシリーズを購入したのでした。

Hシリーズはデフォルトでインクリメンタル出力不可に設定されており、内部のレジスタを書き換えることでインクリメンタル出力にできます。
書き換えはシリアル同期通信(USART not UART)、、、なのですが、特有の奇妙なスタート、ストップコンディション、同一ポートの送信と受信切り替え、その他バイト単位でないレジスタアクセスなど、難解なIO操作が必要で、とても同期通信モジュールみたいなブラックボックス使ってやっていける状況ではありませんでした。(助言を求めた方には全く聞く耳持たないことして申し訳ないです)


そういうわけで、仕方なく全操作をSTM32のGPIOのHigh,Low切り替えでこなすことに。昨年作製した開発ボードと変換基板に実装したAS5145をブレッドボードで接続。

面倒でしたがトラブルは起きないのである意味気が楽でした。その時に使ったプログラムをブログの追記に延々と載せておくので何かの参考になればお使いください。

何もしなくてもインクリメンタル出力になるAS5040は優秀だなあ、、、とか思いつつレジスタを書き換え、読みだして目的のレジスタが書き変わったことを確認。インクリメンタル出力の様子をSTM32のタイマで読み取って性能評価しようとしましたが、どういうわけか出力がドリフトしました。カウントするタイマの値が静止時にひたすら減っていったり、増えていったり、、、
探索の速度でも問題ない程度かもしれませんがAS5040ではこのようなことはなく、精度はむしろ悪くなってるんじゃないかという印象を受けました。
まあ、自分がいい加減な(データシートで保証してないサイズの磁石使用と目分量の磁石配置)使い方してるからだと思いますが、それでもAS5040が動いていた以上このやり方でやりたいのでAS5145の使用は断念し、今年の新作もAS5040で作ることにします。








// AS5145開発用プログラム
#define Time 0.001F // half fleq
unsigned char read_data_buff[1000] = {0};

////////////////////////////////////////////////////////////////////////////////
/** @brief 指定時間処理を止める
@details
SysTickを使って指定時間処理を止める.割り込みは使用していない.
@note
割り込みがおよそ0.5sec以上持続するような状況下では正しくカウントできない.
*///////////////////////////////////////////////////////////////////////////////
void wait(float time)
{
// カウンタの設定値を計算する
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
uint64_t val = RCC_Clocks.HCLK_Frequency / 8 * time;
unsigned int count = val / 0x1000000 + 1; // アンダーフロー回数
unsigned int load = val / count;

// SysTickの設定
SysTick->CTRL = 0;
SysTick->LOAD = load - 1;
SysTick->VAL  = 0;
SysTick->CTRL = 1;

unsigned int i;
for(i=0;i<count;i++){
while((SysTick->CTRL & 0x00010000) == 0);
}
SysTick->CTRL = 0;
}

void PDIO_High()
{
GPIO_SetBits(GPIOC, GPIO_Pin_12);
}

void PDIO_Low()
{
GPIO_ResetBits(GPIOC, GPIO_Pin_12);
}

volatile unsigned char Read_PDIO_Data_Bit()
{
return GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_12);
}

void CLK_High()
{
GPIO_SetBits(GPIOC, GPIO_Pin_11);
}

void CLK_Low()
{
GPIO_ResetBits(GPIOC, GPIO_Pin_11);
}

void CSn_High()
{
GPIO_SetBits(GPIOC, GPIO_Pin_10);
}

void CSn_Low()
{
GPIO_ResetBits(GPIOC, GPIO_Pin_10);
}

void IOs_Config()
{
// クロックを有効にする
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);

// デバッグ用ポートを無効にする
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);

// 出力ポートの設定
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // push-pull output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);

PDIO_High();
CLK_Low();
CSn_Low();

}

void Set_IO_for_PDIO_Output()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // push-pull output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}

void Set_IO_for_PDIO_Input()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // pull_down input
GPIO_Init(GPIOC, &GPIO_InitStructure);
}

void Read_Operation_AS5145()
{
Set_IO_for_PDIO_Output();
wait(0.1);
PDIO_High();
CLK_Low();
CSn_Low();
wait(0.1);

CSn_High();
wait(Time);
CSn_Low();
wait(Time);

CLK_High();
wait(Time);
CLK_Low();
wait( (Time/2) );
PDIO_Low();
wait( (Time/2) );

CLK_High();
wait( (Time/2) );

//read_command
CSn_High();
wait( (Time/2) );

CLK_Low();
wait(Time);
//first_rising
CLK_High();
wait(Time);
CLK_Low();
Set_IO_for_PDIO_Input(); // keep Low(by internal pull-down)
wait(Time);

//when i = 0,second_rising(mbit1)
int i;
for(i=0;i<220;i++){
CLK_High();
wait( (Time/2) );
read_data_buff[i] = Read_PDIO_Data_Bit();
wait( (Time/2) );
CLK_Low();
if(i == 219) CSn_Low(); // Exit condition
wait(Time);
}

CLK_High();
wait(Time);
CLK_Low();
wait(Time);

CLK_High();
wait( (Time/2) );

CSn_High();
wait( (Time/2) );

CLK_Low();
wait(Time);

Set_IO_for_PDIO_Output();
wait(0.1);
PDIO_High();
CLK_Low();
CSn_Low();
}

void WRITE_Operation_AS5145()
{
unsigned char write_data_buff[55] = {0};
int i = 0;
for(i=0;i<54;i++){
write_data_buff[i] = read_data_buff[i];
}
write_data_buff[54] = 0; // 余分なクロックのためのデータが必要

write_data_buff[4] = 1; // md1:0 to 1

Set_IO_for_PDIO_Output();
wait(0.1);
PDIO_High();
CLK_Low();
CSn_Low();
wait(0.1);

CSn_High();
wait(Time);
CSn_Low();
wait(Time);

CLK_High();
wait(Time);
CLK_Low();
wait( (Time/2) );

//write_command
CSn_High();
wait( (Time/2) );

CLK_High();
wait(Time);
CLK_Low();
wait(Time);

CLK_High();
wait(Time);
CLK_Low();
wait(Time);

for(i=0;i<55;i++){ // 1clock余分に必要らしい
CLK_High(); // when i = 0,Mbit1(written value:1)
wait(Time);
CLK_Low();
if(i < 54){
if(write_data_buff[i+1] == 0) PDIO_Low();
else PDIO_High();
}
else if(i == 54) CSn_Low(); // Exit condition
wait(Time);
}

CLK_High();
wait(Time);
CLK_Low();
wait(Time);

CLK_High();
wait( (Time/2) );

CSn_High();
wait( (Time/2) );

CLK_Low();
wait(Time);

wait(0.1);
PDIO_High();
CLK_Low();
CSn_Low();
}


// after setting of incrementalmode,use this
void Power_On_Reset()
{
PDIO_Low();
CLK_Low();
CSn_High();
wait(0.1);
CSn_Low();
}



0 件のコメント:

コメントを投稿