SPI NAND 首次启动失败 · 样机排查手册
编制日期 2026-09-21 | 版本号 Rev 1.0
XTX 芯天下 · FAE 样机 bring-up 技术文档 | 面向第一次上电 / 手焊 / 飞线场景 | 2026-09 版
页大小、块大小、OOB 大小与布局、ECC 算法与强度、上电等待时间、BootROM 的 BOOT 区范围与读取策略 —— 全部以器件 datasheet 与主控平台手册为准。本文只讲机制与定位方法,不代替 datasheet。
- SPI NAND 的页 / 块 / OOB 参数没有统一值:页常见 2 KB / 4 KB,一块常见 64 或 128 页,OOB 常见 64 / 128 / 256 字节 —— 都只是常见值,必须逐颗核对该料号 datasheet。
- ECC 是 NAND 的生死线:算法(BCH / RS 一类)、纠错强度、校验码放在 OOB 的哪个偏移,由烧录器、BootROM、驱动三方约定,任一方不一致都是「能烧不能启」。
- BootROM 读 NAND 的行为是平台固化的:BOOT 区包含多少个 block、是否跳坏块、是否做多副本、用片内 ECC 还是软件 ECC,以主控厂商的 TRM / BootROM 手册与 SDK 源码为准。
- 本文出现的所有命令码与参数均为常见写法示例,不是通用常量;凡标注「以手册为准」的条目,现场必须复核后再动手。
一句话结论:SPI NAND 起不来,绝大多数不是「数据没烧进去」,而是「烧进去的位置、ECC 的算法、坏块的处理方式」与 BootROM 期望的不一致。NOR 是「给个地址就给你数据」,NAND 是「先认器件、再搬页、再查 ECC、还要躲开坏块」—— 多出来的每一步都是一个独立的失败点,定位时必须按步骤切开看,不能当成一件事。
这份文档解决什么
解决的是样机第一次上电:串口无输出、报 ECC error / bad block / 读超时、或读到空片这一类问题的定位与修复。全文按「差异 → 定段 → 决策树 → 分成因 → 速查 → 清单」组织:第 1 章讲 NAND 与 NOR 在启动这件事上的五条本质差异,第 2 章给出四步手工定位法与抓包断点,第 3 章是决策树,第 4 章是七类根因的原理 + 实操 + 验证,第 5 章是速查表,第 6 章是清单与结案模板。
区分侧重:本文讲样机首次 bring-up(飞线、手焊、转接板、第一次上电、最小系统);产线批量烧录失败、治具供电、烧录器参数卡属于量产篇,两者根因分布不同,不要混用结论。
1. 与 NOR 的本质差异:为什么 NAND 启动难查得多
SPI NOR 与 SPI NAND 都挂在同一个 SPI 控制器上、用几乎一样的引脚,所以很多人下意识把它们当成「同一种东西的不同容量」。但在「启动」这件事上,两者的差别是结构性的:NOR 是给个地址就给你数据,NAND 是一整套带状态、带校验、带坏块管理的存取协议。
1.1 七条必须记住的差异
把这张表压缩成三句话,现场就能用:
- NOR 没有状态,NAND 有状态。NOR 上电就能读;NAND 要先等内部初始化,读页还要等页搬到缓存,每一步都有时间参数(以 datasheet 为准)。
- NOR 没有坏块,NAND 出厂就有坏块。这意味着「第 N 块」这个说法在 NAND 上是不确定的 —— 同一个逻辑偏移,在不同片子上可能落在不同物理块上。
- NOR 不需要 ECC,NAND 必须有 ECC。ECC 不是一个开关,而是一整套约定(算法、强度、校验码在 OOB 里的位置),三方必须完全一致。
1.2 BOOT 区:BootROM 只看最前面那几个 block
这是 SPI NAND 启动最核心、也最容易被忽略的概念。BootROM 不可能去跑完整的 NAND 坏块管理与磨损均衡 —— 它的代码量有限,所以绝大多数平台采用「BOOT 区」方案:把器件最前面固定数量的 block(常见说法是前 1 MB 或前若干个 block,具体以平台手册为准)划为 BOOT 区,BootROM 只用最简单的方式(顺序读、有限次重试、或有限的多副本)从这里取 SPL。
由此直接推出三条排查结论:
- BOOT 区里的坏块是致命的。后面的块坏了可以靠文件系统或坏块表躲开,BOOT 区坏了 BootROM 没地方可躲 —— 所以要么用平台提供的多副本/重映射机制,要么在烧录时就把 BOOT 区规划在出厂保证无坏块的范围(具体机制以平台手册为准)。
- BOOT 区内的烧录策略必须与 BootROM 完全一致。烧录器如果在 BOOT 区里跳坏块,而 BootROM 不跳(或跳法不同),偏移就会逐块累积 —— 这是「烧录成功但不开机」里最难查的一类。
- BOOT 区之外的分区错误不会导致不开机。如果 SPL 已经跑起来了、报错在挂载根文件系统阶段,那已经不是 BOOT 区的问题,应该转到驱动/文件系统那一侧排查。
SPI NAND 不像 NOR 那样「基本都能读」。很多平台的 BootROM 或 SPL 里维护了一张器件支持表(按 JEDEC ID 匹配页大小、块大小、OOB 布局、ECC 参数)。
如果这颗料号不在表里,或者表里的参数与 datasheet 不一致,表现出来的症状和「镜像烧错」一模一样,但根因完全不同。样机阶段换料号、换批次之后突然起不来,第一件事就是核这张表。
2. 分段定位:读 ID → 读页 → 回读比对 → 扫坏块表
NAND 的启动链路比 NOR 长,但相应地可观测点也更多。本章给一套四步手工定位法:先让主控停在能敲命令的地方(U-Boot / 驱动调试层),然后按 ID → 页 → 比对 → 坏块的顺序把问题切开。定段之前不重烧、不换片、不改配置。
2.1 四步手工定位法
# ① 让主控停在 U-Boot / 驱动调试层,先确认能识别到器件
sf probe 0 # 或平台对应的 nand 命令,以 SDK 为准
nand info # 打印页大小 / 块大小 / OOB / 总容量,逐项与 datasheet 核对
# ② 手工读一页并回读比对(地址与长度按页大小换算,以下为示意)
nand read 0x42000000 0x0 0x800
md.b 0x42000000 0x100
# ③ 逐 block 扫描坏块表,重点看 BOOT 区范围内有没有坏块
nand bad # 命令名以平台 U-Boot 为准
# ④ 与烧录器侧的读回 dump 做二进制比对
cmp target_page0.bin host_page0.bin
md5sum target_page0.bin host_page0.bin
四步各自的判读规则:
| 步骤 | 期望结果 | 不符合时说明什么 | 下一步 |
|---|---|---|---|
| ① 读 ID / 打印参数 | ID 正确;页大小、块大小、OOB 大小与 datasheet 完全一致 | ID 读不到 → 硬件链路问题;参数不一致 → 器件支持表需要适配该料号 | 修链路 / 补器件表参数 |
| ② 读一页并回读 | 读出来的内容与预期内容一致,无 ECC 报错 | 报 ECC error → 第 4 类根因;读到全 0xFF → 该页是空的或该块是坏块 | 核 ECC 参数 / 检查是否真的烧进去了 |
| ③ 扫坏块表 | BOOT 区范围内无坏块;坏块标记位置与平台约定一致 | BOOT 区有坏块 → 第 4 类根因;标记位置不对 → OOB 布局理解不一致 | 换用多副本/重映射策略,或换片 |
| ④ 两边 dump 比对 | 主控读回与烧录器读回二进制一致 | 不一致 → BOOT 区内的跳坏块策略或页对齐不一致 | 统一烧录器与 BootROM 的块映射策略 |
2.2 逻辑分析仪:抓 BootROM 的命令序列,看断点在哪
串口无输出、或者平台没有可用 BootROM LOG 时,抓包是唯一的手段。抓 SPI NAND 与抓 NOR 的最大区别:NAND 的命令序列更长、中间有「读页到缓存」和「轮询状态寄存器」这两个 NOR 没有的步骤,而恰恰是这两步最容易出问题。
抓包的三条实操要点:
- 探头要够。除了 CS#、CLK、DI(IO0)、DO(IO1),Quad 模式还要接 IO2、IO3;多 die 器件必要时还要看片选相关的信号。
- 解码要分两段。读 ID 阶段通常是单线,读缓存输出阶段可能已经切到 Quad。用同一套解码参数解全程会解出乱码,先按单线解到读 ID,再按抓到的读命令码判断后面该按几条线解。
- 重点看 OIP 轮询有没有出现、出现了几次。如果 BootROM 发完读页命令后没有轮询就直接取数据,说明它用的是固定延时 —— 那就要核这个延时是否覆盖该料号的最坏情况(以 datasheet 为准)。
① 禁止用 SPI NOR 的算法/工程烧 SPI NAND。NAND 需要页编程 + ECC + 坏块管理,用 NOR 的裸写方式会「假成功」—— verify 通过但主控读不出来,而且会破坏 OOB 里的 ECC 与坏块标记。
② 禁止在定段之前反复擦除重烧。NAND 的擦除次数有限,更重要的是每擦一次坏块表和 OOB 标记就可能变一次,故障变得不可复现。
③ 禁止手动改写 OOB 区。OOB 里的坏块标记一旦被写坏,好块会被当成坏块(或反过来),整个器件的块映射全乱,这种情况下只能整片重新规划,数据不可恢复。
④ 禁止带电补焊 / 飞线。与 NOR 同理,但 NAND 的页缓冲区在掉电瞬间更容易被写到一半,风险更高。
3. 决策树:从上电现象到根因类目
把第 2 章的四步定位固化成一张图:两个判据、四条出口,每条出口直接指向一个根因类目和该段的首查动作。NAND 的决策树比 NOR 更依赖「读 ID 是否成功」这个分水岭 —— 因为 NAND 的器件识别本身就包含了参数协商。
3.1 走树时的四条纪律
- 先确认参数,再确认数据。ID / 页大小 / 块大小 / OOB 大小只要有任一项与 datasheet 不符,后面所有的数据比对都没有意义。
- 每条分支都要留下物证。走完树不能只说「我核过 ECC」,要留下 ECC 配置值、抓包文件、坏块表输出、比对文件的 md5。
- 一次只改一个变量。ECC 参数、坏块策略、页对齐三个一起改,就算通了也不知道是哪一个生效的,下次还会复发。
- 换片对比是有效的判据。换一颗同料号新片:如果好了,说明是这颗片子的坏块分布问题(第 4 类根因);如果还是一样,说明是配置或板级问题 —— 但换片之前必须先把原片的坏块表导出来,否则证据就丢了。
NAND 的偶发失败比 NOR 更常见,因为坏块和 ECC 都带随机性。做法与 NOR 相同:连续 50~100 次上电,记录每次的停点与报错码。
额外加一步:记录每次失败时报错的块号/页号。如果失败集中在固定的几个块,几乎可以确定是坏块或其邻块的读干扰问题;如果块号随机,优先怀疑上电时序与 OIP 等待(第 5 类根因)。
4. 分成因排查:七类根因的原理、实操与验证
七个根因按样机首次 bring-up 的出现概率排序。每一条按原理 → 实操 → 验证三段给,「验证」是判断是否真的解决了的标准。
4.1 根因 1:镜像未按页 / 块对齐,OOB 被当成数据
原理。NAND 的最小写入单位是页、最小擦除单位是块,而且每页后面跟一段 OOB(spare)区。镜像是按「连续数据流」组织的,而 NAND 是按「页 + OOB」组织的 —— 这两者之间必须有一个明确的映射规则。
三种典型的对齐错误:
- 页大小不一致:烧录器按 2 KB 页算偏移,器件实际是 4 KB 页,每一页的起点都错。
- OOB 被当成数据搬:把 OOB 区的内容一起读到数据缓冲区里,或者把数据写进了 OOB —— ECC 校验码的位置全乱。
- 块边界没对齐:一个逻辑分区的起点落在块的中间,擦除时把前一个分区的尾巴一起擦掉。
实操。
- 把三方的参数抄到一张纸上对照:datasheet 的值、烧录工程里的值、主控侧
nand info/驱动打印出来的值。三方必须完全一致。 - 确认烧录器的「是否包含 OOB」「spare 区处理方式」这一项设置,与平台期望的方式一致(有的平台要求 ECC 由烧录器算好写进 OOB,有的要求烧录器只写数据区、ECC 由主控算 —— 以平台手册为准)。
- 手工读一页,把数据区和 OOB 分别 dump 出来,确认数据区是镜像内容、OOB 里是 ECC 校验码而不是镜像数据。
验证。三方参数完全一致;手工读页与预期内容二进制一致;OOB 的内容和布局与平台约定一致。
4.2 根因 2:烧录器跳坏块策略与 BootROM 不一致
原理。这是 NAND 独有、也是最隐蔽的一类根因。烧录器写镜像时,遇到坏块会跳过去,把后续数据写到下一个好块,这样「逻辑上连续的镜像」在物理上就是「跳过坏块的非连续布局」。而 BootROM 的读取策略是另一套:它可能按物理块顺序读、也可能自己跳坏块,但跳转规则未必与烧录器一致(具体以平台手册为准)。
后果是偏移逐块累积:BOOT 区里只要有 1 个坏块,它后面的所有块号就整体错开 1 个;有 2 个就错开 2 个。BootROM 读「第 N 块」时期望的是镜像的第 N 块,实际读到的是第 N+k 块的内容 —— 数据本身是正确的,只是位置全错了。
实操。
- 先导出整片的坏块表,看 BOOT 区范围内(具体范围以平台手册为准)有没有坏块。
- 查烧录工程的「坏块处理策略」:跳过 / 保留 / 替换为预留块,与平台 BootROM 的期望策略对照。
- 如果平台提供多副本或重映射机制,确认烧录时确实生成了副本 / 写入了重映射表。
- 在 BOOT 区范围内逐块读出块首的标记,人工核对「第 N 个物理块里装的是不是镜像的第 N 块」。
验证。BOOT 区内逐块核对通过(物理块序与镜像块序一一对应),或平台的多副本/重映射机制已确认生效且上电连续 100 次都能起来。
很多平台的做法是:BOOT 区用「固定块 + 多副本」的简单策略,数据区才用完整的坏块管理。原因是 BootROM 跑不了复杂算法。
所以「烧录器的坏块策略」往往不是全局一个开关,而是分区各自配置。只改了全局开关、没改 BOOT 区的策略,症状就是「数据区都对了、就是起不来」。
4.3 根因 3:ECC 算法 / OOB 布局不一致
原理。NAND 的位翻转是物理特性,必须靠 ECC 纠正。ECC 不是「开或关」,而是一整套约定:用哪种算法(BCH / RS 一类)、能纠几位、校验码占多少字节、放在 OOB 的哪个偏移、覆盖的数据范围是整页还是分段。
典型的三方不一致:
| 不一致的点 | 具体表现 | 后果 |
|---|---|---|
| 片内 ECC vs 软件 ECC 混用 | 器件内部自带 ECC 引擎,烧录器又按软件 ECC 算了一遍写进 OOB | 两套校验码互相干扰,主控读出时校验必然失败 |
| 纠错强度不同 | 烧录器按纠 4 位算,主控按纠 8 位解 | 校验码长度与位置都对不上,报 ECC error |
| OOB 内偏移不同 | 校验码写在 OOB 起始处 vs 写在 OOB 中间 | 数据区内容是对的,但主控找不到校验码 |
| 覆盖的数据范围不同 | 整页一个校验块 vs 每 512 字节一个校验块 | 部分数据能过校验、部分不能,症状看起来像随机坏块 |
实操。
- 确认该料号是片内 ECC 还是需要外部 ECC(以 datasheet 为准);如果是片内 ECC,主控侧就不要再算一遍。
- 确认平台 SDK 里配的 ECC 强度与 OOB 布局,与烧录工程里配的逐项对照 —— 包括校验码长度、偏移、覆盖粒度。
- 手工读一页,把 OOB 的十六进制打出来,人工数一遍校验码的起始偏移与长度,验证与配置一致。
验证。手工读页不再报 ECC error;连续读 BOOT 区所有页 100 次,无一次校验失败。
4.4 根因 4:BOOT 区出现坏块且未做重映射
原理。如 1.2 节所述,BootROM 只在 BOOT 区的固定 block 里找代码。boot 区里的坏块是致命的,因为 BootROM 没有复杂的坏块管理可以躲。
样机阶段高发的场景:同一料号换了一个批次,坏块分布变了 —— 上一批的 BOOT 区全是好块,这一批的第 2 个 block 就是坏块,于是「同样的工程、同样的操作,换批就不开机」。
实操。
- 导出完整坏块表,标出 BOOT 区范围内所有坏块的块号。
- 查平台手册确认该平台对 BOOT 区坏块的处理机制:多副本(把 SPL 烧在多个固定块、BootROM 逐个试)/ 重映射表(把坏块映射到预留的好块)/ 出厂保证前 N 块无坏块。
- 按平台要求重新生成镜像与烧录配置:副本数、副本块号、重映射表位置,都必须严格按手册来。
- 如果平台机制要求「BOOT 区必须在出厂保证无坏块的范围」,就把 BOOT 区规划到更小的范围(以平台手册为准)。
验证。在多颗不同批次的片子上(至少 3 颗,含已知 BOOT 区有坏块的)连续上电 100 次,全部能起来。
4.5 根因 5:上电等待与 OIP 忙等未处理
原理。NAND 上电后需要内部初始化(上电复位时间一类的参数,以 datasheet 为准),之后才能接受命令;发出「读页到缓存」命令后,还要等器件把整页搬到缓存,这段时间由状态寄存器里的忙标志(常见叫 OIP / BUSY)指示。
两类典型故障:
- 上电等待不足:主控在器件还没初始化完就发命令,器件不响应,读 ID 返回全 0x00 或全 0xFF。样机上如果电源爬升慢、或者复位释放太早,这一类会偶发。
- 发完读页命令没有轮询忙标志:主控用固定延时代替轮询,延时不够时读到的是上一次的残留数据或全 0xFF;延时够但没轮询,则在温度升高、器件变慢时失效。
实操。
- 示波器抓上电瞬间 VCC 与复位脚,确认从 VCC 稳定到第一个 CS# 下降沿的时间,不小于 datasheet 要求的上电等待时间。
- 抓包确认 BootROM 在读页命令之后有没有轮询状态寄存器;如果没有,说明它用固定延时 —— 记录这个延时的实测值。
- 把实测延时与该料号 datasheet 里「读页到缓存」的最坏时间对比,不足则需要平台侧调整(以平台手册为准,不要自行改 BootROM)。
- 高低温拉偏:在最恶劣温度下重复上电,确认没有因器件变慢而读错。
验证。在全温度范围内、电源在最慢爬升条件下,连续上电 100 次全部成功启动。
4.6 根因 6:多 die 未选片 / die 间差异
原理。大容量的 SPI NAND 常把多个 die 封装在一起。访问不同 die 需要先发选片命令(或地址里带 die 位),没选片或选错片,读出来的是另一个 die 的内容 —— 内容合法、ECC 也可能对,但完全不是你要的那个地址的数据。
实操。
- 从 datasheet 确认该料号是单 die 还是多 die,以及选片的方式(专用选片命令 / 地址高位 / 其它,以 datasheet 为准)。
- 抓包看 BootROM 在跨 die 边界访问时有没有发选片命令;如果 BOOT 区跨了 die 边界而没有选片,这就是根因。
- 如果平台器件表支持该料号,确认表里的 die 相关参数正确;不支持则需要适配。
- 规避方案:在平台允许的前提下,把 BOOT 区规划在第一个 die 之内,避免 BootROM 阶段跨 die 访问。
验证。在 die 边界两侧各读写一组 pattern,回读确认读到的就是写进去的内容,没有串到另一个 die。
4.7 根因 7:样机专属 —— 飞线、转接板、手焊
原理。与 NOR 一样,这一类只会在样机阶段出现。但 NAND 对它的敏感度更高:NAND 的读页涉及「命令 → 长延时 → 读输出」多个阶段,中间任何一次信号完整性问题都会让整个页读失败,而且失败表现为 ECC error,很容易被误判成 ECC 配置问题。
| 样机特有做法 | 引入的问题 | 排查 / 规避动作 |
|---|---|---|
| 飞线过长(>10 cm) | CLK 边沿变缓,命令相位采样错误,表现为随机 ECC error | 尽量缩短;CLK 串联阻尼电阻;先降到最低频率验证 |
| CLK 与 DI/DO 并行长距离走线 | 串扰导致命令码本身被读错,抓包看到的是「奇怪的命令」 | 信号之间插地线;或把 CLK 单独走、远离数据线 |
| 转接板 / 烧录座没有地回流路径 | 回流面积大,Quad 读时 DO 上的毛刺被当成数据 | 转接板上铺地、多打地过孔;用尽量短的排线 |
| 手工焊接虚焊 / 助焊剂残留 | 接触电阻大,表现为「时好时坏」,与坏块/ECC 故障很难区分 | 显微镜下复检;清洗助焊剂;先排除它再查 ECC |
| 多颗器件共用一套飞线 | 片选隔离没做好,总线上有两个驱动源 | 确认未选中的器件处于高阻;必要时只焊一颗做最小系统 |
当怀疑是样机板级问题时,按这个顺序砍变量:
① 只焊一颗 SPI NAND,去掉板上所有其它外设;② 用最短的线、直连而不是飞线;③ SPI 时钟降到最低、强制单线模式;④ 烧最小可启动镜像(只要 SPL 能打印即可)。
四步做完能起来,再逐项把变量加回来,每加一项上电验证一次。这一步能把「板级 / 参数配置 / 镜像布局」三类问题干净地分开,比在完整系统上猜要快得多。