Arduinoで実験 (外部EEPROM (I2C))

2013/05/06


◆ I2C 制御の EEPROM の の取り扱い。

既に I2C 制御でキャラクタ液晶の表示を行っているので、コマンドの書込みは学習している。 ディスプレイなどのデバイスはだいたい I2C アドレスが決められているので、この液晶ならアドレスは○○番と何も考えずに設定すればよかったが、EEPROM 等で同じデバイスを複数接続する場合があります。 たとえば 16kバイトの EEPROM を 4つ使って 64kバイトとして扱うような場合です。

ここでは秋月で購入した I2C 制御の EEPROM  24LC1025 を使用してみます。

24LC1025 は 1Mビット(128kバイト)の大容量なので EEPROM のアドレス全てを 2バイトで表現することができません。 そのため I2C アドレスを設定する A0 ~ A2 ピンのうち A2 ピンを HIGH 又は LOW とすることで 1ビット付加させ 128kバイトを表現します。単純に 2つの I2C デバイスをアドレスを変えて制御すると考えた方が解りやすいです。

24LC1025 の他に 64kビット(8kバイト)や512kビット(64kバイト)のものがありこちらは I2C アドレスが A0 ~ A3 ピンで指定したアドレスとなります。

このシリーズは、 3.3V、5V どちらでも動作するので Arduino で簡単に取り扱う事ができます。

WP は HIGH で書込み禁止となりますが、一般的には GND へそのまま配線しておきます。

以下は A0 ~ A3 ピンのアドレスのパターンです。 アドレスが競合しないようなら全て GND にした方が配線が楽になります。

ピン アドレス
0x 1010(A2)(A1)(A0) 7ビット
A2 A1 A0
LOW LOW LOW  0x 1010000 = 0x50 
LOW LOW HIGH  0x 1010001 = 0x51 
LOW HIGH LOW  0x 1010010 = 0x52 
LOW HIGH HIGH  0x 1010011 = 0x53 
HIGH LOW LOW  0x 1010100 = 0x54 
HIGH LOW HIGH  0x 1010101 = 0x55 
HIGH HIGH LOW  0x 1010110 = 0x56 
HIGH HIGH HIGH  0x 1010111 = 0x57 

6番ピンのSLCを Arduino の A5 に、5番ピンの SDA を A4 に配線します。 1kΩ ~ 3kΩ 程度のプルアップ抵抗を入れる方がよいのですが、ATmega328P の内部プルアップで特に問題が起きていないので実験の段階ではプルアップはしません。どうしてもデータのロストが怖ければ教科書どおりにプルアップ抵抗を入れておいた方がよいでしょう。


◆ I2C 制御の書込みと読込み

1バイトの書込み命令と、1バイトの読込み命令を作ります。 I2C はマイコンの速度に比べかなり通信速度が遅いので十分な待機時間を設ける必要があります。 速度的に不都合がある場合は SPI 制御の EEPROM を使用する手もありますが、結局書込みに要する時間が必要なので余り意味がありません。

個々の命令については Arduino 日本語リファレンスを参考にしてください。

書込みについては、初めにデバイスへ書き込みアドレスを送信します。 後に続くデータを順に書き込んでゆきます。

読み込みについては読込みの先頭アドレスを送信後、読込みバイト数を指定しデータが送信されるのを待ちます。

//
// 13-01 I2C による外部 EEPROM 制御の実験スケッチ
//

#include <Wire.h>

#define I2C_addr 0x50  // EEPROM の I2C アドレス


void setup() {
  Serial.begin(9600);  // モニタ用にメッセージを出力
  Serial.println("EEPROM Test Start");

  Wire.begin(0);       // I2C マスターに設定  
}

void loop() {
}

// 1バイト書込み関数
void eprWriteByte(int addr, byte b) {
  int ans;

 Wire.beginTransmission(I2C_addr);
  Wire.write(highByte(addr));
  Wire.write(lowByte(addr));
  Wire.write(b);

  ans = Wire.endTransmission;

  delay(5);
}

// 1バイト読込み関数
byte eprReadByte(int addr) {
  byte ret;

 Wire.beginTransmission(I2C_addr);
  Wire.write(highByte(addr));
  Wire.write(lowByte(addr));
  Wire.requestFrom(I2C_addr, 1);

  while (1) {
    if (Wire.available()) {
      ret = Wire.read();
      break;
    }
  }

  delay(5);
  return (ret);
}

上記のように 1 バイトずつ書込み命令を与えてゆくとデータ数分だけ書込み回数がカウントされるの早く寿命がきてしまいます。まとまったデータを書き込む際には書き込みの先頭アドレスを指定後、連続してデータを送ると続けてデータを書き込むことができます。

Arduino の Wire ライブラリは 32 バイトのバッファを持っているので最大 32 個のデータを送信することができます。

送信完了は Wire.endTransmission の戻り値で完了を確認できます。 寿命がきて書き込みができなかった場合などを想定しなければならない場合などはキチンとエラー処理を付けておいた方がよいかもしれません。

24LC1025 を使用する際には I2C アドレスを 2つ用意しておき切り替えて使用するか、書込み/読込みアドレスで判断して I2C アドレスを切り替え使用します。

思ったような値が書込み/読込み出来なかった場合にはタイミングを疑ってみてください。 delay 関数等で余裕をもった待機時間を設けないと思ったような動作ができない場合があります。