NAND Flash 是一种非易失闪存介质,常作为 eMMC、UFS、SSD、U 盘和存储卡的底层存储颗粒;它能在断电后保留数据,但写入、擦除、寿命和错误模型都和普通内存不同。
它的关键特性是:通常按 page 读写、按 block 擦除,而且不能在已有数据上任意原地覆盖。
核心问题
嵌入式设备需要便宜、密度高、断电不丢数据的存储。NAND Flash 满足容量和成本,但代价是软件或控制器必须处理:
- 擦除粒度大,写入前通常要先擦除整个 block。
- 单个存储单元写擦次数有限。
- 出厂和运行过程中可能出现坏块。
- 读出数据可能有 bit error,需要 ECC(错误纠正码)。
- 多次读同一区域可能引入 read disturb,多次写邻近页也可能引入干扰。
所以裸 NAND 不能简单当作“可以无限覆盖的数组”。
核心对象
| 对象 | 含义 | 工程关注点 |
|---|---|---|
| cell | 存储电荷的基本单元 | SLC/MLC/TLC/QLC、寿命、保持时间 |
| page | 最小常见读写单位 | 通常几 KiB 到十几 KiB,附带 OOB/spare 区 |
| block | 最小擦除单位 | 包含多个 page,坏块和磨损以 block 为核心 |
| plane / die | NAND 内部并行结构 | 并发、交错读写、性能 |
| OOB / spare area | page 旁的额外区域 | ECC、坏块标记、元数据 |
| P/E cycle | Program/Erase cycle | 写擦寿命指标 |
核心机制
NAND Flash 的基本规则是:
read: page -> data
program: erased_page + data -> programmed_page
erase: block -> all_pages_erasedread以 page 为单位读取数据。program写入一个已擦除 page;一般不能把已写 page 随意改成另一组数据。erase以 block 为单位把该 block 内所有 page 恢复到可写状态。
如果主机想更新一个逻辑扇区,控制器通常不会原地覆盖旧 page,而是写到新 page,然后更新映射:
old_physical_page becomes invalid
logical_address -> new_physical_page旧 page 留待后续垃圾回收。垃圾回收会把某个 block 中仍有效的 page 搬走,再擦除整个 block,释放空间。这就是为什么随机小写会产生写放大。
工程用途
- eMMC、UFS、SSD、SD 卡等托管式存储内部介质。
- 裸 NAND 启动设备中存放 bootloader、kernel、UBI/UBIFS 或 YAFFS 等文件系统。
- 大容量、低成本的嵌入式数据存储。
调试 NAND 相关问题时,要区分裸 NAND 与托管式存储。裸 NAND 问题常暴露为 bad block、ECC corrected/failed、UBI attach 失败;eMMC/UFS 则通常只暴露块设备层错误、寿命指标或控制器日志。
边界与常见坑
- NAND 不是 NOR Flash:NOR 更适合随机读取和 XIP,NAND 更适合大容量块存储。
- NAND 不是普通 RAM:不能任意字节覆盖,写入前有擦除约束。
- 容量越高不代表越耐用:TLC/QLC 密度高但单元容错和寿命通常低于 SLC。
- 坏块是正常现象:NAND 设计上允许坏块存在,关键是管理机制是否正确。
- 断电时序很重要:写入、垃圾回收或映射表更新中断,可能造成数据丢失或一致性问题。