こんにちは、ENGかぴです。
ESP32-WROOM-32EはArduino環境で開発できるためEEPROMライブラリを使うことで電源をOFFしてもデータ保持ができます。EEPROMのライブラリを使ってデータの読み書きを行う方法と使用例をまとめています。
ESP32シリーズではEEPROMは非推奨(データシートのペリフェラルにも記載なし)でありFLASHを使うことが推奨されています。Arduino環境でEEPROMを使った開発できるため下位互換としてEEPROMライブラリが実装されています。
ESP32-WROOM-32E開発ボード(秋月電子)を使用しArduino IDEで開発を行います。また、LCDはAQM1602XA-RN-GBW(秋月電子)を使用しています。LCDの使い方については下記記事にまとめています。
Seeeduino XIAOを使ってBME280のデータをLCDに表示する
ESP32-WROOM-32Eで動作確認したことについてリンクをまとめています。
ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方
EEPROMの使い方
ESP32 Dev Module用のスケッチ例にEEPROMが準備されているためスケッチ例を流用しながら使い方をまとめています。
EEPROMライブラリではEEPROMクラスが実装されておりユーザーが定義した領域と予め準備されている領域を使ってEEPROMを使用することができます。
EEPROMの初期設定
//ボードライブラリ更新前の例2.0.0
#include "EEPROM.h"
EEPROMClass MAIN("eeprom1", 0x80); //ユーザー定義のEEP領域
EEPROMClass CHK("eeprom2", 0x80); //ユーザー定義のEEP領域
//ボードライブラリ2.0.3の例
#define EEP_SZ 0x80
EEPROMClass MAIN("eeprom1"); //ユーザー定義のEEPエリア
EEPROMClass CHK("eeprom2"); //ユーザー定義のEEPエリア
EEPROMライブラリを使用するためにEEPROM.hをインクルードします。ユーザー定義のEEP領域を使用する場合はEEPROMClassの変数を定義します。
例ではMAINとCHKを宣言しています。ボードライブラリが2.0.0ではMAINでは領域名を「eeprom1」としサイズを0x80(128バイト)としています。CHKでは領域名を「eeprom2」としてサイズを0x80(128バイト)としています。
ボードライブラリが2.0.3の場合は領域名の指定のみになり、サイズはbegin()関数で指定します。
PR:わからないを放置せず、あなたにあった最低限のスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
EEPROM動作開始
void EepRead(void){
//ユーザー定義の領域を使用する場合
if( !MAIN.begin(EEP_SZ)){
Serial.println("Restarting...");
delay(1000);
ESP.restart();
}
//通常の領域を使用する場合
if( !EEPROM.begin(0x100)){
Serial.println("Restarting3...");
delay(1000);
ESP.restart();
}
}
ユーザー定義の領域を使用する場合と通常の領域を使用する場合どちらも最初にbegin()関数でEEPROMの領域を確定する必要があります。begin()関数で使用するサイズを指定しなかった場合はデータの読み書きができません。
begin()関数の引数に使用したいサイズを指定します。指定するサイズがEEPROMの領域をオーバーすると動作が不安定になるためbegin()でサイズを指定した戻り値でサイズがオーバーしていないかの確認を行っています。
最大のサイズ長については把握していませんが0x1000を超えたあたりからサイズオーバーになることがあります。今回の例では合計で0x2800程度が限界でした。
サイズオーバーした場合は動作が不安定となる可能性があるためリスタートしています。リスタートしてもサイズオーバーすることは変わりがないため繰り返しリスタートしてしまいますが、通常動作中に暴走するよりかはましです。
PR:RUNTEQ(ランテック )- マイベスト3年連続1位を獲得した実績を持つWebエンジニア養成プログラミングスクール
EEPROMのデータを読み込む
void EepRead(void){
uint8_t dat;
uint8_t chk;
//begin()関数
MAIN.get(0,dat);
CHK.get(0,chk);
if(dat == chk){ //二重化チェック
if( dat == 0xFF){
dat = 0;
}
btncntInit = dat;
}
}
get()関数を使用すると第2引数で指定した変数の型に応じた読み込みができます。Read()関数を使用した場合は1バイトデータの読み込みになります。第1引数は読み込みをスタートする位置を指定します。
MAINは「eeprom1」・CHK「eeprom2」の領域に同じデータを書き込んでいます。EEPROMのデータを読み込んだ時データの健全性を確認するために2つの領域のデータを比較しています。
2つのデータが一致する場合はEEPROMのデータが健全であるとみなして変数に格納します。EEPROMのデータはイレースした場合や初期状態では0xFFとなるため0xFFが採用されないようにしています。
PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!
EEPROMへデータを書き込む
void mainApp(void){
if( btncnt != btncntInit){ //データに変更があったか
MAIN.put(0,btncnt); //EEP書き込み準備
MAIN.commit(); //書き込み確定
CHK.put(0,btncnt);
CHK.commit();
//EEPROM.put(0,btncnt);
//EEPROM.commit();
btncntInit = btncnt;
}
}
EEPROMへの書き込みの回数を限定するためデータに変化があった場合のみ書き込み処理に遷移するようにしています。
put()関数を使用すると第2引数の型に応じた書き込みができます。Write()関数を使用した場合は第1引数に指定したアドレスから第2引数に指定したデータを1バイトずつ書き込みます。
put()関数の第1引数は書き込みを開始する位置を指定します。put()やWrite()は書き込み開始ではなく書き込みの準備となるためcommit()関数によってデータを書き込みます。
私の場合は2つのデータでチェックを行った後に範囲チェックする方法でソフト開発を行うことが多いのですがEEPROMがハード的に問題となったことが一度もないため範囲チェックのみ十分だと感じています。
EEPROMの書き込み回数が有限であるため可能な限り不要な書き込みを防ぐことが推奨されます。上の例では2つの変数が不一致であった場合のみEEPROMのデータの書き込みを行うようにしています。
動作確認

ESP32-WROOM-32EのWire(I2C)をLCDに接続しSW1をDIに接続します。SW1を押した回数をLCD上に表示します。SW1を2秒間長押しすると現在のボタンを押した回数をEEPROMに書き込みます。長押しする際もSW1を押した回数がカウントされるためEEPROMに書き込む前にカウント値を-1するようにしています。
EEPROMへの書き込みが終わる(カウントが-1された後)と電源をOFF(モジュール上のリセットボタンでもよい)します。EEPROMに保存されているデータは電源をOFFしても保持されるため次に電源をONしたときにEEPROMのデータの確認を行いデータが消えていないことを確認します。

電源をONすると初期画面が2秒表示されます。メイン処理に遷移すると初期化時に読み込んだEEPROMのデータを表示します。LCDの1段目に「EEP DATA READ:15」と表示されているためEEPROMのデータが読み出せていることが分かります。
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。
関連リンク
Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方
ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方
広告
マイベスト3年連続1位を獲得した実績を持つ実践型のプログラミングスクール
最後まで、読んでいただきありがとうございました。