EEPROM

EEPROM は Atmega328P 等に内蔵されている不揮発性のメモリです。



概要

EEPROM (Electrically Erasable Programmable Read-Only Memory) はその名の通り、書き換えられる ROM です。

マイコン内蔵で手軽に扱える反面、書き換え回数に限度がある (100,000 回程度) ため、ログのような高頻度で書き換える用途には向きません。


容量

Arduino で使える EEPROM の容量は以下のようになっています。

MCU ボード 容量
ATMega8 NG, USBasp 512 bytes
ATMega328P UNO, NANO, Mini 05, Pro Mini 1,024 bytes
ATMega32U4 LEONARDO, MICRO, Pro Micro 1,024 bytes
ATMega2560 MEGA2560 4,096 bytes
ATMega4809 Nano Every 256 bytes


EEPROM ライブラリの使い方

標準ライブラリなので、EEPROM.h をインクルードするだけで使えます。

#include <EEPROM.h>

容量の取得

EEPROM の容量をコードで取得するには、EEPROM.length() を使います。

#include <EEPROM.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);
  int value = EEPROM.length();
  Serial.println(value);  
}

void loop() {

}

また、EEPROM.begin() で開始アドレス、EEPROM.end() で終了アドレスを返すハズなのですが...

#include <EEPROM.h>

void setup() {
  char buf[32] = "";

  Serial.begin(9600);
  while (!Serial);

  sprintf(buf, "Start Address: %04X", EEPROM.begin());
  Serial.println(buf);  
  sprintf(buf, "End Address: %04X", EEPROM.end());
  Serial.println(buf);  
}

void loop() {

}

EEPROM.end() は EEPROM.length() と同じく EEPROM の容量を返します。

メソッド名的には UNO だと 03FF を返して欲しいのですが...。


バイト単位の読み込み

EEPROM の内容をバイト単位で読み込むには、EEPROM.read() を使います。

#include <EEPROM.h>

void setup() {
  uint16_t Address = 0;
  byte CheckSum;
  byte Sums[17];
  char buf[10];

  Serial.begin(9600);
  while (!Serial);

  do{  
    // Header
    Serial.println("Add  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F Sum");
    memset(Sums, 0sizeof(Sums));

    for (int i = 0; i < 16; i++){  
      // Address
      sprintf(buf, "%04X ", Address);
      Serial.print(buf);

      // Data
      CheckSum = 0;
      for (int l = 0; l < 16; l++){
        byte Value = EEPROM.read(Address);
        sprintf(buf, "%02X ", Value);
        Serial.print(buf);
        CheckSum += Value;
        Sums[l] += Value;  
        Address++;
      }
      Sums[16] += CheckSum;  

      // CheckSum (Horizontal)
      sprintf(buf, ":%02X", CheckSum);
      Serial.println(buf);
    }

    // Footer / CheckSum (Vertical)
    Serial.println("--------------------------------------------------------");
    Serial.print("Sum: ");
    for (int i = 0; i < 16; i++){
      sprintf(buf, "%02X ", Sums[i]);
      Serial.print(buf);
    }  
    sprintf(buf, ":%02X", Sums[16]);
    Serial.println(buf);
    Serial.println("");
  } while (Address < EEPROM.length());  
}

void loop() {

}

このコードを実行すると EEPROM の ダンプリストが表示されます。

工学社系のダンプリストですね (w


バイト単位の書き込み (その1)

EEPROM の内容をバイト単位で書き込むには、EEPROM.write() を使います。

#include <EEPROM.h>

void setup() {
  char buf[16] = "";

  Serial.begin(9600);
  while (!Serial);

  // Read
  byte Value = EEPROM.read(0);
  sprintf(buf, "Old Value: %02X", Value);
  Serial.println(buf);

  // Write
  Value++;
  EEPROM.write(0, Value);
  sprintf(buf, "New Value: %02X", Value);
  Serial.println(buf);
}

void loop() {

}

このコードを実行する度に EEPROM の アドレス 0 の値がインクリメントされます。


バイト単位の書き込み (その2)

EEPROM.write() と全く同じ使い方のできる EEPROM.update() というメソッドがあります。こちらは現在の値が書き込もうとしている値と同じ場合には書き込まれません。結果は同じなので、EEPROM の寿命を延ばすには write() ではなく update() を使うといいでしょう。

#include <EEPROM.h>

void setup() {
  char buf[16] = "";

  Serial.begin(9600);
  while (!Serial);

  // Read
  byte Value = EEPROM.read(0);
  sprintf(buf, "Old Value: %02X", Value);
  Serial.println(buf);

  // Write
  Value++;
  EEPROM.update(0, Value); // 値が同じ場合には書き込まれない
  sprintf(buf, "New Value: %02X", Value);
  Serial.println(buf);
}

void loop() {

}

上記コードでは常に値が変化するため、結局は EEPROM.write() と同じ処理になってしまいます。


バイト単位の読み書き

EEPROM.read() / EEPROM.write() は EEPROM[] という演算子で置き換える事ができます。例えば上記コードは以下のようにも記述できます。

#include <EEPROM.h>

void setup() {
  char buf[16] = "";

  Serial.begin(9600);
  while (!Serial);

  // Read
  byte Value = EEPROM[0];
  sprintf(buf, "Old Value: %02X", Value);
  Serial.println(buf);

  // Write
  Value++;
  EEPROM[0] = Value;
  sprintf(buf, "New Value: %02X", Value);
  Serial.println(buf);
}

void loop() {

}

動作は全く同じです。書き込みの際は write() と同じです。


任意の型での読み書き

任意の型での読み書きを行うには EEPROM.get()EEPROM.put() を使います。例えば以下のコードは 32bit 整数を EEPROM のアドレス 0 に読み書きします。

#include <EEPROM.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // Write
  int32_t Value = 0xdeadbeef;
  EEPROM.put(0, Value);

  // Read
  Value = 0;
  EEPROM.get(0, Value);
  Serial.println(String(Value, HEX));  
}

void loop() {

}

EEPROM.put() はバイト単位での EEPROM.update() 相当です。例えば 00 00 00 00 という状態で 00 00 00 01 というデータを put() した場合には、4 バイト目しか書き込まれません。


See Also:



ESP-WROOM-02 の EEPROM

仮想 EEPROM です。begin() / end() メソッドの役割が異なっており、begin() メソッドで容量を指定して使用開始、end() メソッドで使用終了、commit() メソッドでフラッシュ (実際に書き込む) となっています。

#include <EEPROM.h>

void setup() {
  Serial.begin(115200);
  while (!Serial);

  EEPROM.begin(1024); // EEPROM として 1024 バイトを確保して使用開始

  // Write
  int32_t Value = 0xdeadbeef;
  EEPROM.put(0, Value);
  EEPROM.commit(); // 実際に書き込む

  // Read
  Value = 0;
  EEPROM.get(0, Value);
  Serial.println(String(Value, HEX));  

  EEPROM.end(); // 使用終了 
}

void loop() {

}

仮想 EEPROM を使うより SPIFFS を使った方が何かと便利かもしれません。

See Also:



ESP-WROOM-32 の EEPROM

仮想 EEPROM です。ESP8266 版からの移植なので、使い方は ESP-WROOM-02 と全く同じです。

#include <EEPROM.h>

void setup() {
  Serial.begin(115200);
  while (!Serial);

  EEPROM.begin(1024); // EEPROM として 1024 バイトを確保して使用開始

  // Write
  int32_t Value = 0xdeadbeef;
  EEPROM.put(0, Value);
  EEPROM.commit(); // 実際に書き込む

  // Read
  Value = 0;
  EEPROM.get(0, Value);
  Serial.println(String(Value, HEX));  

  EEPROM.end(); // 使用終了 
}

void loop() {

}

特定バージョンの Arduino IDE との組み合わせによっては [-Werror=maybe-uninitialized] のエラーが出てコンパイルできないかもしれません。その場合には以下のトピックを参考に EEPROM.cpp を書き換えてください。

仮想 EEPROM を使うより SPIFFS を使った方が何かと便利かもしれません。

See Also:



STM32F103 の EEPROM

仮想 EEPROM です。ちょっと特殊で put() / get() は使えません。

#include <EEPROM.h>

void setup() {
  Serial.begin(115200);
  while( !Serial );
  while(!Serial.isConnected())
    delay(10);                 

  // Write
  Serial.println("Write Data");
  uint16 Value = 0xbeef;
  EEPROM.update(0, Value);

  // Read
  Serial.print("Read Data: ");
  Value = EEPROM.read(0);
  Serial.println(String(Value, HEX));  
}

void loop() {

}

連続したバイトデータを読み書きするには向いていない気がします。

See Also:


ここにある情報が役に立って、「調べる手間が省けたからオマイに飯でもおごってやるよ」 というハートウォーミングな方がいらっしゃいましたら、下のボタンからどうぞ。

メニュー: