3. Flash存储芯片原理:NAND Flash的页、块、平面结构,以及读写擦除操作特性

做嵌入式系统这么多年,我接触过各种各样的存储介质。从早期的NOR Flash到现在的NAND Flash,从eMMC到UFS,底层原理其实都绕不开一个核心——NAND Flash芯片本身。今天咱们就把它扒开看看。

说实话,很多做文件系统的人,对Flash的物理特性一知半解。结果就是——明明硬件很强,性能却跑不出来。或者更惨,用着用着,Flash就坏了。嗯,这期内容,我希望能帮你把底层逻辑彻底理清楚。

3.1 NAND Flash的物理结构

先看一张图,这是我画的NAND Flash内部结构简图。你一看就明白。

NAND Flash 芯片内部结构层次 Die(芯片) Plane 0(平面) Plane 1(平面) Block 0(块) 128~256 Pages Block 1 Block 2 Block 3 ...... Block N-1 Block 0 Block 1 Block 2 Block 3 ...... Block N-1 Page(页):4KB/8KB/16KB 数据区 + 128B/256B/512B OOB(带外数据区) Die Plane Block

这张图展示的是NAND Flash的层级关系。从上到下依次是:Die(芯片)→ Plane(平面)→ Block(块)→ Page(页)。每个层级都有它的物理意义和操作约束。

3.2 页(Page)—— 读写的最小单位

页是什么?说白了,就是你能读、能写的最小数据单元。我当年刚接触NAND时,总以为可以像操作硬盘那样,想写几个字节就写几个字节。结果一写就报错——嗯,教训深刻。

一个典型的Page结构长这样:

区域 大小(典型值) 用途
数据区(Main Area) 4KB / 8KB / 16KB 存储用户数据
OOB区(Spare Area) 128B / 256B / 512B ECC校验码、坏块标记、元数据

这里有个关键点:写操作只能发生在空白(已擦除)的Page上。你不能覆盖写,只能先擦除再写。而且擦除的最小单位是Block,不是Page。这就引出了一个大坑——

⚠️ 注意: 我曾经在一个项目里,因为没处理好Page的写入顺序,导致频繁的读-改-写操作。结果Flash寿命急剧下降。后来才意识到——同一个Block内的Page,必须按顺序从低到高写入。跳着写?不行。重复写?更不行。

3.3 块(Block)—— 擦除的最小单位

块是NAND Flash的擦除单位。一个Block通常包含64、128或256个Page。举个例子,如果Page大小是16KB,Block包含256个Page,那一个Block就是4MB。

为什么擦除要以Block为单位?这跟Flash的物理结构有关。你可以把Flash想象成一个个「浮栅晶体管」组成的矩阵。擦除操作需要给整个Block的衬底加高电压,把电子从浮栅中「吸」出来。这个操作没法精细到Page级别——物理上做不到。

我个人的习惯是,在设计文件系统时,一定要把Block大小作为对齐基准。比如UBIFS的LEB(逻辑擦除块)大小,就是基于物理Block大小来设计的。你想想看,如果文件系统写数据时跨了Block边界,那擦除和垃圾回收的代价会翻倍。

3.4 平面(Plane)—— 并行操作的硬件基础

平面这个概念,很多人容易忽略。其实它是NAND Flash实现并行操作的关键。

一个Die内部通常包含2个或4个Plane。每个Plane有自己的页缓存(Page Buffer)和寄存器。这意味着什么?意味着你可以同时对多个Plane发起操作。

💡 实战技巧: 我在做NAND驱动优化时,利用多Plane并行操作,把写入吞吐量提升了将近一倍。具体做法是——将数据分散到不同Plane的Block中,然后同时下发写入命令。注意,这里要求不同Plane的Block编号必须相同(比如Plane0的Block0和Plane1的Block0)。

多Plane操作有个限制:操作的Block偏移必须一致。比如你不能同时操作Plane0的Block0和Plane1的Block1。这是硬件设计决定的,没办法。

3.5 读写擦除操作特性

好,咱们把三个核心操作拆开来看。

3.5.1 读操作

读操作相对简单。你给NAND控制器发一个读命令,带上Page地址,它就把数据从存储阵列搬到Page Buffer里,然后你从Buffer里取数据。

读操作的速度一般在25μs到100μs之间(取决于Page大小和工艺)。但要注意——读操作也会干扰相邻Page的数据,这叫「读干扰」。频繁读同一个Page,可能导致它周围的Page数据出错。

🔧 避坑指南: 我曾经在一个监控设备项目里,日志分区被频繁读取,结果半年后出现了大量ECC错误。后来加了读干扰管理策略——每读1000次就搬移一次数据。问题解决了。

3.5.2 写操作(编程操作)

写操作也叫Program操作。它通过施加高电压脉冲,把电子注入浮栅中。写一个Page的时间通常在200μs到1ms之间。

写操作有几个硬性约束:

  • 只能写空白页——写过数据的Page必须先擦除才能再写
  • 必须顺序写入——同一个Block内,Page编号必须从小到大写
  • 写后立即校验——硬件会自动做Program Verify,确保数据写进去了

3.5.3 擦除操作

擦除操作是把整个Block的电子全部拉出来,让所有Page回到「1」状态(注意,Flash的初始状态是1,写操作是把1变成0)。

擦除一个Block的时间比较长,通常在1ms到10ms之间。这也是为什么垃圾回收(GC)那么耗时——它要搬数据、擦除Block,一套下来几十毫秒就没了。

3.6 关键性能参数对比

操作 典型延迟 最小操作单位 注意事项
读(Read) 25~100 μs Page 存在读干扰,需定期搬移
写(Program) 200~1000 μs Page 只能写空白页,需顺序写入
擦除(Erase) 1~10 ms Block 最耗时的操作,影响GC效率

你看这个表格就明白了——擦除是最慢的。所以文件系统的设计核心,就是尽量减少擦除次数。怎么减?通过磨损均衡(Wear Leveling)和垃圾回收(GC)策略来优化。

3.7 总结一下

NAND Flash的物理特性,决定了文件系统的设计方向:

  • Page是读写单位——文件系统要按Page对齐,避免碎片
  • Block是擦除单位——GC和磨损均衡都要基于Block来设计
  • Plane是并行单位——利用多Plane可以提升吞吐量
  • 读写擦各有特性——读干扰、写约束、擦除慢,这些都要在驱动层处理好

我个人觉得,理解这些底层原理,比背一堆文件系统参数有用得多。你想想看,当你知道了Flash的「脾气」,再去选型Rootfs或调优性能,心里就有底了。

下一节,咱们会深入讲NAND Flash的坏块管理和ECC纠错。嗯,那又是另一个有意思的话题了。


可可精品资料库