一、嵌入式系统的本质与层级
嵌入式系统的官方定义是:以应用为中心,以计算机技术为基础,软硬件可剪裁的专用计算机系统。它与通用计算机最大的不同,在于完全围绕具体应用场景设计,可根据需求对功耗、体积、环境适应性、稳定性和可靠性进行深度定制。比如工业控制场景中,它需要在 - 40℃~85℃的宽温环境下稳定运行;而在可穿戴设备中,极致的低功耗则是首要目标。
从层级上看,一个典型的嵌入式系统分为三层:
- 应用层(APP):直接面向用户的业务逻辑,如智能家居的控制界面、工业设备的监测程序、汽车的仪表盘显示。
- 操作系统层(SYS):负责资源管理、任务调度和硬件抽象,如嵌入式 Linux、FreeRTOS、RT-Thread。
- 硬件系统层:由核心处理器、存储器、外设构成的物理基础,如本文主角 Cortex-A7 内核的 i.MX6ULL 开发板,就是一个典型的硬件平台。
这个层级结构也对应了计算机系统的经典划分:硬件系统 + 软件系统(应用软件 + 系统软件)。其中硬件系统的基本组成包括运算器、控制器、存储器、输入设备和输出设备,这也是理解所有计算机工作原理的起点。
二、核心处理器家族:从 CPU 到 SoC
在嵌入式领域,处理器的分类远比通用 PC 丰富,每一类都针对特定场景做了优化:
- CPU(Central Processing Unit):通用中央处理器,擅长复杂逻辑控制和通用计算,是系统的核心。
- GPU(Graphics Processing Unit):图形处理器,专为并行计算和图像渲染设计,在车载娱乐、智能显示等场景中不可或缺。
- FPU(Floating Point Unit):浮点运算单元,加速浮点数的计算,在工业控制、信号处理中至关重要。
- MPU(Micro Processing Unit):微处理器,偏向通用数据处理,如早期的 ARM7,常搭配外部存储器和外设使用。
- MCU(Micro Controller Unit):微控制器,集成了 RAM、Flash 和外设,侧重控制,如 STM32 系列,广泛应用于物联网传感器、电机控制等场景。
- DSP(Digital Signal Processor):数字信号处理器,专为高速数学运算和信号处理设计,如音频编解码、雷达信号处理。
- SoC(System On Chip):片上系统,将 CPU、GPU、DSP、外设控制器等集成在一颗芯片上,是现代嵌入式设备的主流选择,如手机中的骁龙芯片、开发板中的 i.MX6ULL。
你可以把 SoC 理解为一个 “城市”:MPU 是市政府负责统筹管理,MCU 是警察局负责实时控制,DSP 是研究所负责技术攻坚,而各种外设控制器(如 GPIO、UART、PWM)则是水、电、交通等基础设施,共同构成一个功能完整的系统。
三、指令集架构:CISC 与 RISC 的分野
处理器的指令集架构(ISA)决定了其底层指令的设计哲学,主要分为两类:
- CISC(Complex Instruction Set Computer):复杂指令集,如 x86 架构。它提供了丰富的复杂指令,一条指令可完成多个操作,但硬件实现复杂,功耗较高,更适合桌面和服务器场景。
- RISC(Reduced Instruction Set Computer):精简指令集,如 ARM、MIPS、RISC-V。它的指令数量少、格式规整、执行速度快,硬件实现简单,功耗更低,完美契合嵌入式场景的需求。
ARM 架构就是典型的 RISC,它经历了 ARM1 到 ARM11 的经典系列,如今演进为 Cortex 系列:
- Cortex-A 系列:面向高性能应用,如手机、平板、开发板(如 Cortex-A7),支持复杂操作系统和多任务处理。
- Cortex-R 系列:面向实时控制,如汽车电子、工业控制,强调高可靠性和低延迟。
- Cortex-M 系列:面向微控制器,如物联网传感器、智能手表,主打低功耗和极简设计。
在 i.MX6ULL 开发板上,我们使用的就是 Cortex-A7 内核,它是 32 位架构,支持 ARMv7 指令集,每个指令长度为 4 字节,兼顾了性能与功耗。
四、ARM 内核的核心器件与功能
ARM 内核是整个系统的 “大脑”,其内部包含多个协同工作的关键组件,每个组件都在系统运行中扮演着不可替代的角色。
1. 算术逻辑单元(ALU)
ALU 是内核的 “计算引擎”,负责执行所有算术运算(加减乘除、移位)和逻辑运算(与、或、非、异或)。任何高级语言编写的表达式,如sum = a + b,最终都会被编译为 ALU 可执行的指令。比如在执行if (a > b) return a;时,ALU 会先比较 a 和 b 的大小,设置 CPSR 中的标志位,再根据标志位决定后续执行流程。
2. 寄存器组
寄存器是 CPU 内部的 “高速数据仓库”,ARM 内核包含 37 个 32 位寄存器,在不同工作模式下会映射出不同的可见寄存器:
- 通用寄存器(R0-R15):R0-R12 用于临时存储运算数据和函数参数;R13(SP,栈指针)指向栈顶,管理函数调用的栈帧,比如在调用
fun(a, b)时,SP 会自动调整以分配局部变量空间;R14(LR,链接寄存器)保存函数调用的返回地址,确保函数执行完成后能回到正确的位置;R15(PC,程序计数器)指向下一条要执行的指令,每执行一条指令,PC 会自动递增 4 字节(因为 ARM 指令是 4 字节对齐的)。 - 状态寄存器(CPSR/SPSR):当前程序状态寄存器(CPSR)记录 CPU 的运行状态,包括条件标志位(N/Z/C/V,用于判断运算结果)、中断屏蔽位(I/F,用于关闭 IRQ/FIQ 中断)和工作模式位(M [4:0],用于切换 7 种工作模式);备份程序状态寄存器(SPSR)则在异常发生时保存 CPSR 的内容,确保异常处理完成后能恢复到原状态。
3. 高速缓存(Cache)
Cache 是 CPU 与主存之间的 “缓冲加速器”,分为指令 Cache(I-Cache)和数据 Cache(D-Cache)。它利用程序的时间局部性(近期访问的数据可能再次被访问)和空间局部性(访问某个地址时,其附近地址也可能被访问)原理,将近期频繁访问的指令和数据暂存到高速 SRAM 中,减少 CPU 等待主存的时间。例如在执行for(i=0; i<1000; i++) sum += i;时,I-Cache 会缓存循环指令,D-Cache 会缓存变量sum和i,大幅提升执行效率。在嵌入式系统中,我们可以通过配置寄存器来开启或关闭 Cache,比如在启动阶段关闭 Cache 以确保指令直接从主存读取,系统稳定后再开启 Cache 提升性能。
4. 内存管理单元(MMU)
MMU 是实现虚拟内存的 “地址翻译官”,负责将 CPU 发出的虚拟地址转换为物理地址。它支持:
- 地址映射:为每个进程提供独立的虚拟地址空间,实现进程隔离,比如在 Linux 系统中,每个进程都认为自己拥有 4GB 的地址空间。
- 权限控制:通过页表设置内存区域的访问权限(读 / 写 / 执行),防止非法内存访问,比如代码段被设置为只读,避免被意外修改。
- 缓存管理:控制 Cache 的缓存策略,确保数据一致性,比如在 DMA 传输时,需要刷新 Cache 以保证主存中的数据是最新的。
在嵌入式 Linux 等需要虚拟内存的系统中,MMU 是必需的硬件组件;而在一些实时操作系统(如 FreeRTOS)中,可能会关闭 MMU 以减少开销。
5. 总线接口单元(BIU)
BIU 是内核与外部设备通信的 “桥梁”,负责管理地址总线、数据总线和控制总线。它通过 AHB(先进高性能总线)连接内核和高带宽外设(如 RAM、NOR Flash),通过 APB(先进外设总线)连接低带宽外设(如 GPIO、UART、PWM),实现高效的数据传输。比如在 i.MX6ULL 开发板上,内核通过 AHB 总线访问 DDR 内存,通过 APB 总线控制 GPIO 引脚输出高低电平。
五、工作模式与异常处理:系统稳定的基石
ARM 内核设计了多工作模式和完善的异常处理机制,以确保系统在各种场景下的稳定性和可靠性。
1. 七种工作模式详解
ARM 内核支持 7 种工作模式,每种模式都有独立的寄存器组,用于隔离不同运行场景的上下文:
| 模式名称 | 触发条件 | 核心用途 |
|---|---|---|
| 用户模式(User) | 普通应用程序运行时 | 非特权模式,供用户程序执行,不能直接访问硬件或修改系统状态,保证系统安全。比如你编写的int a=100; int b=200; sum=a+b;就运行在用户模式下。 |
| 系统模式(System) | 操作系统内核任务 | 使用用户模式寄存器组,但拥有特权,用于运行需要访问系统资源的内核任务,比如内存管理进程。 |
| 管理模式(Supervisor) | 系统复位、软中断(SWI) | 操作系统内核的主要运行模式,负责系统初始化、内存管理和进程调度。当用户程序需要访问硬件时,必须通过 SWI 指令进入管理模式,由内核代为执行。 |
| 中止模式(Abort) | 内存访问错误(预取中止 / 数据中止) | 处理内存访问异常,如页错误、总线错误。比如当程序访问一个不存在的物理地址时,会触发数据中止异常。 |
| 未定义模式(Undefined) | 遇到无法识别的指令 | 处理未定义指令,可用于软件仿真协处理器指令。比如当 CPU 执行一条 ARMv8 特有的指令时,在 ARMv7 内核上会触发未定义异常。 |
| 中断模式(IRQ) | 外部中断请求 | 处理普通外部中断,如定时器中断、UART 中断。比如当 UART 接收到数据时,会触发 IRQ 中断,CPU 进入中断模式执行中断服务函数。 |
| 快速中断模式(FIQ) | 快速中断请求 | 处理对响应时间要求极高的中断,如高速数据传输(DMA)、实时事件。FIQ 拥有更高的优先级,并且有更多的私有寄存器,减少了上下文切换的开销。 |
2. 异常向量表的核心作用
当系统发生异常(中断、复位、指令错误等)时,CPU 会立即暂停当前程序,跳转到异常向量表中对应的固定地址,执行异常处理程序。
异常向量表是一个位于内存起始地址(通常是 0x00000000 或 0xFFFF0000)的地址列表,每种异常对应一个固定入口:
| 异常类型 | 向量地址(ARMv7) |
|---|---|
| 复位 | 0x00000000 |
| 未定义指令 | 0x00000004 |
| 软中断(SWI) | 0x00000008 |
| 预取中止 | 0x0000000C |
| 数据中止 | 0x00000010 |
| 保留 | 0x00000014 |
| IRQ 中断 | 0x00000018 |
| FIQ 快速中断 | 0x0000001C |
它的核心作用包括:
- 快速响应:每种异常都有固定入口,CPU 可在一个周期内跳转到处理程序,保证实时性。比如当 UART 接收到数据触发 IRQ 中断时,CPU 会立即跳转到 0x00000018 地址执行中断服务函数。
- 统一入口:为所有异常提供统一的分发点,便于操作系统集中管理和处理异常事件。比如在 Linux 内核中,异常向量表的入口会跳转到统一的异常分发函数,再根据异常类型调用对应的处理程序。
- 上下文保护:异常发生时,硬件自动将 PC 和 CPSR 保存到对应模式的 LR 和 SPSR 中,确保异常处理完成后能正确恢复到原状态。比如在 IRQ 中断发生时,CPU 会将当前 PC 保存到 IRQ 模式的 LR,将 CPSR 保存到 IRQ 模式的 SPSR,处理完成后通过
SUBS PC, LR, #4指令恢复现场并返回。 - 优先级处理:通过向量表的地址顺序和硬件优先级,实现多异常的嵌套处理(如 FIQ 优先级高于 IRQ)。当多个异常同时发生时,CPU 会先处理优先级最高的异常。
六、流水线与内存布局:性能与效率的保障
1. 三级流水线
ARM 内核采用预取 - 译码 - 执行三级流水线设计,让 CPU 可以在执行当前指令的同时,预取和译码下一条指令,显著提升指令执行效率。这种并行处理的思想,是现代处理器提升性能的关键。比如在执行第 1 条指令时,第 2 条指令正在译码,第 3 条指令正在预取,理论上可以达到每个周期执行一条指令的效率。不过,流水线也会带来数据相关和控制相关的问题,比如当指令的执行结果依赖于前一条指令的结果时,会导致流水线停顿,需要通过硬件或软件优化来解决。
2. 内存布局
嵌入式系统的内存布局决定了代码、数据和栈的存储位置,典型的布局从高地址到低地址依次为:
- 内核区:操作系统内核代码和数据,位于高地址区域,受硬件保护,用户程序无法直接访问。
- 栈区:由高地址向低地址增长,存储函数的局部变量和返回地址。每个函数调用都会创建一个栈帧,函数返回时栈帧被销毁。比如在执行
main()函数调用fun(a, b)时,会为fun()函数分配栈帧,存储局部变量和 LR 的值。 - 堆区:由低地址向高地址增长,用于动态内存分配,如
malloc()和free()操作。堆区的管理由操作系统负责,需要注意内存泄漏和碎片问题。 - 全局 / 静态区:存储全局变量和静态变量,程序启动时初始化,程序结束时释放。比如
int a = 100;这样的全局变量就存储在这个区域。 - 代码段:存储可执行的指令,通常是只读的,防止被意外修改。比如
fun(a, b)函数的指令就存储在代码段中。
在 i.MX6ULL 开发板上,内存布局由 U-Boot 和 Linux 内核共同决定。U-Boot 会初始化内存,并将 Linux 内核加载到指定的内存地址(如 0x80800000),然后启动内核。内核启动后,会建立虚拟内存映射,将物理地址转换为虚拟地址,为每个进程提供独立的地址空间。
七、总线架构与外设交互
嵌入式系统的总线架构决定了内核与外设之间的数据传输效率。i.MX6ULL 采用了多总线架构,主要包括:
- AHB(Advanced High-performance Bus):先进高性能总线,用于连接内核、DDR 内存、NOR Flash 等高带宽设备,传输速度快,支持突发传输。
- APB(Advanced Peripheral Bus):先进外设总线,用于连接 GPIO、UART、PWM 等低带宽设备,传输速度相对较慢,但硬件实现简单,功耗低。
- AXI(Advanced eXtensible Interface):在更高级的 ARM 内核中(如 Cortex-A9),会使用 AXI 总线替代 AHB,提供更高的带宽和更灵活的传输模式。
通过这种多总线架构,系统可以根据外设的带宽需求选择合适的总线,平衡性能与功耗。比如在控制 GPIO 引脚时,内核通过 APB 总线访问 GPIO 的外设寄存器,设置引脚的输入输出模式和电平状态;而在访问 DDR 内存时,则通过 AHB 总线进行高速数据传输。