Skip to content

LV012-EEPROM与Flash

LV010-常见存储器中,我们简单了解了 RAM、ROM、FLASH 等常见存储器。本文聚焦嵌入式里最常用的两种非易失性存储器——EEPROM 与 Flash,从底层原理讲到工程选型,把"为什么 EEPROM 贵""为什么代码放 NOR 里""NAND 为什么不能直接跑代码"这些问题一次盘明白。

一、认识 EEPROM 与 Flash

1. 先纠正三个常见误解

你以为的实际是这样的
EEPROM 读写很快,名字里带个 E,像内存。写一个字节要几毫秒,内部要先擦后写
Flash 能单字节改写,直接改地址就行。Flash 必须先擦除扇区,想改先擦一整片
都叫 ROM,只能读,出厂写死那种。ROM 也能电擦写,只是方式粗细不同

2. 本质区别:擦除粒度

EEPROM 和 Flash 都属于非易失性存储器,断电后数据都不丢。两者真正的分水岭是擦除粒度:EEPROM 按字节擦,Flash 按扇区擦。两者的寿命、成本、用途差异,全都是从这一个区别"长"出来的。理解了这一点,后面的所有内容都是它的自然延伸。

3. 非易失存储器家谱:一路跟"擦"较劲

回顾非易失存储器的演进史,其实就是一部"怎么擦除更方便"的历史:

非易失存储器家谱

从 ROM 到 Flash,擦除越来越方便、越来越快,但擦除的粒度也在变化:EEPROM 保留到了"字节级"的精细擦除,而 Flash 为了容量和成本,选择了"块级"的粗粒度擦除。

二、底层原理:浮栅里的电荷

1. 存储单元:浮栅晶体管

EEPROM 和 Flash 的存储单元都是浮栅晶体管(Floating Gate),靠浮栅里有没有被"困住"的电荷来表示 0 和 1。

1.1 写:逐个塞电荷

写操作是往浮栅里塞电荷,一个单元一个单元地来,是精细活。

1.2 擦:开闸放水(整片)

擦操作是把电荷放掉。EEPROM 每个字节有独立的放电路径;而 Flash 的放电路径是整片共享的,一开闸,一个扇区全部清零。所以"按块擦"是硬件结构决定的,不是软件偷懒。

2. 擦除通道:一个字节一扇门 VS 一个扇区一间通铺

同样是存储阵列,擦除通道的接法不同,擦除粒度就天差地别:

擦除结构对比

2.1 EEPROM:每个字节一扇小门

每个字节都有独立的擦除电路,想擦哪个擦哪个。

  • 代价:每个字节都要独立电路 → 面积大、成本高、容量做不大。

2.2 Flash:一个扇区一间通铺

大量存储单元共享同一套擦除闸门,要擦就是整个扇区一起擦。

  • 优势:电路省 → 密度高、便宜、容量大。

2.3 鱼和熊掌不可兼得

一句话:门装得越多越贵——EEPROM 灵活,Flash 便宜。这也回答了"为什么 EEPROM 贵"。

3. Flash 的铁律:写只能 1→0,擦才能 0→1

这是 Flash 最重要的一条特性:

  • 写操作只能把 1 变成 0(给浮栅塞电荷);
  • 想把 0 变回 1,必须靠擦除(放掉电荷),而擦除是按扇区进行的。

3.1 为什么没有"原地改写"

想修改 Flash 里的数据,直接写只能把 1 写成 0;要把 0 变回 1 就必须擦除,而一擦就是一整个扇区。所以 Flash 里没有"原地改写",永远是"先擦后写"

3.2 这条铁律决定了什么

项目里所有的 Flash 数据存储设计(日志式写入、磨损均衡、双备份等),都建立在这条铁律上。

三、Flash 家族:NOR 与 NAND

1. 两大流派对比

Flash 家族内部还分两派:NOR Flash 和 NAND Flash。

NOR FlashNAND Flash
读取方式支持随机读(字节级)读写按页,顺序访问
代码执行可直接运行(XIP)不能直接跑代码
擦写与容量擦写慢,容量做不大容量大,成本低
可靠性坏块极少,不用管天生带坏块,要管理
典型用途适合存代码适合存海量数据

面试一句话总结:NOR 当内存用(可随机寻址取指),NAND 当硬盘用(存大块数据)

2. 为什么代码要放 NOR:XIP

CPU 取指本质上是"给一个地址,返回该地址的指令",是随机地址访问。XIP(eXecute In Place,片内执行)指代码可以原地执行、不需要先搬到 RAM。

2.1 NOR:能原地跑

  • NOR 支持字节级随机读,总线直连,CPU 可以直接取指执行;
  • 坏块极少,不需要复杂管理。

2.2 NAND:得先搬家

  • 读写按页进行,没有字节级随机读;
  • 有坏块,需要 ECC 纠错;
  • CPU 无法直接取指,代码必须先拷贝到 RAM 再运行。

一个能原地跑,一个得先搬家——这就是 XIP 的本质。STM32 内部的 Flash 就是 NOR Flash,所以程序可以直接在 Flash 里原地执行。

四、正面对比与选型

1. 参数正面对比

特性EEPROMFlash
擦除单位1 个字节扇区 / 块
擦写寿命约 100 万次约 10 万次量级
容量几 KB ~ 几 Mb几 Mb ~ 几 Gb
价格与接口贵,接口少引脚(常用 I2C/SPI)便宜,容量密度高
适合场景配置 / 校准参数固件 / 日志 / 大块数据

一句话:EEPROM 用灵活换小容量,Flash 用容量换擦除的麻烦

2. 改一个字节:直写 VS 先擦后写

想把一个字节从 0x12 改成 0x34,两边流程差多远?

改一个字节流程对比

2.1 EEPROM:3 步搞定

(1)发地址:告诉芯片"我要改 0x12";

(2)直接写:芯片内部自动先擦后写;

(3)完成:约几毫秒,完事。

2.2 Flash:4 步折腾

(1)找到扇区:0x12 所在的整个扇区;

(2)整体擦除:整片变成 0xFF(全 1);

(3)整页写回:该字节改成 0x34,同页其他数据原样重写;

(4)校验:读回确认,收工。

改一个字节,EEPROM 只动它自己;Flash 要拉上一整个扇区"陪葬"——读出整个扇区、擦除、再整体写回。

3. 寿命算账:每秒写一次,多久报废?

擦写寿命是有限次数的,算一笔账就知道它有多重要(假设每秒写一次):

器件擦写寿命每秒写一次能撑
EEPROM约 100 万次≈ 11.6 天,日常低频使用无压力
NOR Flash约 10 万次≈ 27.8 小时,已经开始慌
NAND SLC约 10 万次≈ 27.8 小时,同 NOR
NAND MLC几千次≈ 1~3 小时,直接报废

所以,把"每秒记录一次日志"这种需求直接怼在 Flash 的同一个地址上,几天就把芯片写报废了。这正是后面"Flash 模拟 EEPROM"要解决的问题。

4. 接口形态:引脚决定一切

实际用到板子上的形态主要有四种:

形态特点
I2C EEPROM两线制,引脚极少;容量小,几毛钱一颗
内部 FlashMCU 片内总线直连,存代码,页/扇区擦除
SPI NOR板级扩存储,W25Q 这类颗粒,几 MB 起
NAND / eMMC大容量场景,并口或 SDIO,GB 级

5. 场景分工:谁家的活

5.1 EEPROM 的天下

  • 设备配置、校准数据;
  • 掉电要记住的小状态;
  • 改得勤、量又小,一字节一字节地存。

5.2 Flash 的天下

  • 程序固件 / Bootloader;
  • 运行日志、字库;
  • OTA 升级包、大文件,动辄几 MB 几十 MB。

方向搞反的后果:要么烧钱(小参数用大 Flash 方案),要么把芯片写死(频繁小数据用 Flash,寿命迅速耗尽)。

五、工程实践:MCU 没带 EEPROM 怎么办

1. 三条路

很多 MCU(比如 STM32F1 系列)压根不带真正的 EEPROM,项目里要掉电存参数,有三条路:

1.1 挂:外挂 EEPROM

I2C/SPI 接口芯片(如 AT24C 系列),几毛钱一颗,简单可靠。

1.2 模:Flash 模拟

用内部 Flash 模拟 EEPROM,不加硬件,但要注意寿命和掉电问题。

1.3 换:换带真 EE 的型号

选型时就选带真正 EEPROM 的型号,如 STM32L0/L4 系列。

2. Flash 模拟 EEPROM

2.1 核心思想:日志式写入

四个字:攒满一页,才擦一次

  • 参数每次变化不急着擦,而是在扇区的新位置追加一条记录(带序号/版本号);
  • 一页写满了,才整体擦除一次。

对比一下:原来"改一次擦一次",十万次寿命眨眼就没了;现在一次擦除能扛几百次修改,寿命翻着倍地省。

注意:这种追加式写入会带来写放大问题(为了改 1 个字节,实际要重写整页数据),这是模拟方案的固有代价,面试时主动提这一点是加分项。

2.2 工程四件套

要把 Flash 模拟 EEPROM 做可靠,工程上有四件套:

2.2.1 磨损均衡

擦除轮流分摊到不同扇区,别可着一个扇区薅。

2.2.2 双备份

主区 + 副本,坏了一个还有救。

2.2.3 校验兜底

每条记录带校验(如 CRC),先验后信。

2.2.4 掉电恢复

写一半断电,上电能发现并回滚。

2.3 掉电保护:四步走

(1)先写备份区:新数据先写到备份区;

(2)更新标志:备份写成功后,才置位"主区有效"的标记;

(3)检测异常:上电时检查标志,发现停在半路(写了备份没更新标志);

(4)恢复数据:用备份区的数据回滚主区。

任意一步断电,上电后都能凭标志位发现异常并用备份区回滚,主区数据始终完整。

3. 代码实战

3.1 STM32 内部 Flash 读写

以 STM32F103(页大小 1KB,写单位是半字)为例,用 HAL 库在内部 Flash 最后一页存一个数据:

c
HAL_FLASH_Unlock();                        // ① 解锁

FLASH_EraseInitTypeDef e = {0};
e.TypeErase = FLASH_TYPEERASE_PAGES;
e.Page     = 255;
e.NbPages  = 1;
HAL_FLASHEx_Erase(&e, &err);               // ② 擦最后一页

uint16_t v = 0x1234;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,
                  0x0800FC00, v);          // ③ 按半字写入

uint16_t r = *(volatile uint16_t *)0x0800FC00;  // ④ 直接读(像读内存一样)

HAL_FLASH_Lock();                          // ⑤ 上锁
3.1.1 要点

顺序:解锁 → 擦页 → 写 → 读 → 上锁。F103 的写单位是半字(16 位),页大小 1KB。

3.2 I2C EEPROM 读写

以 AT24C32 这类 I2C EEPROM 为例:

c
uint8_t buf[8] = {1, 2, 3, 4, 5, 6, 7, 8};

/* ① 写:设备地址 0xA0,内部地址 0x10,写 8 字节 */
HAL_I2C_Mem_Write(&hi2c1, 0xA0, 0x10,
                  I2C_MEMADD_SIZE_8BIT, buf, 8, 100);

HAL_Delay(5);  /* ② 等待内部擦写完成(tWR,约几毫秒) */

/* ③ 读:随时可读,不用等待 */
HAL_I2C_Mem_Read(&hi2c1, 0xA0, 0x10,
                 I2C_MEMADD_SIZE_8BIT, buf, 8, 100);
要点
  • 写后必须等 tWR(内部写周期,几毫秒),期间芯片不响应;
  • 读随时可以进行,不用等待;
  • 跨页写要分批:AT24C32 一页 32 字节,一次写入不能跨越页边界,否则会回卷覆盖页首数据;
  • 掉电不丢,寿命百万次。

六、常见问题与总结

1. 常见问题

1.1 本质区别

Q:EEPROM 和 Flash 最本质的区别是什么?

A:擦除粒度。EEPROM 按字节擦,Flash 按扇区擦;粒度不同,寿命、成本、用途全跟着不同。

Q:往 Flash 里改一个字节,会发生什么?

A:整个扇区被擦掉重写。直接写地址只能把 1 变 0,改不回去——所以 Flash 数据区要用"日志式写入 + 磨损均衡"来管理。

面试金句:Flash 里没有"原地改写",只有"先擦后写"

1.2 选型与执行

Q:为什么 NAND 不能像 NOR 一样直接跑代码?

A:页式读写、没有字节级随机访问,还有坏块和纠错问题;代码必须先拷到内存(RAM)里再执行。

Q:MCU 没有 EEPROM,项目里怎么存参数?

A:外挂 EEPROM 芯片、内部 Flash 模拟、或者选型时直接选带真 EEPROM 的型号;模拟方案要提防写放大和磨损均衡问题。

加分点:主动说出"模拟方案有写放大",说明你真踩过坑。

2. 高频翻车点

实际项目中五个常见错误:

序号翻车点后果
1把 Flash 当 EEPROM 用直接改字节、忘擦扇区,改不进去
2高频写日志不看寿命每秒一次,几天写报废
3不做掉电保护写一半断电,数据损坏
4把 EEPROM 当内存用毫秒级速度,卡到怀疑人生
5NAND 不管坏块不做 ECC,数据悄悄烂掉

3. 面试加分项:主动抛这四个点

  • XIP 原理:字节级随机读,代码才能原地执行;
  • 磨损均衡 + 双备份:擦除轮流分摊,主备双区保数据安全;
  • 日志式写入:攒满一页才擦,寿命翻倍省;
  • 坏块 + ECC:NAND 专属课题,NOR 不用操心。

4. 总结

4.1 一句话总结

EEPROM:字节擦,灵活贵;Flash:扇区擦,便宜糙。

存储只有读和写两件事,这两个芯片最大的区别在"擦":

  • EEPROM 按字节擦、寿命百万次,适合频繁修改的小数据;
  • Flash 按扇区擦、必须先擦后写,适合大块数据和固件。

4.2 常用芯片"报菜名"

选型时按方向记,三个方向就够:

方向代表芯片典型用途
I2C EEPROMAT24C 系列配置参数,掉电记忆
SPI NOR FlashW25Q 系列板级扩存储
NAND / SD / eMMC海量数据,文件系统、音视频
内部 FlashMCU 片内代码 + 模拟 EEPROM,一芯两用

4.3 记住这三句话

(1)EEPROM 按字节擦——寿命百万次,灵活但小贵;

(2)Flash 按扇区擦——永远先擦后写,便宜又大碗;

(3)选型看场景——参数用 EEPROM,代码用 NOR,海量数据用 NAND。

原理、选型、工程实践都理顺了,EEPROM 与 Flash 这点事,一般再难也不倒你。