1. ARM Cortex-M4 架构概述
各位同学,咱们开始第一课。Cortex-M4 这颗内核,我这些年打交道最多的就是它。说它是嵌入式开发的「万金油」一点不过分——性能够用、功耗可控、生态成熟。今天咱们就把它的底牌翻一翻。
1.1 处理器内核:到底强在哪?
Cortex-M4 是 ARMv7-M 架构的典型代表。它最大的卖点,就是那颗 单精度浮点单元(FPU)。我在做电机控制项目时,PID 计算里大量用到浮点运算,没有 FPU 的话,光算一个周期就得卡半天。
核心特性一览:
- 32 位 RISC 处理器,支持 Thumb/Thumb-2 指令集
- 三级流水线(取指、译码、执行)
- 单周期乘法和硬件除法
- 可嵌套中断控制器(NVIC),最多支持 240 个中断
- 6 个系统异常 + 最多 240 个外部中断
- 位带操作(Bit-Banding),方便 GPIO 等外设的位级控制
你可能会问:「三级流水线会不会有分支预测问题?」嗯,确实有。但 Cortex-M4 用了静态分支预测——默认预测分支不跳转。我踩过这个坑:一个循环里频繁跳转,流水线被刷了好几次,性能直接掉了 20%。后来改成条件执行指令,才把效率拉回来。
1.2 存储器映射:一张表看懂全局
Cortex-M4 的 4GB 地址空间是固定的。不管你用哪家芯片,这个布局基本不变。我个人习惯把这张表贴在工位上,写驱动时随时瞄一眼。
| 地址范围 | 区域名称 | 用途 |
|---|---|---|
| 0x00000000 - 0x1FFFFFFF | Code 区 | 程序代码、向量表、启动代码 |
| 0x20000000 - 0x3FFFFFFF | SRAM 区 | 堆栈、全局变量、位带别名区 |
| 0x40000000 - 0x5FFFFFFF | 外设区 | GPIO、UART、SPI、定时器等寄存器 |
| 0x60000000 - 0x9FFFFFFF | 外部 RAM 区 | 扩展内存(SDRAM、NOR Flash) |
| 0xE0000000 - 0xE00FFFFF | 系统控制区 | SCB、NVIC、MPU、FPU 等系统寄存器 |
避坑指南:我曾经在调试时,把一个外设寄存器地址写到了 SRAM 区。结果写进去的值莫名其妙被改掉,查了两天才发现是地址映射搞错了。记住:外设寄存器只能在 0x40000000 开始的区域访问。
1.3 系统控制块(SCB):内核的「控制面板」
SCB 位于系统控制区,地址从 0xE000E000 开始。它管的事很杂:系统复位、异常优先级、睡眠模式、MPU 配置……说白了,它就是内核的「总控台」。
常用的几个寄存器:
- CPUID(0xE000ED00):只读,告诉你芯片是 M0、M3 还是 M4。我经常用它做运行时版本检测。
- ICSR(0xE000ED04):中断控制状态寄存器。可以软件触发 PendSV 或 SysTick 中断。
- VTOR(0xE000ED08):向量表偏移寄存器。做 Bootloader 时必改,不然中断向量会跑飞。
- SCR(0xE000ED10):系统控制寄存器。控制睡眠模式和深度睡眠。
- SHPR1-SHPR3(0xE000ED18-0xE000ED20):系统异常优先级寄存器。可以设置 PendSV、SysTick、SVC 的优先级。
注意:SCB 寄存器只能用 字访问(32 位)。半字或字节访问会导致 HardFault。我见过新手用 *(uint8_t*) 去读 CPUID,结果直接卡死。
1.4 嵌套向量中断控制器(NVIC):中断管理的核心
NVIC 是 Cortex-M4 中断系统的灵魂。它支持最多 240 个外部中断,每个中断都可以独立设置优先级(8 位优先级寄存器,但实际只用高 4 位)。
NVIC 的关键寄存器组:
| 寄存器组 | 地址偏移 | 功能 |
|---|---|---|
| ISER[0..7] | 0x100 - 0x11C | 中断使能设置寄存器 |
| ICER[0..7] | 0x180 - 0x19C | 中断清除寄存器 |
| ISPR[0..7] | 0x200 - 0x21C | 中断挂起设置寄存器 |
| ICPR[0..7] | 0x280 - 0x29C | 中断挂起清除寄存器 |
| IABR[0..7] | 0x300 - 0x31C | 中断活动状态寄存器(只读) |
| IPR[0..59] | 0x400 - 0x4EC | 中断优先级寄存器(每个中断 8 位) |
举个例子,使能 UART 中断:
// 假设 UART 中断号是 42
NVIC->ISER[1] = (1 << (42 - 32)); // ISER[1] 对应中断号 32-63
NVIC->IPR[10] = (NVIC->IPR[10] & ~(0xFF << 8)) | (0x80 << 8); // 设置优先级为 0x80
我的经验:中断优先级分组(Priority Grouping)是个容易搞混的点。Cortex-M4 支持 5 种分组模式,通过 SCB->AIRCR 寄存器配置。我一般用分组 3(4 位抢占优先级,0 位子优先级),简单粗暴,不容易出问题。
1.5 异常与中断的优先级模型
Cortex-M4 的异常系统分两层:
- 系统异常:复位、NMI、HardFault、MemManage、BusFault、UsageFault、SVCall、PendSV、SysTick。共 15 个(编号 1-15)。
- 外部中断:编号 16 及以上,最多到 255。
优先级数值越小,优先级越高。复位和 NMI 是固定最高优先级,不可更改。
关键点:PendSV 和 SysTick 的优先级通常设到最低。这样在 RTOS 里,上下文切换不会打断真正紧急的中断服务。我见过有人把 PendSV 优先级设得比定时器中断还高,结果系统响应变得一塌糊涂。
1.6 知识结构图:Cortex-M4 架构全景
下面这张图把今天讲的核心模块串起来,方便你建立整体认知。
1.7 本章小结
今天咱们把 Cortex-M4 的骨架搭起来了:处理器内核、存储器映射、SCB、NVIC。这些是后续所有驱动开发和 RTOS 集成的基础。你写驱动时,脑子里要时刻清楚:这个寄存器在哪个地址空间?这个中断归 NVIC 管还是 SCB 管?