以前にInfineon製の磁気エンコーダTLE5012Bについて
紹介しました。
TLE5012Bの問題点はSPIインタフェース互換のSSCという通信方式で
MOSIとMISOが1つで双方向に通信を行います。
前回はMOSIとMISOに抵抗を挟んで通信しましたが、
STM32のHALライブラリにはSSCに対応したHalf Duplexモードがあるため、
そちらを使用して通信してみました。
CubeMXではHalf Duplex Masterとして設定します。

配線ではMISOは使用せず、
MOSIのみで双方向に通信します。
MOSIのみで双方向に通信します。
1本のみの通信のため、抵抗値を0にしています。
コードは下記の通りです。
uint16_t GetEncPos(){
uint8_t sData[6];
uint8_t rData[6];
uint8_t rCRCBuff[12];
uint16_t res;
uint8_t rData[6];
uint8_t rCRCBuff[12];
uint16_t res;
HAL_GPIO_WritePin(ENC_CS1_GPIO_Port, ENC_CS1_Pin,0);//CS
sData[0]=0x80;sData[1]=0x21;
HAL_SPI_Transmit(&hspi1,sData,2,500);
HAL_SPI_Transmit(&hspi1,sData,2,500);
sData[0]=0x00;sData[1]=0x00;sData[2]=0x00;sData[3]=0x00;
rData[0]=0;rData[1]=0;rData[2]=0;rData[3]=0;
for(int i=0; i<1; i++)asm("nop");//Point
HAL_SPI_Receive(&hspi1,(uint8_t*)&rData,4,500);
HAL_GPIO_WritePin(ENC_CS1_GPIO_Port, ENC_CS1_Pin,1);//CS
uint8_t rCRC;//CRC from Recieve data
uint8_t dCRC;//Calc CRC from Data
rCRCBuff[0]=0x80;
rCRCBuff[1]=0x21;
rCRCBuff[2]=rData[0];
rCRCBuff[3]=rData[1];
uint8_t dCRC;//Calc CRC from Data
rCRCBuff[0]=0x80;
rCRCBuff[1]=0x21;
rCRCBuff[2]=rData[0];
rCRCBuff[3]=rData[1];
rCRC=rData[3];
dCRC=GetCRC8(rCRCBuff, 4);//CRC check
if(rCRC!=dCRC){
ENC_Err_Count++;
return 0;
}
res =(rData[0]<<8)+rData[1];
return 0x7FFF&res;
dCRC=GetCRC8(rCRCBuff, 4);//CRC check
if(rCRC!=dCRC){
ENC_Err_Count++;
return 0;
}
res =(rData[0]<<8)+rData[1];
return 0x7FFF&res;
}
uint8_t GetCRC8(uint8_t *buff, size_t size )
{
uint8_t crc=0xFF;
uint8_t i;
while(size--){
crc^= *buff++;
for(i=0;i<8;i++){
crc=crc&0x80?(crc<<1)^0x1d:crc<<1;
}
}
return (~crc)&0xFF;
}
{
uint8_t crc=0xFF;
uint8_t i;
while(size--){
crc^= *buff++;
for(i=0;i<8;i++){
crc=crc&0x80?(crc<<1)^0x1d:crc<<1;
}
}
return (~crc)&0xFF;
}
以前紹介したコードとの差はHalf Duplex Masterのため、
HAL_SPI_TransmitReceiveを使用せずに
HAL_SPI_ReceiveとHAL_SPI_Transmitを使用している点です。
自動的にMOSIの入出力がHALライブラリ内で切り替わります。
また、SafetyWordのCRCチェックを行っています。
実際に高速で通信した際に
角度読み出しコマンド実行後にすぐに角度を読み出すと、
正しい値を返さない現象が発生しました。
Infineonのフォーラムでも同じような不具合のディスカッションがされており、
角度読み出しコマンド実行後に10us待ってから読み出すことが重要なようです@2MHz
実際にFullDuplexMasterで以前紹介したようなMOSIとMISOを使用する配線で
10us待つためには
sData[0]=0x80;sData[1]=0x21;
HAL_SPI_TransmitReceive(&hspi1,sData,rData,2,200);
sData[0]=0x00;sData[1]=0x00;sData[2]=0x00;sData[3]=0x00;
rData[0]=0;rData[1]=0;rData[2]=0;rData[3]=0;
HAL_SPI_Receive(&hspi1,(uint8_t*)&rData,4,200);
sData[0]=0x00;sData[1]=0x00;sData[2]=0x00;sData[3]=0x00;
rData[0]=0;rData[1]=0;rData[2]=0;rData[3]=0;
HAL_SPI_Receive(&hspi1,(uint8_t*)&rData,4,200);
とすると丁度良い待ち時間になりました。
通信クロックに関して、
FullDuplexMasterではSPIクロック最大2MHz、
HalfDuplexMasterではSPIクロック最大4MHzという結果でした。
8MHzではビット読み違いが多発し、CRCチェックで値が落ちて通信できませんでした。
最終的に値取得周期は
TLE5012Bが2個、FullDuplexMaster@2MHzで約120us
TLE5012Bが2個、HalfDuplexMaster@4MHzで約100us
という結果となりました。
値読み出しコマンドとSafetyWord分の通信が必要なため、
1回の通信で8bit x 6回の通信が必要です。
SafetyWordを読み込まない場合でも8bit x 4回の通信が必要です。
TLE5012Bは内部更新周期42.7usで読み出すためには
SPIクロックを8MHzにしてなんとか実現可能なレベルということが分かりました。
AMS社のAS5048Aでは8bit x 2回の通信で済むため、
比べると通信量が多いことが分かります。
安さと15bit分解能、フィルタ内蔵というのは良いですが
SSCインタフェース、通信量の多さ、
角度読み出しコマンド後の待機時間の曖昧さには要注意です。