GPIO (sysfs) を使ったソフトウェア I2C
普通の GPIO 経由で I2C できたらなんとなく嬉しいかなと思って作ってみた。つまりソフトウェアでピン状態をいじって I2C 通信するというもので、いわゆる bit banging というやつです。
[tech] Ruby の I2C ライブラリ | Sun, Feb 16. 2014 - 氾濫原 で I2C ライブラリを書いたけど、これは i2c-dev という Linux 組込みのドライバを使ったもので、ハードウェアが持ってる I2C の機能を使うので、もしハードウェアに I2C がない場合 (普通あるけど) で、GPIO はあるという場合に使えることがあるかもしれません。
使いかた
最終的には以下のような感じで使えるようになった。もちろん Raspberry Pi には I2C ついてるのでこんなことする必要は全くない。
require "i2c/device/mpl115a2"
require "i2c/driver/gpio"
mpl = MPL115A2.new(address: 0x60, driver: I2CDevice::Driver::GPIO.new(
sda: 23, # pin 16 in raspberry pi
scl: 24, # pin 18 in raspberry pi
))
p mpl.calculate_hPa 実装
コードは以下の通りだけど、けっこう時間がかかった割にはコードサイズはそうでもない。
普通に仕様通りに実装するだけだけど、いくつか問題があった
- sysfs 経由のピン状態書きかえが非常に遅い
- C + sysfs だと5KHz 程度 (Raspberry Pi 上)
- Ruby + sysfs だと 1.2kHz 程度 (Raspberry Pi 上)
- GPIO export 直後に EACCESS (パーミッションエラー) がでる
- GPIO direction 直後での初期状態
遅い
I2C は Standard-mode でも 100kbit/s を規定してるので、全く届いていない。ただ、I2C はマスターが常に生成するクロックラインを持っていて、クロックが High のときだけデータが有効という感じで、大抵のデバイスはデータシート上では対応クロックを 0 〜 100kHz とか 0 〜 400kHz とかで書いてあるので、動くものは動くはず…… MPL115A2 というデバイスでは動いてくれた。
もちろんマスターとしてしか動かない。また、調停とかも実装してない。
ループ展開とかいろいろやったけど、多少改善はするものの、上記の通りのスピードは超えることができないので、諦めて可読性優先で富豪的に書いてある。
CPU 特化のネイティブなライブラリを使えば当然早くはなるんだけど、今回 sysfs 経由で抽象化された gpio でなければやる意味がないなと思ってやってない。
EACCESS
GPIO export 直後の EACCESS はよくわからなくて、pi を gpio グループに入れてやってるせいかもしれない。ただ、時間が経てばアクセスできるようになるので (たぶん sysfs がバグってる感じがするって人のせい的に書いといたら、カっとなって誰か調べてくれそう)、EACCESS を rescue して retry かけている。
direction 直後の状態
direction を単純に "out" に設定すると、たぶん active_low に従って初期状態が設定されると思うんだけど、うっかり SCL ラインを High にしてしまうとその後困ったことになるので、アトミックに direction 切り替え + ピンの High 又は Low 設定を行う必要がある。
しばらくわからなかったんだけど、普通に direction に対して "high" や "low" を書きこむと、初期状態が指定した状態の "out" になるみたいだった。
関連エントリー
- Raspberry Pi のローレベル周辺機器の電源を特定プロセスが動いているときだけオンにする GPIO ピンからとれる電源は普通に電源回路直結なので、Raspberry Pi 自体が起動していようがしていまいが、電源ケーブルさえ接続さ...
- Ruby で sysfs 経由での GPIO 操作 GPIO の操作はいろいろやる方法があるみたいだけど、LL からだと sysfs への IO を行うのが一番簡単っぽい。以下のような感じでか...
- Linux 上の LL で I2C する (Ruby) なんとなく i2c-dev.h とかで定義されているAPIを呼ばないと使えないのかなあと思っていたけど、デバイスファイルの読み書きと ioc...
- Node.js の fs モジュールだけで GPIO の割込みを扱うには? 以下のようにすれば動くことが確認できた。 select や poll を明示的に呼び出すことができないが、edge を設定しさえすれば fs...
- 続・GPIO (sysfs) を使ったソフトウェア I2C なんかうまく AVR だと動かなかったりしたので、カっとなってテストを充実させた。(動くようになった) とはいえ、コード上でテストだけ書いて...