Raw NAND 驱动库学习


author: xiexun

tags: Raw NAND, ONFI, SEMC, BootROM, OOB, ECC


Raw NAND 驱动库学习

代码学习:NXP i.MX RT BootROM 风格的并行 NAND 驱动库ONFD(GitHub - JayHeng/RT-RNAND: An ONFI-compliant Raw NAND flash universal driver | 一款基于ONFI标准的并行NAND Flash通用驱动,适配多款MCU硬件接口,目前主要适配i.MXRT的SEMC接口 · GitHub)


核心概念

Raw NAND :主机直接面对 Page/Block 命令接口;ECC、坏块、地址映射由主机侧完成。

Managed NAND(eMMC/UFS 等):主机多使用 LBA;ECC/坏块/磨损由片内 FTL 完成,OOB 对主机不可见。

ONFI(Open NAND Flash Interface):并行 Raw NAND 规范集合,覆盖命令集、时序、Parameter Page、存储组织等,不仅是软件协议名。

text 复制代码
Device → Plane/LUN → Block → Page → Main + Spare(OOB)
单位 含义
Page Read / Program 粒度
Block Erase 粒度
Plane/LUN 并行/多逻辑单元组织

Main / Spare(OOB):同一 Page 内主数据区与冗余区。Spare 存放:

内容 作用
ECC 校验/纠正 Main(或 ECC chunk)bit 错误
坏块标记 标识 Block 是否禁用(位置以 datasheet 为准,常见在特定 Page 的 Spare)
元数据 逻辑页号、有效标志等管理信息(是否使用取决于软件)

寻址:

视图 含义
线性字节地址 mem_read/write(addr) 的入参;软件抽象
pageIndex + column Flash 层单位;addr/pageSize、addr%pageSize
Column (CA) / Row (RA) 器件周期;由 SA = pageIndex × pageSize 按 COL 位宽拆分

操作约束:

  1. 擦后为 0xFF;Program 将目标 bit 置 0,不可按 RAM 原地改写

  2. 阵列操作后必须等 Ready(R/B# 或 Status 0x70)

  3. 必须处理 ECC 与坏块

    薄地址抽象对比FTL: memory 层做线性换算、页缓存、DBBT 整块跳过;无磨损均衡/GC/精细 LPN 映射。

上层:RT BootROM、Flashloader下载工具;并非通用文件系统块层。

【控制器 IP 行为】

SEMC(fsl_semc)职责:把软件意图变成命令/地址/数据周期,硬件自动翻译成 ONFI 8080 总线时序波形,并完成与 NAND 芯片的硬件交互、等待响应、数据收发闭环。

  1. 命令编码 :get_nand_code 打包 NAND 命令字节与地址/命令模式(CMD+ADDR、HOLD、READ/WRITE),硬件行为输出时序:CLE 拉高、ALE 拉低、WE# 脉冲,将命令字节锁存进 NAND
  2. 地址拆分 :软件提供字节地址 SA;IP 按 columnAddressWidth 生成 CA/RA(x8/x16 规则不同)。Spare 访问时 COL 可能多扩 1 bit(convert_nand_address) ,硬件行为输出时序:ALE 拉高、CLE 拉低、WE# 连续脉冲,逐周期发送地址。
  3. 数据通路:命令完成后经 IP Bus 或 AXI 搬 Main;Ready 走 R/B# 或 Status。

【软件驱动逻辑】

text 复制代码
BootROM / Flashloader
  → semc_nand_memory    # 线性地址、页缓存、DBBT、FCB/DBBT
    → semc_nand_flash   # ONFI 页/块、Parameter、ECC
      → fsl_semc        # IP 事务
        → NAND
层 对外接口 职责
fsl_semc IP 命令事务 地址转换、发令、搬数
semc_nand_flash pageIndex / blockIndex 命令序列、ECC
semc_nand_memory 字节 address 换算、缓存、跳坏块、Boot 控制块

Boot 相关数据 :FCB(含 nandConfig、固件副本表、DBBT 搜索区);DBBT(坏块列表)。mem_init:默认配置拉起 → 搜 FCB → 按 FCB 重 init → 搜 DBBT。

生命周期:片内 BootROM 极简路径加载下一级后交权;完整驱动在 Flashloader/应用侧接力,一般不同时占用同一套 SEMC+NAND 软件栈。本 archive 即 Boot/下载链路风格实现。


关键代码片段

配置字段(semc_nand_flash.h):

c 复制代码
uint32_t bytesInPageDataArea;   /* Main */
uint32_t bytesInPageSpareArea;  /* Spare/OOB */
uint32_t pagesInBlock;
uint32_t blocksInPlane;
uint32_t planesInDevice;

页读:页号 → SA → SEMC → issue (semc_nand_flash_read_page):

c 复制代码
ipgCmdAddr = pageIndex * config->bytesInPageDataArea; /* 字节 SA */
ipgCmdAddr = semc_ipg_command_convert_nand_address(&config->memConfig, ipgCmdAddr);
status = semc_nand_issue_read_page(config, ipgCmdAddr); /* 0x00/0x30 + wait */
/* 再 IP/AXI 搬 Main,并按配置做 Device/Software ECC */

Spare 路径地址整形 (semc_ipg_command_convert_nand_address):

c 复制代码
/* 输入始终为 byte address;Main 路径通常直接使用 SA */
if (columnAddressOption == SpareAreaAccess) {
    converted = (sa >> col) << (col + 1);
    converted |= sa & ((1u << col) - 1u);
}

线性读 (semc_nand_mem_read):

c 复制代码
pageIndex = address / pageSize;
pageColumnAddress = address % pageSize;
semc_nand_skip_bad_blocks(&pageIndex); /* DBBT:逻辑连续,物理可跳块 */
/* cache miss → flash_read_page;再按 column 切片拷出 */

调用链:

text 复制代码
mem_read → pageIndex/column + skip BB → flash_read_page
        → convert_nand_address + issue_read_page + 搬数/ECC

相关推荐
wixzjsh2 小时前
嵌入式Linux系统启动与内核驱动开发全解
linux·运维·驱动开发
喜欢打篮球的普通人2 小时前
MiniMind 学习笔记(二十二):数学 Cookbook——把概率空间、期望、似然一次讲明白
人工智能·笔记·学习
JWASX3 小时前
【agent 开发】agent 开发学习 - LangChain(3)
学习·langchain
dadaobusi3 小时前
一个有趣的物理假设
学习
JWASX4 小时前
【agent 开发】agent 开发学习 - LangChain(2)
python·学习·langchain
li星野5 小时前
【学习记录】立创EDA专业版核心概念全解析:数据整理、设计验证与器件四层模型
学习
知识分享小能手5 小时前
C学习教程,从入门到精通,C语言输入和输出(4)
c语言·开发语言·学习
旖旎夜光5 小时前
【LangGraph实战】LangGraph 学习笔记(四):持久化——从线程记忆到跨会话长期记忆
人工智能·笔记·python·学习·ai编程·langgraph
幼儿园蛋小黄5 小时前
从设备树到 ARM 驱动:嵌入式 Linux 驱动开发学习总结
linux·arm开发·驱动开发