普通のパソコンでもGPIOを使ってみよう[I2C通信編]
はじめに
前回はデジタルI/O編ということで、FT2232Dを使用して単純な入出力を試してみましたが、今回はI2C通信を試してみたいと思います。
まず結論から先に話してしまいますが、FT2232DではI2C通信をする事は出来るのですが時折失敗する事があります。この問題はpyftdiライブラリでも触れているのでこちらについても解説していきたいと思います!
導入部分については、前回の記事を参照してください
I^2C とは
そもそも正式名称は Inter Integrated Circuitの頭文字を取ってIICと言います。
表記・発音
表記
正式な表記は
発音
発音としては[アイ・スクエアド・シー]/[アイ・アイ・シー]が正しいものになります。
ただし、正しい表記でも記載したように上付き文字を使って表記する事は多くない事からI2C[アイ・ツー・シー]の表記・発音でも問題ないです。
知り合いの回路エンジニアや組み込みエンジニアと話しても普通に[アイ・ツー・シー]と発音しているので、どれを使っても問題は無いでしょう。
※個人的には[アイ・アイ・シー]と発音するケースには今まで遭遇したことはありません。
通信方式
2本の信号線のうち1本をクロック・もう1本をデータの送受信に使い、クロックに同期させてデータのやり取りを行う、同期型シリアル通信となります。
2本の線を使って通信をすることから TWI(Two Wired Interface) とも呼ばれています。
この通信には主導権を握るマスターと、マスター側の指示によってのみ動くスレーブの2種類あります。
マスターの役割
マスターは同期用のクロック生成と、スレーブとの通信開始/終了を行おいます。
マスターはスレーブアドレスと呼ばれる7bitのアドレスでバス上にあるスレーブデバイスを指定し、データの送受信を行います。
スレーブの役割
マスターの指示によって値を受け取ったり、返したりする。
スレーブは自ら動く事やスレーブ同士での通信は行えません。
実際にパソコンでI2C通信をしてみる
使用するもの
-
FT2232D
※PCとの接続インターフェースがUSB-miniBとなります - ブレッドボード
- ジャンプワイヤ(オスーオス)
-
M5Stack用環境センサユニット ※販売終了
(代替品)M5Stack用温湿度気圧センサユニット Ver.4(ENV Ⅳ)
※代替品を利用すれば同様に温湿度が取得できますが、中で使用しているICが違うため、スレーブアドレスおよび各種シーケンス、データフォーマットまで違う可能性があるので、使用するセンサーのデータシートを参照ください。
センサの仕様
M5Stack用環境センサユニットの温湿度センサーを使用します。
温湿度センサーはDHT12というセンサーで仕様は下記のようになっています。
[DHT12]
スレーブアドレス:0x5c
その他詳細はDHT12データシートを参照
データフォーマット
アドレスの0x00から5byte分読み込みます。
この5byteのデータ中に、温湿度とチェックサムが含まれています。
例として・・・
[0x38,0x08,0x1A,0x06,0x60]という5byteデータが受信されました。
-
湿度
0byte目 -> 湿度の整数値 = 56
1byte目 -> 湿度の小数値 = .8
湿度 = 56.8%RH -
温度
2byte目 -> 温度の整数値 = 26
3byte目 -> 温度の小数値 = .6
温度 = 26.6℃ -
チェックサム
0~3byteを全て加算した値 == 4bye目の値 となれば受信データは正しいことが分かります。
異なる場合は受信データが異常と判断し破棄します。
今回の例では0~3byte目の合計が0x60で4byte目と一致していることが分かります。
回路図と配線
回路図
回路図は下記のようになります。
回路図を見てAD1,AD2の端子がショートしており「おや?」と思った方がいるかと思いますが、一般的にI2Cのデータ線は基本的にSDAというラインで 入出力を行うのですが、FT2232D(MPSSEをサポートするチップ全般)は1つのピンで双方向のやり取りができないため、SDAの入力と出力をそれぞれ1つずつのピンで機能を担います。よって、I2Cのスレーブデバイスと接続する際は、SDA_OとSDA_Iをショートさせたうえで接続します。
配線
上記の回路図を元にに配線しました。
※線の色が回路図とバラバラですみません。。。
ソースコード
今回もGPIO編同様にPythonとpyftdiを使用して実装したいと思います。
import time
from pyftdi.ftdi import Ftdi
from pyftdi import gpio, i2c
# デバイスのURL
FTDI_DEVICE_URL = "ftdi://ftdi:2232:0:1/1"
def main():
test_i2c()
# I2C通信
def test_i2c():
ftdi_i2c = i2c.I2cController()
ftdi_i2c.force_clock_mode(True) # FT2232DでI2Cを使う際には必須
ftdi_i2c.configure(url=FTDI_DEVICE_URL)
slave_dev_dht12 = ftdi_i2c.get_port(0x5c) # 温湿度センサーDHT12のスレーブアドレス(0x5c)
while True:
slave_dev_dht12.flush()
read_bytes = slave_dev_dht12.read_from(regaddr=0, readlen=5)
check_sum = 0
# チェックサムの計算
for index in range(len(read_bytes)-1):
check_sum += read_bytes[index]
# チェックサムの比較
if check_sum == read_bytes[len(read_bytes)-1]:
# 湿度の算出
hum = read_bytes[0] + float(read_bytes[1]) * 0.1
# 温度の算出
temp = read_bytes[2] + read_bytes[3] / 10
print("\r" + "温度:{}℃ 湿度:{}%RH".format(temp, hum), end="")
else:
print("\r" + "チェックサムNG", end="")
time.sleep(0.1)
if __name__ == "__main__":
main()
実行結果
温湿度を取得することはできたが課題あり
と表示され、手元の室温計付きのデジタルクロックの温度とも大きな差はありませんでした。
ただ、年数が経過しているセンサーなのか、湿度は10%程低く表示されています。
課題
時折チェックサムNG
の表示が出ていました。
その時のデータを見ると全て0xFFで埋め尽くされていたりしており、正常に取得できていない事があるようです。
ちなみに、Arduino等のマイコンから取得した場合は特にチェックサムでNGになることはなかったので、FT2232Dもしくはpyftdi側の問題である可能性があります。
特にpytftdiのページには下記のように記載されており、
Force unsupported I2C clock signalling on devices that have no I2C capabilities (i.e. FT2232D).
FT2232DでのI2C通信は完全にサポートされていないようです。
※以降は考察になります
本来はハードウェアで生成するクロック信号をソフトウェア処理で生成することでFT2232DでI2Cを扱えるようにしていると思いますが、ハードウェア生成のクロックと違いソフトウェア生成のクロックは精度が良くないので、I2Cの通信仕様におけるクロックの許容誤差を外れてしまった事が原因なのかなと思いました。
このあたりはAPIリファレンスやハードウェアのデータシートを全部読み込んだり、オシロスコープで波形解析等できれば詳しい事は判明してくるとは思いますが、APIリファレンスの中でも注意書きが記載されているという事もあり、この件の課題調査はここまでとします。
結論
- 普通のPCからでもI2C通信でセンサーとのやりとりができる!
- FT2232DでもI2C通信はできるが若干難あり
- 入手性も良くI2CもちゃんとサポートされているFT232Hを使う事を強くお勧めします!
まとめ
以上のことから、デジタルI/Oに続き、センサーとのインターフェースとして多く使われているI2C通信も普通のPCで使えるようになりました。
ただ、普通のPCでGPIOを使えることが開発上必ず有利になるかと言えばそうでもなく、RaspberryPiやJetsonなどメーカーが提供している公式OSの方が、GPIOや各種デバイスがすぐに使えるような仕組みやツールなども用意されており、実はこちらの方が素早くプロトタイピングできる事もあります。
開発の内容や形に応じて適切な選択を取るようにするのが良いと思います。
また、今回の記事がその選択肢の一つになれば幸いです。
Discussion