STM32用に書いているライブラリを使って、I2Cデバイスの検出プログラムを書いてみました。
このプログラムはI2Cのアドレス0からアドレス127(0X7F)まに順にダミーの出力を書き込んで、ACK/NAKのどちらが帰ってくるかを見ています。書き込みデータ長は0ですので、ACK/NACKの判定はI2Cデバイスがアドレスに対して返すACK/NACKについて行います。デバイスがないときにはマスターはNACKと判断するため、結果的にACKのところだけにデバイスがあると判断できます。
inline void MasterTask::TaskBody(const void* ptr)
{
uint8_t tx_buf[1];
murasaki::debugger->Printf(" Probing I2C devices \n\r");
murasaki::debugger->Printf(" | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\r");
murasaki::debugger->Printf("---+------------------------------------------------\n\r");
for ( int v = 0; v < 128; v+=16)
{
murasaki::debugger->Printf("%2x |", v);
for ( int h = 0; h <16; h++)
{
murasaki::I2cStatus result;
// check whether device exist or not.
result = murasaki::platform.i2c_master->Transmit(v+h, tx_buf, 0);
if ( result == murasaki::ki2csOK) // device acknowledged.
murasaki::debugger->Printf(" %2X", v+h);
else if ( result == murasaki::ki2csNak) // no device
murasaki::debugger->Printf(" --");
else
murasaki::debugger->Printf(" ??"); // unpredicted error.
}
murasaki::debugger->Printf("\n\r");
}
while (true) // dummy loop
{
murasaki::platform.led1->Toggle(); // toggling LED
murasaki::Sleep(static_cast<murasaki::WaitMilliSeconds>(700));
}
}
とくに変わったことはありません。128アドレスを行列に並べるため、2重ループになっています。
内側のループではデバイスに0を送ってACKが帰ってくれば現在のアドレスを、NACKならば”–“を、それ以外のエラーなら”??”を出力します。「紫」ライブラリではI2Cの実行結果を返り値として表明しますので、その値で出力を決めています。NACKが帰る場合、STM32 HALではエラー割り込みが発生しますが、紫ではこの割り込みをクラス変数内部で処理しているため、ユーザーからは割り込みも送受信のステータスとして見えることになり、使い勝手が良いです。
実行結果は以下のとおりです。0x50番地にあるのはI2Cメモリ、0x7C番地にあるのはSTM32L152上のI2C2ポートです。このポートはCubeMXで0x7Cをアドレスとして設定しており、紫のI2Cスレーブ・クラスを別スレッドで使用してI2Cデバイスとして動かしています。
