IchigoJamとArduinoでI2Cバス通信を試してみる
IchigoJamとArduino間でI2Cバスを使ってデータ通信を試してみました。
Arduinoをスレーブとして接続し、マスタであるIchigoJamからの要求に答えます。
先に結論をいうと、ArduinoのI2Cライブラリ Wireにバグがあるため、
Arduinoをスレーブとして完全に使い込むことは出来ません。
ライブラリの修正が必要となります。
=> 2016/05/36 追記
バグは1.6.6で対応されているようです。
よって、本記事の内容はArduino IDE 1.6.5までのお話しです。
また、ArduinoのSDA/SCL端子はプルアップ抵抗有効化されているため
回路図の2.2kΩ抵抗は無くても動作します。
まずは、正常に動作するIchigoJamからArduinoにデータを送信するパターンの
動作確認です。
1)IchigoJamからコマンド2バイト+データ4バイトをArduinoに送信する例
IchigoJam側のプログラム(I2Cマスタ)
10 'send data
20 POKE #700,1,2
30 POKE #702,3,4,5,6
40 R=I2CW(#10,#700,2,#702,4)
50 ?R
60 END
#700番地から格納されている2バイトデータ 1, 2 をコマンド、
#702番地から格納されている4バイトデータ 3,4,5,6 をデータとして
I2Cアドレス #10(7ビット)に送信します。
Arduinoのプログラム
#include <Wire.h> // マスターからを受信 void receiveEvent(int n) { byte d; Serial.println("recept data"); for (int i=0; i < n; i++) { if(Wire.available()) { d = Wire.read(); Serial.print(d,HEX); Serial.print(" "); } Serial.println(); } } //セットアップ void setup() { Serial.begin(115200); Wire.begin(0x10) ; // I2Cの初期化、自アドレスを10とする Wire.onReceive(receiveEvent) ; // マスタからのデータ送信対応のコールバック関数登録 Serial.println("i2c slave test"); } void loop() { }
I2Cアドレスとして#10を設定し、データ受信時に呼び出されるコールバック関数
recevEventを登録し、その関数内でデータを表示しています。
実行結果
IchigoJam側
正常終了しました。
arduino側も受信したデータを問題なく表示しました。
次に問題のIchigoJamからのデータ取得要求について試してみます。
IchigoJamでArduinoから送られてくるデータを受信するパターンです。
2)IchigoJamでArduinoからのデータを受信する
具体的な例としてはEEPROMからデータを取得するような通信です。
一回の通信で、IchigoJamからI2Cアドレスとデータを送信し、Arduino側からの
送信データを受信するパターンです。
IchigoJam側のプログラム
#700番地から格納されている2バイトデータ 1, 2 をコマンド、
#702番地から4バイト分がスレーブから受信データを格納する領域として指定、
I2Cアドレス #10(7ビット)にデータをリクエストします。
Arduino側のプログラム
#include <Wire.h> // マスターからを受信 void receiveEvent(int n) { byte d; Serial.println("recept data"); for (int i=0; i < n; i++) { if(Wire.available()) { d = Wire.read(); Serial.print(d,HEX); Serial.print(" "); } Serial.println(); } } // マスターからのリクエストに対するデータ送信 void requestEvent() { Serial.println("resept request."); Wire.write("Hello"); } //セットアップ void setup() { Serial.begin(115200); Wire.begin(0x10) ; // I2Cの初期化、自アドレスを10とする Wire.onRequest(requestEvent) ; // マスタからのデータ取得要求のコールバック関数登録 Wire.onReceive(receiveEvent) ; // マスタからのデータ送信対応のコールバック関数登録 Serial.println("i2c slave test"); } void loop() { }
データ取得要求に対して、requestEvent()で応答を返します。
これを実行すると
IchigoJamにデータが返されず、通信もエラーとなります(Rの値が0でない)。
Arduino側のターミナル出力にはrequestEvent()で記述しているメッセージが
表示されません。
ロジックアナライザで調べてみると、
2バイトのデータ送信後、受信に切り替えるリピートStart+I2Cアドレス送信が
うまくいってないようです。
当初、原因が分からなかったのですが、Arduino側が明らかにおかしいと判断し、
I2Cライブラリ Wireを調べると、原因がわかりました。
\libraries\Wire\utility\twi.cのISR(TWI_vect)のリピートStartの処理で次のようなことを
行ています。
case TW_SR_STOP: // stop or repeated start condition received // put a null char after data if there's room if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ twi_rxBuffer[twi_rxBufferIndex] = '\0'; } // sends ack and stops interface for clock stretching twi_stop(); // callback to user defined callback twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); // since we submit rx buffer to "wire" library, we can reset it twi_rxBufferIndex = 0; // ack future responses and leave slave receiver state twi_releaseBus(); break;
TW_SR_STOPはSTOPまたは、リピートSTARTを受信時に処理を行う箇所です。
この中で、リピートSTART受信のため、直前に受信したバッファ内データを
twi_onSlaveReceive()を実行してrecevEvent()を呼び出しています。
これにより、IchigoJamからの送信データは受信できます。
その後の処理が問題でこのタイミングでtwi_stop()を実行しています。
明らかにおかしいと思い、色々と調べると、同様のことを指摘している情報が
いくつかありました。次のリンクはその一つです。
上記の文書では、twi_stop()をコメントアウトすることで対応可能と書かれています。
実際にやってみると、
正常に動作しました。
Arduino側のモニター出力にも正常に呼び出されたメッセージが表示されました。
ということで、ArduinoのI2Cライブラリのスレーブ処理にはバグがあります。
最新版の1.6.4でも試したのですが、いまだに対処されていないようです。
なぜ、対応されないのでしょうね。まあ、スレーブとして使うことはあまりないですからね。
2016/04/30 追記
上記のバグは1.6.6で対応されているようです。
リリースノートの抜粋
下記は1.6.8(現時点最新版)
\Arduino 1.6.8\hardware\arduino\avr\libraries\Wire\src\utility\twi.cのISR(TWI_vect)
case TW_SR_STOP: // stop or repeated start condition received // ack future responses and leave slave receiver state twi_releaseBus(); // put a null char after data if there's room if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ twi_rxBuffer[twi_rxBufferIndex] = '\0'; } // callback to user defined callback twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); // since we submit rx buffer to "wire" library, we can reset it twi_rxBufferIndex = 0; break;
« 書籍「挿すだけ!ARM32ビット・マイコンのはじめ方」を購入 | トップページ | IchigoJamとArduinoでI2Cバス通信を試してみる (2) »
「arduino」カテゴリの記事
- Arduino UNO R4 WiFiに関するメモ(2024.03.21)
- Arduino用 美咲フォントライブラリを更新しました(2024.03.21)
- Arduino用ライブラリの自作用のメモ(2024.03.18)
- 豊四季Tiny Basic for micro:bit のマニュアルを更新しました(2020.11.21)
- 豊四季タイニーBASIC for Arduino 機能拡張版 V0.08の更新(2020.07.27)
「IchigoJam」カテゴリの記事
- Ichigojam Rが届きました(2021.02.05)
- β版 IchigoJam Rを予約注文しました(2021.01.23)
- IchigoJamのファームウェア 1.4.1が正式に公開されました(2019.12.10)
- 「ichigoツール」をGithubにて公開しました(2019.11.09)
- ichigojamのファームウェアを1.4b13にアップデートしました(2019.11.06)
« 書籍「挿すだけ!ARM32ビット・マイコンのはじめ方」を購入 | トップページ | IchigoJamとArduinoでI2Cバス通信を試してみる (2) »
コメント