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デバイスとして動かしています。