3. 启动模式与介质:NAND Flash启动、NOR Flash启动、SD/eMMC启动、SPI Flash启动、USB/串口下载模式
做 Bootloader 这么多年,我最大的体会就是:启动介质选不对,后面全是白费力气。不同的 Flash 类型、不同的接口协议,决定了你的 Bootloader 该怎么设计、怎么调试。今天咱们就把这几种常见的启动模式掰开揉碎了聊一聊。
核心观点:启动介质的选择,本质上是“CPU 上电后第一条指令从哪里取”的问题。不同的介质,决定了 Bootloader 的大小、加载方式、以及调试手段。
3.1 NAND Flash 启动
NAND Flash 在嵌入式系统里用得非常多,尤其是大容量存储场景。但说实话,它做启动介质挺麻烦的。
为什么麻烦?因为 NAND 是页式访问,不能像 NOR 那样直接寻址。CPU 上电后,通常需要先把 NAND 前几页的内容拷贝到内部 SRAM 或 DDR 里,然后跳过去执行。这个过程叫 “NAND 启动自拷贝”。
我在项目中遇到过一个问题:某款芯片的 NAND 控制器在启动时只支持 2KB 页大小,结果我用的 NAND 是 4KB 页的。上电后死活起不来,查了两天才发现是页大小不匹配。嗯,这个坑你们一定要记住。
| 参数 | NAND Flash | NOR Flash |
|---|---|---|
| 读取方式 | 页读取,不能直接寻址 | 随机访问,类似内存 |
| 启动流程 | 需自拷贝到 RAM 执行 | 可直接在 Flash 中执行(XIP) |
| 坏块管理 | 必须处理坏块 | 通常无坏块问题 |
| 典型 Bootloader 大小 | 4KB ~ 128KB | 64KB ~ 512KB |
注意:NAND 启动时,Bootloader 的前几页必须放在 无坏块区域。我曾经见过有人把启动代码放在第 0 块,结果那块正好是出厂坏块,整批板子都起不来。后来我们强制要求:启动代码必须放在前 4 块,并且做坏块检查。
3.2 NOR Flash 启动
NOR Flash 最大的优势是 XIP(eXecute In Place),也就是代码可以直接在 Flash 里运行,不用拷贝到 RAM。这对 Bootloader 来说太友好了。
我个人习惯在 NOR 启动的场景下,把 Bootloader 做得稍微大一点,反正可以直接跑。但要注意:NOR 的写入速度很慢,而且擦除粒度大(通常 64KB 或 128KB 一个扇区)。所以调试时如果频繁改代码,擦写一次要等好几秒。
你想想看,NOR 启动的典型流程是什么?
- CPU 上电后,从 NOR 的起始地址(通常是 0x00000000 或 0xBF000000)取第一条指令。
- Bootloader 直接在 NOR 中执行,初始化硬件(时钟、DDR、串口等)。
- 如果需要加载操作系统,再从 NOR 中读取内核镜像到 DDR,然后跳转。
小技巧:NOR 启动时,可以把 Bootloader 的 .text 段链接到 NOR 的地址空间,.data 和 .bss 段放在 DDR 里。这样既利用了 XIP 的优势,又能正常使用全局变量。
3.3 SD/eMMC 启动
现在很多应用处理器都支持从 SD 卡或 eMMC 启动。这种方式的优点是:容量大、速度快、可更换。但缺点也很明显——启动流程复杂。
SD/eMMC 启动通常分几个阶段:
- ROM Code 阶段:芯片内部的 ROM 代码会尝试从 SD/eMMC 的特定扇区读取第一级 Bootloader(通常是 1KB ~ 32KB)。
- 第一级 Bootloader:初始化 DDR 和存储控制器,然后从 eMMC 的 Boot 分区或用户分区加载第二级 Bootloader。
- 第二级 Bootloader:也就是我们常说的 U-Boot 或类似的东西,负责加载操作系统。
我记得有一次调试 eMMC 启动,板子总是卡在 ROM Code 阶段。用示波器量 eMMC 的 CMD 线,发现 ROM Code 发了命令但 eMMC 没回应。后来发现是 eMMC 的 Boot 分区没使能,需要发特定的 CMD 才能激活。这个坑,很多新手都会踩。
关键点:eMMC 的 Boot 分区和 RPMB 分区是独立的,默认可能没使能。你需要在第一次烧录时通过特定的命令或配置字来激活它们。
3.4 SPI Flash 启动
SPI Flash 启动在低成本、小体积的场景下非常常见。它通过 SPI 接口连接,引脚少,但速度相对较慢。
SPI Flash 启动的典型流程:
- CPU 上电后,通过 SPI 控制器读取 Flash 的前几个字节(通常是 4 字节的跳转指令或启动头)。
- 如果支持 XIP,可以直接在 SPI Flash 中执行代码(但速度很慢,因为 SPI 时钟通常只有几十 MHz)。
- 更常见的做法是:Bootloader 把自己拷贝到内部 SRAM 或 DDR 中,然后跳转执行。
我个人建议:SPI Flash 启动的 Bootloader 一定要做压缩。因为 SPI 读取速度慢,如果 Bootloader 太大,启动时间会很长。我做过一个项目,Bootloader 有 256KB,从 SPI Flash 读到 DDR 花了将近 2 秒,后来用 LZMA 压缩到 64KB,启动时间缩短到 0.5 秒。
| SPI Flash 类型 | 典型时钟频率 | 读取速度 | 适用场景 |
|---|---|---|---|
| 普通 SPI | 20 ~ 50 MHz | ~ 25 MB/s | 小容量 Bootloader |
| Dual/Quad SPI | 50 ~ 100 MHz | ~ 100 MB/s | 中等容量 Bootloader |
| QSPI (DDR 模式) | 100 ~ 200 MHz | ~ 200 MB/s | 大容量 Bootloader 或 XIP |
注意:SPI Flash 启动时,CPU 的 SPI 控制器必须支持 内存映射模式(Memory Mapped Mode),否则无法直接读取 Flash 内容。有些低端芯片不支持这个模式,那就只能通过 SPI 命令逐字节读取,启动速度会非常慢。
3.5 USB/串口下载模式
USB 和串口下载模式,说白了就是 “把 Bootloader 或固件通过通信接口灌进去”。这种模式通常用于工厂烧录、开发调试、或者恢复变砖的设备。
串口下载是最古老的,速度慢(通常 115200 bps),但兼容性好。USB 下载则快得多(USB 2.0 全速 12 Mbps,高速 480 Mbps)。
我遇到过最头疼的情况是:某款芯片的 USB 下载模式需要先安装特定的驱动,但客户的电脑是 Linux 系统,驱动死活装不上。后来我们改成了串口下载,虽然慢了点,但至少能用。
USB/串口下载的典型流程:
- 进入下载模式:通常通过拉高/拉低某个 GPIO、或者检测特定的按键组合来触发。
- 握手协议:芯片通过串口或 USB 发送特定的握手信号,等待上位机响应。
- 数据传输:上位机将固件分包发送,芯片接收后写入 Flash。
- 校验与跳转:接收完成后做 CRC 或 MD5 校验,然后跳转到新固件执行。
经验之谈:USB 下载模式一定要做 超时处理。我曾经见过一个产品,USB 下载时如果上位机没发数据,芯片会一直死等,导致看门狗超时复位。后来我们在协议里加了个 5 秒超时,超时后自动退出下载模式,进入正常启动流程。
3.6 启动模式选择与调试要点
说了这么多,到底怎么选?我个人的经验是:
- 容量优先:选 NAND 或 eMMC。
- 速度优先:选 NOR 或 QSPI。
- 成本优先:选 SPI Flash 或串口下载。
- 可维护性优先:选 SD/eMMC,方便升级。
调试时,我建议你准备一个 逻辑分析仪。不管是 NAND 的 RE/WE 信号、SPI 的 CLK/MOSI/MISO、还是 eMMC 的 CMD/DAT 线,逻辑分析仪都能帮你快速定位问题。
下面这张图总结了不同启动介质的核心流程和关键点: