1.1 基本存储单元与层次结构

!请添加图片描述(https://i-blog.csdnimg.cn/direct/44b9b78c6edb413c937ecb2c97de601d.png
| 参数 | GD5F4GM8 实例 | 说明 |
|---|---|---|
| 总容量 | 512 MiB (0x20000000) | bit 厂商标 4Gbit |
| Page Size | 2048 bytes | 最小读/写单位(主数据区) |
| OOB Size | 128 bytes | 存放 ECC、坏块标记、元数据 |
| Block Size | 128 KiB (64 pages) | 最小擦除单位 |
| 擦写寿命 | ~10 万次/块 | 需坏块管理和磨损均衡 |
地址计算方式:
c
物理地址 = Block 编号 × Block Size + Page 编号 × Page Size + Column 偏移
例:Block 0, Page 0 → 0x0000_0000
Block 1, Page 0 → 0x0002_0000 (128KiB = 0x20000)
Block 0, Page 1 → 0x0000_0800 (2KiB = 0x800)
1.2 关键操作特性
NAND Flash 的三种基本操作有严格约束,是驱动设计和使用的前提:
| 操作 | 单位 | 方向 | 约束 |
|---|---|---|---|
| 读(Read) | Page | 任意 | 无约束,可随机读 |
| 写(Program) | Page | 1 → 0 | 只能将 bit 1 写为 0,不能反向;写前必须擦除 |
| 擦(Erase) | Block | 全部复位 0xFF | 以 Block 为单位,整块擦除 |
1.3 OOB 区域与坏块管理
OOB(Out-Of-Band)是每个 Page 附带的备用字节区域,用于存储元数据:
c
GD5F4GM8 OOB 布局(128 bytes)
Byte 0 : 坏块标记(Bad Block Marker,BBM)
非 0xFF → 该 Block 为坏块,驱动应跳过
Byte 1-3 : 保留
Byte 4-63 : 用户可用 / 文件系统元数据(UBI EC/VID header 可存于此)
Byte 64-127 : On-die ECC 校验数据(由芯片硬件自动写入/校验)
坏块两种类型:
| 类型 | 产生时间 | 标记位置 | 处理方式 |
|---|---|---|---|
| 出厂坏块(Factory Bad Block) | 芯片出厂前 | Block 0 或 1 的 OOB byte 0 非 0xFF | 驱动扫描时跳过 |
| 运行时坏块(Runtime Bad Block) | 使用过程中 | 擦写失败后由驱动标记 | UBI 重映射到备用 PEB |
坏块扫描流程(MTD 驱动初始化时):
plain
spinand_init()
→ 扫描所有 Block 的 OOB byte 0
→ 非 0xFF 的标记为坏块
→ 注册到 MTD 的 bbt(bad block table)
→ UBI 挂载时读取 bbt,跳过坏块 PEB
工作中注意事项:
-
不要手动擦除 Block 0(通常存储 U-Boot,且含出厂坏块标记)
-
UBI 会自动管理坏块,无需上层显式处理
-
nanddump --oob可查看每个 Block 的 OOB 坏块标记
1.4 SPI NAND vs 并行NAND
| 对比项 | SPI NAND | 并行 NAND (Raw NAND) |
|---|---|---|
| 接口 | SPI / QSPI(4 线) | 8/16 bit 并行总线 + CLE/ALE/CE |
| 引脚数 | 少(6-8 根) | 多(20+ 根) |
| 内置 ECC | 通常有(on-die ECC) | 通常需外部 ECC 引擎 |
| 驱动复杂度 | 较低(spinand 子系统) | 较高(需处理时序/ECC) |
| 最高速度 | 较低(受 SPI 总线限制) | 较高(并行带宽大) |
| 典型场景 | IoT、车载、消费类 | 大容量、高性能存储 |
| 本项目 | GD5F4GM8 via QSPI | --- |
SPI NAND 命令流程

1.5 ECC 错误纠正码
ECC 用于检测和纠正存储单元因衰老、辐射等导致的 bit 翻转(bit flip)。
GD5F4GM8 on-die ECC 规格:
| 参数 | 值 |
|---|---|
| ECC 算法 | BCH |
| 纠错能力 | 8 bits per 512 bytes |
| ECC 数据位置 | OOB 区域(由芯片硬件维护) |
| 状态寄存器 | STATUS5:4 → ECCS bits |
ECC 状态码:
plain
ECCS[1:0] = 00 → 无错误
ECCS[1:0] = 01 → 有错误已纠正(bit flip ≤ 8)
ECCS[1:0] = 10 → 有错误已纠正但接近阈值(≥ 8 flip,需关注!)
ECCS[1:0] = 11 → 不可纠正错误(UE),该页数据不可信
驱动处理逻辑(gigadevice.c ecc_get_status):
c
static int gd5fxgq4_variant2_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
switch (status & GD5FXGQ4_STATUS_ECC_MASK) {
case GD5FXGQ4_STATUS_ECC_NO_BITFLIPS:
return 0; // 正常
case GD5FXGQ4_STATUS_ECC_1_7_BITFLIPS:
return 7; // 有翻转,已纠正
case GD5FXGQ4_STATUS_ECC_8_BITFLIPS:
return 8; // 接近极限
case GD5FXGQ4_STATUS_ECC_UNCOR_ERROR:
return -EBADMSG; // 不可纠正,MTD 返回 EIO
}
}
工作中注意:
-
ECC 接近阈值(如返回 7~8)不是立即故障,但 UBI 会将该 PEB 标记为疑似坏块并搬迁数据
-
系统日志出现大量
mtd: corrected X bit errors说明 Flash 老化,需关注
1.6 Flash 可靠性与寿命
工作中影响 NAND 可靠性的几个重要概念:
磨损均衡(Wear Leveling):
NAND 每个 Block 有约 10 万次擦写寿命。如果某个区域被频繁写入(如日志),会提前损坏。UBI 通过磨损均衡算法(Wear Leveling)在所有可用 Block 上均匀分配写操作。
plain
UBI 维护每个 PEB 的 EC(Erase Count):
- 写操作时选择 EC 最小的空闲 PEB
- 静态数据也会定期迁移(static wear leveling)
- EC 差值超过阈值(默认 4096)时强制迁移
写放大(Write Amplification):
由于 NAND 必须先读-修改-写(如修改一个字节需读整页→修改→擦整块→写整页),实际写入量远大于逻辑写入量。UBIFS 通过日志结构化写入尽量减少写放大。
数据保持(Data Retention):
-
NAND 存储电荷会随时间泄漏,通常保证 1~10 年(取决于温度和擦写次数)
-
高温加速衰减,长期不通电设备存在数据丢失风险
-
ECC 可以纠正少量 bit flip,UBI 的 scrubbing 机制会定期重写数据
Read Disturb:
读取一个 Page 时,同一 Block 内其他 Page 的存储单元会受到轻微干扰(高压影响)。多次读取后可能导致 bit flip。UBI 的 scrubbing 可以检测并纠正这种问题。