フォト
2017年3月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
無料ブログはココログ

« IchigoJamの新しいファームウェア 1.2 リリースのようです | トップページ | Arduino(あちゃんでいいの)でmicroSDカード利用の動作確認 »

2016年4月29日 (金)

Arduino(あちゃんでいいの)によるI2C EEPROMのエミュレーション

Arduino(あちゃんでいいの)によるI2C EEPROM エミュレーションをやってみました。

目的はIchigoJamとの連携です。
IchigoJamはプログラム保存デバイスとしてI2C EEPROMをサポートしています。
そのインタフェースを使って「通信をしてしまおう!」という目論見です。

05

IchigoJamからは容量 1kバイトの24系のI2C EEPROM として利用出来ます。
(実際はSRAM上に保存のため ROMではないですが.. 最終的にはSDカードに保存したい)

Arduino の I2Cライブラリ(Wire) のスレーブ実装機能が今一問題ありで苦労しましたが、
何とか出来ました。

接続はこんな感じ。ちなみにArduino として aitendo「あちゃんでいいの」を使っているのは、
3.3V 16MHz稼働で利用出来るからです。

Dscn5124

IchigoJamからはプログラム保存番号100として利用出来ます。
実際に動かしてみるとこんな感じです。

02

起動後、LOAD 0 命令で本体保存プログラムをロードし、SAVE 100 でエミュレーションした
プログラム保存番号100 に保存します。 認識されてちゃん動作しています。

次に FILES 100 命令でファイルリストの表示。100番もちゃんと表示出来ました。
ここでプログラムを消して、プログラム保存番号100 をロードします。

03

ちゃんとロードしました。内容も確認。

04

問題無くロード出来ています。

Arduino側でも保存状態を確認出来ます。

06

メニュー選択でプログラムを表示すると、同じものが保存されているのが分かります。

IchigoJam固有フォントで表示出来ない文字はダンプ表示で確認します。

07

容量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で応答します。

08

この対応としては、write()関数で多めにデータを送信することで対処出来ることが分かりました。
ライブラリ内部ではマスターからNACKを受け取ると送信はそこで終了するようです。
(ロジックアナライザで確認にて確認)

09

プログラムでは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」カテゴリの記事

AVR」カテゴリの記事

IchigoJam」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/571408/63554469

この記事へのトラックバック一覧です: Arduino(あちゃんでいいの)によるI2C EEPROMのエミュレーション:

« IchigoJamの新しいファームウェア 1.2 リリースのようです | トップページ | Arduino(あちゃんでいいの)でmicroSDカード利用の動作確認 »