Arduino(あちゃんでいいの)によるI2C EEPROMのエミュレーション
Arduino(あちゃんでいいの)によるI2C EEPROM エミュレーションをやってみました。
目的はIchigoJamとの連携です。
IchigoJamはプログラム保存デバイスとしてI2C EEPROMをサポートしています。
そのインタフェースを使って「通信をしてしまおう!」という目論見です。
IchigoJamからは容量 1kバイトの24系のI2C EEPROM として利用出来ます。
(実際はSRAM上に保存のため ROMではないですが.. 最終的にはSDカードに保存したい)
Arduino の I2Cライブラリ(Wire) のスレーブ実装機能が今一問題ありで苦労しましたが、
何とか出来ました。
接続はこんな感じ。ちなみにArduino として aitendoの 「あちゃんでいいの」を使っているのは、
3.3V 16MHz稼働で利用出来るからです。
IchigoJamからはプログラム保存番号100として利用出来ます。
実際に動かしてみるとこんな感じです。
起動後、LOAD 0 命令で本体保存プログラムをロードし、SAVE 100 でエミュレーションした
プログラム保存番号100 に保存します。 認識されてちゃん動作しています。
次に FILES 100 命令でファイルリストの表示。100番もちゃんと表示出来ました。
ここでプログラムを消して、プログラム保存番号100 をロードします。
ちゃんとロードしました。内容も確認。
問題無くロード出来ています。
Arduino側でも保存状態を確認出来ます。
メニュー選択でプログラムを表示すると、同じものが保存されているのが分かります。
IchigoJam固有フォントで表示出来ない文字はダンプ表示で確認します。
容量1kバイトでは全然実用でないですが、SDカードに保存なんか出来るように
したいと思います。
Arduioのスケッチについて
プログラム的にはArduinoをI2CスレーブにしてEEPROMをエミュレーションしています。
利用しているI2Cライブラリ(Wire)をI2Cスレーブとして使う場合、微妙に機能不足で
若干問題ありです。かなりハマりました。
1)受信バッファの問題
まず、受信バッファが32バイトしかなくEEPROMのような一回のトランザクションで
大量のデータ通信を行うスレーブの実装は無理です。
IchigoJamでは一回のトランザクションで34バイトの通信を行うためギリギリでOUTでした。
仕方がなく、ライブラリのバッファサイズ指定部を32にから64に変更しました。
(2ヶ所修正、詳細はソースに記載)
汎用的なEEPROM機能をエミュレーション出来ず、1回あたり64バイトまでの転送という
制約が付きます。
2)スレーブ時のwrite()関数のマスター応答が取得できない問題
また、EEPROMでは可変長データリードをサポートするのですが、この機能を
Arduinoで実装するにあたり、マスターにデータを渡すのにwrite()関数を使うのですが、
この関数は渡した応答(ACK/NACK)を取得することが出来ません。
ちょっと困った仕様です。
下図はそのパケットの仕様でマスターが次のデータの受信が不要の場合、NACKで応答します。
この対応としては、write()関数で多めにデータを送信することで対処出来ることが分かりました。
ライブラリ内部ではマスターからNACKを受け取ると送信はそこで終了するようです。
(ロジックアナライザで確認にて確認)
プログラムではwrite()関数で常に64バイトを送信していますが、実際にはマスターが
NACKを返した時点で送信は終了します。ちょっと美しくないですね。
ここでwrite()関数が実際に送信したバイト数を返してくれればよいのですが64が帰って
きます。関数のソースを見ると引数の送信バイト数をそのまま復帰値として返すと
いう手抜きをやってくれていました。
何処にもそんな仕様が書かれていないようですし.. まあ、この対処で良しとしましょう。
スケッチ ダウンロード Ichigoepprom.zip (2.0K)
// // I2C EEPROMエミュレーション調査 // 2016/04/26,4/30 Tamakichi // // 注意:このスケッチの動作にはWireライブラリの修正が必要 // 修正箇所 // \libraries\Wire\utility\twi.h #define TWI_BUFFER_LENGTH 32 => #define TWI_BUFFER_LENGTH 64 // \libraries\Wire\Wire.h #define BUFFER_LENGTH 32 => #define BUFFER_LENGTH 64 // #include <Wire.h> #define DEVICE_ADDRESS 0x50 // AT24C1024B I2Cデバイスアドレス #define MYDEBUG 0 // 0:デバッグ表示on(=1)/off(=0) uint8_t buf[1088]; // プログラム保存領域 uint16_t adr; // EEPROM アクセスアドレス // I2Cマスタからのデータ受信ハンドラ void receiveEvent(int len) { uint16_t d1,d2; int n = 0; // アドレス情報取得 d1 = Wire.read(); d2 = Wire.read(); adr = (d1<<8) + d2; adr &= 0x3ff; #if MYDEBUG == 1 Serial.print("adr="); Serial.print(adr,HEX); Serial.write(' '); Serial.println(len,DEC); #endif // 送信されたデータを受信(データがある場合) while (Wire.available()){ buf[adr++] = Wire.read(); if (adr >= 1024) { adr= 0; } } } // I2Cマスタからの要求の処理 void requestEvent() { uint16_t n; uint8_t sts; uint8_t i; #if MYDEBUG == 1 Serial.print("req "); Serial.println(adr,HEX); #endif Wire.write(&buf[adr], 64); } // // 保存プログラムのダンプ表示 // void disp_prog() { uint16_t ptr = 0; // 参照位置 uint16_t nm,n1,n2; // 行番号 uint8_t sz; // 行サイズ Serial.println("Ichigojam program list"); while (1) { n1 = buf[ptr++]; n2 = buf[ptr++]; nm = n1 + (n2<<8); if (!nm) break; sz = buf[ptr]; ptr++; Serial.print(nm,DEC); Serial.write(' '); for (uint8_t i= 0; i < sz; i++) Serial.write(buf[ptr++]); Serial.println(); ptr++; } } // // 書込みデータのダンプリスト // dt(in) : データ格納先頭アドレス // n(in) : 表示データ数 void dump(byte *dt, int n) { unsigned long sz; char buf[64]; int clm = 0; byte data; byte sum; byte vsum[16]; byte total =0; int saddr =0; int eaddr =n-1; sz = eaddr - saddr; Serial.println(F("----------------------------------------------------------")); for (int i=0;i<16;i++) vsum[i]=0; for (unsigned long addr = saddr; addr <= eaddr; addr++) { data = dt[addr]; if (clm == 0) { sum =0; sprintf(buf,"%05lx: ",addr); Serial.print(buf); } sum+=data; vsum[addr % 16]+=data; sprintf(buf,"%02x ",data); Serial.print(buf); clm++; if (clm == 16) { sprintf(buf,"|%02x ",sum); Serial.print(buf); Serial.println(""); clm = 0; } } Serial.println(F("----------------------------------------------------------")); Serial.print(" "); for (int i=0; i<16;i++) { total+=vsum[i]; sprintf(buf,"%02x ",vsum[i]); Serial.print(buf); } sprintf(buf,"|%02x ",total); Serial.print(buf); Serial.println(""); Serial.println(""); } // セットアップ void setup() { adr = 0; Serial.begin(115200); Wire.begin(DEVICE_ADDRESS) ; // I2Cの初期化、自アドレスをA0とする Wire.onRequest(requestEvent) ; // I2Cコマンド要求割込み関数の登録 Wire.onReceive(receiveEvent) ; // I2Cデータ受信割込み関数の登録 Serial.println("start"); } // メイン処理 void loop() { byte c; Serial.print(F("Menu(1:disp 2:dump 3:init) =")); while ( !Serial.available() ); c = Serial.read(); if (c == '1') { Serial.println(); disp_prog(); } else if (c == '2') { Serial.println(); dump(buf, 1024); } else if (c == '3') { Serial.println(); adr = 0; for (uint16_t i = 0; i < 1088; i++) buf[i] =0; } else { Serial.println(); } }
« IchigoJamの新しいファームウェア 1.2 リリースのようです | トップページ | Arduino(あちゃんでいいの)でmicroSDカード利用の動作確認 »
「arduino」カテゴリの記事
- Arduino IDE+Arduino STM32環境で指定と異なるgccが使われてしまう(2025.01.23)
- Zorin OSでArduino Uno互換機(CH340)が認識しない(2025.01.19)
- Arduino IDE 2.3.4でArduino STM32を利用する(2025.01.12)
- Arduino用 SKK日本語変換ライブラリの開発 その1(2024.12.28)
- NeoPixel(WS2812B)の制御 その5(2024.09.15)
「AVR」カテゴリの記事
- NeoPixel(WS2812B)の制御 その5(2024.09.15)
- Arduino用SJIS漢字フォントライブラリ SDカード版を作成しました(2018.10.30)
- ATtiny13AでI2C接続キャラクタLCDを利用する(4)(2018.04.16)
- ATtiny13Aで赤外線リモコン受信センサーを使う(2)(2018.04.15)
- ATtiny13AでHC-SR04を使った距離計測(2018.04.14)
「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)
« IchigoJamの新しいファームウェア 1.2 リリースのようです | トップページ | Arduino(あちゃんでいいの)でmicroSDカード利用の動作確認 »
コメント