😎

ソフトウェアでI2C通信を実現するときの注意点

2025/02/08に公開

I2Cデバイスを制御していると、デバイスによっては通信に癖があり、マイコン内蔵のペリフェラルではうまく通信できないケースが多々あります。(特にClock Stretchingなどのあたりで)
そうなると、ソフトウェアで対応しなければならないケースが多々あります。そんな時の注意点をまとめておきます。(自分用の忘備録)


信号の制御

ソフトウェアでI2Cの信号を制御するには単純にGPIOを出力にしてH/Lするのでは動きません。信号線がオープンドレイン接続でプルアップされているからです。このような場合の制御は以下のように行います。(Arduinoの例で記載します)

信号線をLにするとき
    pinMode(pin, OUTPUT);       // GPIOを出力に切り替える
    digitalWrite(pin, LOW);     // GPIOの出力をLにする
信号線をHにするとき
    pinMode(pin, INPUT);       // GPIOを入力に切り替える

Hにするとき、GPIOの出力でなく入力とすることでHi-Z状態になり、信号線がプルアップされてHになります。たまに信号線をプルアップするのを忘れちゃったときなどは、マイコンにプルアップの機能があれば、INPUTからINPUT_PULLUPとして内臓のプルアップ機能を有効にすると幸せになれるかもしれません。


クロックストレッチの処理

クロックストレッチ(Clock Stretching)はI2Cのスレーブ側の機能です。マスターからの要求に対し、スレーブの処理が間に合わない場合、スレーブ側がSCLを処理が終わるまでLowに落とし、マスター側に待たせる機能です。

マイコン内蔵のペリフェラルを使ってマスター機能を実装しようとすると、デバイスごとに挙動が違い、全く使えないもの、使えるけどタイムアウト時間があるもの、きちんと処理できるものなど様々です。デバイスとの組み合わせもあるので実際動かしてみるまで分からない部分もあります。

マスター側処理をソフトウェアで実装する場合、SCLをHighにした後読み出し、Lowになっていないか確認を行います。この時、Highにしてすぐ読むと、Slave側がSCLをLowにする処理が間に合わなく、正常と判断して進んでしまう場合があります。このようなときはHighにした後、少しWaitを入れてあげる必要があります。


どのマイコンで使えるのか?

基本的にどのマイコンでも利用できます。Arduino UnoR3、ESP32などで動くことを確認しています。

  • クロックストレッチングが正しく動作していそうなマイコン

    • Arduino Uno R3(Microchip ATmega328)
  • 使えるはずだけど微妙なもの

    • Arduino Uno R4(Renesas RA4M1)、ESP32系列
  • ダメだったもの

    • TWELITEのI2C(NXP JN516X)

Raspberry PiもI2C0、I2C1はクロックストレッチが使えません。その場合、デバイスツリーでi2c-gpioを指定するとソフトウェアで処理されるようになり、クロックストレッチも正しく処理されます。
Raspberry Pi 4から追加されたI2C2,I2C3などはうまく処理できるようです。


デメリットは?

ソフトウェアでの処理になるので速度は当然遅くなります。ただ、I2Cデバイスでそこまで高速な通信処理が必要なものもあまりないので問題になることは少ないでしょう。


使い道はどこか?

センサーやバッテリーなど、クロックストレッチを使用するデバイスは多いので、使い道は多いと思います。動かないよりはよいので。

※令和のこの時代に自前で実装することになるとは思いませんでした。。。

Discussion