NandFlash特性详解
NAND闪存属于非易失性存储(断电后数据不丢失),其核心结构基于浮栅晶体管,通过控制栅极电压改变浮栅中的电子数量来存储数据。这种结构决定了它既有远超传统硬盘的优势,也存在独特的“痛点”,这些特性直接主导了后续Linux存储技术的设计方向。
Nand存储结构

以NAND Flash MT29F4G08为例,其存储结构如下:
- 块(Block):NAND Flash由多个块组成,每个块是擦除的最小单位。通常,一个块包含多个页。
- 页(Page):页是数据读写的最小单位。每个页由两部分组成:
- 数据存储区(Data Area):用于存储有效数据的区域。对于MT29F4G08,数据存储区的大小为2KB。
- 备用区域(Spare Area):用于存储额外的信息,如ECC(纠错码)校验值、坏块管理信息等。备用区域的大小为64字节,用于实现坏块管理和磨损均衡等功能。
Nand寻址
Nand寻址基础

NAND Flash 的寻址方式:
-
列地址(Column Address):
- 列地址用于在一个页(Page)内部寻址,它决定了所选取的数据位于所选页内的哪一列。
对于 MT29F4G08,列地址需要 12 根地址线(CA0~CA11),因为每个页的数据长度为 2112 字节。
- 列地址用于在一个页(Page)内部寻址,它决定了所选取的数据位于所选页内的哪一列。
-
页地址(Page Address):
- 页地址用于在一个块(Block)内部寻址,它决定了所选取的数据位于所选块内的哪一页。
对于 MT29F4G08,页地址需要 6 根地址线(PA0~PA5),因为每个块包含 64 个页。
- 页地址用于在一个块(Block)内部寻址,它决定了所选取的数据位于所选块内的哪一页。
-
块地址(Block Address):
- 块地址用于进行块级寻址,它决定了所选取的数据位于哪一个块内。
对于 MT29F4G08,块地址需要 12 根地址线(BA6~BA17),因为总共有 4096 个块。
- 块地址用于进行块级寻址,它决定了所选取的数据位于哪一个块内。
nand只能按页读写,那为什么MT29F4G08有列地址,可以按字节读写?
MT29F4G08 本质上依然遵循 NAND Flash “按页读写” 的核心规则,其列地址并非用来打破该规则,而是实现页内字节级精准寻址,再配合芯片内部的数据寄存器与缓存寄存器,最终模拟出按字节读写的效果,并非真正意义上绕开页操作的独立字节读写。
执行读写操作时,并非直接对存储阵列中的字节进行操作。比如读取字节时,芯片会先把目标页的完整数据读取到缓存寄存器和数据寄存器中,接着依据列地址从寄存器里提取指定字节并输出;写入字节时,先通过列地址确定寄存器中的目标位置,将字节数据写入寄存器,后续再通过页编程操作,把寄存器中的数据整体写入对应的页存储单元
Nand控制命令举例
READ PAGE

PROGRAM PAGE

坏块管理与ECC校验
坏块管理和磨损均衡是在 NAND Flash 存储器中常见的管理策略,用于延长存储器的寿命和提高可靠性。
坏块管理
坏块管理包括三部分:识别标记坏块,转换表,保留区
识别标记坏块

坏块识别和标记:坏块识别是指在初始化或运行时检测 NAND FLASH 中的坏块,并将其标记为不可用。常见的识别方法包括:
- 读取厂家预留的坏块标记:在每个块的第一个和第二个页的备用区域的第一个字节中,厂家会写入非 0xFF 的特殊值来标记坏块。
- 写入-读取测试:向每个块写入数据(例如 0xFF 或 0x00),然后再读取出来,并检查数据是否完全一致。不一致的块即为坏块。
- ECC 检验:在读取数据时,通过 ECC 校验来检测块中是否存在错误。如果 ECC 错误超过阈值,则将该块标记为坏块。
转换表

转换表是确保文件系统正常运行的关键之一,它需要在系统启动时进行初始化,并在运行过程中动态地维护和更新,以适应 NAND FLASH 存储器的使用和变化情况。

文件系统与LUT交互
无“现成LUT”可供文件系统直接读取,LUT是文件系统(如YAFFS2、JFFS2)或NAND驱动 主动构建的。下面结合MT29F4G08的硬件特性(2048字节数据区+64字节备用区、按页操作、坏块限制),详细拆解文件系统的“LUT获取-使用”全流程:
- 文件系统初始化时,扫描NAND构建初始LUT
当系统上电、文件系统首次挂载(如mount命令)时,文件系统会触发“NAND扫描流程”,核心目的是收集所有物理块/页的状态,构建初始LUT:- 底层驱动操作(对接MT29F4G08):
文件系统调用NAND驱动,遍历MT29F4G08的所有物理块(MT29F4G08共1024个块,每个块64页),对每个块执行:
① 读取块内任意一页的备用区(64字节),检查“坏块标识位”(通常是备用区第1个字节,0xFF为好块,0x00为坏块);
② 若为好块,继续读取该块内各页备用区的“逻辑地址标记”(文件系统预先定义的格式,比如用4字节存储该物理页对应的逻辑页号)。 - 文件系统构建LUT:
- 底层驱动操作(对接MT29F4G08):
文件系统根据扫描结果,在内存中创建一张表格(LUT),核心条目格式如下:
| 逻辑页号(文件系统视角) | 物理地址(MT29F4G08视角) | 块/页状态 |
|---|---|---|
| L0 | 块0 + 页10 | 正常 |
| L1 | 块1 + 页3 | 正常 |
| … | … | 坏块(跳过) |
这一步就是“文件系统获取LUT”的过程——本质是自己扫描、构建,而非从芯片中“读取现成的”。
- 运行时将LUT缓存到内存,提升访问效率
初始LUT构建完成后,文件系统会将其完整加载到内存(RAM)中,原因是:
- MT29F4G08的备用区读取是“按页操作”(需先选中块→选中页→读取备用区),速度慢(毫秒级);
- 内存访问速度是纳秒级,文件系统读写数据时,可直接查询内存中的LUT,快速完成“逻辑地址→物理地址”转换。
此时内存中的LUT是“工作副本”,备用区中的是“持久化副本”,后续对LUT的修改先在内存中完成。
- LUT更新后同步到备用区,保障断电不丢失
当文件系统执行写/擦除操作导致LUT变化时(比如坏块替换、数据重映射),会及时将更新后的LUT条目同步到MT29F4G08的备用区,避免断电丢失:
- 示例场景:文件系统要写逻辑页L2,发现对应的物理页(块2+页5)是坏块,需替换到块3+页8;
- 操作流程:
① 内存中LUT新增条目:L2 → 块3+页8;
② 文件系统调用驱动,将“L2”这个逻辑地址标记写入块3+页8的备用区(比如写入备用区第2-5字节);
③ 同时在原坏块(块2)的备用区更新“坏块标识”,避免后续再次使用。
MT29F4G08的64字节备用区完全足够存储这些信息(ECC校验值占16-24字节,剩余空间可存逻辑地址、坏块标识等)。
保留区

ECC校验
ECC校验(Error Correction Code)是一种用于检测和纠正数据传输中错误的算法。在 NAND FLASH 存储器中,由于存储单元的串行组织结构以及信号衰减等因素,读取数据时可能会出现错误。ECC算法能够检测出这些错误,并尝试修正错误的数据位,提高数据的可靠性。
在 NAND FLASH 存储器中,常用的 ECC 算法有汉明码(Hamming Code)、RS码(Reed Solomon Code)和BCH码(Bose-Chaudhuri-Hocquenghem Code)。在 STM32 的 FMC 模块中,硬件支持 ECC 计算,使用的是汉明码算法。汉明码虽然无法对错误进行修正,但可以检测出错误的位置,从而提高数据的可靠性。
对于 ECC 算法的应用,需要按照一定的规则生成 ECC 校验数据,并将其与原始数据一起存储。在读取数据时,将读取到的数据与相应的 ECC 校验数据进行比较,以检测出错误并尝试修正错误的数据位。
以 STM32 的 FMC 模块为例,它支持按照不同的页大小(如256、512、1024、2048、4096和8192字节)进行 ECC 计算。对于512字节为单位的数据,通常只需要24bit的 ECC 校验数据来表示,这样就可以检测出并纠正数据传输中的错误。

参考:【正点原子STM32】FSMC_FMC——NAND FLASH实验(存储原理、存储结构、坏块管理和磨损均衡、控制命令、FMC-NAND FLASH接口、NAND FLASH驱动步骤)
浙公网安备 33010602011771号