只读分享解决方案文档原理方案设计📅 2026-09-25🔖 V1.1✅ 长期有效
🔧解决方案&应用市场分析 -> 原理方案设计 -> 并行总线系列产品方案 -> NAND_MCP_软件设计规范

NAND_MCP_软件设计规范

生成时间 2026-09-28 14:30:44 长期有效
同系列 · 原理方案设计

NAND MCP 软件设计规范

编制日期 2026-09-25 | 版本号 V1.1

面向 XTX XT61M4G8D2TA-B8Bxx / XT61M2G8D2TA-B8Bxx 系列(SLC NAND die + LPDDR2 die 合封,BGA-162)的固件驱动设计约定 —— 覆盖 异步 25 ns 命令组帧、5 周期地址映射、双 plane(2-plane) 并行与 Cache 流水、主机 8 bit/544 B ECC、 坏块判定与 BBT、LPDDR2 初始化与刷新、掉电数据完整性,逐条给出可落地的命令序列、判据与核查清单。

文档编号NAND-MCP-SW-SPEC-001 · V1.1版本V1.1(依手册 A1.9 / A1.6 校订)
适用器件XT61M4G8D2TA-B8Bxx(4 Gb + 2 Gb)
XT61M2G8D2TA-B8Bxx(2 Gb + 2 Gb)
参考手册XTX nMCP SPEC A1.9(4G2G,2025-12-06)
XTX nMCP SPEC A1.6(2G2G,2024-09-24)
NAND 接口异步 x8,tRC ≥ 25 ns,无同步模式配套文档NAND MCP 电路设计指南(硬件侧)

目的与范围

本文规定 XTX nMCP 中 NAND Flash 部分与 LPDDR2 部分的软件设计约束:命令组帧、地址映射、读写擦流程、主机 ECC、坏块管理、性能手段、DRAM 初始化与电源管理。

本文以手册 Table 3 命令表为唯一命令真值来源,以 Table 6 状态输出表为状态判据,所有时序数值均取自手册 AC / Program & Erase 特性表。

不覆盖范围:硬件原理图与布线(见电路设计指南);文件系统与 FTL 算法选型(本文只给约束,不指定实现);LPDDR2 控制器 IP 的内部实现(本文只给初始化与刷新约束);量产测试流程。

这颗器件不是 ONFI 同步器件,也没有多 CE 交错能力。把 eMMC 或 ONFI 2.x/3.x 的经验直接套过来,是本文档要拦住的第一类错误。

4 Gb SLC
+ 2 Gb LPDDR2
合封容量(基准料号)
4096 + 256
页大小(B)/块 = 64 页
25 µs
tR 阵列→寄存器(典型;最大 60 µs)
300 µs
tPROG 页编程(Typ)
3.5 ms
tBERASE 块擦除(Typ)
8 bit
/ 544 B
强制 ECC 要求
50 000
P/E 次数(配 8 bit ECC)
2008
~ 2048
有效块数 NVB(Min/Max)

文档使用说明

三条铁律,先记住再往下看
  1. 没有内部控制器。ECC、坏块管理、磨损均衡、掉电保护全部由主机软件承担;SoC 必须具备硬件 ECC 引擎(8 bit/544 B)。
  2. 只有异步模式。手册命令表里没有 ECh / EFh / EEh,也没有 NV-DDR2/3 同步时序模式——不存在「Set Features 切同步」这一步。
  3. 只有 1 个 CE#、1 个 R/B#。因此不存在多 CE interleave。并行只能靠「双 plane(2-plane) 同时操作」与「Cache 流水」两种手段。
符号约定
命令 用十六进制 + h 表示;危险 表示会导致数据丢失或器件损坏;建议 表示工程经验而非硬性约束。所有「典型值」在未标注时均指 25 ℃、VCC = 1.8 V 条件。
数值口径
手册同时给出 Typ 与 Max 两栏时,软件超时预算一律按 Max 取值,性能估算按 Typ 取值。本文表格会同时列出两栏,避免混用。

1 · 器件定位与合封架构

XTX nMCP 把一颗 SLC NAND die 与一颗 LPDDR2 die 封进同一个 BGA-162。两者电气上完全独立、可各自操作,共用的是封装、电源轨与上电时序。软件必须先认清「这是异步 Raw NAND,不是 ONFI 同步器件」,否则后面所有配置都会做无用功。

1.1 器件定位与关键参数

项目XT61M4G8D2TA-B8BxxXT61M2G8D2TA-B8Bxx软件影响
NAND 容量 / 位宽4 Gb(512 M × 8)2 Gb(256 M × 8)均为 x8,列地址 2 周期
页大小(4096 + 256) B(2048 + 128) Bspare 区不同,OOB 布局参数必须按料号取
块大小(256 K + 16 K) B = 64 页(128 K + 8 K) B = 64 页都是 64 页/块 → 块地址 = 页地址 >> 6
块数20482048行地址 PA6~PA16 共 11 bit
District(Plane)2 个,各 1024 块2 个,各 1024 块见 1.3,是唯一的片内并行手段
内部寄存器2 × 4352 B2 × 2176 BPage Buffer + Data Cache,Cache 流水的基础
接口模式异步 Only,串行读周期 25 ns(Min)无同步模式、无 Set Features
ECC 要求8 bit / 544 B硬件 ECC 引擎的硬指标
P/E 次数50 000(配 8 bit/544 B ECC)磨损均衡的预算基数
数据保持10 年(Typ)巡检周期设定依据
有效块 NVB2008(Min)~ 2048(Max)最多 40 个出厂坏块 ≈ 2%
NAND 电源VCC 1.7 ~ 1.95 V(单电源)没有 VCCQ,见第 11 章
LPDDR22 Gb(8 Banks × 8 M × 32),1066 Mbps两料号 DRAM 侧完全一致
封装162 ball BGA 8 × 10.5 × 0.9 mm162 ball BGA 8 × 10.5 × 0.95 mm仅硬件选型相关
选型硬门槛:SoC 必须有硬件 ECC 引擎

NAND 侧没有片内 ECC,手册明确要求 8 bit/544 B 由主机完成。若 SoC 只有 NAND 接口而无硬件 ECC 引擎,软件实现的 BCH 解码耗时远大于 tR(25 µs),性能与实时性都无法满足——不要选这颗 MCP。

块 0 保证有效。手册承诺出厂时 Block 0 是好块,因此 boot 代码放在块 0 是安全的。但请注意:BBT 不要存在块 0——很多 SoC 的 boot ROM 强制从块 0 读取,把元数据放在那里会互相干扰。

1.2 合封架构与两套总线

nMCP:NAND 与 LPDDR2 各有一套独立总线,仅共用封装与电源轨XT61M4G8D2TA · BGA-162 · 8 × 10.5 mmNAND Flash die(SLC)I/O0 ~ I/O7 命令 / 地址 / 数据复用CLE / ALE 命令、地址锁存使能CE# / WE# / RE# 片选、写、读WP# 硬件写保护(低有效)R/B# 开漏,需上拉至 VCCLPDDR2 die(2 Gb)CK / CK# 差分时钟(最高 533 MHz)CS#0 / CKE0 / CA[9:0] 命令地址DQ[31:0] / DQS[3:0] / DM[3:0]ZQ0 / RZQ0 校准基准(外接电阻)VREFCA / VREFDQ 参考电压输入共用电源轨(上电/掉电必须按序,见 11.1)NAND:VCC 1.7 ~ 1.95 V(单电源,无独立 VCCQ)DRAM:VDD1 1.70 ~ 1.95 V | VDD2 / VDDCA / VDDQ 1.14 ~ 1.30 V两套总线在软件上完全隔离,不得复用同一组引脚
图 1 nMCP 双总线架构:NAND 侧异步 8 位,DRAM 侧 LPDDR2,两者仅共用封装与电源

1.3 阵列组织与 District

手册把 NAND 阵列划分为 2 个 District(等价常见说法的「双 plane / 2-plane」),这是这颗器件唯一的片内并行能力:

层级划分数量
DistrictDistrict 0 = 偶数块(Block 0/2/4 … 2046)
District 1 = 奇数块(Block 1/3/5 … 2047)
2
Block每个 District 1024 块2048
Page每块 64 页131 072
Byte每页 4352 B(4 Gb 料号)/ 2176 B(2 Gb 料号)—
双 plane(2-plane):偶块归 D0、奇块归 D1,两个 District 可同时操作(Multi Page / Multi Block)District 0Block 0 / 2 / 4 … 2046(偶数块)1024 块 × 64 页 × 4352 BPage Buffer + Data CacheDistrict 1Block 1 / 3 / 5 … 2047(奇数块)1024 块 × 64 页 × 4352 BPage Buffer + Data CacheMulti 操作约束:每个 District 最多选 1 个块,且两块的块内页号 PA0~PA5 必须相同District 的先后顺序无要求:(60)[D0](60)[D1](30) 与 (60)[D1](60)[D0](30) 都可接受全器件只有 1 个 CE#、1 个 R/B# → 不存在多 CE interleaveMulti Page / Multi Block 结束时用 71h 读状态:70h 无法分辨是哪个 District 失败,I/O1 = 1 只表示「两页中有任一页失败」
图 2 双 plane(2-plane) 阵列组织与 Multi 操作约束

1.4 地址映射与 ID 识别

地址固定 5 个周期(列 2 + 行 3),手册 Table 1 定义如下:

周期I/O7I/O6I/O5I/O4I/O3I/O2I/O1I/O0
第 1 周期CA7CA6CA5CA4CA3CA2CA1CA0
第 2 周期LLLCA12CA11CA10CA9CA8
第 3 周期PA7PA6PA5PA4PA3PA2PA1PA0
第 4 周期PA15PA14PA13PA12PA11PA10PA9PA8
第 5 周期LLLLLLLPA16

位域含义:CA0~CA12 列地址(页内偏移 + spare);PA0~PA16 页地址;其中 PA6~PA16 是块地址(11 bit),PA0~PA5 是块内页号(6 bit,64 页)。

因此:页地址 = (块号 << 6) | 块内页号;擦除时行地址 = 块号 << 6。手册同时说明第 6 个地址周期会被芯片忽略,不要多发。

上电后通过 90h ID Read 读回 5 字节识别码,两个料号的取值:

字节含义XT61M4G8D2TAXT61M2G8D2TA
1stMaker Code98h98h
2ndDevice CodeAChAAh
3rdChip Number / Cell Type90h(1 chip,SLC)90h(1 chip,SLC)
4th页大小 / 块大小 / 位宽26h15h
5thPlane(District)Number76h76h

识别表必须收录两个 Device Code。同封装不同容量的料号可能在产线上互换,驱动只认一个码会直接返回 MCP_ENODEV 导致整机不开机。建议识别流程:先校验 Maker Code = 98h,再按 Device Code 查表取几何参数;未知码一律报错,不做「猜配置」。

2 · 术语与缩写

先统一语言。尤其注意 District / Page Buffer / Data Cache 这三个词——它们来自 XTX 手册,与 ONFI 规范里的 Plane / Cache Register 不是同一套说法,混用会导致对命令流程的误解。

2.1 术语表

术语全称 / 对应本文含义
MCP / nMCPMulti-Chip Package本文特指 XTX 的 NAND + LPDDR2 合封器件
District手册用词(≈ Plane)片内两个可独立操作的子阵列;D0 = 偶块,D1 = 奇块
Page Buffer页缓冲寄存器4352 B(2 Gb 料号 2176 B)静态寄存器之一,阵列与 Data Cache 之间的中转
Data Cache数据缓存寄存器另一个同级寄存器,主机串行读写的直接对象
Page页编程 / 读出的最小单位:4096 B 数据 + 256 B spare
Block块擦除的最小单位:64 页
Spare / OOB冗余区页尾额外区域,放 ECC 校验位与元数据
NVBNumber of Valid Blocks有效块数,2008(Min)~ 2048(Max)
CLE / ALECommand / Address Latch Enable区分当前周期是命令还是地址
R/B#Ready/Busy开漏输出,低 = 忙,需外部上拉
tRCell array to register阵列→寄存器时间,典型 25 µs / 最大 60 µs
tPROG编程时间300 µs(Typ)/ 700 µs(Max)
tBERASE块擦除时间3.5 ms(Typ)/ 10 ms(Max)
tDCBSYR1Read Cache 忙时间31h / 3Fh 之后,25 µs(Max)
tDCBSYW1/2Write Cache 忙时间11h 后 10 µs(Max);15h 后 700 µs(Max)
NOPNumber of Partial Program Cycles同一页可分段编程的次数,Max 4
MRW / MRRMode Register Write / ReadLPDDR2 的模式寄存器读写命令
DAIDevice Auto-InitializationLPDDR2 上电自检完成标志,轮询 MR0.DAI 获知
PASR / ATCSR部分阵列自刷新 / 温补自刷新LPDDR2 的低功耗特性
BBTBad Block Table主机维护的坏块表,需持久化到 NAND
UECCUncorrectable ECC超出纠错能力的不可纠正错误

2.2 书写约定

  • 命令码一律写成 00h / 30h 形式,与手册 Table 3 保持一致。
  • 地址周期按手册 Table 1 的 CAn / PAn 位域描述,不写「第几个字节」这类含糊说法。
  • 时序数值标注 Typ / Max:软件超时预算取 Max,性能估算取 Typ。
  • 状态位按手册 Table 6 的 I/O0~I/O7 编号,不采用 ONFI 的 FAIL / ARDY / RDY 命名。
  • 凡是本文给出但手册未明确规定的做法(如 BBT 结构、错误码),均标注为建议。

为什么不用 ONFI 术语:这颗器件的命令表里没有 ECh(Parameter Page)、EFh/EEh(Set/Get Features)、78h(Read Status Enhanced),也没有同步时序模式。它是异步 Legacy 接口的 SLC NAND,几何参数靠 90h ID 与料号识别表获得,而不是读参数页。用 ONFI 的命名去描述它,会让人误以为可以发这些命令。

3 · 驱动架构与初始化

初始化要解决三件事:让 LPDDR2 起来、让 NAND 进入已知状态、拿到正确的几何参数。三者有严格的先后顺序,且 NAND 侧在上电内部初始化期间只接受 FFh 与 70h——发别的命令一律无效。

3.1 软件分层

层级职责是否本文范围
文件系统 / FTL映射表、磨损均衡、垃圾回收仅给约束
NAND 抽象层坏块表 BBT、替换池、ECC 分级处置、掉电保护是
NAND 驱动命令组帧、地址映射、R/B# 等待、状态判定是
硬件 ECC 引擎8 bit / 544 B 编解码,返回纠正位数约束
NAND 控制器异步时序产生、CE#/CLE/ALE/WE#/RE# 控制约束
LPDDR2 控制器初始化、MRW/MRR、刷新、自刷新是
电源管理上电/掉电时序、PFO 检测是

3.2 上电初始化流程

上电初始化:电源 → LPDDR2(tINIT1~5 + MRW + ZQ)→ NAND(FFh 识别)→ 加载 BBT① 电源稳定(tINIT0 ≤ 20 ms 爬升)VCC 1.7~1.95 V(NAND)|VDD1 1.70~1.95 V|VDD2/VDDCA/VDDQ 1.14~1.30 V② LPDDR2 上电复位时序tINIT1:CKE 低 ≥ 100 ns | tINIT2:时钟稳定 ≥ 5 tCK 后 CKE 拉高tINIT3:CKE 拉高后空闲 ≥ 200 µs | tINIT4:复位命令后 ≥ 1 µs③ 轮询 DAI + 配置模式寄存器MRR 读 MR0.DAI 直到 ready(≤ tINIT5 = 10 µs)→ MRW 写驱动强度 / RL / WL / BL④ ZQ 校准(ZQCL)ZQ0/RZQ0 外接基准电阻,校准驱动强度与 ODT 后才能正常读写⑤ NAND 内部初始化(R/B# 保持 Busy)此期间只接受 FFh 或 70h;WP# 拉低可防误写⑥ 发 FFh → 90h 读 ID → 建立几何参数 → 加载 BBT(详见 3.3 / 7.3)
图 3 nMCP 上电初始化:DRAM 先行,NAND 内部初始化期间只能发 FFh / 70h

3.3 器件识别与几何参数建立

这颗器件没有参数页可读,几何参数来自两条路径:90h ID 识别表 + 料号常量表。推荐做法是「ID 校验 + 表驱动」:

/* 伪代码:识别并建立几何参数 */
static const struct mcp_geom {
    uint8_t dev_code;   /* 90h 读回的第 2 字节 */
    const char *name;
    uint32_t page_data; /* 数据区字节数 */
    uint32_t page_spare;/* spare 区字节数 */
    uint32_t pages_per_block;
    uint32_t blocks;
} geom_table[] = {
    { 0xAC, "XT61M4G8D2TA", 4096, 256, 64, 2048 },
    { 0xAA, "XT61M2G8D2TA", 2048, 128, 64, 2048 },
};

int mcp_nand_probe(void)
{
    uint8_t id[5];

    nand_reset();              /* FFh,等待 R/B# 回高 */
    nand_read_id(id);          /* 90h + 地址 00h,读 5 字节 */

    if (id[0] != 0x98)         /* Maker Code 必须为 98h */
        return MCP_ENODEV;

    for (i = 0; i < NR(geom_table); i++)
        if (geom_table[i].dev_code == id[1])
            return apply_geom(&geom_table[i]);

    return MCP_ENODEV;         /* 未知器件码:报错,绝不猜配置 */
}

三个识别陷阱:

  • 只比对 Device Code 而忽略 Maker Code,可能把别家的同码器件认进来;
  • 用页大小去反推料号,而不是用 ID——一旦同容量新料号上市就会误判;
  • 识别失败后仍用默认几何参数继续跑,这是最危险的一种:读写地址全错,且症状是「有时对有时错」。

3.4 上电与掉电时序约束

  • 上电期间 WP# 拉低:手册指出 WP# 可用于上电/掉电期间防止数据被意外改写;初始化完成后再拉高。
  • NAND 内部初始化期只发 FFh / 70h:发其它命令无效且可能损坏数据。
  • 掉电前不得进行写/擦:手册明确要求「写/擦完成前不要断电」,电量低时应主动停止写入。
  • PFO 中断处理:收到掉电预警立即停止新操作,完成在途写,刷写 BBT 与映射表。
  • 电源爬升 ≤ 20 ms(tINIT0):超出该上限需检查 PMIC 配置与软启动。

boot 阶段的特殊路径:若 SoC 的 boot ROM 直接从 NAND 读取启动代码,此时 DRAM 尚未初始化,驱动不能依赖任何缓存。建议实现一条裸读路径:只用栈上小缓冲、只发 00h-30h 顺序读、不做 ECC 之外的任何处理,等 DRAM 起来后再切到完整驱动。

4 · 命令集与组帧

本章所有命令逐条取自手册 Table 3。这颗器件不支持 ECh(读参数页)、EFh/EEh(Set/Get Features)、78h(增强状态读)与任何同步模式命令——如果你在别处看到这些命令的用法,那是 ONFI 同步器件,不适用这里。

4.1 命令表(手册 Table 3 真值)

功能第一周期第二周期Busy 期间可接受软件要点
串行数据输入80h——编程序列的起始,后接地址与数据
读(Read)00h30h—00h 后发 5 周期地址,30h 启动阵列搬运
随机读出列地址变更05hE0h—读 spare / 跳读页内位置,后面再跟 2 周期列地址
带 Cache 读31h——把下一页从 Page Buffer 搬到 Data Cache
Cache 读最后一页启动3Fh——结束 Cache 读序列,漏发会停在 Cache 模式
自动页编程80h10h—10h 后才真正写入阵列
随机写入列地址变更85h——分段编程,受 NOP ≤ 4 约束
带 Cache 自动编程80h15h—Cache Program,掉电风险见 6.3
多页编程(无 Cache)80h11h—两个 District 同时编程
多页编程(最后一页)81h10h—第二个 District 用 81h 起始
多页带 Cache 编程81h15h—与 80h-15h 配对使用
页拷贝读出00h3Ah—Copy-Back 的读阶段
页拷贝带 Cache 编程8Ch15h—Copy-Back 的写阶段
页拷贝最后页编程8Ch10h—结束 Copy-Back 序列
自动块擦除60hD0h—两周期设计用于防误擦
ID 读取90h——地址 00h,读 5 字节
状态读取70h—○单页 / 单块操作用它
多页编程 / 多块擦除状态读取71h—○Multi 操作结束必须用它
复位FFh—○终止当前操作
Busy 期间只允许 70h / 71h / FFh

手册明确规定:器件处于 Busy 状态时,除状态读与复位外不得输入任何命令。这条约束可以用来简化驱动设计——忙时不需要考虑命令仲裁,只管判状态。

80h 之后的命令白名单。一旦发出 80h,后续只允许 85h(换列)、10h(编程)、11h(多页)、15h(Cache 编程)、FFh(复位)。输入其它命令会导致本次编程不执行,且器件切换到该命令指定的模式——表现为「写成功但数据没进去」,极难定位。

4.2 命令-地址-数据组帧

组帧:CLE 选命令周期、ALE 选地址周期;地址固定 5 周期(列 2 + 行 3)CLE00h 命令ALE ×1CA0~CA7ALE ×2CA8~CA12ALE ×3PA0~PA7ALE ×4PA8~15×5PA16地址位域(手册 Table 1)PA0~PA5 = 块内页号(6 bit,64 页) | PA6~PA16 = 块地址(11 bit,2048 块)页地址 = (块号 << 6) | 页号;擦除时行地址 = 块号 << 6读序列末帧 30h30h 之后进入 tR,R/B# 拉低 ≤ 25 µs编程序列末帧 10h10h 之后进入 tPROG,R/B# 拉低 ≤ 700 µs第 6 个地址周期会被芯片忽略 —— 不要多发
图 4 五周期地址组帧:列地址 2 周期 + 行地址 3 周期,无同步模式概念

4.3 异步时序约束

器件只有异步模式,以下参数决定控制器时序配置(Ta = −40 ~ 85 ℃,VCC = 1.7 ~ 1.95 V):

符号参数MinMax单位
tRC读周期时间25—ns
tWC写周期时间25—ns
tREARE# 访问时间—20ns
tRP读脉冲宽度12—ns
tWP写脉冲宽度12—ns
tCSCE# 建立时间20—ns
tCLS / tALSCLE / ALE 建立时间12—ns
tDS / tDH数据建立 / 保持12 / 5—ns
tWBWE# 高到 Busy—100ns
tRRReady 到 RE# 下降沿20—ns
tWHRWE# 高到 RE# 低60—ns
tRHWRE# 高到 WE# 低30—ns
tWWWP# 高到 WE# 低100—ns

两条手册注释:① tCLS 与 tALS 不得短于 tWP;② tCS 应长于 tWP + 8 ns。控制器配置时把这两条作为约束检查项,而不是只看最小值。

4.4 状态读取与判据(手册 Table 6)

状态输出:70h 看整体成败,71h 能定位到 District;I/O5 / I/O6 判忙闲,I/O7 判写保护I/O0 Chip status 1  Pass = 0 / Fail = 1  编程、擦除有效;Cache 编程为当前页;读操作下 InvalidI/O1 [70h] Cache 编程的上一页成败;普通编程 / 擦除下 Invalid  [71h] District 0 的 Chip status 1,且为两 District 的 OR——任一失败即置 1I/O2 [71h] District 1 的 Chip status 1  (70h 下 Not used,恒 0)I/O3 [71h] District 0 的 Chip status 2  (70h 下 Not used,恒 0)I/O4 [71h] District 1 的 Chip status 2  (70h 下 Not used,恒 0)I/O5 Page buffer Ready/Busy  Ready = 1 / Busy = 0I/O6 Data cache Ready/Busy  Ready = 1 / Busy = 0(Cache 编程结束判据)I/O7 Write protect  未保护 = 1 / 已保护 = 0(低有效,别读反)判据顺序:先等 R/B# 回高 → 再发 70h/71h → 先判 I/O0 成败 → 再判 I/O7 保护位I/O0 / I/O1 的成败只在 Ready 态有效;71h 能定位 District,70h 的 I/O1 只能说「有页失败」
图 5 状态位定义:70h 与 71h 的 I/O1 ~ I/O4 语义不同,忙闲在 I/O5 / I/O6
/* 状态位定义(手册 Table 6) */
#define SR_FAIL         0x01   /* I/O0:1 = 失败 */
#define SR_CS2          0x02   /* I/O1:70h = Cache 编程的上一页;71h = District 0 CS1(两 District 的 OR) */
#define SR_D1_CS1       0x04   /* I/O2:71h = District 1 CS1;70h 下 Not used 恒 0 */
#define SR_D0_CS2       0x08   /* I/O3:71h = District 0 CS2;70h 下 Not used 恒 0 */
#define SR_D1_CS2       0x10   /* I/O4:71h = District 1 CS2;70h 下 Not used 恒 0 */
#define SR_PB_READY     0x20   /* I/O5:1 = Page buffer 就绪 */
#define SR_DC_READY     0x40   /* I/O6:1 = Data cache 就绪 */
#define SR_WP_N         0x80   /* I/O7:0 = 处于写保护 */

int nand_wait_ready(uint32_t timeout_us)
{
    uint8_t st;

    while (!rb_is_high()) {              /* 优先判引脚,最快 */
        if (--timeout_us == 0)
            return MCP_ETIMEOUT;
        delay_1us();
    }
    st = nand_status(0x70);
    if (!(st & SR_WP_N))                 /* 写保护生效 */
        return MCP_EPROGFAIL;
    if (st & SR_FAIL)                    /* 本页失败 */
        return MCP_EPROGFAIL;
    return MCP_OK;
}
极性陷阱:三处容易读反
  • I/O0 = 1 是失败(与「1 表示成功」的直觉相反);
  • I/O5 / I/O6 = 1 是就绪,与 R/B# 引脚「高 = 就绪」方向一致,但一个是位值一个是引脚电平,不要混用同一套变量名;
  • I/O7 = 0 是写保护生效——读到 0 时写/擦根本不会执行。

70h 与 71h 的分工:普通单页编程 / 单块擦除用 70h;多页编程(80h-11h、81h-10h、81h-15h)与多块擦除必须用 71h。因为 71h 下 I/O1 ~ I/O4 分别给出两个 District 的 Chip status 1 / 2(其中 I/O1 还是两个 District 的 OR),能定位到具体 District;而 70h 只有 I/O1 会置位表示「有任一页失败」,定位不到——这就是 Multi 结束必须用 71h 的原因。若确实只读了 70h,就应判定两个块都要读回校验,不能只处理其中一个。

4.5 复位的正确用法

复位时机手册说明软件处理
Read 中tRST ≤ 5 µs复位后可直接发新命令
Program 中tRST ≤ 10 µs被中断页内容不可信,需重新擦除
Erase 中tRST ≤ 500 µs等待时间比其它状态长两个数量级,别按 5 µs 写延时
Ready 中tRST ≤ 5 µs正常
Cache 编程中可能连前一页编程一起停止受影响的页都要重新处理

连续发两次 FFh 是允许的,手册专门列出了这种情况。但复位后不要立刻假设器件状态——先发 70h 确认回到 Ready,再继续后续操作。