嵌入式系统基础:CPU、内存、外设、存储设备与启动介质

嵌入式系统是U-Boot与Linux内核运行的物理载体。理解CPU如何取指执行、内存如何组织地址空间、外设如何被映射访问,以及NOR/NAND/eMMC/SD等存储介质在电气特性与访问协议上的本质差异,是理解Bootloader启动流程的前提。本章将围绕“硬件资源如何被软件抽象与驱动”这一主线,剖析嵌入式系统的核心组件,并重点对比各类启动介质的特性,为后续分析U-Boot如何从介质中加载内核打下坚实的硬件认知基础。

嵌入式系统硬件抽象与启动介质选择 CPU 核心 ARM Cortex-A / RISC-V PC指针 · 异常向量 MMU / Cache 内存 (RAM) DDR3/DDR4/LPDDR SDRAM 控制器 地址映射 · 掉电丢失 外设 UART / I2C / SPI GPIO / DMA / 中断控制器 寄存器映射 (MMIO) 启动存储介质 NOR Flash XIP直接执行 · 容量小 · 读取快 NAND Flash 页/块访问 · 容量大 · 坏块管理 eMMC MMC协议 · 内置控制器 · 块设备 SD Card SPI/SDIO模式 · 可移动 · 兼容性好 总线 总线 启动加载路径 DMA/拷贝 启动介质选择逻辑 ROM → BootROM → U-Boot → Kernel 根据eFuse/拨码开关选择启动源

上图展示了嵌入式系统中CPU、内存、外设与存储介质之间的核心关系。CPU通过总线访问内存与外设,而启动介质则通过特定的接口(如SPI、MMC、SDIO)与CPU连接。启动时,CPU首先执行固化在ROM中的BootROM代码,再由BootROM引导U-Boot,最终由U-Boot加载内核到内存中运行。理解这一链路是掌握启动流程的关键。

2.1 CPU核心:取指执行与地址空间

核心原理:CPU(Central Processing Unit)是嵌入式系统的运算与控制中心。在启动阶段,CPU的行为相对简单:从复位向量(Reset Vector)地址取出第一条指令,然后按照程序计数器(PC)的指引依次执行。ARM Cortex-A系列处理器复位后,PC通常被设置为0x00000000或0xFFFF0000(由硬件配置决定),而RISC-V架构则从0x00001000或0x80000000开始执行。CPU内部集成了MMU(Memory Management Unit)和Cache,但在启动早期,MMU通常被关闭,CPU直接以物理地址访问内存和外设寄存器。

判断方法:在阅读SoC(System on Chip)数据手册时,需要重点关注复位向量地址、启动模式引脚(Boot Mode Pins)以及异常向量表(Exception Vector Table)的布局。例如,i.MX6ULL处理器通过BOOT_CFG引脚决定从NOR、NAND、SD还是eMMC启动。CPU的地址总线宽度决定了可寻址空间,32位CPU可寻址4GB空间,其中一部分映射到DDR内存,另一部分映射到外设寄存器(MMIO区域)。

实战场景:在调试U-Boot时,经常需要查看CPU的启动模式。例如,使用JTAG调试器连接开发板,读取复位向量处的指令,确认CPU是否从BootROM开始执行。如果CPU没有从预期介质启动,首先检查启动引脚的电平配置,其次确认BootROM是否被烧写正确。

常见误区:初学者常误以为CPU启动时MMU是开启的。实际上,在U-Boot的start.S汇编代码中,第一步通常是设置CPU为SVC模式、关闭中断、关闭MMU和Cache,以确保后续操作在“平坦”的物理地址空间中进行。若MMU未关闭,访问的地址可能被重映射,导致启动失败。

2.2 内存系统:DDR初始化与地址映射

核心原理:内存(RAM)是程序运行时的临时存储介质,具有掉电丢失的特性。嵌入式系统通常使用DDR(Double Data Rate)SDRAM作为主内存。DDR控制器集成在SoC内部,负责管理行/列地址、刷新时序、数据选通等复杂操作。在U-Boot启动早期,DDR控制器尚未初始化,CPU只能使用芯片内部的SRAM(通常只有几十KB到几百KB)。因此,U-Boot的SPL(Secondary Program Loader)阶段通常运行在SRAM中,完成DDR初始化后,再将完整的U-Boot拷贝到DDR中运行。

操作流程:DDR初始化的典型步骤包括:

  1. 配置DDR控制器的时钟频率与PLL(锁相环)参数。
  2. 设置DDR芯片的模式寄存器(MR0-MR3),包括CAS延迟、突发长度等。
  3. 执行ZQ校准(针对DDR3/DDR4)以调整驱动强度。
  4. 进行读写训练(Write Leveling / Read DQS Gating),确保数据采样窗口正确。
  5. 将DDR地址映射到CPU的物理地址空间(如0x80000000)。
内存类型工作电压典型容量访问方式启动阶段作用
SRAM1.8V/3.3V16KB - 512KB字节/字访问U-Boot SPL运行场所
DDR31.5V256MB - 4GB突发传输U-Boot与内核运行场所
DDR41.2V1GB - 16GB突发传输高性能嵌入式系统
LPDDR41.1V2GB - 8GB低功耗突发移动/物联网设备

经验提醒:DDR初始化是U-Boot移植中最容易出问题的环节。若DDR参数配置错误,系统可能表现为启动后无输出、随机死机或数据校验错误。建议使用SoC厂商提供的DDR压力测试工具(如DDR Stress Test)验证初始化代码的稳定性。

2.3 外设与MMIO:寄存器映射与访问

核心原理:外设(Peripheral)包括UART、I2C、SPI、GPIO、DMA、中断控制器等。CPU通过内存映射I/O(MMIO)方式访问外设寄存器,即每个外设寄存器被分配一个物理地址,CPU使用普通的读写指令即可操作。例如,UART的发送数据寄存器可能位于0x21C00000地址处。在U-Boot中,访问外设寄存器通常通过定义结构体指针或使用readl/writel宏来完成。

判断方法:查看SoC数据手册的“Memory Map”章节,可以获取外设寄存器的基地址。例如,i.MX6ULL的UART1基地址为0x02020000,GPIO1基地址为0x0209C000。在编写U-Boot驱动时,需要根据基地址加上偏移量来访问具体寄存器。

// 示例:U-Boot中访问UART寄存器
#define UART1_BASE 0x02020000
#define UART_URXD  0x00  // 接收寄存器
#define UART_UTXD  0x40  // 发送寄存器

void uart_putc(char c) {
    volatile unsigned int *tx_reg = (unsigned int *)(UART1_BASE + UART_UTXD);
    *tx_reg = c;  // 写入数据
}

常见误区:外设寄存器通常要求32位对齐访问,且有些寄存器是只读或只写的。直接使用C语言的普通变量赋值可能导致编译优化问题,必须使用volatile关键字修饰指针,防止编译器将多次访问合并为一次。

2.4 启动存储介质:NOR/NAND/eMMC/SD深度对比

核心原理:启动介质是存储Bootloader、内核镜像、设备树和根文件系统的非易失性存储设备。不同介质在电气接口、访问粒度和可靠性方面差异显著,直接影响U-Boot的移植策略。

  • NOR Flash:支持XIP(Execute in Place),CPU可以直接从NOR中取指执行,无需拷贝到RAM。读取速度快,但写入速度慢、容量小(通常1MB-64MB)、成本高。常用于存储SPL或小型Bootloader。
  • NAND Flash:以页(Page)为读写单位,以块(Block)为擦除单位。容量大(128MB-8GB)、成本低,但存在坏块(Bad Block)问题,需要软件进行坏块管理和ECC校验。CPU不能直接从NAND执行代码,必须先将代码拷贝到RAM中。
  • eMMC:是嵌入式的MMC存储芯片,内部集成了NAND Flash和控制器,对外提供标准MMC接口。支持块访问,自动处理坏块和擦写均衡,容量可达32GB以上。U-Boot通常通过MMC子系统访问eMMC。
  • SD Card:与eMMC协议兼容,但采用可移动封装。支持SPI和SDIO两种模式,U-Boot中通过mmc命令识别。SD卡常用于开发阶段的启动介质,便于快速更新镜像。
特性NOR FlashNAND FlasheMMCSD Card
访问单位字节/字页(2KB-16KB)块(512B-4KB)块(512B-4KB)
XIP支持是否否否
坏块管理无需软件管理内置控制器内置控制器
典型容量1-64MB128MB-8GB4-128GB1-512GB
启动速度快(XIP)慢(需拷贝)中(块读取)中
U-Boot支持CFI/SPI NOR驱动MTD/NAND驱动MMC子系统MMC子系统

案例拆解:某工业控制板卡选用i.MX6ULL处理器,需要从NAND Flash启动。初始现象:U-Boot无法启动,串口无输出。分析过程:首先检查启动引脚配置,确认BOOT_CFG设置为NAND启动;其次使用JTAG读取BootROM执行状态,发现BootROM无法从NAND读取SPL。进一步检查NAND芯片的ID读取命令,发现U-Boot的NAND驱动中时序参数与芯片手册不匹配。实际操作:修改drivers/mtd/nand/raw/mxc_nand.c中的时序配置,重新编译U-Boot并烧写。结果对比:启动成功,U-Boot正确识别NAND容量并加载内核。复盘经验:NAND启动问题多与时序、ECC算法和坏块标记位置有关,建议使用SoC厂商的烧写工具验证硬件连接。

经验提醒:在选择启动介质时,需综合考虑启动速度、容量、成本、可靠性和可维护性。NOR适合存放关键的小型引导代码,eMMC适合大容量系统存储,而NAND则需要在软件层面付出更多管理成本。

总结复盘:嵌入式系统的启动过程本质上是CPU从非易失性介质中逐步加载并执行代码的过程。CPU负责执行,内存提供运行空间,外设提供交互接口,而存储介质则决定了启动的起点和方式。理解NOR的XIP特性、NAND的坏块管理、eMMC的控制器封装以及SD卡的兼容性,是进行U-Boot移植和启动调试的基础。在实际项目中,应优先阅读SoC参考手册的启动章节,明确BootROM的行为,再针对具体介质编写或适配驱动。