PPI NAND Flash 软件设计规范
编制日期 2026-10-05 | 版本号 Rev 1.4
PPI-NAND-SW-SPEC-001 · V1.2
面向嵌入式系统 PPI NAND(并行接口 / Parallel NAND,含 ONFI Async、NV-DDR、Toggle)驱动、BBM/FTL 与中间件的设计约束与推荐实现。阵列语义与《SPI NAND》对齐,差异集中在并行总线接口、命令组帧与 HAL 职责边界。
1. 目的与范围
本规范规定 PPI NAND(Parallel Peripheral Interface NAND,即传统 并行接口裸 NAND)软件层的设计约束与推荐实现,目标是:
- 正确实现 CLE / ALE / CE# / WE# / RE# / R/B#(及可选 DQS)时序下的命令、地址、数据周期
- 规范 HAL / NFC 控制器 与驱动的职责边界(时序寄存器、位宽、EDMA、ECC 引擎)
- 保证读/编/擦可靠性(超时、R/B# + Status 双重确认、Fail 位、掉电安全)
- 正确处理 坏块管理(BBM)、片上/主机 ECC(含 8-bit 下 ≥6 bit 迁块标坏)、OOB/Spare
- 落实 整页一次写入 与 Partial Page Program 次数限制(默认 ≤4)、块内顺序编程、擦后 Blank Check
- 控制物理擦写次数(软件防抖 / 磨损均衡 / 读干扰 scrub / FTL)
- 规范使用 ONFI Parameter Page、Read ID、UID、OTP、WP# / 分区锁、Cache、多 Plane 等能力
- 落实 SDR 保底与 NV-DDR/Toggle 防变砖、替换池耗尽降级、Boot 非 XIP
- 规范 PPI NAND 与文件系统 的分层选型、分区(重要性/频率隔离)、挂载与掉电策略
与 SPI NOR / SPI NAND / SD NAND 的本质差异(必须理解):
| 维度 | SPI NOR | SPI NAND | PPI NAND | SD NAND |
|---|---|---|---|---|
| 主机视角 | SPI 字节命令 | SPI 页 Cache 命令 | 并行总线命令周期(CLE/ALE) | SD 块设备 |
| 坏块 / ECC | 通常无 / 可选 | 主机 BBM + ECC | 主机 BBM + ECC(同裸 NAND) | 片内 FTL 完成 |
| 忙判定 | WIP(05h) |
Feature C0h OIP | R/B# 引脚 + Status 70h |
DAT0 Busy / 令牌 |
| 发现参数 | SFDP | Feature + Param Page | ONFI Parameter Page / ID 表 | CID/CSD |
| 接口 | SPI/QSPI | SPI/QSPI | 8/16-bit IO + 控制线 | SD/SPI |
| 文件系统 | 可直挂友好 FS | 禁裸挂 FatFS | 禁裸挂 FatFS(同 SPI NAND) | 可挂 FatFS |
PPI NAND 与 SPI NAND 在阵列语义上高度一致(页编程、块擦除、坏块、ECC、FTL);差异几乎全在 主机接口与命令组帧。本规范 BBM / ECC / FS 策略对齐《SPI NAND》,接口与 HAL 章节按并行总线展开。
不在本规范范围: PCB 走线与 DDR/Toggle 电气完整性细则、具体厂商扩展命令全表(以 Datasheet 为准)、完整 FTL 算法论文级细节、某一 SoC NFC 寄存器手册全文。
2. 术语与缩写
| 术语 | 说明 |
|---|---|
| PPI NAND | Parallel Peripheral Interface NAND;并行接口裸 NAND(相对 SPI NAND) |
| CLE / ALE | Command Latch Enable / Address Latch Enable;锁存命令或地址 |
| CE# / WE# / RE# | Chip Enable / Write Enable / Read Enable(低有效惯例) |
| R/B# | Ready/Busy#;忙时拉低,完成后释放为高(开漏常见,需上拉) |
| I/Ox | 双向数据总线;常见 ×8 或 ×16 |
| DQS | 源同步数据选通(NV-DDR / Toggle 模式) |
| SDR / Async | 异步单数据速率接口(经典并行 NAND,本规范默认) |
| NV-DDR / Toggle | ONFI / Toggle 源同步高速模式 |
| NFC / EBI / FSMC | SoC 侧并行 NAND / 外部总线控制器(名称因芯片而异) |
| Page | 编程最小单位;常见 2KB+64B、4KB+128/218/224B 等(含 OOB) |
| Block | 擦除最小单位;常见 64/128/256 页 |
| Plane / LUN / Die / Target | 多平面/逻辑单元/Die/目标片选;影响并行与 CE# 选择 |
| Column / Row | 页内字节偏移 / 页号(含 Block+Page,多 Plane 含平面位) |
| OOB / Spare | 页外带区;ECC、坏块标记、FTL 元数据 |
| Status Register | 读状态命令(常 70h)返回的 SR;含 Ready、Fail、WP 等 |
| Fail | Program Fail / Erase Fail 状态位(命名因厂而异) |
| ONFI | Open NAND Flash Interface |
| Parameter Page | ONFI 参数页(几何、时序、特性、CRC) |
| ECC 强度 | 每码字可纠正最大比特数;本规范默认示例 8-bit |
| 位翻转阈值 | 可纠正错误达阈值时迁块;默认 8-bit 下 ≥6 bit |
| PPP | Partial Page Program,同一物理页在两次 Erase 之间的部分编程次数 |
| BBM | Bad Block Management |
| FBBT | Factory Bad Block Table;由扫描 OOB 工厂标记生成 |
| BB Marker | 坏块标记:通常为 Block 内指定页 Spare 首字节非 0xFF |
| 初始坏块率 | 出厂允许坏块比例,行业常见上限约 2% 总块数 |
| FTL / NFTL | Flash Translation Layer;向通用 FS 提供块设备抽象 |
| LBA | Logical Block Address |
| GC | Garbage Collection |
| tCLS/tCLH/tALS/tALH | 命令/地址建立与保持时间 |
| tWP / tWH / tRP / tREH | WE#/RE# 脉冲宽度与高电平时间 |
| tWB / tR / tPROG / tBERS / tRST | 命令后忙、读阵列、编程、擦除、复位时间 |
| tVSL / tPOR | 上电到允许命令的等待时间 |
| WP# | Write Protect 引脚;硬件写保护 |
| Cache Read / Program | 页缓冲流水命令,用于吞吐优化 |
| Copyback | 片内页搬移;默认禁止作用户迁移主路径 |
容量与几何换算约定:
- 软件内部统一用 字节逻辑地址 或 (target, lun, plane, block, page, column);驱动层必须能互转
- 禁止把 PPI NAND 当成“按 4KB Sector 擦的 NOR”或“SD 块设备”来建模
- 禁止把 SPI NAND 的
13h/0FhFeature 帧直接套到 PPI 总线上 - ×16 器件:能力表必须写明 Column 与主机缓冲是按 字节 还是按 字 计数
3. 软件分层架构(推荐) 推荐
┌──────────────────────────────────────────────┐
│ 应用 / 文件系统 (UBIFS / LittleFS+FTL...) │
├──────────────────────────────────────────────┤
│ FTL / 磨损均衡 / 逻辑卷 │
├──────────────────────────────────────────────┤
│ BBM(坏块表、替换、标记) │
├──────────────────────────────────────────────┤
│ PPI NAND 驱动(命令序列、ECC、超时、ONFI) │
├──────────────────────────────────────────────┤
│ HAL:周期原语 + 时序/位宽/DMA/硬件 ECC │
├──────────────────────────────────────────────┤
│ 并行 NAND 控制器(FSMC/EBI/NFC/GPIO bitbang)│
└──────────────────────────────────────────────┘
强制要求:
- 应用层禁止直接拨 CLE/ALE 发 Erase / Program;必须经驱动统一入口。
- 坏块判定与替换不得散落在业务代码;统一由 BBM 层处理。
- HAL 只提供:发命令 / 发地址 / 写数据 / 读数据 / 读 R/B# / 可选硬件 ECC 结果;不得在 HAL 内散落业务超时策略。
- 驱动初始化必须完成:
- 等待 tVSL → Reset(
FFh)→ 等 R/B# → Read ID → 读 ONFI Parameter Page / 静态几何表 → - 配置时序/位宽/ECC → 扫描/加载坏块表 →(可选)挂载 FTL。
- 同一颗料的 SDR / DDR / Toggle 模式切换必须有能力表与恢复路径;禁止未验证就开高速模式。
图 2 · 上电初始化七步:tVSL 等待是并行总线特有的强制前置,远重于 MCU 复位释放 3.1 上电时序 tVSL(强制) 强制
VCC 到达工作电压后,PPI NAND 不能立刻接收命令。Datasheet 规定的 tVSL / tPOR(厂商命名不一)未满足时发 90h/70h/FFh 等,可能导致:ID 全 0x00/0xFF、R/B# 假 Ready、擦写进入不确定态,甚至把控制器时序状态机卡死在错误模式。并行总线比 SPI 更依赖电源稳定——IO 上拉、CE# 默认态、R/B# 开漏在上电斜坡期间都可能处于中间电平。
| 项 | 要求 |
|---|---|
| 等待起点 | 以“电源好 / 电压监控释放 / ADC 确认 VCC≥VCC(min)”为起点,而非仅以 MCU 复位释放为起点 |
| 等待时间 | ≥ 目标器件 Datasheet Max tVSL / tPOR;多料号兼容时取清单内最大值 |
| 典型量级 | 常见数十 µs ~ 数 ms(以 Datasheet 为准;禁止凭经验写死过小值) |
| 与 BOR 关系 | Brown-out 恢复后视为重新上电,必须重新等待 tVSL,并强制回 SDR 安全时序 |
| 首条命令 | tVSL 满足前:禁止 Read ID / Status / Parameter Page / 擦写 / 切 DDR |
| Soft Reset | FFh 后须满足 tRST 并等 R/B# Ready(双重确认),再发其它命令 |
| R/B# 上拉 | 开漏必须有合适上拉;上电初期高阻/毛刺不得判为 Ready——以 Status 为准 |
| 实现位置 | 建议在 ppi_nand_init() 最前部统一等待,避免各调用点遗漏 |
wait_until_vcc_ok()
delay_at_least(tVSL_max)
hal_set_bus_sdr_safe() // 控制器回异步安全时序
nand_reset() // CLE: FFh
wait_rb_ready_double() // R/B# 或 Status Ready,双重确认
id = read_id() // CLE: 90h + ALE + 读 ID
param = read_parameter_page() // ECh 等
configure_timing_ecc_wp()
scan_or_load_bbt()
3.2 Boot / 启动架构(强制) 强制
PPI NAND 通常不支持像 SPI NOR 那样的 CPU Memory-Map XIP 直接取指启动(部分 SoC 的 NFC BootROM 属专项认证例外)。
| 项 | 要求 |
|---|---|
| 启动介质 | BootROM / 片内 ROM / 小容量 SPI NOR / eMMC 等可执行介质加载一级 Loader |
| NAND 角色 | 存放 App、文件系统、资源;由 Loader/App 通过命令模式访问 |
| 禁止 | 假定把 NAND 映射到地址空间即可执行代码(除非芯片与料号明确支持且已专项认证) |
| 双 Flash | 推荐:NOR 存 Bootloader + 关键恢复镜像;PPI NAND 存大容量数据 |
| 恢复 | NAND BBT/FTL 损坏时,仍须能从 NOR/ROM 进入维护模式重刷 |
| Loader 接口 | Loader 必须能在 Async SDR 下完成 Reset / ID / 基本页读 |
Power-On → ROM/NOR 启动 Loader
→ 初始化 PPI NAND 驱动(§3.1)
→ 加载 BBT / 挂载 FTL
→ 校验并跳转 App(代码先拷入 RAM,或按平台支持方式加载)
3.3 HAL 原语与职责边界(强制) 强制
| HAL 原语(示例) | 职责 |
|---|---|
cmd(uint8_t c) |
CLE=1, ALE=0,写入命令字节,满足 tCLS/tCLH/tWP |
addr(uint8_t *a, n) |
CLE=0, ALE=1,写入 n 个地址字节 |
write_data(buf, n) |
CLE=0, ALE=0,WE# 写入数据 |
read_data(buf, n) |
CLE=0, ALE=0,RE# 读出数据 |
rb_is_busy() |
采样 R/B#(注意开漏与毛刺) |
ecc_hw_* |
可选:启动/取回硬件 ECC 结果 |
| 项 | 要求 |
|---|---|
| 禁止 | HAL 内写死某料号的“擦完延时 3ms 就返回成功” |
| 禁止 | 业务层直接操作 NFC 寄存器绕过驱动锁 |
| EDMA | DMA 完成 ≠ 阵列操作完成;仍须 Ready 双重确认 |
| 中断 | R/B# 边沿中断可唤醒轮询,不可单独作为成功依据 |
3.4 控制器时序配置(强烈推荐) 强烈推荐
软件必须在能力表/设备树中配置(名称因 SoC 而异),并与 Datasheet 全温最差取交:
| 参数类 | 示例 | 说明 |
|---|---|---|
| 命令/地址 | tCLS, tCLH, tALS, tALH, tCS, tCH | 建立/保持 |
| 写脉冲 | tWP, tWH, tDS, tDH | 数据建立相对 WE# |
| 读脉冲 | tRP, tREH, tREA, tRHZ | 数据有效窗 |
| 模式 | SDR / DDR / Toggle、DQS 延迟 | 高速模式专项 |
| 位宽 | ×8 / ×16 | 与料号一致 |
配错 tREA/tRP 的典型症状:读数据偶发错位、ECC 误报升高、ID 字节漂移。量产前必须在高低温下抽测。
4. 读 / 编 / 擦操作与 Timeout(强制) 强制
图 3 · 命令模型对照:SPI NAND 的 13h/0Fh Feature 帧严禁套到 PPI 总线上 4.1 命令模型(与 SPI NAND 对照)
PPI NAND 通过 命令周期 + 地址周期 + 数据周期 访问阵列,不是 SPI 单帧 Opcode。
4.1.1 读页(Page Read)— 典型 ONFI / 传统序列
1. CLE: 00h
2. ALE: Column(通常 2 字节)+ Row(通常 3 字节) // 以 Datasheet 为准
3. CLE: 30h
4. 等待 tWB 后轮询 R/B# → Ready(双重确认);或读 Status Ready
5. 检查 / 准备 ECC(On-Die 状态或主机解码)
6. (可选)CLE: 05h(2 周期列地址)→ E0h 随机数据输出(Random Data Output)→ RE# 突发读出 Main/OOB
7. 主机侧处理 OOB / 软件 ECC(若未用 On-Die / 硬件 ECC)
4.1.2 Random Data Output(页内随机读出)
1. 已完成 00h-30h 且 Ready
2. CLE: 05h
3. ALE: Column
4. CLE: E0h
5. RE# 读出从 Column 起的数据
用途:只读 OOB、只读某 ECC step、BBT 扫描。禁止用错误 Column 宽度导致读飞。
4.1.3 编程(Page Program)
1. CLE: 80h
2. ALE: Column + Row
3. 写入 Main [+ OOB] 数据(WE# 周期;主机 ECC 则先编码)
4. CLE: 10h
5. 等待 R/B# Ready(双重确认)
6. CLE: 70h 读 Status;检查 Fail;失败则按坏块策略处理
4.1.4 Random Data Input(页内随机写入)
CLE: 85h + ALE Column + 写数据
仍计入 PPP;与 Main 同一次 10h 提交前的多次 85h 也计入次数(以 Datasheet 为准)。
4.1.5 擦除(Block Erase)
1. CLE: 60h
2. ALE: Row(指向块内约定页,通常首页)
3. CLE: D0h
4. 等待 R/B# Ready(双重确认)
5. Status 检查 Erase Fail;失败则标记坏块
多 Plane 擦除(若启用):按 Datasheet 使用 60h-60h-D0h 等变体;默认产品路径关闭。
4.2 与 SPI NAND 命令映射(防混用速查)
| 操作 | SPI NAND(典型) | PPI NAND(典型) |
|---|---|---|
| 页读到阵列完成 | 13h + 轮询 C0h OIP |
00h…30h + 等 R/B# |
| 从页缓冲读出 | 03h/0Bh… |
RE# 读数据 / 05h-E0h |
| 编程 | 06h+Load+10h |
80h+data+10h |
| 擦除 | 06h+D8h |
60h+D0h |
| 读状态 | Get Feature 0Fh+C0h |
70h Status |
| 读 ID | 9Fh |
90h |
| Reset | FFh / 66h+99h |
FFh |
| 参数页 | Feature OTP + Page Read | ECh Read Parameter Page |
| 配置 | Set Feature 1Fh |
ONFI EFh/EEh(若支持) |
4.3 基本原则
并行 NAND 的“操作完成”由阵列内部状态决定,主机无法从“发完命令”推断结果。噪声、假 Ready、掉电半完成都会让“盲延时成功返回”变成静默坏数据。
强制规则:
- 所有 Page Read(阵列搬移)/ Program / Block Erase 必须:
- 按 Datasheet 发送完整命令/地址/数据周期(CLE/ALE/数据节拍不得缺周期)
- 等待 R/B# Ready,并用 Status 双重确认(见 §4.5;本规范唯一合法完成模板)
- 同时施加 分类 Timeout(读 / 编 / 擦 / Reset 分表,禁止万能超时)
- 完成后检查 Fail / ECC status;Fail 或不可纠正 ECC 不得当成功
- 禁止仅靠固定
delay_ms()盲等;轮询为主,Timeout 为辅。 - Timeout 到期后:禁止假定成功;应读 Status、必要时 Soft Reset(
FFh)并回 SDR,返回可区分错误码。 - 禁止在 R/B# 忙期间发起无关命令(除 Datasheet 允许的 Read Status
70h)。 - 禁止在未持驱动锁时穿插另一任务的 CLE/ALE 序列(总线被打断等价于命令损坏)。
- Program/Erase 前确认目标块不在坏块表;读路径也须拒绝对已知坏块的“当好块用”。
4.4 Timeout 取值策略
Timeout 过短 → 正常慢擦被当成失败并误标坏块;Timeout 过长 → 真卡死拖死整机看门狗。并行 NAND 的 tR / tPROG / tBERS 随工艺、温度、循环次数变化大,必须按料号分类配置。
| 优先级 | 方法 | 说明 |
|---|---|---|
| 1 | Datasheet Max | tR / tPROG / tBERS / tRST 最大值 + 20%~50% 余量 |
| 2 | Parameter Page | 若提供典型/最大时间字段则优先解析并交叉核对 Datasheet |
| 3 | 产品配置表 | 按 Read ID / ONFI 签名查本地能力表(兼容无有效 Parameter 的料) |
推荐默认量级(仅参考,必须以料号为准):
| 操作 | 典型量级 | 软件 Timeout 建议 |
|---|---|---|
| Page Read(tR) | 20 ~ 100 µs | Max × 1.5,且 ≥ 1 ms |
| Page Program(tPROG) | 0.3 ~ 3 ms | Max × 1.5,且 ≥ 10 ms |
| Block Erase(tBERS) | 2 ~ 15 ms(SLC)~ 更长(MLC/TLC) | Max × 1.5,且 ≥ 50~100 ms |
| Soft Reset(tRST) | 按 Datasheet | Max + 余量;单独配置 |
| Cache 相关 | 按 Datasheet | 单独配置,禁止复用 tR/tPROG |
| 命令后进忙(tWB) | 数十~数百 ns 量级 | 轮询前可插入极短等待,但不得替代 Ready 判定 |
禁止与 SPI NOR 共用 Sector/Chip Erase 超时表;禁止与 SPI NAND 共用“只轮询 Feature、不接 R/B#”的实现;禁止全项目一个“万能 5 秒超时”。
高温、接近寿命末端时 tPROG/tBERS 可能显著变长:能力表可提供 timeout_hot_scale(例如 ×1.2),与 §7.5 温度策略联动。
图 4 · R/B# 与 Status(70h)双重确认:R/B# 只表示「忙窗口结束」,成功与否以 Status 为准 4.5 R/B# 与 Status 双重确认(强制) 强制
擦写/页读阵列操作期间,R/B# 引脚可能因 上拉过弱、线缆噪声、ESD、控制器采样毛刺、器件内部状态切换瞬间 等原因出现偶发假 Ready;单独一次 Status 读也可能因总线毛刺得到假 Ready 位。
因此:仅观察到一次 Ready,不得判定 Page Read / Program / Erase 完成。
与《SPI NOR》§4.3(WIP 双重确认)、《SPI NAND》§4.4(OIP 双重确认)同级加严;接口不同,语义相同。
实现注意: 本节以下伪代码为唯一合法完成判定模板。禁止再实现“R/B# 变高就返回成功”或“读一次 70h Ready 即成功”的简化逻辑。
强制规则:
- 判定 Page Read / Program / Erase 完成前,必须满足:
- R/B# 为 Ready,且 连续 ≥2 次 独立读 Status(
70h)均为 Ready;或 - 无可靠 R/B# 连线时:连续 ≥2 次 Status Ready(两次独立命令事务),并仍强烈建议接 R/B#。
- 两次 Status 读之间应有短暂间隔(建议 ≥ 1~10 µs);至少完成两次独立 CLE
70h事务。 - 若第一次 Ready、第二次 Busy:视为未完成,清零确认计数,继续轮询直至双重确认成功或 Timeout。
- 双重确认通过后,再检查 Fail / ECC(编擦看 Fail;读看 ECC)。Fail 或不可纠正不得当成功。
- DMA/EDMA 半包/全包中断后,禁止用“已传输字节数”代替 Ready 判断——DMA 完成 ≠ 阵列操作完成。
- R/B# 上拉过弱或干扰导致毛刺时,以 Status 为准,并记录
rb_glitch类告警;长期毛刺须改硬件/时序。 - Soft Reset、模式切换、故障恢复路径同样适用本规则。
推荐伪代码(标准实现 — 唯一合法模板):
t0 = now()
ready_streak = 0
required = 2 // 连续 Ready 次数,默认 2,可配置 ≥2
do {
if (rb_pin_is_busy()) {
ready_streak = 0
} else {
st = read_status_70h() // 独立命令事务:CLE 70h + 读 1B
if (!status_ready(st)) { // Ready 位定义须按料号替换
ready_streak = 0
} else {
ready_streak++
if (ready_streak >= required)
break
}
}
if (now() - t0 > timeout)
return PPI_NAND_ERR_TIMEOUT
yield_or_sleep(poll_interval) // 建议 10µs~1ms,避免占死 CPU
} while (1)
if (op == PROGRAM && status_fail(st)) return PPI_NAND_ERR_P_FAIL
if (op == ERASE && status_fail(st)) return PPI_NAND_ERR_E_FAIL
if (op == READ) return decode_ecc_status(...) // 见 §6
说明:
- 部分 Datasheet 仅要求“等 R/B# 再读 Status”;本规范在此基础上加严为 R/B# + 连续两次 Status Ready(或无脚时两次 Status)。
- Status 位定义(Ready / Fail / WP)因厂而异,能力表必须提供解析掩码;附录 E 仅为模板。
- Memory-Mapped NFC 读阵列 不得代替 Status 忙判定。
- 多 LUN / 多 CE# 时,确认的是本次命令目标的状态(必要时用 Enhanced Status
78h等,以 Datasheet 为准)。
4.6 Cache Read / Cache Program(可选增强) 可选
| 项 | 要求 |
|---|---|
| 目的 | 流水化提升顺序吞吐 |
| 启用 | 能力表显式打开;单页路径验证稳定前禁止 |
| 退出 | 异常、BBT 扫描、模式切换、故障恢复前必须回到已知空闲态(必要时 FFh) |
| 错误 | Cache 路径同样必须检查 Fail / ECC;禁止“为快而跳过状态” |
| 与锁 | Cache 序列必须原子持锁,禁止中途插入其它 Target 命令 |
4.7 失败与恢复
| 失败类型 | 处理 |
|---|---|
| Timeout | 记录 op/row/status/R/B#;尝试 Soft Reset;重新 ID;返回 ERR_TIMEOUT |
| Program Fail | 该页/块视为不可靠;标记坏块;返回 ERR_P_FAIL |
| Erase Fail | 标记坏块;返回 ERR_E_FAIL |
| ECC 不可纠正 | 返回 ERR_ECC_UNCORRECTABLE;按 §6 整块迁移 + 标记坏块 |
| ECC 可纠正且 bitflip ≥ 迁块阈值(8-bit 默认 ≥6) | 按 §6 整块迁移 + 标坏 |
| ECC 可纠正且 bitflip < 阈值 | 返回成功并上报 corrected bits |
| 时序模式异常 | 回 SDR + Reset;返回 ERR_TIMING_MODE |
5. 坏块管理 BBM(强制) 强制
NAND 出厂允许存在坏块;运行中编程/擦除失败也会新增坏块。无 BBM 的驱动视为不合格。
本节与《SPI NAND》§5 对齐(并行 NAND 本是坏块标记惯例的源头)。
5.1 出厂坏块数量(行业惯例)
| 项 | 行业常见约定 | 软件要求 |
|---|---|---|
| 出厂初始坏块上限 | 多数 Datasheet 按 不超过总 Block 约 2% | 以目标料号为准 |
| 零坏块料 | 部分筛选料可宣称 0 | 仍须具备运行期 BBM |
| 寿命期新增 | P_FAIL/E_FAIL/ECC 仍可能产生 | 替换池再按 ≥2% 预留 |
| 分区影响 | 坏块可能聚集 | 小分区按最坏留余量;禁止假设“前 N 块一定好” |
总块数 N
出厂坏块预算 ≈ ceil(N × 2%)
运行期替换池 ≥ ceil(N × 2%)
用户可见好块 ≤ N - 出厂已标坏 - 替换池 - BBT/系统保留
图 5 · 出厂坏块标记位置:Spare 区首字节约定(常见 0x800),扫描须覆盖 Page0 与冗余 Page1 5.2 出厂坏块标记位置(扫描强制) 强制
| 项 | 行业常见约定 |
|---|---|
| 判定 | 规定位置标记字节 ≠ 0xFF |
| 主位置 | Block Page 0 Spare/OOB 第 1 字节 |
| 辅位置 | 常同时检查 Page 1 Spare 第 1 字节 |
| 末页 | 少数料号要求;以 Datasheet 为准 |
| ×16 器件 | 标记可能占 1~2 字节;能力表写 bb_marker_len |
| Main 区标记 | 极少数老流程;现代料 以 Spare 为准 |
for block in all_blocks:
for page in bb_marker_pages: // 默认 {0, 1}
raw_read_oob(block, page, off=0, len=bb_marker_len) // 关 ECC / Raw
if any_byte != 0xFF:
mark_factory_bad(block)
break
典型页布局(2KB+64B 例):
Page 0:
Main[0 .. 2047] | OOB[0]=BB_MARKER ← 工厂坏块看这里是否为 0xFF
| OOB[1 ..] 用户/ECC(ECC on 时部分为 parity,勿当标记)
| 项 | 要求 |
|---|---|
| 时机 | 首次擦写之前完成 FBBT;禁止先 Erase 再扫 |
| ECC | 扫标记必须 关 On-Die ECC / 关硬件 ECC 或走 Raw |
| Cache | 扫 BBT 前退出 Cache 流水 |
| 禁止擦标记 | 对已识别坏块 禁止 Erase(除受控写运行期标记) |
| 能力表 | bb_marker_pages[]、bb_oob_offset、bb_marker_len、是否查 last page |
图 6 · 运行期标坏流程:先迁数据后落标,映射最后改,全步骤掉电可重入 5.3 运行期坏块标记(强制) 强制
| 项 | 要求 |
|---|---|
| 写入位置 | 与工厂一致:优先 Page 0 OOB[0]=非 0xFF(常用 0x00);Datasheet 要求则 Page1 同写 |
| 流程 | 先搬迁有效数据 → 写 OOB 标记 → 提交 BBT(掉电安全见 §11) |
| ECC | 写标记按厂商要求 Raw/关 ECC,避免 parity 覆盖标记字节 |
| 与用户 OOB | 标记字节占用的 offset 不得再给 FTL/FS |
触发条件:
- Program Fail / Erase Fail
- ECC 不可纠正
- ECC 可纠正但 corrected bits ≥ 迁块阈值(8-bit 默认 ≥6)
标准动作:
- 从空闲好块池分配目标块
- 将该坏/濒危块内仍可读的有效页全部搬迁到新好块
- 更新 FTL/BBM 映射并提交
- 写 OOB 坏块标记 + 更新 BBT 多副本
- 向上层返回可区分错误/告警码
5.4 强制禁止 强制
- 禁止假设“新片子无坏块”跳过扫描。
- 禁止对已知坏块 Erase/Program(除受控写标记)。
- 禁止坏块表单副本无备份。
- 禁止业务层绕过 BBM 裸写物理地址。
- 禁止未扫 FBBT 前全盘 Erase。
- 禁止用“Main 是否全 0xFF”代替 OOB 坏块判定。
- 禁止在 ECC 开启时用“读到的 OOB 第一字节”直接当工厂标记而不走 Raw。
5.5 保留区规划(推荐) 推荐
| 区域 | 说明 |
|---|---|
| BBT 副本区 | ≥2 个相隔较远的好块 |
| FTL 超级块/映射 | 多副本 + 世代号 |
| 替换块池 | 预留 ≥2% 好块;耗尽见 §5.7 |
| OTP/工厂数据 | 与主数据隔离 |
图 7 · BBT 格式:魔数 + 版本 + JEDEC ID + 带来源标记的表项 + CRC;上电优先加载持久化表 5.6 BBT 格式与存放(强制) 强制
| 项 | 要求 |
|---|---|
| 内容 | 魔数、版本号、Device ID、容量/几何摘要、坏块位图或列表(区分 factory/runtime)、CRC32 |
| 多副本 | ≥2 份,分属不同物理 Block;启动选 CRC 正确且世代更新者 |
| 与 FBBT | 首次扫 OOB 生成;运行期坏块合并,不得丢掉工厂坏块 |
| 启动 | 优先加载持久化 BBT;仅工厂/维修/BBT 全损时全盘扫描 |
| 更新 | 标坏后先写新 BBT 再提交 |
| 禁止 | 无版本无 CRC;单副本;与可 GC 用户数据混放无钉扎 |
5.7 替换池耗尽降级(强制) 强制
| 状态 | 行为 |
|---|---|
| 池水位低(如剩余 < 0.5% 或 < N 块) | 告警,仍可写 |
| 池空 | 返回 PPI_NAND_ERR_NO_SPARE |
| 耗尽后 | 只读/降级;拒绝用户擦写 |
| 上报 | spare_exhausted 对云端/UI 可见 |
| 恢复 | 维护模式换片或重建 |