【STM32】NVIC_Init函数内部的优先级计算和写入过程

这篇文章解析STM32 中 NVIC_Init() 函数内部关于中断优先级计算与写入 IP[x] 寄存器的过程。

NVIC_Init 函数内部优先级计算与写入过程详解(STM32F10x)

函数原型:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

结构体如下:

typedef struct
{
  uint8_t NVIC_IRQChannel;                    // 中断编号
  uint8_t NVIC_IRQChannelPreemptionPriority;  // 抢占优先级
  uint8_t NVIC_IRQChannelSubPriority;         // 响应优先级
  FunctionalState NVIC_IRQChannelCmd;         // ENABLE / DISABLE
} NVIC_InitTypeDef;

优先级寄存器结构 IP[240]

__IO uint8_t IP[240];  // 每个 IP[x] 对应一个中断

// 每个中断对应一个 8 位优先级寄存器
// 实际只有 `高 4 位有效`
// 低 4 位 `保留未使用`

优先级分组决定位宽分配

NVIC_PriorityGroupConfig() 设置 SCB->AIRCR.PRIGROUP[10:8] 位,决定:

Group 抢占位数 响应位数 可用总位数:4
0 0 4
1 1 3
2 2 2 ✅ 推荐
3 3 1
4 4 0

源码分析:优先级计算部分

这里是 STM32F10x 标准库 misc.cNVIC_Init() 函数中关于优先级计算的核心代码:

tmppriority = (NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << subprioritybits);
tmppriority |=  NVIC_InitStruct->NVIC_IRQChannelSubPriority;

tmppriority = tmppriority << 4;  // 写入 IP 寄存器时须左移4位(高4位有效)
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;

优先级计算流程:(假设当前分组为 Group 2(抢占2位 + 响应2位))

示例:

NVIC_IRQChannel = 37; // USART1
PreemptionPriority = 1; // 抢占优先级
SubPriority = 2;        // 响应优先级

步骤1️⃣:获取响应位宽

subprioritybits = (uint8_t)(0x04 - NVIC_PriorityGroup); // 4 - 2 = 2

步骤2️⃣:合并优先级值

tmppriority = (1 << 2) | 2 = 4 | 2 = 6

步骤3️⃣:左移4位(只使用高4位)
因为 ARM Cortex-M 的 NVIC 只使用每个 IP[x] 的高 4 位作为有效优先级位(低 4 位在早期 Cortex-M3 芯片中无效,保留)

tmppriority = 6 << 4 = 0x60

步骤4️⃣:写入 IP[37]

NVIC->IP[37] = 0x60;

即:IP[37] = 0110 0000
其中:

  • 0110(高4位)表示综合优先级(抢占+响应)
  • 0000(低4位)保留未用

优先级比较机制
最终写入的高 4 位值越小,优先级越高。
优先级比较时:
	先比较抢占优先级(高位)
	抢占相同时,再比较响应优先级(低位)

总结:优先级写入流程图

用户设置:
    抢占优先级 = P
    响应优先级 = S
    分组 = Group_n(n = 0~4)

步骤流程:
1. sub_bits = 4 - Group_n
2. tmp = (P << sub_bits) | S
3. tmp <<= 4
4. IP[IRQn] = tmp

STM32 中 NVIC_Init() 函数通过将抢占优先级与响应优先级合并为一个 4 位值,左移 4 位写入 IP[x] 高位,从而完成中断优先级的配置。其行为受到 PRIGROUP 分组控制,决定了优先级位的分配方式。

以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!

你可能感兴趣的:(【STM32】NVIC_Init函数内部的优先级计算和写入过程)