I2C DriverをPythonで制御してI2C通信を見える化

2019年7月7日

電子工作でセンサを扱うと必ず出くわす「I2C(アイ・スクウェアド・シー)」という通信方式。
I2Cで何をやっているかわかりにくく躓きやすかったりします。

そんな時、通信を可視化して分かりやすくしてくれる凄いデバイスを発見しました。
seeed studio」の「I2C Driver」です!

ということで、使い方を紹介します。

準備するモノ

  • I2C Driver (seeed studio のサイトから購入可能。2週間ほどで到着。3000円強)
  • USB A – micro B ケーブル(スマートフォンのマイクロUSBケーブルでOK)
  • パソコン(macを使用。Python使えればLinuxでも同じ。)
    • Homebrewをユーザーディレクトリにインストールして使っています。
    • Python2/3どちらでも動くようです。
  • I2C接続のセンサ(秋月電子で入手したBME280使用の温湿度・気圧センサモジュール)

Pythonのライブラリセットアップ

pythonのライブラリをインストールします。ついでに、GUI用のライブラリも入れておきます。
環境によってはpythonとpipが別々のバージョンを指していたりするので、適宜pip2やpip3などを使ってインストールしてみてください。

pip install pyserial
pip install i2cdriver	
pip install -U wxPython

次に、適当なフォルダにgit cloneします。

git clone https://github.com/jamesbowman/i2cdriver.git

中にサンプルプログラムが入っているので、試しに i2cgui.py を動かしてみます。

cd i2cdriver/python/samples/		
python i2cgui.py		

うまくいけばこのような画面が表示されます。

※I2C driverを接続していないので、特に何も触るところはありません。確認できたらウィンドウを閉じましょう。

BME280センサモジュールの準備

秋月電子で購入した「BME280使用の温湿度・気圧センサモジュール」を組み立てます。

説明書を読みながら、「ヘッダーピン」をハンダ付けします。

次に、動作モードを設定するジャンパにハンダ付けします。BME280は、I2CだけではなくSPIでも接続できので、今回はI2Cで通信するように「J3」にハンダを盛ります。プルアップ抵抗はI2C Driverに載っているので「J1、J2」はそのままオープンにしておきました。

最後は、アドレス設定のため「SDO」ピンを「GND」に接続してアドレスを「0x76」にします。データシートでは「フローティングにするな」と書いてあったので、GND(0x76)か、VDD(0x77)のいずれかになるように配線します。ブレッドボードを使うのが面倒だったので、ヘッダーピンに直接ハンダ付けしました。

秋月電子通商で購入した「BME280センサモジュール基板」にヘッダーピンをハンダ付けし、J3を接続、アドレス設定用に「SDOとGND」をジャンパー線で接続したところ。

I2C Driverにセンサモジュールを接続する

I2C Driverのセットには「ヘッダーピン用接続ケーブル」が3本入っています。これを使って接続します。
I2C Driver基板のヘッダーピンの所に色つきラベルが貼ってあるので、ケーブルの色と合わせながら接続します。ケーブルを下表の通りにセンサモジュールと接続します。

I2C Driverセンサモジュール
GNDGND
VCCVDD
SDASDI
SCLSCK

FTDIのUSBドライバを入れる

I2C DriverはUSBでパソコンに接続しますが、通信用のチップとしてFTDIのチップが載っています。
過去にFTDIチップのUSBシリアル変換ケーブル等を使用したことが無い方は、FTDIのサイトから自分のOSに適したVirtual COM Port Driver (略して VCP Driver)をダウンロードして、インストールしましょう。

USBケーブルを接続してシリアルポートを調べる

USBドライバをインストールしたら、まず初めに、ターミナルを起動して以下のコマンドを実行します。

ls /dev/tty.*

もしくは、

ls /dev/cu.*

次に、I2C DriverをUSBケーブルで接続して、もう1度同じコマンドを実行します。
正しく認識されていれば、先ほどなかったデバイスが追加されているのがわかると思います。

私の環境では以下のように表示されていました。
/dev/cu.usbserial-XXXXXXXX

これで下準備は完了です。

BME280の動作モードをざっくり調べる

BME280にアクセスするための手順を、データシートを見て把握します。
基板を購入した「秋月電子」の該当ページに、参考資料としてデータシートが掲載されていますのでこれを眺めてみます。

※英語が苦手な方は、適宜Google翻訳などを使うと良いと思います。

とりあえず「General Description」を見ると、3つのパワーモード(Sleep, Normal, Forced)がある(詳細はチャプター3.3)と書いてあります。

チャプター3.3を見ると、電源を入れた直後は「Sleep」状態で、計測はしていないけど、全てのレジスタにアクセスでき、Chip-IDや補正係数は読み出せマッセ!と書いてあります。

ということで、最も簡単な手順として「電源投入」→「Chip-IDの読み出し」を行ってみます。

Pythonで読み出すプログラムを書く

SwitchScienceさんがgit(https://github.com/SWITCHSCIENCE/BME280)に公開されている、「BME280にアクセスしてデータを取り出すためのソースコード」を、まんまI2C Driver用に修正したものが「DIY環境(denshi.club)」さんのサイトに公開されていました。感謝しながら参考にさせていただきました。

今回は動作の理解のために、もの凄く単純化したコードを作成します。

適当な名前でファイルを作成します。
vim bme280-id.py

そして、必要なのはたったこれだけ!

# coding: utf-8

import i2cdriver

device="/dev/cu.usbserial-XXXXXXXX" # 自分の環境に合わせて修正
bme280_addr=0x76
_write_=0
_read_=1

## デバイスを指定してi2cインスタンスを作成
i2c = i2cdriver.I2CDriver(device)

## i2cのマップ表示(なくてもOK)
i2c.scan() 

# 1. Chip-IDのアドレスを指定
## 1-1. writeモードでスタートコンディションを発行
## 1-2. 読み出したいレジスタのアドレスを書き込む
## 1-3. ストップコンディションを発行
i2c.start(bme280_addr, _write_) 
i2c.write([0xD0]) 
i2c.stop() 

# 2. Chip-IDの値を読み出す
## 2-1. readモードでスタートコンディションを発行
## 2-2. 1 byte 読み込んでIDに格納
## 2-3. ストップコンディションを発行
i2c.start(bme280_addr, _read_)
ID=i2c.read(1)
i2c.stop() 

# 読み出したIDを16進数で表示
print(ID.hex()) 

できたら実行します。
実行結果として、マップとIDが表示されます。

そして、ここからが一番凄いところ!
I2C Driverの画面を見ると、、、

こんな感じで実行した内容がわかりやすく表示されています!

  • S: スタートコンディション
  • P: ストップコンディション
  • 緑丸: ACK
  • 赤丸: NACK
  • 黄色い右向き三角: 書込み
  • 黄色い左向き三角: 読込み

センサ未接続だと応答がないので全部NACKになっています。

こちらがセンサ接続時の応答。 最後にChip-IDが読み出せています。

まとめ: I2C Driver をpythonで動かして、I2C通信を簡単に可視化できた!

seeed studio」の「I2C Driver」を用いてI2C通信を可視化する方法を紹介しました。
PCに接続して、Pythonから簡単に制御することができ、通信の仕組み理解やデバッグにとても役立つと思います!

それではみなさん、よい電子工作生活を!