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 Flash | NAND 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. 参数正面对比
| 特性 | EEPROM | Flash |
|---|---|---|
| 擦除单位 | 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 | 两线制,引脚极少;容量小,几毛钱一颗 |
| 内部 Flash | MCU 片内总线直连,存代码,页/扇区擦除 |
| 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 最后一页存一个数据:
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 为例:
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 当内存用 | 毫秒级速度,卡到怀疑人生 |
| 5 | NAND 不管坏块 | 不做 ECC,数据悄悄烂掉 |
3. 面试加分项:主动抛这四个点
- XIP 原理:字节级随机读,代码才能原地执行;
- 磨损均衡 + 双备份:擦除轮流分摊,主备双区保数据安全;
- 日志式写入:攒满一页才擦,寿命翻倍省;
- 坏块 + ECC:NAND 专属课题,NOR 不用操心。
4. 总结
4.1 一句话总结
EEPROM:字节擦,灵活贵;Flash:扇区擦,便宜糙。
存储只有读和写两件事,这两个芯片最大的区别在"擦":
- EEPROM 按字节擦、寿命百万次,适合频繁修改的小数据;
- Flash 按扇区擦、必须先擦后写,适合大块数据和固件。
4.2 常用芯片"报菜名"
选型时按方向记,三个方向就够:
| 方向 | 代表芯片 | 典型用途 |
|---|---|---|
| I2C EEPROM | AT24C 系列 | 配置参数,掉电记忆 |
| SPI NOR Flash | W25Q 系列 | 板级扩存储 |
| NAND / SD / eMMC | — | 海量数据,文件系统、音视频 |
| 内部 Flash | MCU 片内 | 代码 + 模拟 EEPROM,一芯两用 |
4.3 记住这三句话
(1)EEPROM 按字节擦——寿命百万次,灵活但小贵;
(2)Flash 按扇区擦——永远先擦后写,便宜又大碗;
(3)选型看场景——参数用 EEPROM,代码用 NOR,海量数据用 NAND。
原理、选型、工程实践都理顺了,EEPROM 与 Flash 这点事,一般再难也不倒你。