はじめに
以前、I2Cの要件を満たすハードウエアを構築することによってノイズ耐性を向上させる記事を書きました。
I2Cのノイズ対策 その1(準備編) - 隠居エンジニアのものづくり (hatenablog.com)
I2Cのノイズ対策 その2(一点接地編) - 隠居エンジニアのものづくり (hatenablog.com)
I2Cのノイズ対策 その3(信号線のGND) - 隠居エンジニアのものづくり (hatenablog.com)
I2Cのノイズ対策 その4(Rpの値 設計計算書の勧め) - 隠居エンジニアのものづくり (hatenablog.com)
I2Cのノイズ対策 その5(まとめ) - 隠居エンジニアのものづくり (hatenablog.com)
I2Cのノイズ対策 その6(オシロスコープを用いた静電容量推定) - 隠居エンジニアのものづくり (hatenablog.com)
自身のロボットは、I2Cのトラブルは全くなかったのですが、ジャパンオープン出場常連校とアメリカ大会連覇のチームの両方から” バスロック状態 ”と思われる時々症状の報告がありました。
どちらのチームも、I2C要件を満たすハードウエア構築について指導済ですが、それでも障害が発生するとの事なので、症状を観測することにしました。
I2Cにノイズ重畳しながらロジックアナライザーで観測してみると、バスロック状態に陥るとWire関数が終了しない状態であることを確認しました。
Arduinoは誰でも簡単に電子工作ができることを目指したマイコンボードとの認識なのでWire関数はバスロックから自動復帰するものと思い込んでましたが、ソフトウエアによる復帰処理が必要です。
ソフトウエア処理
I2Cでロックが発生する代表例はノイズによるクロックずれにより、スレーブ側がSDA=LOWの状態でマスター側からの次のクロックを待っている状態が発生、マスターはSDA=HIGH & SCL=HIGHでないとスタートできないので、ずっと待つことになります。
” I2C バスロック ” で検索して頂くと、色々なマイコンのバスロック状態からの復帰処理に関する情報が入手できます。
手順としては
①マスター側にて一定時間以上SDA=LOWであれば、バスロックと判断
②マスター側からダミークロックを送ることでスレーブのデータ送信を終了させる
③データ消失に関する処理
となります。
ここでは、検索してもなかなか見つからないArduino Uno用の ” 簡単かつ確実な ” ソフトウエア対策について述べます。
Wire.h
Arduinoに予め準備されている関数です。
前述の通り、このWire関数がタイムアウトしないのが問題です。
" Wire.h " の中身を見ると
void setWireTimeout(uint32_t timeout = 25000, bool reset_with_timeout = false);
タイムアウトを設定する関数がありました。
最大25000μsですが、6軸センサなど12Byte連続送信するデバイスを想定し、余裕をみて3000μsとしました。
報告された不具合は、旋回角度を制御する為に、ジャイロセンサーの値を連続で取得している最中のロック状態ですので、不具合時のデータは破棄しても問題ありません。
確実なバス復旧を優先するので、バスリセットします。
以下のソースにてバスロックが発生しても3ms後には次のデーター要求が開始されます。
void setup()
{
Wire.begin();
Wire.setWireTimeout(3000, true);
Serial.begin(115200);
}
GIFファイルがアップロードできないのが残念ですが、ロジックアナライザー観測にて、復帰動作を確認済みです。
※ATmega328pのI2Cに依存する関数ですので、Uno、Pro Miniなどが対象です。