メモリ・ストレージ

EEPROM

少量データを書き換え保存する不揮発メモリ。

概要

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ページメーカー
AT24C01128BI2C8BMicrochip
AT24C324KBI2C32BMicrochip
AT24C51264KBI2C128BMicrochip
AT25010128BSPI8BMicrochip
M9525632KBSPI64BSTMicro
CAT24C25632KBI2C64Bonsemi

動作原理

セル構造(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年)データを保持できます。

関連用語

参考リンク