2015年10月1日木曜日

RaspberryPiでラズベリー栽培 I2CでセンサをコントロールするスケッチVer1.0

I2C通信がまれによくIOError: [Errno 5] Input/output errorを出していた原因がわかったので、いろいろ変更を加えてI2CsensorHUB Ver1.0としました。
ソースコードはこちらからDLできます。→https://gist.github.com/PiTshan/5025d7ba2e5985db494f
RaspPi側のPythonスクリプトはこちらです。→https://gist.github.com/PiTshan/49e4ec32120039a7645f

ちなみに、待機電流は現時点で36mAくらい。基板上のチップLEDと、USBインターフェイスを取り除けば、5mAくらいまで落とせそうです。

●結局、原因は?
Arduinoの仕様というべきか、PWMのせいだったみたいです。
Arduinoは複数のPWMを実装するために、Timer0のオーバーフロー割り込みを使っているものと思われます。(思われますというのは、ソースを確認したわけではないからです。途中でめんどくさry)
で、I2C通信中に偶然にもPWMの割り込みが入ってしまい、割り込みプライオリティの低いI2Cのほうが中断され、通信が途切れたために起こっていたようです。
なので、Wire.begin(SLAVE_ADDRESS)のあとに
TIMSK0 = 0;
を追加してタイマー割り込みを停止させることで解決しました。

従って、PWMの機能は無効になりますが、sensorHubではディジタルピンをPWMとして使用しないため問題ありません。

●PWMが使いたい場合
Timer0、Timer1、Timer2を使って、ハードウェアPWM(Timerモジュールを使ったPWM)を使うと実現できると思います。
OC0A(AIN0、ArduinoのA0)、
OC1A(PB1、PCINT1, ArduinoのDigital9)、
OC2A(PB3、MOSI、PCINT3, ArduinoのDigital11)
ピンにPWM出力することが出来ます。(試してないけど)
ただし、ライブラリがなければ、Timerのコントロールレジスタに直接設定しないといけないので面倒です。
ほかにもいくつかI2CとPWMを両方実装する方法を考えてはみましたが、めんどくさいので今度やります。(やらないかもしれません)


そのほかの修正

●内部プルアップを無効に
あまり問題ではないと思いますが、WireライブラリではSDA、SCLピンの内部プルアップを強制的に有効にしています。が、すでにRaspPiの基板上でチップ抵抗でPullUpされているので必要ありません。(むしろ内部プルアップは無いほうがいい)
Wire.begin(SLAVE_ADDRESS)のあとに
digitalWrite(SDA, 0);
digitalWrite(SCL, 0);
を追加しました。

●レジスタマップを変更
コントロールレジをまとめ、シーケンシャルにアクセスするような並びにしました。レジスタアドレスの0x00から順番にアクセスしていけばADCの値を得ることができます。

●デバイスディスクリプションとか
0x10~0x13にアクセスすると、SHUBのテキストが得られます。これでSMBusの接続が上手くいってるのか確認できます。(今までは電源投入時はAllZeroだった)

●ReadOnly
コントロールレジスタ、ADCVALUEレジスタ以外は全てReadOnlyとしました。いちおうレジスタ領域は確保したままですが、何かの機能を付け足すために、将来的に削るかもしれません。


ATmega48に移植できるかもしれない
スケッチのコンパイル結果は、
プログラムストレージ領域3118Byte
グローバル変数481Byte
となっています。ATmega48に移植できるかもしれません。(面倒だからやりません!)
ちなみに、ATmega328 250円、 ATmega48 QFPパッケージ 150円
DIPパッケージはもう売ってないようです


0 件のコメント:

コメントを投稿