Cortex-M 内核结构 
Author:余生
我们将从一个系统级性能与实时响应能力的视角深入剖析 ARM Cortex-M 内核结构与工作模式。这个角度不仅与前文所讲的 USART、I²C、SPI、ADC、DAC 等外设通信机制密切相关,更与 中断系统(NVIC)、时钟系统、总线架构(AHB/APB) 紧密耦合,是理解 32 位微控制器 “为何能高效、实时地处理外设事件” 的核心所在。
我们将以 “中断驱动的实时响应机制” 为主线,揭示 Cortex-M 如何通过其独特的内核架构(寄存器组、堆栈管理、异常模型、NVIC、总线接口)实现从 “外设产生事件” 到 “CPU 执行中断服务程序(ISR)” 这一过程的极致低延迟、高确定性与高效率。我们将层层递进,从硬件结构到软件行为,从指令周期到系统调度,力求呈现一幅完整、深入、可实践的技术图景。
一:问题的起点 —— 外设事件如何被 CPU 感知? 
在前文我们详细讲解了:
- USART 接收到一个字节,产生 RXNE(接收数据寄存器非空)中断。
- ADC 转换完成,EOC(End of Conversion)标志置位,可触发中断。
- I²C 检测到总线错误或地址匹配,发出中断请求。
- 定时器溢出,触发更新中断,可用于 PWM 或周期性任务。
这些外设事件是异步发生的,CPU 不能一直轮询(Polling),否则效率极低。因此,现代微控制器采用 中断机制(Interrupt) 来实现 “事件驱动” 的高效运行。
核心问题:当一个外设(如 USART)发出中断请求时,Cortex-M 内核是如何在最短时间内响应,并跳转到对应的中断服务程序(ISR)执行的?
答案就藏在 Cortex-M 的异常模型、NVIC、堆栈机制和流水线设计中。
二: Cortex-M 的异常模型 —— 中断即 “异常” 
Cortex-M 将所有中断和异常统一管理,统称为 “异常(Exception)”。
2.1 异常类型 
| 类型 | 编号 | 来源 | 是否可屏蔽 | 
|---|---|---|---|
| Reset | -3 | 芯片复位 | 否 | 
| NMI (Non-Maskable Interrupt) | -2 | 不可屏蔽中断 | 否 | 
| HardFault | -1 | 内核错误(如非法指令、总线错误) | 否 | 
| 可配置异常 | |||
| MemManage | 4 | 存储器管理错误 | 是 | 
| BusFault | 5 | 总线访问错误 | 是 | 
| UsageFault | 6 | 使用错误(如未对齐访问) | 是 | 
| SVCall | 11 | 系统服务调用(用于操作系统) | 是 | 
| Debug Monitor | 12 | 调试监控 | 是 | 
| PendSV | 14 | 可挂起的系统调用(OS 上下文切换) | 是 | 
| SysTick | 15 | 系统滴答定时器 | 是 | 
| 外部中断(IRQ) | 16+ | 外设(USART, ADC, TIM, EXTI 等) | 是 | 
关键点:
- 所有外设中断都是 IRQ(Interrupt Request),编号从 16 开始。
- Cortex-M 使用 向量表(Vector Table) 存储每个异常的入口地址。
- 响应中断 = 响应一个特定编号的异常。
三:NVIC —— 嵌套向量中断控制器 
NVIC(Nested Vectored Interrupt Controller)是 Cortex-M 内核的一部分,负责所有中断的优先级管理、嵌套、挂起与响应。
3.1 中断优先级 
Cortex-M 支持 可编程优先级,每个 IRQ 都可以设置一个 8 位优先级值(实际使用位数由芯片厂商决定,如 STM32 通常为 4 位,即 16 级)。
- 数值越小,优先级越高(0 最高)。
- 支持 抢占(Preemption) 和 子优先级(Subpriority): - 高优先级中断可以抢占正在执行的低优先级 ISR。
- 相同抢占优先级的中断按子优先级或中断号顺序执行(不可抢占)。
 
3.2 NVIC 寄存器(STM32 示例) 
| 寄存器 | 作用 | 
|---|---|
| NVIC_ISER[0] | 中断使能设置寄存器(Set Enable) | 
| NVIC_ICER[0] | 中断使能清除寄存器(Clear Enable) | 
| NVIC_ISPR[0] | 中断挂起设置寄存器(Set Pending) | 
| NVIC_ICPR[0] | 中断挂起清除寄存器(Clear Pending) | 
| NVIC_IPR[0~239] | 中断优先级寄存器(每个占 8 位,通常只用高 4 位) | 
配置 USART1 中断优先级(底层) 
// 使能 USART1 中断
NVIC->ISER[0] |= (1 << (USART1_IRQn & 0x1F));
// 设置优先级(抢占=1, 子优先级=0)
NVIC->IPR[USART1_IRQn] = (1 << 4); // 高 4 位为抢占优先级2
3
4
四:中断响应过程 —— 从硬件到软件的飞跃 
这是 Cortex-M 实时性能的核心体现。我们以 USART 接收中断为例,完整走一遍从 “RXNE 置位” 到 “执行 ISR” 的全过程。
步骤 1:外设产生中断请求 
- USART 接收到一个字节,硬件将 SR寄存器的RXNE位置 1。
- 如果 CR1寄存器的RXNEIE位使能,则 USART 向 NVIC 发出中断请求。
步骤 2:NVIC 仲裁与响应 
- NVIC 检查当前中断优先级是否高于正在执行的任务(包括其他 ISR)。
- 如果可以响应,NVIC 通知内核进入 “异常进入” 流程。
步骤 3:异常进入(Exception Entry)—— 硬件自动压栈 
这是 Cortex-M 的革命性设计:中断上下文保存由硬件自动完成,无需软件干预,极大减少延迟。
内核自动将以下 8 个寄存器压入当前使用的堆栈(MSP 或 PSP):
SP → | xPSR  |  ← 程序状态寄存器(含 N,Z,C,V,IPEND,THUMB 等)
     | PC    |  ← 返回地址(下一条将要执行的指令)
     | LR    |  ← 链接寄存器(异常返回地址)
     | R12   |
     | R3    |
     | R2    |
     | R1    |
     | R0    |  ← 通用寄存器2
3
4
5
6
7
8
关键点:
- 仅需 6 个时钟周期(Cortex-M3/M4),即可完成 8 个寄存器的压栈。
- 这是 Cortex-M 相比传统 MCU(如 8051、AVR)在中断响应速度上的数量级优势。
步骤 4:切换堆栈与模式 
Cortex-M 支持两种操作模式和两个堆栈指针:
| 模式 | 堆栈指针 | 用途 | 
|---|---|---|
| 线程模式(Thread Mode) | PSP(Process Stack Pointer) | 用户任务(如 main 函数) | 
| 处理模式(Handler Mode) | MSP(Main Stack Pointer) | 异常处理(ISR) | 
- 在异常进入时,内核自动切换到 Handler Mode,使用 MSP。
- 这保证了 ISR 使用独立的堆栈空间,提高可靠性。
步骤 5:获取向量地址,跳转 ISR 
- 内核根据异常编号(如 USART1_IRQn = 37),查 向量表(Vector Table)。
- 向量表位于内存起始地址(通常为 0x0000_0000 或可重定位到 0x0800_0000)。
- 读取对应条目的值(即 ISR 函数地址),跳转执行。
// 向量表示例(startup_stm32f10x_hd.s)
Vectors:
    DCD     Reset_Handler             ; 0x0000_0000
    DCD     NMI_Handler               ; 0x0000_0004
    DCD     HardFault_Handler         ; 0x0000_0008
    ...
    DCD     USART1_IRQHandler         ; 0x0000_0074 (37 * 4)2
3
4
5
6
7
步骤 6:执行中断服务程序(ISR) 
void USART1_IRQHandler(void) {
    if (USART1->SR & USART_SR_RXNE) {
        uint8_t data = USART1->DR; // 读取数据
        // 处理数据...
    }
}2
3
4
5
6
注意:ISR 应尽可能短小精悍,避免复杂运算或阻塞操作。
步骤 7:异常返回(Exception Return)—— 硬件自动出栈 
- ISR 执行 BX LR或POP {PC}指令。
- 内核检测到 LR 的低 4 位为特定值(如 0xFFFF_FFF9),触发 “异常返回”。
- 硬件自动将之前压栈的 8 个寄存器弹出,恢复现场。
- 切换回 Thread Mode(如果之前是线程模式)。
- 继续执行被中断的代码。
整个中断响应 + 返回过程,硬件自动完成上下文保存与恢复,软件只需写 ISR 逻辑。
五:总线架构与中断延迟 —— AHB 与 APB 的角色 
中断响应速度不仅取决于内核,还受 总线架构 影响。
5.1 典型总线结构(STM32F103) 
         +------------------+
         |     Cortex-M3    |
         |     内核         |
         +--------+---------+
                  |
                  | ICode Bus / DCode Bus
                  |
         +--------v---------+
         |      指令/数据    |
         |     AHB 总线     |
         +--------+---------+
                  |
        +---------+---------+-----------------+
        |         |         |                 |
+-------v--+ +----v----+ +--v-------+ +-------v-------+
|  Flash   | |  SRAM   | |  APB2    | |     APB1      |
| (ICode)  | | (DCode) | | (高速外设)| |   (低速外设)   |
|          | |         | | TIM1,ADC | | USART,I2C,TIMx|
+----------+ +---------+ +----------+ +---------------+2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
5.2 中断延迟的关键路径 
- 外设到 NVIC:通过 APB 总线,延迟取决于 APB 时钟。
- NVIC 到内核:极短,片内连接。
- 向量表访问:通过 ICode Bus 从 Flash 读取 ISR 地址。 - 如果 Flash 无缓存,可能需要等待(STM32F1 需 6 个等待周期 @72MHz)。
- 建议:将向量表重映射到 SRAM(0x2000_0000),实现 0 等待访问。
 
- ISR 执行:代码在 Flash 中执行,可能受 Flash 等待周期影响。
优化建议:
- 使能 Flash 预取缓冲(Prefetch Buffer)和 ART Accelerator。
- 将关键 ISR 放入 SRAM 执行(通过
attribute((section(".sramfunc"))))。
六:工作模式与特权级别 
Cortex-M 支持两种操作模式和两种特权级别:
| 模式 | 特权级别 | 访问权限 | 
|---|---|---|
| 线程模式(Thread Mode) | 非特权(User)或 特权(Privileged) | 可配置 | 
| 处理模式(Handler Mode) | 特权(Privileged) | 固定 | 
- 处理模式(ISR 中)总是特权级,可访问所有系统寄存器(如 NVIC、SCB)。
- 线程模式 可通过 CONTROL寄存器切换:- CONTROL[0] = 0:使用 MSP,特权级。
- CONTROL[0] = 1:使用 PSP,非特权级。
 
安全性:操作系统(如 FreeRTOS)利用此机制实现任务隔离,用户任务运行在非特权级,防止非法访问系统资源。
七:SysTick —— 系统滴答定时器 
Cortex-M 内核内置 SysTick 定时器,是操作系统节拍(Tick)的基础。
工作原理 
- 24 位递减计数器,时钟可选 HCLK 或 HCLK/8。
- 计数到 0 时: - 自动重载(LOAD 值)。
- 置位 COUNTFLAG。
- 触发 SysTick 异常(IRQ #15)。
 
配置 SysTick(1ms 节拍,HCLK=72MHz) 
void SysTick_Init(void) {
    SysTick->LOAD = 72000 - 1;        // 72MHz / 72000 = 1000Hz = 1ms
    SysTick->VAL  = 0;                 // 清空当前值
    SysTick->CTRL = 
        SysTick_CTRL_CLKSOURCE_Msk |  // 时钟源 = HCLK
        SysTick_CTRL_TICKINT_Msk   |  // 使能中断
        SysTick_CTRL_ENABLE_Msk;      // 启动
}
// SysTick 异常服务程序
void SysTick_Handler(void) {
    // 操作系统增量节拍
    // osSystickHandler();
}2
3
4
5
6
7
8
9
10
11
12
13
14
结语:Cortex-M 实时性能的体系化设计 
ARM Cortex-M 内核之所以能在嵌入式领域取得巨大成功,其根本原因在于它通过一系列软硬件协同设计,实现了高性能、低延迟、高可靠性的实时响应能力:
- 统一异常模型:将中断与异常统一管理,简化设计。
- NVIC 优先级管理:支持抢占与嵌套,满足复杂实时需求。
- 硬件自动压栈:6 个周期完成上下文保存,响应速度极快。
- 向量表跳转:直接跳转 ISR,无软件调度开销。
- 双堆栈指针(MSP/PSP):隔离任务与中断,提高安全性。
- 内置 SysTick:为操作系统提供标准节拍源。
这些特性与前文所述的 USART、I²C、SPI、ADC、DAC 等外设完美配合,使得开发者可以轻松实现 “外设中断 → CPU 响应 → 数据处理 → 结果输出” 的高效闭环,构建出响应迅速、稳定可靠的嵌入式系统。
理解 Cortex-M 的这一底层机制,不仅是掌握其工作模式的关键,更是优化系统性能、诊断中断延迟、设计实时操作系统(RTOS)的基石。