概要
EEPROM(Electrically Erasable Programmable Read-Only Memory: 電気的消去・書き込み可能ROM)は、電気的に読み書き・消去ができる不揮発性半導体メモリです。電源を切ってもデータを保持し、バイト単位での消去・書き込みが可能な点が最大の特徴です。
組み込みシステムでは、工場出荷時のキャリブレーション値・設定パラメータ・機器固有ID(シリアル番号・MACアドレス)・ユーザー設定など、少量だが永続的に保持したいデータの格納に使われます。容量は数バイト〜数十KBと小さく、フラッシュメモリより大容量ですが、バイト単位の書き換えが自由な点で優れています。
インターフェースはI2C(最も一般的)・SPIの2種類が主流で、MCUから簡単に接続できます。Microchip(旧Atmel)の24シリーズ(I2C)・25シリーズ(SPI)が広く使われています。また、マイコン内蔵EEPROMを持つ製品(AVRシリーズ等)も存在し、追加コンポーネントなしでデータ保存が可能です。
歴史・背景
EEPROMの前身は1956年に開発されたPROM(Programmable ROM)、続いて紫外線で消去するEPROM(UV-EPROM)です。EPROMは消去に紫外線を当てる必要があり、窓付きセラミックパッケージが特徴的でした。
1978年にIntelがE2PROM(Electrically Erasable PROM)を発表し、電気的にバイト単位での消去・書き込みが可能になりました。当初は高価でしたが、製造技術の向上とともに価格が下がり、1980年代〜1990年代に産業機器・家電・自動車の設定保存メモリとして広く普及しました。
1990年代、フラッシュメモリがEEPROMの市場を侵食しはじめましたが、EEPROMはバイト単位書き換え・高信頼性・小容量・低消費電力という特性を維持し、設定値保存という特定ニッチ用途で生き残っています。
現代では多くのマイコンがフラッシュのEEPROMエミュレーション機能を持ちますが(STM32のEEPROM Emulation Library等)、専用EEPROMは独立してデータを保持できること・マイコンと電源を分離できることから、重要設定値の格納に引き続き使われています。
技術仕様
主要仕様
| 項目 | 典型値 | 備考 |
|---|---|---|
| 容量 | 128B〜2MB | よく使われるのは1KB〜64KB |
| 書き込み時間 | 1〜10ms/ページ | ページ単位で発生 |
| 書き込みサイクル | 1,000,000回以上 | バイト単位書き換え |
| データ保持期間 | 40〜100年 | 常温保管時 |
| 動作電圧 | 1.7V〜5.5V | 製品により異なる |
| インターフェース | I2C(100kHz〜1MHz)、SPI(最大20MHz) | - |
| ページサイズ | 8B〜256B | ページ書き込みで高速化 |
I2C EEPROMのアドレス構成
Microchip AT24Cシリーズ(I2C EEPROM)のアドレス:
7ビットI2Cアドレス構成:
1 0 1 0 | A2 A1 A0
↑固定 ↑ピンで設定
A2・A1・A0ピンをH/Lにすることで最大8個(アドレス 0x50〜0x57)を同一バスに接続可能
代表的なEEPROM製品
| 製品 | 容量 | I/F | ページ | メーカー |
|---|---|---|---|---|
| AT24C01 | 128B | I2C | 8B | Microchip |
| AT24C32 | 4KB | I2C | 32B | Microchip |
| AT24C512 | 64KB | I2C | 128B | Microchip |
| AT25010 | 128B | SPI | 8B | Microchip |
| M95256 | 32KB | SPI | 64B | STMicro |
| CAT24C256 | 32KB | I2C | 64B | onsemi |
動作原理
セル構造(FLOTOX: Floating Gate Tunnel Oxide)
EEPROMセルはフローティングゲートMOSFETをベースとしますが、NORフラッシュとは異なりトンネル酸化膜を薄くして(約10nm)、低電圧でのFowler-Nordheimトンネリングを実現しています。これによりバイト単位の消去・書き込みが可能です。
コントロールゲート
|
薄いトンネル酸化膜(〜10nm)
|
フローティングゲート
|
フィールド酸化膜
|
ソース ─────── ドレイン
基板
書き込み・消去サイクル
消去(バイト単位): コントロールゲートにGNDを、ドレインに高電圧(〜20V)を印加してフローティングゲートの電子を引き抜く。
書き込み(プログラム): コントロールゲートに高電圧を、ドレインにGNDを印加してフローティングゲートに電子を注入する。
EEPROMの高電圧は内部チャージポンプで生成するため、外部から5V(または3.3V)供給するだけで書き込みが可能です。
I2Cによるアクセス手順
書き込みシーケンス(ページ書き込み):
START → デバイスアドレス(W) → ACK → アドレスH → ACK → アドレスL → ACK
→ データ0 → ACK → データ1 → ACK → ... → STOP
読み出しシーケンス(ランダム読み出し):
START → デバイスアドレス(W) → ACK → アドレスH → ACK → アドレスL → ACK
START → デバイスアドレス(R) → ACK → データ0 → ACK → データ1 → NACK → STOP
書き込み後は内部書き込みサイクル(〜5ms)が必要で、この間はI2Cアクセスを受け付けません(ACKポーリングで書き込み完了を確認)。
用途・ユースケース
設定値・キャリブレーション値の保存
センサーのオフセット・ゲイン・温度補正係数など、工場出荷時に書き込み現場では変更しない値をEEPROMに格納します。電源断でも値が保持されるため、起動時にEEPROMから読み出して使います。
// I2C EEPROM 読み書き例(STM32 HAL)
#define EEPROM_ADDR 0xA0 // AT24C32 デバイスアドレス (A2=A1=A0=0)
#define CAL_OFFSET 0x00 // キャリブレーション値の格納先
// 書き込み(4バイト)
uint8_t txBuf[6] = {0x00, 0x00, 0x12, 0x34, 0x56, 0x78};
// [0][1]: メモリアドレス, [2..5]: データ
HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, txBuf, 6, HAL_MAX_DELAY);
HAL_Delay(10); // 書き込み完了待ち(tWR)
// 読み出し
uint8_t addrBuf[2] = {0x00, 0x00};
uint8_t rxBuf[4];
HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, addrBuf, 2, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDR | 0x01, rxBuf, 4, HAL_MAX_DELAY);
機器固有情報の格納
製造番号・MACアドレス・デバイスIDなど機器ごとに異なる固有情報をEEPROMに格納します。製造ラインでEEPROMに書き込み、起動時にマイコンが読み出して使用します。
// MACアドレス格納アドレス(例)
#define MAC_ADDR_EEPROM_OFFSET 0x10 // 6バイト
uint8_t mac[6];
eeprom_read(MAC_ADDR_EEPROM_OFFSET, mac, 6);
RTCバックアップデータ
RTC(リアルタイムクロック)モジュール(DS3231・PCF8563等)にはEEPROMが内蔵されており、時刻精度補正値・アラーム設定をEEPROMに保持します。
ユーザー設定の永続化
ユーザーが変更できる設定(表示輝度・通信速度・動作モード等)を構造体でEEPROMに保存します。構造体全体をページ書き込みでまとめて書くことで効率化できます。
typedef struct {
uint8_t brightness; // 0-100
uint32_t baud_rate; // シリアル通信速度
uint8_t mode; // 動作モード
uint16_t checksum; // データ整合性確認
} UserConfig;
void save_config(const UserConfig *cfg) {
// チェックサム計算
UserConfig tmp = *cfg;
tmp.checksum = calc_checksum(cfg, sizeof(UserConfig) - 2);
eeprom_write_page(CONFIG_EEPROM_ADDR, (uint8_t*)&tmp, sizeof(UserConfig));
}
bool load_config(UserConfig *cfg) {
eeprom_read(CONFIG_EEPROM_ADDR, (uint8_t*)cfg, sizeof(UserConfig));
return cfg->checksum == calc_checksum(cfg, sizeof(UserConfig) - 2);
}
実装・開発のポイント
書き込み完了待ち(ACKポーリング)
EEPROMの書き込みは非同期で行われます。書き込みコマンド後、内部書き込みサイクル(tWR: 1〜10ms)の間はACKを返さないため、ポーリングで完了を確認します。
// ACKポーリングで書き込み完了確認
HAL_StatusTypeDef wait = HAL_BUSY;
while (wait != HAL_OK) {
wait = HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, NULL, 0, 1);
// ACKが返ってきたら書き込み完了
}
ページ境界をまたぐ書き込みに注意
I2C EEPROMはページ境界をまたいで書くと、アドレスがページ先頭にラップアラウンドします。必ずページ単位でアクセスするよう分割して書き込みます。
// ページ境界を考慮した書き込み(疑似コード)
void eeprom_write_safe(uint16_t addr, const uint8_t *data, size_t len) {
while (len > 0) {
uint8_t page_offset = addr % EEPROM_PAGE_SIZE;
uint8_t write_len = EEPROM_PAGE_SIZE - page_offset;
if (write_len > len) write_len = len;
eeprom_write_page(addr, data, write_len);
eeprom_wait_ready();
addr += write_len;
data += write_len;
len -= write_len;
}
}
ウェアレベリングの考慮
EEPROMのバイト書き換え耐久性は100万回以上ありますが、毎秒1回の書き込みを行うと約11日で限界(100万÷86400≒11.5日)に達します。頻繁に書き換えるデータは複数アドレスをローテーションするか、書き込み頻度を下げる設計にします。
データ整合性の確保
EEPROMへの書き込み中に電源断が発生するとデータが壊れる可能性があります。チェックサム(CRC8/CRC16等)を付加して検証するか、2面書き込み(プライマリ・バックアップ)で冗長化します。
uint8_t calc_crc8(const uint8_t *data, size_t len) {
uint8_t crc = 0xFF;
for (size_t i = 0; i < len; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
crc = (crc & 0x80) ? (crc << 1) ^ 0x31 : (crc << 1);
}
}
return crc;
}
他技術との比較
EEPROM vs フラッシュ
| 項目 | EEPROM | フラッシュ(NOR) |
|---|---|---|
| 消去単位 | バイト単位 | セクタ単位(KB〜) |
| 書き換え耐久性 | 100万回以上 | 10〜10万回 |
| 容量 | 小(〜2MB) | 大(MB〜GB) |
| コスト(単価) | 高い | 低い |
| 用途 | 設定値・少量永続データ | プログラム・大容量データ |
EEPROM vs マイコン内蔵フラッシュエミュレーション
STM32のEEPROM Emulationライブラリはフラッシュのセクタ2面を使ってEEPROM動作をエミュレートします。追加コンポーネントが不要ですが、フラッシュのセクタ消去(10万回)が書き換え耐久性の上限になります。独立したEEPROMはマイコンの電源と切り離して保護できるため、安全性が重要な設定値には専用EEPROMが適しています。
EEPROM vs SRAM+バッテリ
SRAMにバッテリバックアップを付ければ不揮発化できますが、バッテリ寿命・コスト・実装面積が課題です。EEPROMはバッテリ不要で長期(40〜100年)データを保持できます。