4. 中断系统原理:ARM Cortex-M NVIC中断控制器,中断优先级分组,中断向量表

在蓝牙芯片适配中,中断系统是连接硬件事件与软件处理的桥梁。ARM Cortex-M 系列内核(如 M4、M33 等)是当前主流蓝牙 SoC 的标配,其嵌套向量中断控制器(NVIC)提供了灵活、低延迟的中断管理机制。理解 NVIC 的工作原理、优先级分组策略以及中断向量表的布局,是编写可靠蓝牙驱动的基础。

核心要点:NVIC 支持最多 240 个中断源,每个中断可独立配置使能、挂起和优先级。优先级分组决定了抢占优先级与子优先级的位数分配,直接影响中断嵌套行为。

4.1 NVIC 中断控制器架构

NVIC 是 Cortex-M 内核的一部分,与 CPU 紧耦合,无需外部中断控制器即可处理所有异常和中断。其关键特性包括:

  • 可嵌套中断:高优先级中断可以抢占低优先级中断,支持硬件自动压栈和出栈。
  • 向量化中断:每个中断对应一个固定的中断向量地址,CPU 直接从向量表加载入口地址,无需软件查询。
  • 尾链技术:当两个中断连续发生时,跳过不必要的出栈/入栈操作,降低延迟。
  • 中断屏蔽:通过 PRIMASK、FAULTMASK、BASEPRI 寄存器实现全局或基于优先级的中断屏蔽。
蓝牙适配提示:蓝牙协议栈通常要求中断响应时间在微秒级。NVIC 的硬件尾链和自动压栈特性,使得在 Cortex-M 上实现低功耗蓝牙(BLE)协议栈成为可能。
NVIC 中断处理流程 外设中断源 NVIC 中断控制器 CPU 内核 ISR 优先级分组寄存器 中断使能寄存器 中断挂起寄存器 NVIC 寄存器组 • ISER:中断设置使能 • ICER:中断清除使能 • ISPRI:中断设置优先级 • ICPRI:中断清除挂起 • IABR:中断活动状态

4.2 中断优先级分组

Cortex-M 使用 8 位优先级寄存器(实际有效位数由芯片厂商决定),通过 优先级分组 将优先级分为抢占优先级和子优先级两部分。分组由 SCB->AIRCR 寄存器的 PRIGROUP 字段控制。

分组编号 抢占优先级位数 子优先级位数 抢占优先级等级数 子优先级等级数
0 7 1 128 2
1 6 2 64 4
2 5 3 32 8
3 4 4 16 16
4 3 5 8 32
5 2 6 4 64
6 1 7 2 128
7 0 8 1 256
常见陷阱:蓝牙芯片厂商(如 Nordic、TI、Dialog)通常只使用 3~5 位有效优先级。配置分组时,务必查阅芯片参考手册,避免使用无效位导致优先级配置失效。

优先级比较规则:

  • 先比较抢占优先级:数值越小,优先级越高。
  • 若抢占优先级相同,再比较子优先级:数值越小,优先级越高。
  • 若两者均相同,则比较中断编号:编号越小,优先级越高(硬件固定)。
优先级分组位分配(分组 3:4位抢占 + 4位子优先级) 8位优先级寄存器 抢占优先级 [7:4] 子优先级 [3:0] 抢占优先级决定中断嵌套能力,子优先级决定同抢占优先级下的响应顺序

4.3 中断向量表

中断向量表是存储在固定地址(通常为 Flash 起始地址 0x00000000)的一张函数指针表。每个中断源对应一个表项,CPU 在响应中断时自动从表中加载入口地址。

向量表结构:

偏移地址 异常/中断号 描述
0x00 - 主堆栈指针(MSP)初始值
0x04 1 复位异常(Reset_Handler)
0x08 2 不可屏蔽中断(NMI_Handler)
0x0C 3 硬错误异常(HardFault_Handler)
0x10 4 内存管理异常(MemManage_Handler)
0x14 5 总线错误异常(BusFault_Handler)
0x18 6 用法错误异常(UsageFault_Handler)
... ... ...
0x40 + (n-16)*4 n 外部中断 n(如 UART、BLE 射频中断)
蓝牙芯片适配要点:BLE 协议栈通常需要将中断向量表重定位到 RAM 或特定 Flash 区域,以便运行时动态修改。通过 SCB->VTOR 寄存器设置新的向量表基址即可实现。
ARM Cortex-M 中断向量表布局 向量表基址(VTOR 指向) 0x00 MSP 初始值 栈指针 系统 0x04 Reset_Handler 复位入口 系统 0x08 NMI_Handler 不可屏蔽中断 系统 0x0C HardFault_Handler 硬错误 系统 0x40+ UART_IRQHandler UART 中断 外设

4.4 中断配置实战代码

以下代码展示了在 Cortex-M4 上配置 NVIC 中断优先级分组、使能外部中断并设置优先级的典型流程:

/* 中断优先级分组配置:4位抢占 + 4位子优先级 */
#define NVIC_PRIORITYGROUP_4       ((uint32_t)0x00000003)  /* 分组 3 */

void NVIC_Configuration(void)
{
    /* 1. 设置优先级分组 */
    SCB->AIRCR = NVIC_PRIORITYGROUP_4 | (0x5FA << SCB_AIRCR_VECTKEY_Pos);

    /* 2. 使能 UART 中断(假设中断号为 42) */
    NVIC_EnableIRQ((IRQn_Type)42);

    /* 3. 设置 UART 中断优先级:抢占优先级 2,子优先级 1 */
    /*    优先级值 = (抢占优先级 << 子优先级位数) | 子优先级 */
    /*    此处子优先级位数为 4,所以优先级值 = (2 << 4) | 1 = 33 */
    NVIC_SetPriority((IRQn_Type)42, 33);

    /* 4. 设置 BLE 射频中断优先级更高:抢占优先级 0,子优先级 0 */
    NVIC_SetPriority((IRQn_Type)BLE_IRQn, 0);
}

/* UART 中断服务函数 */
void UART_IRQHandler(void)
{
    /* 检查中断标志 */
    if (USART1->SR & USART_SR_RXNE) {
        uint8_t data = USART1->DR;
        /* 处理接收数据 */
    }
}
关键点:
  • 优先级值越小,优先级越高。抢占优先级 0 为最高。
  • BLE 射频中断通常设置为最高优先级,以确保协议栈时序。
  • 中断服务函数名必须与启动文件中的向量表名称一致,否则链接器无法正确绑定。

4.5 中断延迟与蓝牙实时性

蓝牙协议栈对中断延迟有严格要求,尤其是 BLE 连接事件和广播事件。NVIC 的硬件特性直接影响延迟指标:

延迟类型 典型值(Cortex-M4 @ 64MHz) 说明
中断响应延迟 12~16 个时钟周期 从中断请求到执行第一条 ISR 指令
中断抢占延迟 6~10 个时钟周期 高优先级中断抢占低优先级时的额外开销
尾链切换延迟 6~8 个时钟周期 连续中断之间的切换,无需完整压栈
中断退出延迟 10~14 个时钟周期 从 ISR 返回主程序
蓝牙适配避坑:如果蓝牙射频中断被低优先级中断长时间阻塞,可能导致连接超时或丢包。建议将射频中断优先级设为最高,并尽量减少 ISR 内的执行时间,将耗时操作放到任务级处理。
中断延迟时序图 t0 t1 t2 t3 t4 IRQ 响应延迟 硬件自动压栈 ISR 执行 出栈返回 总中断延迟 = 响应延迟 + 压栈时间,典型值 12~16 个时钟周期

4.6 中断嵌套与优先级设计原则

在蓝牙芯片适配中,合理设计中断优先级是系统稳定性的关键。以下原则可供参考:

  1. 射频中断最高:BLE 射频中断(如 RADIO_IRQ)应设置为最高优先级,确保协议栈时序。
  2. 定时器中断次高:协议栈使用的定时器中断(如 RTC、TIMER)优先级次之,用于链路层调度。
  3. 外设中断中等:UART、SPI、I2C 等外设中断设置为中等优先级。
  4. 非实时中断最低:GPIO 按键、调试接口等非实时中断设置为最低优先级。
  5. 避免同优先级嵌套:同优先级中断不会互相抢占,可能导致响应延迟不可控。
实战建议:在蓝牙协议栈初始化前,调用 NVIC_PriorityGroupConfig() 设置分组,之后不要再修改。中断优先级一旦配置,在整个系统运行期间保持不变。