2. BootROM 启动流程全景:上电复位、CPU 从复位向量取指、BootROM 代码执行、硬件初始化
芯片上电那一刻,到底发生了什么?
很多人觉得 BootROM 启动很神秘。其实说白了,就是芯片从「死」到「活」的第一个步骤。我做了十几年固件,每次调试启动失败,最后发现的问题往往都出在这个阶段。所以,把这一章吃透,后面会省很多力气。
2.1 上电复位:芯片的「第一口气」
按下电源键,或者系统刚上电,芯片内部并不是瞬间就稳定了。电压会有一个爬升过程,时钟也需要时间起振。这时候,芯片内部有一个硬件模块叫 POR(Power-On Reset,上电复位),它负责做一件事:
- 监测电源电压是否达到稳定阈值
- 监测外部复位引脚是否释放
- 等待时钟 PLL 锁定
当这三个条件都满足后,POR 会释放一个内部复位信号。这个信号会告诉 CPU 核心:「可以开始干活了」。
2.2 CPU 从复位向量取指:第一行代码在哪?
CPU 被复位后,它的程序计数器(PC)会被硬件强制设置为一个固定地址。这个地址就是 复位向量(Reset Vector)。
不同的架构,复位向量位置不一样:
| 架构 | 复位向量地址 | 说明 |
|---|---|---|
| ARM Cortex-M | 0x00000000(向量表基址) | 从该地址取栈顶指针,再取复位中断入口 |
| ARM Cortex-A | 0x00000000 或 0xFFFF0000 | 由硬件配置引脚决定 |
| RISC-V | 0x00000000 或 0x80000000 | 由 mtvec 寄存器复位值决定 |
| Xtensa(ESP32) | 0x40000000 | 直接映射到内部 ROM |
CPU 从这个地址读到的第一条指令,就是 BootROM 的第一行代码。注意,这时候 DDR/SDRAM 还没有初始化,CPU 只能访问芯片内部的 SRAM 或 ROM。
2.3 BootROM 代码执行:芯片的「自检与引导」
CPU 开始执行 BootROM 代码后,会按顺序做以下几件事:
- 设置栈指针 —— 因为后面要调用 C 函数,必须先有栈。
- 初始化关键硬件 —— 比如时钟、看门狗、中断控制器。
- 检查启动模式 —— 通过 GPIO 电平或 eFuse 判断是从 Flash、UART 还是 USB 启动。
- 加载并验证启动镜像 —— 从启动介质读取第一级 Bootloader,校验签名或 CRC。
- 跳转到下一级代码 —— 将控制权交给 SPL 或 U-Boot。
这个过程,我习惯把它叫做 「芯片的自我认知阶段」。因为这时候芯片还不知道自己要从哪里启动,需要先「问」一下硬件引脚。
2.4 硬件初始化:让芯片「活起来」
BootROM 中的硬件初始化,和操作系统启动后的驱动初始化完全不同。它只做最基础、最必要的初始化:
- 时钟系统:配置 PLL,让 CPU 跑在目标频率。我见过一个项目,PLL 锁定时间太长,导致 BootROM 超时复位,反复重启。
- 看门狗:先喂一次狗,然后设置超时时间。防止 BootROM 卡死。
- 中断控制器:默认关闭所有中断,只允许 NMI(不可屏蔽中断)。
- 内存控制器:如果芯片有内部 SRAM,需要初始化时序。如果是外部 DDR,BootROM 通常不碰,留给下一级 Bootloader。
- 启动介质接口:比如 SPI Flash 控制器、SD/MMC 控制器、USB 设备控制器。BootROM 需要能用它们读取数据。
嗯,这里要注意:BootROM 的初始化顺序是固定的。你不能先初始化 Flash 再初始化时钟,因为 Flash 控制器依赖时钟。这个顺序在芯片设计阶段就定死了。
2.5 启动流程全景图
下面这张图,把整个流程串起来了。我建议你把它存下来,后面调试启动问题时会经常用到。
2.6 几个容易踩的坑
做 BootROM 调试这么多年,我总结了几条血泪教训:
- 复位向量指向了未初始化的内存 —— 有些芯片复位后内存控制器默认是关闭的,CPU 取指直接挂死。解决办法是确保复位向量落在 ROM 或已使能的 SRAM 区域。
- 看门狗没有及时喂 —— BootROM 执行时间如果超过看门狗超时时间,芯片会反复复位。我遇到过一例,因为 Flash 读取速度太慢,导致 BootROM 超时,最后只能调整看门狗预分频。
- 启动模式检测引脚电平不稳定 —— 如果 GPIO 上拉/下拉电阻没焊,或者外部电路有干扰,BootROM 可能检测到错误的启动模式,从错误的介质加载镜像。
好了,这一章的内容就是这些。BootROM 启动流程,说白了就是芯片从「死」到「活」的四个关键步骤。理解了这个全景,后面讲烧录流程时,你就能明白为什么有些烧录方式需要先进入「下载模式」—— 那其实就是 BootROM 在启动模式检测阶段做的手脚。