ちょっとググってもいい感じのドキュメントが見つからず難儀したので、Perl でやるならこれで!! って感じで、コピペして使えるようなサンプルコードを書きました
社内でちょっと喋る必要があったので資料もあります (公開しても良さそうなように資料をつくってあります)
ちょっとググってもいい感じのドキュメントが見つからず難儀したので、Perl でやるならこれで!! って感じで、コピペして使えるようなサンプルコードを書きました
社内でちょっと喋る必要があったので資料もあります (公開しても良さそうなように資料をつくってあります)
なんかうまく AVR だと動かなかったりしたので、カっとなってテストを充実させた。(動くようになった)
とはいえ、コード上でテストだけ書いてもよくわからないので、可視化させながらやった。つまり時系列にバスの動きをシミュレーションできるようなコードを書いた。Ruby で cairo が結構かんたんに使えたので良かった。Time.now によってグラフを書いているので、多少ゆらぎがある。しかしこうすることで、意図せず状態を変えてしまっているのが一目でわかるようになったので大変役にたった。
例えば、i2cset のテストの場合
i2cget のテストの場合
見ての通り get のほうが複雑、というのも get するためにどのアドレスを get するかを書かないといけないから……
テストと同じデータの送受信 (対 AVR)。波形を綺麗にするために速度を 1kHz 程度に制限して (周辺処理に時間がかかるので最終的に400Hz程度だけど) sleep をちゃんと入れるようにしている。速度は下がるけど波形は綺麗になる。時間の単位さえ気にしなければ I2C 動いてる感がある。
AVR 向けだと repeated start condition を発行したとき AVR がハングする問題があって、解決方法がわからないので stop condition を常に挟むように実装を変えた。MPL115A2 だと普通に動くんだけど……
普通の 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
コードは以下の通りだけど、けっこう時間がかかった割にはコードサイズはそうでもない。
普通に仕様通りに実装するだけだけど、いくつか問題があった
I2C は Standard-mode でも 100kbit/s を規定してるので、全く届いていない。ただ、I2C はマスターが常に生成するクロックラインを持っていて、クロックが High のときだけデータが有効という感じで、大抵のデバイスはデータシート上では対応クロックを 0 〜 100kHz とか 0 〜 400kHz とかで書いてあるので、動くものは動くはず…… MPL115A2 というデバイスでは動いてくれた。
もちろんマスターとしてしか動かない。また、調停とかも実装してない。
ループ展開とかいろいろやったけど、多少改善はするものの、上記の通りのスピードは超えることができないので、諦めて可読性優先で富豪的に書いてある。
CPU 特化のネイティブなライブラリを使えば当然早くはなるんだけど、今回 sysfs 経由で抽象化された gpio でなければやる意味がないなと思ってやってない。
GPIO export 直後の EACCESS はよくわからなくて、pi を gpio グループに入れてやってるせいかもしれない。ただ、時間が経てばアクセスできるようになるので (たぶん sysfs がバグってる感じがするって人のせい的に書いといたら、カっとなって誰か調べてくれそう)、EACCESS を rescue して retry かけている。
direction を単純に "out" に設定すると、たぶん active_low に従って初期状態が設定されると思うんだけど、うっかり SCL ラインを High にしてしまうとその後困ったことになるので、アトミックに direction 切り替え + ピンの High 又は Low 設定を行う必要がある。
しばらくわからなかったんだけど、普通に direction に対して "high" や "low" を書きこむと、初期状態が指定した状態の "out" になるみたいだった。
Locale::Maketext::Extract::Plugin 以下にはいろいろ対応してるフォーマットがあったりする。まぁ大抵一緒なので頑張って使う必要もないけど、これらを使って .po ファイルを作らないまでも、msgid の抽出だけ行いたいという場合があったりします。そんなときは直接 LME インスタンスを作って extract_file をかけて compile すれば、とれるようになるみたいです。
use Locale::Maketext::Extract;
use Locale::Maketext::Extract::Plugin::Xslate;
use File::Zglob;
my $lme = Locale::Maketext::Extract->new(
plugins => {
perl => [ 'pm' ],
xslate => {
syntax => 'TTerse',
extensions => [qw/ tt /],
},
generic => [ 'js' ]
},
warnings => 1,
verbose => 0,
);
for (zglob('lib/**/*.pm'), zglob('template/**/*.tt'), zglob('static/**/*.js')) {
$lme->extract_file($_);
}
$lme->compile(1); # これをしないと msgids がとれない
for my $msgid ($lme->msgids) {
say $msgid;
$lme->msg_positions($msgid); # 見つかった場所がとれる
}
Ruby から Linux の i2c-dev 経由でデバイスを操作するライブラリを適当に書いた。
比較的汎用的な I2CDevice クラスと、サブクラスとして特定デバイス用のものをいくつかまとめた。汎用クラスはそんな重要ではなくて、特定デバイスの操作を纏めるのを主な目的とする感じ……
デバイスごとのドライバを必要になり次第書いておいていく感じにするつもりなので (そんなに増えないと思うけど)、rubygems としてはアップロードしてない。
GPIO でのインターフェイスを追加して、gem にあったほうが便利な気がしてきたので、gem push しました。https://rubygems.org/gems/i2c-devices
今のところあるのは