2. NVIC 简介:定义、位置与核心功能
在 Cortex-M 系列 MCU 的中断体系中,NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器) 是管理所有中断请求的核心硬件模块。它直接决定了中断的响应顺序、嵌套深度以及优先级仲裁方式。理解 NVIC 的结构与功能,是进行中断配置的前提。
2.1 NVIC 的定义
NVIC 是 ARM Cortex-M 处理器内核中集成的中断控制器,负责处理来自片内外设和外部引脚的所有异常(Exception)与中断(Interrupt)请求。与传统的 8 位或 16 位 MCU 的中断控制器不同,NVIC 具备以下关键特性:
- 可嵌套性:高优先级中断可以抢占低优先级中断的服务例程,实现多级中断嵌套。
- 向量化:每个中断源对应一个固定的中断向量地址,CPU 响应中断时直接从向量表中加载服务函数入口,无需软件查询中断源。
- 可编程优先级:支持多达 8~256 级(取决于具体 Cortex-M 内核版本)的可编程中断优先级。
- 尾链(Tail-Chaining):当多个中断同时等待处理时,NVIC 自动跳过冗余的入栈/出栈操作,直接执行下一个中断服务函数,降低延迟。
关键概念: 在 Cortex-M 中,“异常”包括系统异常(如 HardFault、SysTick)和外部中断。NVIC 统一管理所有异常,但通常我们所说的“中断配置”特指外部中断(IRQ)。
2.2 NVIC 在 Cortex-M 内核中的位置
NVIC 位于 Cortex-M 处理器核心内部,紧邻 CPU 和系统总线。下图展示了 NVIC 在典型 Cortex-M3/M4 内核架构中的位置与数据流关系:
架构要点: NVIC 不通过总线访问外设寄存器,而是直接通过专用中断线接收请求。这种紧耦合设计使得中断响应延迟极低(通常为 12 个 CPU 周期)。
2.3 NVIC 的主要功能
NVIC 的功能可以归纳为以下五个核心模块,每个模块对应一组可编程的寄存器:
| 功能模块 | 描述 | 关键寄存器 |
|---|---|---|
| 中断使能/除能 | 独立控制每个中断源的使能状态,除能的中断不会被 NVIC 响应。 | ISER / ICER |
| 中断挂起/清除 | 软件可以手动挂起一个中断(用于测试或软件触发),或清除挂起状态。 | ISPR / ICPR |
| 中断优先级配置 | 为每个中断分配抢占优先级和子优先级,支持优先级分组。 | IPR0~IPR59 |
| 中断状态查询 | 读取当前正在服务的中断号、挂起状态、激活状态。 | IABR / 挂起状态寄存器 |
| 系统异常控制 | 管理 SysTick、PendSV、SVC 等系统异常的优先级和触发方式。 | SHPR1~SHPR3 |
2.4 NVIC 的优先级管理机制
NVIC 使用 优先级分组(Priority Grouping) 机制将优先级寄存器中的位划分为抢占优先级和子优先级两部分:
- 抢占优先级(Preempt Priority):决定中断是否可以打断正在执行的低优先级中断。数值越小,优先级越高。
- 子优先级(Subpriority):当两个中断的抢占优先级相同时,子优先级决定谁先被响应。子优先级不参与嵌套抢占。
优先级分组由 SCB->AIRCR 寄存器的 PRIGROUP 位域控制。以 Cortex-M3/M4 为例,支持 5 种分组方式:
| 分组编号 | 抢占优先级位数 | 子优先级位数 | 抢占优先级等级数 | 子优先级等级数 |
|---|---|---|---|---|
| 0 | 0 | 4 | 1 | 16 |
| 1 | 1 | 3 | 2 | 8 |
| 2 | 2 | 2 | 4 | 4 |
| 3 | 3 | 1 | 8 | 2 |
| 4 | 4 | 0 | 16 | 1 |
常见误区: 优先级数值越小,优先级越高。例如,抢占优先级为 0 的中断可以抢占抢占优先级为 1 的中断。许多初学者容易将数值大小与优先级高低混淆。
2.5 NVIC 的嵌套与尾链行为
NVIC 在中断处理过程中自动管理以下三种关键场景:
- 嵌套(Nesting):当高优先级中断请求到达时,NVIC 暂停当前 ISR,自动将 CPU 寄存器入栈,然后执行高优先级 ISR。高优先级 ISR 返回后,自动恢复低优先级 ISR 的执行。
- 尾链(Tail-Chaining):当低优先级 ISR 即将返回时,如果有一个高优先级中断正在等待,NVIC 不会执行出栈/入栈操作,而是直接执行高优先级 ISR,节省 12~16 个 CPU 周期。
- 迟到(Late-Arriving):在低优先级 ISR 的入栈阶段,如果高优先级中断到达,NVIC 会放弃低优先级 ISR 的入栈,直接处理高优先级中断,进一步降低延迟。
实战提示: 尾链机制是 NVIC 提升实时性能的关键。在中断频繁的系统中(如通信协议栈),合理利用尾链可以显著降低 CPU 开销。但尾链是硬件自动行为,开发者无需手动配置,只需确保中断优先级设置正确即可。
2.6 NVIC 与系统控制块(SCB)的关系
NVIC 与 系统控制块(SCB,System Control Block) 紧密协作。SCB 负责管理系统异常(如 HardFault、MemManage)的优先级和配置,而 NVIC 管理外部中断。两者共享部分寄存器空间,但功能分工明确:
- SCB:位于地址 0xE000_ED00,控制系统异常优先级(SHPR1~SHPR3)、系统异常使能、以及系统复位。
- NVIC:位于地址 0xE000_E100,控制外部中断的使能、挂起、优先级和激活状态。
在编程时,通常使用 CMSIS 核心层提供的 API 来操作 NVIC,无需直接访问寄存器地址:
// 使能中断 IRQn
NVIC_EnableIRQ(USART1_IRQn);
// 设置中断优先级(抢占优先级 1,子优先级 0)
NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(0, 1, 0));
// 清除挂起位
NVIC_ClearPendingIRQ(USART1_IRQn);
// 读取当前激活的中断号
uint32_t active_irq = NVIC_GetActive(USART1_IRQn);