I2C通信に触れてみた

最近仕事でI2C通信に触れる機会があり、触ったことが無かったため、体験する良い機会だと思い、自分で機材を買って動作確認を行った。

OSはUbuntu 22.04を使った。最近Ubuntuに嵌ってしまい、Windowsに戻りたくない病を患っている。Ubuntuを使ってつくづく思うのは、Windowsはとても恵まれた環境だということだ。使っている人数がUbuntuとは桁違いに多いため、企業が積極的にサポートしているおかげで、ドライバは必ず対応されている。それに比べてLinux環境は、最新のものを使おうとするとドライバが自動でインストールされないことがあるため、自分で探してきてインストールする必要があったり、ドライバのアクセス権を宣言しないとドライバ自体が使えなかったりと色々な知識やググりが必要になる。

今回I2C通信を体験するにあたり買った機材は、以下の2つ。

サンハヤト USB・I2C(SMBus)変換モジュール MM-CP2112
https://www.sunhayato.co.jp/material2/ett09/item_1052
→USBポートからI2Cへ変換するCP2112というICが搭載されたもの。I2Cのマスター側として動作する。

I2C通信のスレーブ側として動作させるのが以下のモジュール。

Grove-I2C高精度温度および湿度センサー(SHT35)

https://jp.seeedstudio.com/Grove-I2C-High-Accuracy-Temp-Humi-Sensor-SHT35.html

I2C通信は、WriteとReadを同時に行うことはできない。Writeしたい場合は、I2Cアドレスに何バイトのデータを書き込むことを伝えて、ACKを受信後、書き込むデータをWriteする。Readしたい場合も同様に、I2Cアドレスに何バイトのデータを読み込むことを伝えて、ACKを受信後、読み込むデータをReadする。主導権は常にマスター側にある。この0x45(default)とox44(optional)の使い方がサンプルソースを読んでも理解できず、2〜3時間悩んだ。SHT35のサンプルソースは以下だが、Arduinoという評価ボードから実行するためのコードであるため、CP2112のAPIとは異なるArduino専用のAPIを使っている点が分かり辛さを増幅していた。

https://github.com/Seeed-Studio/Seeed_SHT35

SHT35のデータシート(以下を参照)には確かに「The ADDR pin must not be left floating. Please note that only the 7 MSBs of the I2C Read/Write header constitute the I2C Address.(I2C Read/Write ヘ ッ ダ の 7 MSB だ け が I2C Address を構成することに注意してください。)」と書いてあるし、
https://github.com/SeeedDocument/Grove-I2C_High_Accuracy_Temp-Humi_Sensor-SHT35/raw/master/res/Datasheet%20SHT3x-DIS.pdf

CP2112のAPI仕様にも「slaveAddress is the address of the slave device to write to. This value must be between 0x02 – 0xFE. The least significant bit is the read/write bit for the SMBus transaction and must be 0.(アドレスはデバイスのスレーブアドレス(0x02-0xFE)です。デバイスはこのアドレスのみを認識します。デフォルトは 0x02 です。最下位ビットはSMBusトランザクションのリード/ライト・ビットで、0でなければなりません。)」と何故か1バイトのうち、1ビット目だけ指定できないようになっている点に疑問を持たなかったのが敗因だが、よくよく考えてみれば不自然な範囲である。

上の図の8ビット目のところは、I2C通信プロトコル固有のビットでWirteなら0、Readなら1に使われる。CP2112のAPI仕様のI2Cアドレスは0x02〜0xFEまでしか指定できないのは、1ビット目が固有ビットになっているから空けておけという意味なのである。
上手く行かなくて悩んでいるとき、「空ける必要があるのであれば、0x45は空いてないから0x44にしないと行けないのかな?」と訳の分からない解釈をしてわざわざジャンパーを0x44に切り替えるために、カッターと半田作業をして余計なことをしていた。。。


以下に今回試したソースコードをアップしました。0x44 << 0x1としている点が味噌です。
https://github.com/zattu1/i2c

上記を動かすには、Qtフレームワークが必要なのと、CP2112のサンプルコードにあるSiliconLabs.rulesを/etc/udev/rules.d/に放り込むのと、CP2112のライブラリ群を/usr/local/lib/に放り込む必要がある。

以下はCP2112のSDK
https://jp.silabs.com/documents/public/software/USBXpressHostSDK-Linux.tar