🐧 Linux 総合学習プラットフォーム
実機制御 GPIO/I2C/SPI・RT ・ 上級

I2Cデバイスの検出と読み取り

I2CはSDA(データ)とSCL(クロック)の2本でセンサやEEPROMなど複数のデバイスを数珠つなぎにできる通信方式で、各デバイスは7ビットのアドレスで識別されます。Raspberry Piでは raspi-config か dtparam でI2Cを有効化し、i2c-tools の i2cdetect -y 1 でバス1につながった機器のアドレス一覧を確認します。個々のレジスタは i2cget でアドレスとレジスタ番号を指定して読み、i2cset で書き込みます。アドレスが衝突していないか、プルアップ抵抗が入っているかが安定動作の鍵です。

I2C(アイ・スクエアド・シー)は、わずか2本の信号線で複数のデバイスをつなげるシリアル通信方式です。使う線は、データをやり取りする SDA と、タイミングを合わせるクロックの SCL の2本だけ。この2本を共有のバスとして、温湿度センサ・気圧センサ・RTC(リアルタイムクロック)・小型のEEPROMなど、たくさんの周辺デバイスを数珠つなぎにできます。ピン数の少ないマイコンやSoCで多数のセンサを扱いたいとき、配線が少なくて済むのが大きな魅力です。通信速度はSPIほど速くありませんが、センサ類のように頻繁に大量のデータを送らない用途では十分実用的です。

2本しか線がないのに複数のデバイスを区別できるのは、各デバイスが固有の「アドレス」を持っているからです。I2Cでは通常7ビットのアドレスが使われ、マスタ(多くはSoC側)が「このアドレスの相手と話したい」と宣言してから通信を始めます。アドレスは 0x76 や 0x68 のように16進数で表され、たとえば気圧センサBMP280/BME280は 0x76 か 0x77、よく使われるRTCのDS3231は 0x68、小型EEPROMは 0x50 付近、というように型番ごとにだいたい決まっています。多くのモジュールにはアドレス選択ピンがあり、はんだジャンパや配線で 0x76/0x77 のように1ビットだけ切り替えられるようになっています。同じアドレスのデバイスを同じバスに2つつなぐと、両方が同時に応答して通信が壊れます。その場合はこの選択ピンで一方のアドレスをずらすか、I2Cバス自体を分ける(別のバスやI2Cマルチプレクサを使う)必要があります。

Raspberry Piで有効化する

Raspberry PiでI2Cを使うには、まず機能を有効にします。`sudo raspi-config` の Interface Options から I2C を有効化するか、/boot/firmware/config.txt(環境により /boot/config.txt)に `dtparam=i2c_arm=on` を書いて再起動します。有効になると、I2Cコントローラが /dev/i2c-1 というデバイスファイルとして現れます(Piの拡張ヘッダはバス1番が標準です)。続いて操作用のツールを入れます。`sudo apt install i2c-tools` で、i2cdetect・i2cget・i2cset・i2cdump といったコマンド群がそろいます。これらはバス番号やアドレスを指定して、コマンドラインから直接デバイスを叩けるので、配線確認や初期の動作チェックに重宝します。

まず i2cdetect で存在確認

配線したら、最初にやるべきは「デバイスが見えているか」の確認です。`i2cdetect -y 1` を実行すると、バス1につながっているデバイスのアドレスが格子状の表で表示されます。-y は確認プロンプトを省くオプション、末尾の 1 はバス番号です。表は縦横にアドレスの桁が並び、応答があったアドレスの位置にその番号が、応答が無い位置にはハイフンが表示されます。表の中に 76 や 68 といった数字が現れれば、そのアドレスのデバイスがバス上で応答している証拠です。逆に、つないだはずのデバイスが表に出てこなければ、配線(SDAとSCLの取り違え、GND未接続、結線のゆるみ)、電源(3.3Vが来ているか)、アドレス設定のいずれかを疑います。この i2cdetect は配線確認の第一手として極めて有用で、ここで相手が見えてからレジスタの読み書きに進む、という順番にするとトラブルの切り分けが格段に楽になります。

i2cget でレジスタを読む

個々のデバイスの内部は「レジスタ」という小さな番地に分かれており、そこに測定値や設定値が入っています。どのレジスタに何が入っているかは、そのデバイスのデータシートに必ず載っています。特定のレジスタを読むのが i2cget です。書式は `i2cget -y 1 0x76 0xD0` のように「バス番号・デバイスアドレス・レジスタ番号」を並べます。この例はBME280のID(チップ番号)レジスタ 0xD0 を読む操作で、正しく配線されていれば 0x60 のような既定値が返り、通信が成立していることの裏取りになります。アドレスは i2cdetect で見えても、こうしてレジスタが期待どおりの値を返すかまで確認すると、配線とデバイスの双方が生きていると確信できます。書き込みは i2cset で、`i2cset -y 1 0x76 0xF4 0x27` のように「アドレス・レジスタ・書き込む値」を指定し、センサの測定モードを設定する、といった使い方をします。複数バイトをまとめて見たいときは i2cdump でレジスタ全体を一覧ダンプでき、デバイスの状態を俯瞰するのに便利です。これらのコマンドで手順を確かめてから、同じレジスタ操作をCやPythonのコードに落とし込みます。

配線と事故の注意、実務の勘どころ

I2Cで安定動作の鍵を握るのがプルアップ抵抗です。SDA/SCLはどのデバイスも「LOWに引っ張る」だけの構造のため、放っておくと電位が定まりません。そこで両線をプルアップ(プルアップ/プルダウンのうちプルアップ側)でHIGHに固定しておく必要があります。Raspberry Piの拡張ヘッダにはあらかじめプルアップが入っているので、多くのセンサモジュールはそのままつながりますが、長い配線や多数接続では値が足りずに通信が不安定になることがあります。配線時はSDA同士・SCL同士・GND同士を正しく結び、電源電圧(多くのI2Cセンサは3.3V系)を取り違えないよう注意します。実務の流れは「有効化 → i2cdetect で存在確認 → i2cget で疎通確認 → 本番プログラムでレジスタを読み書き」が定番で、まずコマンドで相手の応答を見てからコードを書くと、ハードとソフトのどちらに問題があるかを切り分けやすくなります。

この項目に出てくる用語

I2Cあいすくえあシー
SDA/SCLの2線で複数機器を接続するシリアル通信。各機器をアドレスで識別。
プルアップ/プルダウンぷるあっぷぷるだうん
入力ピンを既定でHIGH/LOWに固定する抵抗設定。

関連コマンド

i2cdetecti2cgeti2cset

▶ 学習アプリでこの続きを学ぶ・演習する