第4章 存储介质与启动设备:NOR Flash、NAND Flash、eMMC、SD卡、SPI Flash的启动特性

做Bootloader移植,第一关就是搞清楚你的代码到底从哪儿启动。不同存储介质,启动流程天差地别。我见过不少工程师,拿着NOR Flash的启动代码往NAND上硬套,结果折腾一周都起不来。说白了,每种介质都有自己的脾气,你得顺着它来。

4.1 存储介质的核心差异

先看一张总览表,把五种常见介质的启动特性说清楚。这是我做项目时经常翻的对照表,建议你收藏。

特性 NOR Flash NAND Flash eMMC SD卡 SPI Flash
接口类型 并行/CFI 并行/NAND协议 MMC协议 SPI/SDIO SPI
读取方式 XIP(片内执行) 需拷贝到RAM 需拷贝到RAM 需拷贝到RAM 部分支持XIP
坏块管理 无 必须软件管理 内置控制器 内置控制器 无
启动速度 快(直接执行) 慢(需搬运) 中等 慢 快(XIP时)
典型容量 1MB~64MB 128MB~8GB 4GB~128GB 1GB~64GB 512KB~32MB
启动场景 早期Bootloader 大容量嵌入式 手机/平板 开发板/单板机 低成本IoT

4.2 NOR Flash:XIP启动的王者

NOR Flash最大的特点就是支持XIP(eXecute In Place)。什么意思?CPU可以直接在Flash上取指令执行,不需要先把代码搬到RAM里。这特性在Bootloader启动阶段太关键了——上电瞬间RAM还没初始化,代码就能跑起来。

关键点:NOR Flash的读时序和SRAM很像,地址线直接映射到CPU的地址空间。比如某款ARM芯片,NOR Flash挂在CS0上,起始地址就是0x00000000。上电后PC指针直接指向这里,开始执行第一条指令。

我在一个工业控制项目里用过NOR Flash启动。当时选的是8MB的并行NOR,映射到0x08000000。Bootloader只有64KB,直接在Flash里跑,速度飞快。但要注意,NOR Flash写操作很慢,擦除一个扇区要几百毫秒。所以运行时数据不能写在NOR里,得放到RAM。

个人习惯:NOR Flash启动时,我会把中断向量表放在Flash开头,然后立即初始化RAM,再把关键数据段搬到RAM里。这样既利用了XIP的快速启动,又保证了运行时的性能。

4.3 NAND Flash:大容量但麻烦多

NAND Flash容量大、价格低,但启动起来特别麻烦。它不支持XIP,CPU不能直接在NAND上执行代码。为什么?因为NAND的读操作是页模式的,一次读一页(通常2KB或4KB),而且有坏块问题。你想想看,CPU取指令时随机访问,NAND根本应付不来。

所以NAND启动的套路是:芯片内部ROM里有一段固化代码(叫ROM Code或BootROM),上电后它先把NAND前几页的数据读到内部SRAM里。这段数据就是你的Bootloader第一阶段(SPL)。SPL负责初始化DRAM,然后把完整的Bootloader从NAND搬到DRAM里执行。

我曾经踩过的坑:NAND Flash出厂时可能有坏块,而且坏块标记通常在每页的 spare area 里。ROM Code读前几页时如果遇到坏块,启动就失败了。后来我学乖了,在烧录时就把Bootloader放在好块区域,并在前几页里加入坏块跳过表。

NAND启动的典型流程:

  1. ROM Code读取NAND第0页(通常是4KB或8KB)到内部SRAM
  2. 执行SPL代码,初始化时钟和DRAM控制器
  3. SPL从NAND读取完整的U-Boot到DRAM
  4. 跳转到U-Boot入口,继续启动

4.4 eMMC:内置控制器的省心方案

eMMC本质上就是NAND Flash加了一个控制器芯片,封装在一起。这个控制器帮你处理了坏块管理、ECC校验、磨损均衡。对Bootloader来说,eMMC就像一个黑盒子,你通过MMC协议读写就行了,不用操心底层细节。

eMMC启动有两种模式:

  • Boot分区模式:eMMC内部有专用的Boot分区,上电后芯片自动从Boot分区读取数据。这分区是只读的,非常安全。
  • 用户分区模式:从用户数据分区的特定扇区启动。这种方式灵活,但容易被误擦除。

我建议:量产产品一定要用Boot分区模式。把Bootloader烧到eMMC的Boot分区里,然后把这个分区写保护。这样即使系统崩溃,Bootloader也不会丢。我在一个行车记录仪项目里就这么做的,返修率降了不少。

4.5 SD卡:开发板的标配

SD卡启动在开发板上最常见。它的协议和eMMC很像,都是基于MMC协议。但SD卡有个特点——它支持SPI模式。很多低成本的MCU没有SDIO控制器,只能用SPI接口读写SD卡。

SD卡启动的典型场景:

  • 树莓派、BeagleBone等开发板从SD卡启动
  • FPGA配置从SD卡加载
  • MCU通过SPI接口读取SD卡中的Bootloader

要注意,SD卡的启动顺序是有讲究的。通常芯片会先检测SD卡是否存在,然后读取MBR(主引导记录)或分区表,找到启动分区。如果分区表损坏,启动就失败了。

调试技巧:SD卡启动失败时,先用读卡器在PC上检查分区表。用fdisk -l看看第一个分区是不是FAT32,启动标志有没有设置。我遇到过好几次,问题就是分区表格式不对。

4.6 SPI Flash:小身材大用途

SPI Flash是成本最低的启动方案。它只有4~8个引脚,占PCB面积小,适合IoT设备。SPI Flash也支持XIP吗?部分支持。有些MCU内部有SPI映射模块,可以把SPI Flash映射到地址空间,实现XIP。但大多数情况下,SPI Flash还是需要把代码搬到RAM里执行。

SPI Flash的启动速度受限于SPI时钟频率。一般SPI时钟在20MHz~50MHz,比并行NOR慢不少。所以SPI Flash启动时,Bootloader要尽量小,通常不超过64KB。如果Bootloader太大,启动时间会很长。

SPI Flash型号 容量 最大SPI时钟 典型启动时间(64KB)
W25Q16 2MB 50MHz 约10ms
W25Q64 8MB 50MHz 约10ms
W25Q128 16MB 50MHz 约10ms

注意:SPI Flash的写操作需要先擦除,擦除单位是扇区(通常4KB)。如果你在Bootloader里需要保存配置参数,一定要规划好存储布局。我曾经把配置参数和Bootloader放在同一个扇区,结果每次更新配置都把Bootloader擦掉了……

4.7 启动介质选择决策树

下面这张SVG图帮你快速决策:你的项目该用哪种介质启动?

启动介质选择决策树 启动介质选择 容量小(<64MB) 容量大(>64MB) 需要XIP? 低成本IoT NOR Flash SPI Flash 需要内置控制器? 开发板调试 eMMC NAND Flash 决策要点 • 需要XIP且容量小 → NOR Flash • 需要XIP且成本敏感 → SPI Flash • 大容量且需要可靠性 → eMMC

4.8 启动故障定位思路

启动不起来怎么办?我总结了一套排查思路:

  1. 先确认硬件连接:用示波器看片选信号、时钟信号、数据线有没有波形。很多时候是虚焊或电平不匹配。
  2. 检查启动配置:芯片的启动引脚(BOOT0、BOOT1等)有没有设置正确?我见过有人把eMMC启动引脚接成了SD卡模式。
  3. 验证存储介质:用编程器读出存储介质前几页的数据,看看Bootloader有没有烧录正确。CRC校验一下。
  4. 跟踪ROM Code:如果芯片有调试接口,单步跟踪ROM Code的执行流程,看它卡在哪个步骤。

核心原则:启动故障定位,从物理层开始,逐层向上排查。不要一上来就怀疑Bootloader代码有问题,先确认硬件和配置是对的。