4. Flash特性与约束:写前擦除机制、擦写寿命管理、坏块处理策略、读干扰与写干扰
做嵌入式存储这么多年,我越来越觉得——搞懂Flash的脾气,比学会文件系统API重要得多。你想想看,文件系统跑在Flash上,就像人住在房子里。房子地基不稳,装修再豪华也白搭。
这一节,咱们就聊聊NOR Flash那些绕不开的“硬约束”。说白了,就是它的物理特性决定了我们该怎么用、怎么管。
4.1 写前擦除机制:为什么不能直接覆盖写?
很多从MCU转过来的朋友,第一次接触NOR Flash都会问:“我直接写一个新数据覆盖旧数据不行吗?”
不行。真的不行。
NOR Flash的存储单元,本质上是一个浮栅晶体管。写入(Program)操作只能把位从1变成0,而擦除(Erase)操作才能把位从0恢复成1。所以,如果你想修改某个字节,必须先擦除整个扇区(Sector),再重新写入。
核心结论:NOR Flash不支持“读-改-写”原地覆盖。写操作前,目标区域必须是擦除状态(全0xFF)。
我在项目中遇到过这样一个坑:有个同事直接调用写接口去更新配置参数,结果数据写进去读出来全是乱的。查了半天,发现那片区域之前写过数据,没擦除就直接写了。嗯,从那以后,我要求所有写操作前必须检查擦除状态。
文件系统怎么解决这个问题?它会在底层维护一个“擦除队列”,把需要擦除的扇区先标记,等空闲时再统一擦除。这样上层应用就不用关心擦除细节了。
4.2 擦写寿命管理:10万次不是无限次
NOR Flash的擦写寿命,通常标称10万次。注意,这是指每个扇区独立的擦写次数。不是整片芯片。
10万次听起来很多,但如果你每秒写一次,三天就用完了。更别说有些场景下频繁写日志、存配置参数。
| Flash类型 | 典型擦写寿命 | 常见应用 |
|---|---|---|
| NOR Flash | 10万次 | 代码存储、配置参数 |
| NAND Flash | 1千~10万次 | 大容量数据存储 |
| EEPROM | 100万次 | 小量频繁改写 |
我个人习惯的做法是:在文件系统设计阶段,就把磨损均衡(Wear Leveling)考虑进去。说白了,就是让所有扇区“轮流干活”,别让一个扇区累死,其他扇区闲着。
避坑指南:我曾经在一个OTA升级项目里,没做磨损均衡,结果升级了5000次后,存放固件的扇区就挂了。后来改用动态映射,把固件分散到多个扇区,寿命直接翻了10倍。
磨损均衡的实现方式有两种:
- 静态磨损均衡:所有扇区轮流使用,不管数据是否频繁更新。
- 动态磨损均衡:只对频繁更新的数据做均衡,冷数据不动。
实际项目中,我建议用动态均衡。因为静态均衡会频繁搬移冷数据,反而增加写放大。
4.3 坏块处理策略:Flash也会“生病”
NOR Flash的坏块问题,比NAND轻得多,但也不是没有。尤其是擦写次数接近寿命终点时,某些扇区可能无法正常擦除或写入。
坏块分两种:
- 出厂坏块:生产过程中就有的,厂商会标记出来。
- 使用中坏块:随着擦写次数增加,慢慢出现的。
文件系统怎么处理?我常用的策略是“坏块跳过+重映射”。
// 伪代码:坏块检测与跳过
int write_to_flash(uint32_t addr, uint8_t *data, uint32_t len) {
if (is_bad_block(addr)) {
// 跳过坏块,映射到备用块
uint32_t new_addr = get_spare_block();
return do_write(new_addr, data, len);
}
return do_write(addr, data, len);
}
嗯,这里要注意:坏块检测不能只在初始化时做。我建议每次擦除或写入后,都做一次校验。如果发现写入失败,立即标记为坏块,并触发重映射。
警告:不要试图修复坏块。一旦某个扇区被标记为坏块,就永远不要再使用它。强行使用会导致数据不可靠。
4.4 读干扰与写干扰:看不见的“邻居效应”
读干扰和写干扰,是Flash存储单元之间的“串扰”现象。你想想看,Flash里几百万个存储单元挤在一起,你读写一个单元,旁边的单元也会受到微弱影响。
读干扰:频繁读取某个地址,会导致相邻单元的电荷泄漏,最终数据出错。
写干扰:写入某个地址时,高电压会影响到相邻单元,导致它们的数据被意外修改。
我记得有一次做数据采集器,连续读取同一个扇区几万次后,发现旁边扇区的数据出现了位翻转。排查了三天,最后定位到是读干扰问题。
怎么解决?
- 读干扰:文件系统会统计每个扇区的读取次数。超过阈值后,主动把数据搬移到新位置,然后擦除原扇区。这个过程叫“读刷新”。
- 写干扰:控制写入电压和时序,避免过冲。同时,写入后做ECC校验,发现错误及时纠正。
经验之谈:我一般把读干扰阈值设为100万次。超过这个数,就触发一次读刷新。写干扰则靠硬件保证,软件层面做好ECC就行。
4.5 知识体系总览
下面这张图,把这一节的核心逻辑串起来了。你一看就明白:
这张图把四个约束放在一起对比。你会发现,它们之间是相互关联的。比如,擦写寿命管理做不好,坏块就会提前出现;读干扰不处理,数据可靠性就下降。
做文件系统移植,说白了就是跟这些物理特性“斗智斗勇”。你理解得越深,系统就越稳。我见过太多项目,文件系统跑着跑着就挂了,最后查下来都是没处理好这些底层约束。
我的建议:在开始移植文件系统之前,先把Flash的数据手册通读一遍。重点关注擦写时间、寿命、坏块管理这些参数。别急着写代码,先搞清楚你的Flash“脾气”怎么样。
公众号:蓝海资料掘金营,微信deep3321