只读分享解决方案文档调试&解决方案📅 2026-09-21🔖 Rev 1.0⏳ 29天有效(至 2026-10-31)
🔧解决方案&应用市场分析 -> 调试&解决方案 -> 存储_样机问题测试 -> SPI_NOR_首次启动失败_样机排查

SPI_NOR_首次启动失败_样机排查

生成时间 2026-09-28 13:34:56 有效期至 2026-10-31 23:59:59(29天有效(至 2026-10-31))
同系列 · 调试&解决方案

SPI NOR 首次启动失败 · 样机排查手册

编制日期 2026-09-21 | 版本号 Rev 1.0

XTX 芯天下 · FAE 样机 bring-up 技术文档 | 面向第一次上电 / 手焊 / 飞线 / 转接板场景 | 2026-09 版

技术事实核查纪律(动手前必读)

命令码、寄存器位、dummy cycle 数值、BootROM 取址行为一律以器件 datasheet 与主控平台手册为准;本文只讲机制与定位方法,不代替 datasheet。

  • SPI NOR 没有统一的强制标准:状态寄存器数量与位定义、QE 位位置、4 字节地址的进入/退出方式、dummy cycle 默认值、QPI 进出命令都由各厂自定,同名位在不同厂、甚至同厂不同系列上含义都可能不同。
  • 本文出现的命令码(如 0x9F 读 ID、0x03 普通读、0x0B 快读、0x6B/0xEB Quad 快读)均为常见写法示例,不是通用常量,必须逐颗核对该料号的正式 datasheet。
  • BootROM 侧的取址 offset、读取模式、dummy 数由平台 BootROM 固化,以主控厂商的 TRM / BootROM 手册与 SDK 源码为准,不以烧录器默认值为准。
  • 凡本文标注「以手册为准」的条目,现场必须打开对应料号与平台的正式文档复核后再动手。
5 段
SPI NOR 启动链路
上电 → 读 ID → 取头 → 搬 SPL → 交棒
第 3 段
样机最高发死亡点
镜像起始 offset 与 BootROM 期望不符
4 组
必须对齐的读取语义
地址长度 / 读命令 / dummy / QE
3 步
降级验证顺序
先 0x03 慢读,再 0x0B,最后开 Quad
2 套
交叉验证必须两边读
烧录器读一遍、主控侧再读一遍比对
1 条
铁律
Verify PASS 只证明搬运正确,不证明读取语义正确

一句话结论:样机上 SPI NOR 起不来,九成不是芯片坏了,而是「烧进去的字节」与「BootROM 读它的方式」在地址长度、读命令、dummy cycle、QE 状态这四件事上没对齐。定位的正确顺序是:先看串口 LOG 停在哪一句,把它映射到启动链路的某一段,再进对应根因 —— 而不是一上来就重烧、换片、改板。

这份文档解决什么

解决的是样机第一次上电:串口无输出、停在 BootROM、或跑起来后崩这一类问题的定位与修复。全文按「链路 → 定段 → 决策树 → 分成因 → 速查 → 清单」组织:第 1 章把看不见的 BootROM 流程拆成 5 段,第 2 章用串口 LOG 停点把死点定位到段,第 3 章给出决策树,第 4 章是六类根因的原理 + 实操 + 验证,第 5 章是可直接翻查的速查表,第 6 章是勾选清单与结案模板。

区分侧重:本文讲样机首次 bring-up(飞线、手焊、转接板、第一次上电、最小系统);产线批量烧录后的不开机问题属于量产篇,两者根因分布不同,不要混用结论。

根因 1
镜像起始 offset 与 BootROM 期望不符
镜像文件头被烧到了 BootROM 不看的低地址,或 BootROM 期望的 header/IVT 根本没烧进去。表现为有 BootROM banner、随后报 no valid header。
样机高发:第一次建工程时 offset 沿用别的项目
根因 2
QE 位与 BootROM 读取模式不匹配
镜像按 Quad 时序烧、或 BootROM 用 Quad 读,但器件上电后 QE 未置位,IO2/IO3 不驱动,读到常电平。
样机高发:只配了烧录器,没管上电后状态
根因 3
dummy cycle 与工作频率不匹配
BootROM 发的 dummy 数与器件在当前频率下需要的 dummy 数不一致,读回来的数据整体错位;在频率/温度边界上表现为偶发。
样机高发:换更高频率的晶振或降频后暴露
根因 4
4 字节地址模式切换不一致
容量超过 3 字节地址寻址上限时,器件上电默认 3B;BootROM 与 SPL/应用对「什么时候切 4B」理解不一致,跨边界地址回卷。
样机高发:从小容量料号换成大容量料号
根因 5
烧录后未做主控侧交叉验证
烧录器 verify 通过只证明它自己写对读对;板上供电、时序、IO 电平不一样,主控侧读到的可能是另一组字节。
样机高发:把烧录器结论当板上结论
根因 6
样机专属:飞线 / 转接板 / 手焊
飞线过长、CLK 与 DI/DO 并行走线、转接板无地回流、手工焊接虚焊/连锡、上拉下拉错位置 —— 高速 Quad 读下全部暴露。
样机高发:只有样机阶段才会出现的故障

1. 启动链路:BootROM 到底做了什么

SPI NOR 是极少数能让 BootROM 直接取指执行的启动介质 —— 这句话既是它最大的优点,也是它最难查的地方:BootROM 固化在芯片内部,你看不见它发了什么命令,只能从串口 LOG 停在哪一句,反推它死在哪一段。本章先把这条看不见的链路拆成 5 段。

1.1 五段链路的标准动作

把 BootROM 从 SPI NOR 取代码的过程抽象成 5 段。不同平台的细节(取址 offset、是否校验签名、是否切 QPI)以各自 TRM/BootROM 手册为准,但「先供电、再认器件、再找头、再搬代码、最后交棒」这个骨架是通用的。

段BootROM 在做什么这一段的关键变量这一段失败的典型后果
第 1 段电源与复位:等待 VCC/VCCQ 稳定、释放复位、拉高 CS#、把 SPI 控制器配成默认模式实测电压、复位释放时刻、上电等待时间(以 datasheet 为准)完全无任何串口输出,电流可能异常
第 2 段识别器件:发读 ID 命令(常见为 0x9F)读 JEDEC ID,与内置器件表比对CS#/CLK/DI/DO 波形、IO 电压域、SPI 模式(CPOL/CPHA)无输出,或报 unknown device / no flash
第 3 段定位镜像头:从 BootROM 约定的固定 offset 读回若干字节,检查 magic / header / IVT镜像起始烧录地址、header 是否真的烧进去、字节序有 banner,随后报 no valid header / bad magic
第 4 段搬运代码:用约定的读命令(常见 0x03/0x0B/0x6B)连续读出 SPL 到内部 SRAM读命令选择、QE 位状态、地址长度、dummy 数、时钟频率报 read fail / timeout,或搬出来的代码是错的
第 5 段交棒执行:跳到 SPL 入口,后续由 SPL 负责初始化 DDR、加载下一级数据完整性、高频下的 dummy 边界、3B/4B 地址模式SPL 打印正常但加载下一级时 CRC 错、随机崩
启动链路:BootROM 从 SPI NOR 取代码的 5 个阶段任一阶段失败,串口就停在对应位置1 上电与复位VCC/VCCQ 稳定复位释放、CS# 拉高2 读 JEDEC ID发 0x9F 读 ID与器件表比对3 定位镜像头从 BootROM 约定offset 取 header4 连续读搬 SPL0x03 / 0x0B / 0x6B按 QE 选读取模式5 交棒执行跳 SPL 入口后续由 SPL 接管串口 LOG 停在哪一句 → 死在第几段 → 首查方向先定段,再进根因串口 LOG 停点(现象)死亡段首查方向完全无输出,串口全程静默(连 BootROM banner 都没有)第 1~2 段VCC/VCCQ 实测、复位脚电平CS#/CLK 有无波形、IO 电压域有 BootROM banner,随后报no valid header / bad magic第 3 段镜像起始 offset、header/IVT是否真烧进去;读回头比对报 SPI read fail / timeout,或长时间无任何进展第 4 段读命令 0x03 / 0x0B / 0x6BQE 位状态、dummy 与频率SPL 打印正常,加载下级时报 CRC error / 随机崩第 5 段高频下 dummy 边界3B / 4B 地址模式、完整性校验冷启动正常,reboot 起不来软复位后必挂第 1~4 段复位释放后 SR / 地址模式 / QE是否回到上电默认值
图 1 · SPI NOR 启动链路 5 段与串口 LOG 死亡分段对照

1.2 为什么「分段」比「猜根因」快

样机阶段最常见的低效行为,是把「不开机」当成一件事,然后按顺序试:重烧一遍、换个芯片、换个烧录器、改个频率。问题在于这四件事对应完全不同的段,试错不会收敛。

分段定位的价值在于:串口 LOG 的停点是一个免费的断点。BootROM 每往前走一步都会留下痕迹,痕迹停在哪一步,就说明上一步通过了、这一步没通过。把范围从「整块板」缩小到「某一段的某一个变量」,后面的排查才有方向。

BootROM 的行为边界(重要)

BootROM 是固化代码,你看不到源码,也改不了它。它能做什么、按什么 offset 取、用几条线读、dummy 给几拍,全部由主控厂商在芯片出厂时定死,只能通过 TRM / BootROM 手册与 SDK 里的 SPL 源码间接推断。

因此本文所有涉及 BootROM 具体行为的条目,结论都是「去查平台手册与 SDK 源码确认」,而不是给一个放之四海皆准的数值。FAE 现场最忌讳把 A 平台的 BootROM 行为套到 B 平台上。

2. 分段定位:串口 LOG 停在哪,就死在哪一段

本章给一套可以直接照做的分段定位动作。核心只有一句话:先定段,再定因;定段之前不重烧、不换片、不改板。

2.1 三段法:把现象归到三个大段里

大类串口表现死在哪几段立刻要取的三项证据
A 类完全无输出,串口全程静默,连 BootROM banner 都没有第 1 段 / 第 2 段① VCC 与 VCCQ 实测值;② 复位脚在上电后的电平轨迹;③ CS# 与 CLK 有没有波形
B 类有 BootROM banner,但随后报 no valid header / bad magic / read fail / 卡死第 3 段 / 第 4 段① 完整 LOG 原文(含报错码);② 主控侧读回的头 256 字节;③ 烧录器侧同一区间的 dump
C 类SPL 打印正常,加载 U-Boot / 内核时 CRC 错、随机崩,或只在特定温度/电压下崩第 5 段① 出错地址与期望值的比对;② 当前 SPI 时钟频率与 dummy 配置;③ 器件容量与地址模式

2.2 取证动作:主控侧读回 vs 烧录器侧读回

分段定下来之后,第一件事不是改配置,而是取证据。最有用的一条证据是「同一个地址区间,两套系统读出来的字节是不是一样的」。

# ① 主控侧(U-Boot 命令行)读回头 256 字节,打印出来
sf probe 0
sf read 0x42000000 0x0 0x100
md.b 0x42000000 0x100

# ② 烧录器侧:把同一颗片子(或同批同一颗)的 0x0 起 256 字节读回存成 bin
#    (以烧录器软件操作为准,注意选「读器件」而不是「读缓冲区」)

# ③ 主机上做二进制比对
cmp target_readback_0x0_256.bin  host_readback_0x0_256.bin
#    或:md5sum 两边文件比对

三条判读规则:

  • 两边一致、且等于镜像文件头:数据没问题,去查读取语义(读命令 / QE / dummy / 地址长度)。
  • 两边一致、但不等于镜像文件头:烧录这一步就错了(offset、文件选错、或者烧的是另一个工程),回去查烧录工程。
  • 两边不一致:这是最有价值的一类 —— 说明「烧录器读得对」与「主控读得对」不是一回事,问题就在读取语义或电气条件上,优先查电压域、时序、QE 与 dummy。
交叉验证的三个前提(否则比对结论不可信)

① 比对区间必须包含 BootROM 真正取址的那一段,而不是只比 0x0 起几个字节 —— 取址 offset 以平台手册为准。

② 主控侧读回必须在 BootROM 之后的稳定状态做(比如停在 U-Boot 命令行),此时 SPI 控制器已经被 SPL 重新配置过,读回来的字节可能与 BootROM 阶段读的不同 —— 这正是要抓的差异,不要当成噪声忽略。

③ 烧录器侧读回的供电与板上供电不同。如果板上 VCCQ 是 1.8 V 而烧录器给的是 3.3 V,两边的读写裕量本来就不一样,比对结果要标注电压条件。

2.3 逻辑分析仪:看不见 BootROM 时,用抓包代替

如果串口完全无输出(A 类),或者平台根本没有可用的 BootROM LOG,就用逻辑分析仪直接抓 SPI 总线。看三件事:有没有命令、第一个命令是什么、命令序列停在哪一条。

  1. 探点接 CS#、CLK、DI(IO0)、DO(IO1);Quad 模式还要接 IO2、IO3。地线尽量短,接在主控侧 GND。
  2. 采样率至少是 SPI 时钟的 8~10 倍;用 CS# 下降沿触发,单次捕获。
  3. 上电,抓完整一段。解码时先按 1-1-1(单线)解,能解出 0x9F 说明链路通。
  4. 如果解出来是 0x9F 之后紧跟一串读命令然后停住 → 死在第 3/4 段;如果连 0x9F 都没有 → 死在第 1/2 段。
  5. 把 BootROM 阶段实际发出的读命令码记下来,与 SPL/内核里配的读命令比对 —— 两边不一致就是第 4 类根因的直接证据。
危险操作:定段之前禁止做的事

① 禁止反复重烧。每重烧一次就多一个变量(擦除是否干净、状态寄存器是否被改写、offset 是否被改动),LOG 停点也会跟着变,问题更难复现。

② 禁止在通电状态下用烙铁补焊 CS# / CLK / IO 飞线。烙铁接地不良会直接打穿器件 IO,也会把主控的 SPI 控制器一起烧掉,故障范围瞬间扩大。

③ 禁止把烧录器的 Verify PASS 当成板上可用的依据。它只证明「烧录器自己按自己的规则写对、读对」,不证明目标 SoC 按它的规则也读得出来。

④ 禁止对状态寄存器做试探性写入。SRP / LB 一类非易失位一旦写入不可撤销,误写只能换片;写之前一定先读回当前值并对照 datasheet 逐位确认。

3. 决策树:从上电现象到根因类目

把第 2 章的三段定位固化成一张图:从「上电」开始,两个判据、五条出口,每条出口直接指向一个根因类目和该段的首查动作。现场按图走完一遍,通常 10 分钟内就能把范围从「整块板」缩到「一个变量」。

样机上电:无启动 LOG / 停在 BootROMQ1 串口有任何 BootROM 输出?无第 1~2 段 硬件链路判据:完全无输出查 VCC/VCCQ 与复位脚查 CS#/CLK 波形与 IO 域有Q2 LOG 停在哪一句 / 报什么错?第 3 段 镜像偏移判据:no valid header重烧并核对起始 offset读回前 256B 逐字节比对第 4 段 读取模式判据:read fail / 卡死查读命令 0x03 / 0x6B查 QE 位与 dummy 数第 5 段 完整性边界判据:头 OK 但跑崩降频与 dummy 边界3B / 4B 地址模式切换交叉验证铁律:烧录器 Verify PASS ≠ 主控读得对同一个字节,两边读的「地址长度 + 读命令 + dummy + QE」可能完全不同 —— 先做二进制比对,再谈换料
图 2 · SPI NOR 首次启动失败决策树

3.1 走树时的三条纪律

  • 每条分支都要留下物证。走完树不能只说「我查了 QE」,要留下 QE 位的读回值、读命令的抓包记录、比对文件的 md5。
  • 一次只改一个变量。从「1-1-1 + 0x03 慢读」往上加配置,每加一项就重新上电验证一次。同时改三个变量,就算通了也不知道是哪一个生效的。
  • 走到叶节点还没解决,回到第 1 段重新走。实践中相当一部分「查遍了配置都没问题」的case,最后根因在第一段 —— 电压在带载瞬间跌落、复位释放太早。
关于「偶发」的处理

如果故障是偶发的(十次起不来一两次),决策树依然适用,但每一次上电都要记录 LOG,连续记录 50~100 次,统计停点分布。停点集中在同一段 → 按该段根因查;停点分散在多段 → 优先怀疑第 1 段(电源/复位)与样机专属的飞线问题。

4. 分成因排查:六类根因的原理、实操与验证

六个根因按样机首次 bring-up 的出现概率排序。每一条都按原理 → 实操 → 验证三段给,「验证」是判断是否真的解决了的标准,不能省。

4.1 根因 1:镜像起始 offset 与 BootROM 期望不符

原理。BootROM 不会去「找」镜像,它只会去一个固定的地址(具体 offset 以平台手册为准)读回若干字节,然后按约定的格式检查 magic / header / IVT。镜像文件内部的布局(header 在文件偏移 0、SPL 在偏移 N)是链接脚本定的,而文件被烧到 Flash 的哪个地址是烧录工程定的 —— 这两件事如果对不上,BootROM 取址点读到的就不是 header,而是 payload 中间的某个字节。

样机阶段高发的三种错位:

  • 镜像文件头直接烧在 Flash 0x0,但 BootROM 从非零 offset 取(或反之)。
  • 镜像原本需要前置一段 header/IVT,但烧进去的是「裸 bin」,header 没生成或没拼进去。
  • 工程沿用了另一个项目/另一颗料号的烧录配置,起始地址参数没跟着改。
① 镜像文件:以文件头为 0 的内部布局数值仅作示意,以链接脚本为准header / IVTSPL 一级 loaderU-Boot / payload空闲 / 填充文件偏移 0 —— 镜像的第一个字节文件偏移递增② 落点对照:文件偏移 0 落到 Flash 的哪个地址示意,非真实数值正确参数区/跳过header / IVTSPLpayloadBootROM 取址点地址递增错误header / IVTSPLpayload取到 SPL 中间BootROM 取址点判据:把镜像文件 0x0 起的头 256 字节,与 Flash 在 BootROM 取址点读回的 256 字节做二进制比对一致才算烧对;不一致就是「烧录器 verify 通过、主控却读不到正确头」的典型错位
图 3 · 镜像文件偏移、Flash 落点与 BootROM 取址点对照示意

实操。三步走:

  1. 从 SDK 构建产物里找到最终烧录的那个 bin(注意不是 SPL 单独编译出来的 elf/bin),用十六进制工具看它偏移 0 起是什么 —— 是不是平台要求的 header 结构。
  2. 打开烧录工程,确认「烧录起始地址」这一项等于平台要求的 offset,而不是默认的 0x0 或上一个项目的值。
  3. 按 2.2 节做交叉验证:主控侧读回取址点起 256 字节,与镜像文件 0x0 起 256 字节比对。

验证。比对完全一致,且重新上电后 BootROM 不再报 no valid header,进入第 4 段(搬运)或第 5 段(执行)—— 这才算 offset 这一项通过。

4.2 根因 2:QE 位与 BootROM 读取模式不匹配

原理。Quad 读(1-1-4 / 1-4-4)需要器件把 IO2、IO3 也用作数据线,这个能力由 QE(Quad Enable)位控制。QE 未置位时,IO2/IO3 处于高阻或被内部上拉,主控按 Quad 时序去采样这两条线,读回来的永远是固定电平(常见为全 1 或全 0)。结果就是:头几个字节的 magic 就已经不对,BootROM 直接判 header 无效 —— 现象与「镜像 offset 错」几乎一模一样,这是最容易被误判的地方。

三个必须知道的事实:

  • QE 位的物理位置各厂不同:在状态寄存器 1、状态寄存器 2、还是专用配置寄存器,取决于料号,以 datasheet 为准。
  • QE 有易失与非易失两种实现:有的器件写进去断电保持,有的器件断电/复位后回到默认。样机上「烧录器设了 QE 但板上没生效」,多半是后者。
  • BootROM 阶段的读取模式是固化的:它不会因为器件 QE 是 0 就自动降级成单线读(具体行为以平台手册为准,不要假设)。

实操。

  1. 先确认 BootROM 阶段用的是几条线:查平台手册,或者用逻辑分析仪抓 BootROM 的读命令码 (0x6B/0xEB 一类是 Quad,0x0B 是 1-1-1 快读,0x03 是普通读)。
  2. 读回器件状态寄存器里 QE 所在的那个 bit(位置以 datasheet 为准),注意要在板上、在上电稳定之后读,而不是看烧录器报告。
  3. 如果 BootROM 用 Quad 而 QE = 0:要么在 SPL 里改成单线读(若平台允许),要么在烧录时把非易失 QE 写进去并确认掉电保持;两条路都要看平台是否支持。

验证。板上读回 QE = 期望值,逻辑分析仪上看到 IO2/IO3 有真实翻转的数据波形,而非常电平;重新上电不再报 header 错。

4.3 根因 3:dummy cycle 与工作频率不匹配

原理。快读命令(0x0B 及各类 Quad 快读)在发完地址之后,需要插入若干个 dummy cycle(空时钟周期)让器件准备数据,然后才开始输出。主控发几个 dummy 是主控侧配置的,器件需要几个 dummy 是器件在给定频率下决定的 —— 两者不一致,读回来的数据就会整体错位。错位在字节层面看不出来(都是合法字节),只有校验和会失败。

为什么它「最难查」:

  • 错位是整体的、恒定的,不是随机的坏数据 —— 所以看起来像「镜像错了」,很多人在这里绕很久。
  • 需要的 dummy 数随频率变化:同一个器件在低频下需要的 dummy 数,在高频下可能就不够。样机换了晶振、或者 SPL 里把 SPI 时钟提上去之后突然起不来,基本都是这一类。
  • 温度会移动这个边界:常温能起来、高温起不来(或反过来),是 dummy 裕量不足的典型特征。

实操。

  1. 先把 SPI 时钟降到最低(或在 SPL 里配成最低分频),用 0x03 普通读(无 dummy)跑通一遍 —— 这是基线。
  2. 逐步提高频率,每档都做一次「读回已知内容并比对」的测试,记录开始出错的频率点。
  3. 把主控侧的 dummy 配置改到器件 datasheet 在该频率下要求的数值,重测该频率点。
  4. 在最容易出错的频率点上做高低温拉偏,确认裕量。

验证。在目标工作频率 + 目标温度范围(至少包含常温与最高温)内,连续 100 次上电启动,读回比对 100% 一致,才算通过。

4.4 根因 4:4 字节地址模式切换不一致

原理。传统 3 字节地址只能寻址到 16 MB。容量更大的器件需要切到 4 字节地址模式,或者用分段/扩展地址寄存器的办法访问高地址。关键点在于:这个切换是一个「状态」,而 BootROM、SPL、应用三方的代码对这个状态的理解可能不一致。

典型故障链:BootROM 用 3B 模式读低地址,SPL 起来之后切到 4B 模式去读高地址的 U-Boot,但器件上电默认是 3B、切换命令的时机或命令码与器件不匹配;或者反过来,SPL 认为已经是 4B 而器件实际还在 3B,高地址被截断回卷到低地址 —— 低地址的 SPL 能起来,高地址的 kernel 却是另一个地址的内容。

实操。

  1. 确认器件容量是否超过 3 字节地址寻址上限;超过就必须规划地址模式。
  2. 查 datasheet 确认该料号进入/退出 4 字节地址模式的命令,以及上电默认是 3B 还是 4B。
  3. 在 SDK 源码里搜索地址模式切换相关代码,确认 BootROM → SPL → 应用这条链上每一步切换之后,下一步的假设与之匹配。
  4. 用逻辑分析仪看地址字节数是 3 个还是 4 个,与实际访问的地址范围对照。

验证。在最高地址段写一组已知 pattern,断电重启后从主控侧读回,确认读到的就是写进去的内容(而不是低地址回卷过来的内容)。

4.5 根因 5:烧录后未做主控侧交叉验证

原理。烧录器的 verify 是一个闭环自查:它按自己的时序、自己的电压、自己的读命令把刚写进去的字节读回来比对。这个闭环里完全不包含目标主控。板上的差异可能来自:供电电压不同、VCCQ 不同、走线带来的信号完整性差异、主控 SPI 控制器的读命令与 dummy 配置不同、主控侧有额外的上拉/下拉。

实操。把交叉验证做成样机 bring-up 的固定动作,见 2.2 节。补充两个容易漏的检查:

  • 烧录时器件是否真的处于可写状态:状态寄存器里的块保护位(BP 一类)如果锁住了目标区间,写操作会被静默忽略,而有些烧录器的 verify 读的是缓存而非器件 —— 这种情况下「verify 通过」是完全假的。
  • 烧录器的供电电压与板上是否一致:3.3 V 烧、1.8 V 用,读的裕量完全不同。样机上如果转接板/座子有自己的供电,一定要确认电压域。

验证。主控侧读回结果与镜像文件二进制一致,且连续多次上电都能稳定读到。

4.6 根因 6:样机专属 —— 飞线、转接板、手焊

原理。这一类根因只会在样机阶段出现,量产板不会出现,因此最容易被忽略:FAE 往往先怀疑配置和镜像,查了一圈才回头看板。飞线把 SPI 信号引到板外,引入了量产板上不存在的寄生参数与噪声耦合。

样机特有做法引入的问题排查/规避动作
飞线过长(>10 cm)CLK 边沿变缓、建立保持裕量丢失;高频下直接读错尽量缩短;CLK 串联阻尼电阻;先降频验证再升频
CLK 与 DI/DO 并行长距离走线串扰,DO 上出现与 CLK 相关的毛刺信号之间插地线;或把 CLK 单独走、远离数据线
转接板 / 烧录座没有地回流路径回流面积大,信号完整性差,Quad 模式下更严重转接板上铺地、多打地过孔;用尽量短的排线
手工焊接虚焊 / 连锡 / 助焊剂残留接触电阻大、漏电,表现为「偶尔能起来」显微镜下复检;清洗助焊剂;必要时重新拖焊
上拉/下拉电阻焊错位置或阻值不对CS# 上电期间不确定、IO 电平被拉偏按原理图逐颗核对;特别注意 CS# 上拉与 WP#/HOLD# 的处理
多颗器件共用一套飞线(没做好片选隔离)多主多从冲突,总线上出现两个驱动源确认未选中的器件处于高阻;必要时只焊一颗做最小系统
最小系统法:把变量一次性砍到最少

当怀疑是样机板级问题时,按这个顺序砍变量:

① 只焊一颗 SPI NOR,去掉板上所有其它外设;② 用最短的线、直连而不是飞线(必要时做一块最小转接板);③ 强制最低频率 + 单线 0x03 读;④ 烧最小可启动镜像(只要 SPL 能打印即可,不要带内核)。

四步做完能起来,再逐项把变量加回来,每加一项上电验证一次。这个方法的价值不在于「修好」,而在于把「板级 / 配置 / 镜像」三类问题干净地分开。

读命令 / QE 状态 / dummy 三者匹配矩阵:BootROM 侧与器件侧必须对齐命令码以 datasheet 为准BootROM / SPL 读取模式器件 QE 状态dummy 与频率结果判定1-1-1 普通读 0x03QE = 0无 dummyOK:最保守,先用来证明链路温度频率拉偏都应通过1-1-1 普通读 0x03QE = 1无 dummyOK:QE 置位不影响单线读可作为降级验证基线1-1-1 快读 0x0B无关dummy 与主控配置不一致数据整体错位,头校验失败现象接近「镜像偏移错」,易误判1-1-4 / 1-4-4 快读 0x6BQE = 0不适用IO2/IO3 未被驱动读到常电平,magic 必不匹配1-1-4 / 1-4-4 快读QE = 1dummy 在频率/温度边界常温通过,边界偶发崩高温或降频后复现,最难查降级验证顺序:先把变量减到最少,再逐个加回来1 强制 1-1-1 + 0x03 慢读先证明链路与镜像都没问题2 再开 0x0B 快读核对主控 dummy 数与器件一致3 最后开 Quad核对 QE 位、dummy、频率边界
图 4 · 读命令 / QE 状态 / dummy 三者匹配矩阵与降级验证顺序

矩阵的用法:先按最上面两行把系统调到「一定能起来」的保守档(1-1-1 + 0x03 慢读),确认链路、供电、镜像都没问题;然后按图下半部分的顺序,一次加一个变量往上走。任何一档加上去之后起不来,根因就锁死在刚加的那个变量上。