启动模式与设备枚举:常见的启动设备、Boot Mode Pins 与优先级轮询

芯片上电后,第一件事就是去取指令、开始执行。但有个问题——它该从哪儿取?

我早年做第一个 SoC 项目时,以为 BootROM 就是死板地从 Flash 读代码。结果板子焊回来,死活起不来。后来发现是 Boot Mode Pins 的电平没拉对,芯片一直在等 UART 数据。嗯,从那以后,我对启动模式这部分就再也不敢马虎了。

说白了,BootROM 的启动流程就是一套「找启动设备」的逻辑。它得知道:从哪个设备读代码?按什么顺序找?找不到怎么办? 这一章,我们就来拆解这些细节。

常见的启动设备

不同的芯片、不同的应用场景,支持的启动设备差别很大。但主流的基本就这几种:

设备类型 接口 典型容量 读速度 特点
NAND Flash 8-bit/16-bit 并行 1Gb ~ 256Gb 中 容量大、有坏块、需 ECC
eMMC MMC/SD 协议 4GB ~ 256GB 快 内置控制器、坏块管理透明
SPI NOR Flash SPI/QSPI 1MB ~ 256MB 中 XIP 执行、可靠性高
UART 串口 N/A 慢 用于调试、下载
USB USB 2.0/3.0 N/A 快 支持 DFU、大文件传输
我的经验: 如果你做消费类产品,eMMC 是最省心的选择——坏块管理、擦写均衡都帮你做了。但成本敏感的项目,NAND + 软件 ECC 还是主流。我个人习惯在 BootROM 里至少留一个 SPI NOR 作为 fallback,哪怕容量小,关键时刻能救命。

启动模式选择引脚(Boot Mode Pins)

芯片怎么知道该从哪个设备启动?靠的是硬件引脚。

一般芯片会留出 2~4 个 GPIO,在复位时采样它们的电平状态。这些引脚就叫 Boot Mode Pins。BootROM 在初始化完最基本的硬件(时钟、引脚复用)后,第一件事就是读这些引脚的电平。

举个例子,一个典型的配置可能是这样:

BOOT[1:0] 启动设备 备注
00 SPI NOR 从片选 0 启动
01 eMMC 从 boot partition 启动
10 NAND 从第 0 块启动
11 UART 等待串口下载
注意: 这些引脚在复位完成后,通常会被释放为普通 GPIO。如果你在应用代码里误操作了这些引脚,下次复位时可能读到错误电平。我曾经见过一个项目,因为 Boot Mode Pins 被复用为 LED 控制,结果上电时序不对,芯片一直进 recovery 模式。排查了两天才找到原因。

启动设备优先级与轮询

Boot Mode Pins 只是第一层选择。很多时候,芯片会支持 启动设备优先级 和 轮询机制。

什么意思呢?比如你设定了从 SPI NOR 启动,但 SPI NOR 里没烧录代码,或者读出来校验失败。这时候 BootROM 不会死等,而是会按预设的优先级列表,挨个尝试下一个设备。

典型的轮询流程是这样的:

  1. 读取 Boot Mode Pins,确定首选启动设备。
  2. 初始化该设备的控制器(比如 SPI 控制器、NAND 控制器)。
  3. 读取设备头部信息(通常是前 512 字节或前 4KB)。
  4. 校验头部签名或 CRC。如果通过,加载并跳转。
  5. 如果校验失败,记录错误,切换到下一个设备。
  6. 所有设备都试过?进入 recovery 模式(比如 UART 等待)。

下面这张图,就是 BootROM 启动设备轮询的典型流程:

BootROM 启动设备轮询流程图 BootROM 启动设备轮询流程 芯片上电复位 采样 Boot Mode Pins 确定首选启动设备 初始化设备控制器 读取头部信息并校验签名 校验通过? 是 加载并跳转执行 否 记录错误,切换设备 还有设备? 是 否 进入 Recovery 模式 说明 轮询顺序由 Boot Mode Pins 和优先级表共同决定
核心要点: BootROM 的轮询不是无脑循环。它通常有超时机制和重试次数限制。比如读 NAND 时遇到坏块,会尝试下一个块,而不是一直卡死。我见过一个设计,轮询超时设了 500ms,结果因为 NAND 初始化慢,每次复位都要等将近 2 秒才 fallback 到 SPI NOR。后来我把超时改成了 200ms,启动速度快了不少。

设备枚举的细节

设备枚举不只是「读一下设备 ID」那么简单。BootROM 需要做几件事:

  • 识别设备类型: 比如同样是 SPI 接口,NOR Flash 和 NAND Flash 的指令集完全不同。
  • 获取设备参数: 容量、页大小、块大小、擦除时间等。这些信息通常通过读 ID 指令或 JEDEC 标准获取。
  • 初始化控制器: 根据设备参数配置时钟、时序、DMA 等。
  • 验证可用性: 比如写一个测试模式,读回来确认总线是否正常。

你想想看,如果 BootROM 不做这些检查,直接按固定时序去读,万一设备没焊好或者总线短路,芯片可能就死机了。所以,健壮性 是 BootROM 设备枚举的第一原则。

避坑指南: 我曾经在一个项目里,BootROM 枚举 SPI NOR 时只读了 JEDEC ID,没做读写验证。结果有一批 Flash 的 ID 读出来是对的,但实际数据线 D2 虚焊,导致 QSPI 模式下读数据全是乱的。后来我在枚举流程里加了一步「写-读-校验」的环回测试,才把这个问题抓出来。

优先级表的配置

启动设备的优先级,通常固化在 BootROM 里,但有些芯片允许通过 OTP 或 eFuse 来修改。典型的优先级表长这样:

优先级 设备 条件
1(最高) SPI NOR Boot Mode Pins = 00
2 eMMC Boot Mode Pins = 01
3 NAND Boot Mode Pins = 10
4 UART Boot Mode Pins = 11 或所有设备失败

这里有个细节:优先级和 Boot Mode Pins 是两回事。Boot Mode Pins 决定的是「首选设备」,而优先级决定的是「首选失败后,下一个试谁」。有些芯片允许你通过软件配置优先级表,但大部分是写死的。

嗯,说到这儿,我想起一个案例。有个客户做工业控制器,要求启动时必须先尝试从 UART 下载固件,如果 5 秒内没收到数据,再切到 SPI NOR。但他们的芯片 BootROM 不支持这种「超时优先」的逻辑。最后我们只能在外围加了一个 CPLD,在复位时控制 Boot Mode Pins 的电平切换,模拟出这个效果。所以,了解你的芯片 BootROM 的灵活性边界,比什么都重要。

重要提醒: 不要假设所有芯片的 BootROM 都支持完整的轮询和 fallback。有些低成本 MCU 的 BootROM 只读一次 Boot Mode Pins,如果首选设备失败,就直接死循环了。选型时一定要看 datasheet 里的「Boot Sequence」章节,确认 fallback 行为。

这一章的内容就到这里。启动模式与设备枚举,说白了就是 BootROM 的「导航系统」。它决定了芯片从哪里找代码、按什么顺序找、找不到怎么办。理解了这些,你就能更好地设计启动流程,也能更快地定位启动失败的问题。