2016年11月25日金曜日

I2C EEPROM(AT24C1024B)をArduino UnoとNucleo F401RE(mbed)で使う。

1MbitのI2C EEPROMのAT24C1024Bの手持ちがあったのでテストしてみた。

仕様としては、I2C接続で電源電圧は2.5V~5.5VなのでArduinoでもNucleoでも気軽に使える。

書き込みはバイト単位、ページ単位、読み込みはランダムリードとシーケンシャルリードができる。

メモリの構成は、512Page × 256Byteになっていてアドレス指定は17bitで行う。

バイト単位の書き込み


1byte目 デバイス・アドレス ( 0x1010 | A2 | A1 | P0 | W )
2byte目 上位アドレス
3byte目 下位アドレス
4byte目 書き込みデータ

となっていて、1byte目のデバイスアドレスは、0x1010は固定、A2/A1はピンの接続と合わせて指定する(1個だけ使う場合はGNDに落として0を指定すると楽)。アドレス17bitのうち最上位1bitをP0で指定する。

バイト単位の読み込み


読み込みの場合は書き込みの1~3byte目と同じものをWモードで送信してアドレスを指定。4byte目のデータは送らずに、再びSTARTコンディションにしてRモードでデバイスアドレスを送信するとデータが返ってくる仕様。

Arduino


配線図


デバイスアドレスのA1/A2はGNDに落とし、I2CのSCL、SDAは1kΩでプルアップした。

ライブラリはArduinoのPlaygroundの「Arduino AT24C1024 I2C EEPROM Library」を使わせてもらった。(バイト単位の読み書きのみに対応)

http://playground.arduino.cc/Code/I2CEEPROM24C1024
https://github.com/jwhiddon/AT24C1024

ExampleのAT24C1024_EEPROM_Benchmarkをそのまま動作させることができた。全アドレスを読み書きするのでシリアル・コンソールにしばらく何も表示されないが、少し待てば「.」が表示されていく。

シリアル出力結果

AT24C1024 EEPROM Library Benchmark Sketch
--------------------------------
Write By Byte Test:
Writing data:...........................DONE
Total Time (seconds): 722
Write operations per second: 181
--------------------------------
--------------------------------
Read By Byte Test:
Reading data:..
Address: 9265 Should be: 25 Read val: 255
.........................DONE
Total Test Time (secs): 82
Read operations per second: 1598
Total errors: 1
--------------------------------

書き込みは181Byte/s、読み込みは1,598Byte/sで、1バイト読み書きに失敗したようだ。

I2C通信のようす

書き込み

ch1:SDA ch2:SCL

読み込み

Nucleo F401RE(mbed)

配線図


こちらも1kΩでプルアップ。

ライブラリはKenji Araiさんの「AT24C1024」ライブラリ(https://developer.mbed.org/users/kenjiArai/code/AT24C1024/)を使わせてもらった。こちらはページ単位の読み書きにも対応している。

テスト・プログラム main.cpp

#include "mbed.h"
#include "AT24C1024.h"

I2C         i2c(D14, D15);      // SDA, SCL
AT24C1024   at24c1024(i2c);     // Atmel 1Mbit EE-PROM

DigitalOut led1(LED1);

int main()
{
    printf("\r\n*** AT24C1024 Test ***\r\n");

    // Byte Read/Write
    // 
    uint8_t dt = 0x55;
    printf("Byte Write: %02x\r\n", dt);
    at24c1024.write(0, dt);     // write addr=0 data=dt
    wait_ms(5);
    dt = at24c1024.read(0);     // read addr=0
    printf("Byte Read: %02x\r\n", dt);

    // Page Read/Write
    // 
    uint8_t eep_buf[258];
    for (int i = 0; i < 256; i++) {
        eep_buf[i] = i;
    }
    printf("Page Write: 0..255\r\n");
    AT24C_STATUS status = at24c1024.write_page(0x1ff00, eep_buf, sizeof(eep_buf));
    wait_ms(5);
    printf("Status: %d\r\n", status);
    printf("Page Read:\r\n");
    status = at24c1024.read_page(0x1ff00, eep_buf, sizeof(eep_buf));
    printf("Status: %d\r\n", status);
    for (int i = 0; i < sizeof(eep_buf); i++) {
        printf("%d ", eep_buf[i]);
    }
    printf("\r\n");

    while(1) {
        led1 = !led1;
        wait(0.2);
    }
}

AT24C1024のWriteはDATASHEETを見ると5msかかるようなのでwait_ms(5)を入れている。waitをかけないと読み込みに失敗する。また、ページ単位の読み書きのバッファ、はメンバ関数内部でI2C通信用に2バイト使うので258バイト確保する必要がある。データはインデックス0から埋める。

<追記:2016.11.25>

write_page()とread_page()はエラーステータス(AT24C_STATUS)を返しますが、I2C通信がうまくいったかどうかは見ない仕様のようです。AT24C_OK = 0が返ってきても通信が失敗している場合もあります。

</追記>

I2C通信のようす


ch1:SDA ch2:SCL

メモ:


SDカードに比べるとR/Wの速度は遅いが、実装面積が節約できるし値段も安い。1Mbitの品種を使っているが、ベースマシンのデータ保存用ならそんなには必要ない。