Flash存储基础:NAND vs NOR Flash,eMMC vs SPI Flash,Flash的物理特性与寿命管理
做OTA升级,说白了就是跟Flash打交道。你想想看,固件要存、要分区、要擦除、要写入,哪一步离得开Flash?我刚开始做嵌入式时,觉得Flash就是个存东西的芯片,后来踩了不少坑才明白——选错Flash类型,OTA方案直接废掉一半。
这一章,咱们把Flash的家底翻一翻。不搞教科书式的罗列,只讲你在OTA实战中必须知道的那些事。
2.1 NAND vs NOR Flash:两种截然不同的脾气
Flash分两大派:NAND和NOR。名字听着像,脾气差很远。
| 特性 | NOR Flash | NAND Flash |
|---|---|---|
| 读取速度 | 快,支持随机读取(类似内存) | 较慢,按页读取 |
| 写入速度 | 慢(按字节/字编程) | 快(按页编程) |
| 擦除速度 | 慢(按扇区擦除,扇区小) | 快(按块擦除,块大) |
| 密度 | 低(通常 512KB ~ 256MB) | 高(通常 128MB ~ 1TB+) |
| 可靠性 | 高,坏块极少 | 出厂就有坏块,需要管理 |
| 接口 | SRAM-like,可直接执行代码(XIP) | I/O复用,需控制器 |
| 典型用途 | Bootloader、代码存储 | 大容量数据、文件系统、OTA镜像 |
| 成本 | 高(每MB价格) | 低(每MB价格) |
NOR Flash 最大的优势是XIP(eXecute In Place)。什么意思?就是CPU可以直接从NOR Flash里取指令执行,不用先把代码拷贝到RAM里。我做过一个工业控制器项目,Bootloader就放在NOR Flash里,上电瞬间就能跑起来,延迟不到1毫秒。
NAND Flash 则相反。它不能XIP,必须先把代码读到RAM再执行。但它的容量大、价格低,适合存OTA镜像包。你想想看,一个完整的Linux内核+根文件系统可能几十上百MB,用NOR Flash存?成本直接爆炸。
实战经验: 我建议OTA方案中,Bootloader用NOR Flash(或SPI NOR),OTA镜像存储区用NAND Flash(或eMMC)。各取所长,别混用。
2.2 eMMC vs SPI Flash:接口与协议之争
说完NAND和NOR,咱们再看两种常见的封装形式:eMMC和SPI Flash。它们本质上是NAND/NOR的“马甲”,但接口和协议完全不同。
2.2.1 SPI Flash
SPI Flash通常是NOR Flash,通过SPI接口通信。引脚少(6~8个),PCB布线简单,非常适合小容量场景。
- 容量范围: 1MB ~ 256MB
- 接口: SPI/QSPI/OSPI
- 特点: 支持XIP(部分型号),擦写次数约10万次
- 典型场景: Bootloader、U-Boot、裸机程序
我记得有个客户做智能门锁,用SPI NOR存固件,容量16MB。OTA升级时,新固件先下载到外部SD卡,再校验、搬移到SPI Flash。方案简单,成本也低。
2.2.2 eMMC
eMMC本质上是NAND Flash + 控制器 + MMC接口的合封芯片。你看到的是一个小芯片,里面其实是一个完整的存储子系统。
- 容量范围: 4GB ~ 256GB
- 接口: MMC/SDIO(8线或4线)
- 特点: 内置坏块管理、磨损均衡、ECC纠错
- 典型场景: Linux根文件系统、应用数据、OTA镜像
避坑指南: 我曾经在一个项目里直接用eMMC存Bootloader,结果发现上电初始化太慢——eMMC控制器需要时间启动,CPU等不了。后来还是加了一颗小容量的SPI NOR放Bootloader,eMMC只放内核和文件系统。
2.3 Flash的物理特性:为什么不能随便写?
Flash不是SRAM,不是想写就写。它有三大物理特性,你必须刻在脑子里。
2.3.1 擦除-写入周期
Flash写入前必须先擦除。擦除的最小单位是扇区(NOR)或块(NAND),不是字节。这意味着:
- 你想改一个字节,得先把整个扇区读到RAM,擦除扇区,再写回修改后的数据
- 擦除操作很慢(毫秒级),频繁擦除会严重影响性能
我见过有人直接在OTA升级时逐字节写入Flash,结果擦除次数暴增,Flash寿命急剧下降。正确的做法是:整块擦除,整块写入。
2.3.2 写放大效应
写放大(Write Amplification)是指:实际写入Flash的数据量,远大于应用层请求写入的数据量。原因就是上面说的——擦除粒度远大于写入粒度。
举个例子:你想写4KB数据,但Flash的擦除块是128KB。你得先擦除128KB,再写回那4KB。实际物理写入量是128KB,写放大因子是32倍。
警告: 写放大不仅降低性能,还加速Flash磨损。OTA升级时,如果分区设计不合理,频繁擦写同一个块,那块Flash会先“死”掉。
2.3.3 读干扰
读Flash也会造成干扰。连续读取同一个页/块,会导致周围存储单元的电荷发生变化,最终引发位翻转。NAND Flash尤其敏感。
我记得有个项目,设备运行几个月后,OTA校验总是失败。排查到最后,发现是频繁读取同一个分区导致读干扰,数据悄悄变了。解决方案:定期刷新(read scrub)或增加ECC校验。
2.4 寿命管理与磨损均衡
Flash的擦写次数是有限的。NOR Flash约10万次,NAND Flash约1万~10万次(取决于制程和类型)。听起来不少?但OTA升级频繁的话,几个月就能耗光。
2.4.1 磨损均衡(Wear Leveling)
磨损均衡的核心思想:让所有存储块被擦写的次数尽量平均,避免某些块过早报废。
有两种实现方式:
- 动态磨损均衡: 只在写入时选择擦写次数最少的块。实现简单,但静态数据(很少更新的数据)所在的块不会被均衡到。
- 静态磨损均衡: 定期把静态数据搬移到擦写次数多的块,把“年轻”的块让给频繁写入的数据。效果更好,但实现复杂,有性能开销。
eMMC内置了磨损均衡,你基本不用操心。但SPI NOR Flash通常没有,需要你自己实现——或者用现成的Flash抽象层(如FlashDB、LittleFS)。
2.4.2 坏块管理
NAND Flash出厂就有坏块,使用过程中还会产生新坏块。eMMC内部帮你管了,但裸NAND需要你自己管。
坏块管理通常有两种策略:
- 跳过坏块: 在分区表中标记坏块,读写时跳过
- 坏块替换: 用保留块替换坏块(类似硬盘的备用扇区)
我建议:能用eMMC就别用裸NAND。除非你团队有存储专家,否则坏块管理会把你逼疯。
2.4.3 寿命估算
你可以估算一下Flash的寿命:
寿命(年) = 擦写次数 × 块数 / (每天擦写次数 × 365)
举例:
- NAND Flash:擦写次数 10000次,块数 1024
- 每天OTA升级1次,每次擦写2个块
- 寿命 = 10000 × 1024 / (1 × 2 × 365) ≈ 14027年
等等,这算出来太长了?因为实际还有写放大、磨损不均衡、读干扰等因素。保守估计,实际寿命是理论值的 1/10 ~ 1/100。
关键点: OTA升级频率越高,Flash寿命越短。如果你的设备每天升级多次,必须用eMMC或带磨损均衡的Flash方案。裸NAND?撑不过半年。
2.5 本章知识结构图
下面这张图帮你理清Flash选型与OTA的关系:
2.6 本章小结
Flash选型没有银弹。你得根据OTA场景做权衡:
- 小容量、高可靠性、需要XIP: 选NOR Flash(SPI Flash)
- 大容量、频繁升级、需要磨损均衡: 选eMMC
- 预算有限、容量适中: 可以考虑SPI NAND(带控制器)
嗯,记住一句话:OTA升级方案的好坏,一半取决于Flash选型。选对了,后面分区设计、升级流程都顺;选错了,后面全是坑。
个人习惯: 我每次做新项目,第一件事就是看Flash数据手册的擦写次数和擦除块大小。这两个参数直接决定分区策略和升级频率上限。别等到OTA出问题了才回头查——那时候已经晚了。