在裸机开发(非 RTOS)时,大多数 STM32 外设的中断优先级通常不需要手动配置,原因如下:
✅ 裸机开发中默认中断优先级行为
特点 | 说明 |
---|---|
默认中断优先级为 0 | 如果你不设置,STM32 HAL 默认设置所有外设中断为 0 (最高优先级) |
没有中断抢占冲突 | 因为没有 RTOS 调度器,也不需要区分 ISR 和任务的优先级 |
ISR 不调用复杂调度逻辑 | 不存在优先级违反 FreeRTOS API 限制的问题 |
常见 HAL 示例也是默认优先级 | STM32CubeMX 生成代码通常直接 SetPriority(0,0) |
🛠 举个例子:裸机中 USART 初始化
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
甚至你在裸机中 可以完全不调用 HAL_NVIC_SetPriority()
,只调用 EnableIRQ()
也能正常运行,因为:
- 启动文件中(CMSIS)中断默认优先级为
0
- 没有任务调度抢占的风险
🚨 但在使用 FreeRTOS 时必须配置
因为:
- FreeRTOS 内核本身运行在中断上下文中
- ISR 优先级太高会 抢占调度器,而调度器不能被中断
- 使用了 FreeRTOS API 的 ISR 优先级必须 ≥
configMAX_SYSCALL_INTERRUPT_PRIORITY
(默认5
)
✅ 总结:裸机 vs RTOS 中断优先级对比
项目 | 裸机开发 | FreeRTOS 下 |
---|---|---|
是否必须配置中断优先级 | ❌ 不需要 | ✅ 必须配置 |
默认优先级 | 0 | 通常不够安全 |
可否在 ISR 中调用复杂逻辑 | ✅ 可以(不推荐) | ❌ 需要优先级保护 |
是否存在调度器限制 | ❌ 无 | ✅ 有严格限制 |
所以:
🟩 裸机时你基本可以不管中断优先级,一切默认值也能跑
🟥 但用上 RTOS 后,中断优先级配置就变成“必须做的事情”
要在 STM32(特别是使用 STM32 HAL 库或 STM32duino)中正确配置 FreeRTOS 的中断优先级宏,你需要理解两部分:
✅ 正确设置 FreeRTOS 与 STM32 的中断优先级宏
🔧 1. 关键宏定义
这些宏应该在 FreeRTOSConfig.h
中配置,主要是以下几个:
#define configPRIO_BITS __NVIC_PRIO_BITS // STM32 定义的中断优先级位数
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
📌 解释各个宏:
宏名 | 含义 | 示例值(假设 4 bit) |
---|---|---|
configPRIO_BITS | NVIC支持的优先级位数(STM32一般为4) | 4 |
configLIBRARY_LOWEST_INTERRUPT_PRIORITY | HAL库中最低优先级(数值大,优先级低) | 15 |
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY | 允许使用 FreeRTOS API 的中断最大优先级(数值小,优先级高) | 5 |
configKERNEL_INTERRUPT_PRIORITY | FreeRTOS kernel 使用的实际中断优先级值 | 15 << (8 - 4) = 240 |
configMAX_SYSCALL_INTERRUPT_PRIORITY | 使用 FreeRTOS API 的中断最大优先级值 | 5 << (8 - 4) = 80 |
⚠️ 必须遵守的规则
- 所有 调用 FreeRTOS API 的中断,它们的优先级必须设置为 等于或低于
configMAX_SYSCALL_INTERRUPT_PRIORITY
(也就是数值大于或等于)。 - Kernel 的中断优先级设置为最低(数值最大),防止抢占其他重要中断。
✅ STM32 示例:如何在 FreeRTOSConfig.h
正确配置
假设你用的是 STM32F4(它是 4-bit 优先级):
#define configPRIO_BITS __NVIC_PRIO_BITS#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
✅ STM32 中断优先级设置对应修改(重要!)
你在使用 HAL 驱动时,还要确保中断优先级设置正确,例如:
HAL_NVIC_SetPriority(USART1_IRQn, 6, 0); // 优先级 6 > 5,允许使用 FreeRTOS API
如果设置为 4 或更高(即数值更小,优先级更高):
HAL_NVIC_SetPriority(USART1_IRQn, 4, 0); // ❌ 错误!优先级太高,不能使用 FreeRTOS API
✅ 总结
要做的事 | 是否必须 |
---|---|
在 FreeRTOSConfig.h 中设置中断优先级宏 | ✅ 必须 |
避免高优先级中断使用 FreeRTOS API(如 xQueueSendFromISR ) | ✅ 必须 |
查看芯片的 __NVIC_PRIO_BITS 定义 | ✅ 建议 |
使用 HAL 配置中断时遵守优先级规则 | ✅ 必须 |
STM32 外设默认的 中断优先级,如果你不手动设置 NVIC
优先级,会根据芯片启动文件(CMSIS 启动代码)和 HAL 库行为,遵循如下逻辑:
✅ 默认 NVIC 中断优先级总结
情况 | 默认优先级 |
---|---|
手动调用 HAL_NVIC_SetPriority() | 你设置的值 |
未调用 HAL_NVIC_SetPriority() (也没配置) | 默认为 0(即最高优先级) |
✅ 所以:如果你不设置,STM32 中断优先级就是 0(也就是“优先级最高”)
📍 示例:STM32 USB 默认优先级(未手动设置时)
例如,在 STM32F4 的 HAL_PCD_MspInit()
中:
HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
⚠️ 所以默认优先级是
(preempt priority = 0, subpriority = 0)
→ 等效为 FreeRTOS 中最高优先级
🚨 问题:和 FreeRTOS 冲突
FreeRTOS 要求调用其 API 的 ISR(中断服务程序)必须使用较低优先级(优先级值 ≥ configMAX_SYSCALL_INTERRUPT_PRIORITY
,通常是 5
)。
而默认优先级是 0
,会违反这个规则,会导致:
xQueueSendFromISR
、xTaskNotifyFromISR
等出错- 系统断言失败(
configASSERT
) - 出现
HardFault
或中断嵌套异常
✅ 如何查看某个外设当前中断优先级?
你可以在调试器或代码中读取:
uint32_t pri = NVIC_GetPriority(OTG_FS_IRQn);
printf("USB 中断优先级: %lu\n", pri);
✅ 建议你总是手动设置中断优先级
不要依赖默认值!
例如:
HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0); // 比 FreeRTOS MAX_SYSCALL 中断优先级(5)低,合法使用 FreeRTOS API
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
🔚 总结
问题 | 默认行为 |
---|---|
STM32 外设中断默认优先级是多少? | 0 (最高) |
会影响 FreeRTOS 使用吗? | 会。若你使用 FreeRTOS API,默认 0 会导致断言失败 |
应该设置吗? | ✅ 必须设置,尤其是在 ISR 中用到了 FreeRTOS API |
好的!以下是 STM32 常见外设的 推荐 NVIC 中断优先级设置清单(在使用 FreeRTOS 的情况下,特别是涉及 xTaskNotifyFromISR
、xQueueSendFromISR
等 API 的时候)。
📌 优先级规则前提(以 4 个优先级位为例)
优先级数值 | 优先级级别 | 说明 |
---|---|---|
0 | 最高优先级 | ❌ 不允许调用 FreeRTOS API |
1 ~ 4 | 高优先级 | ❌ 不建议使用 FreeRTOS API |
5 ~ 15 | 合法范围 | ✅ 可使用 FreeRTOS API(建议 5~10) |
✅ 所有 使用 FreeRTOS API 的中断必须设置优先级为 ≥
configMAX_SYSCALL_INTERRUPT_PRIORITY
(通常为5
)
✅ 常见外设中断推荐优先级表
外设类型 | 中断名称(示例) | 推荐优先级(preempt) | 是否允许使用 FreeRTOS API | 说明 |
---|---|---|---|---|
USB FS/HS | OTG_FS_IRQn , USB_LP_CAN_RX0_IRQn | 6 | ✅ 是 | TinyUSB 常用 |
USART / UART | USARTx_IRQn | 6 或 7 | ✅ 是 | 接收中断中常用队列、通知 |
TIM 定时器 | TIMx_IRQn | 7 或 8 | ✅ 是 | 软件定时器事件、任务唤醒等 |
EXTI 外部中断 | EXTI0_IRQn , EXTIx_IRQn | 6 ~ 10 | ✅ 是 | 按键、外部触发事件 |
DMA | DMAx_Streamx_IRQn | 6 ~ 8 | ✅ 是 | 用于通知任务数据到位 |
I2C / SPI | I2Cx_EV_IRQn , SPIx_IRQn | 6 ~ 10 | ✅ 是 | 通信完成后唤醒任务 |
ADC / DAC | ADCx_IRQn | 8 ~ 12 | ✅ 是 | 可用于数据采样后任务处理 |
看门狗 / 硬件错误 | WWDG_IRQn , HardFault_IRQn | 0 ~ 2 | ❌ 否 | 不应使用 FreeRTOS API |
📌 示例配置代码(推荐)
// USB
HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);// USART
HAL_NVIC_SetPriority(USART1_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);// TIM 定时器
HAL_NVIC_SetPriority(TIM2_IRQn, 8, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
⚠️ 注意:STM32 优先级是“数值越小,优先级越高”
所以:
0
是最高优先级(❌ 禁止用于 FreeRTOS ISR API)15
是最低优先级
✅ 建议配置总结
类型 | 推荐优先级范围(Preempt) | 举例 |
---|---|---|
非实时,允许用 FreeRTOS API | 5 ~ 10 | USB / USART / TIM |
高实时需求 ISR(不用 RTOS API) | 0 ~ 4 | ADC / HardFault / 高速通信 |
RTOS 调度器自身 | 通常为 15 | 自动配置 |
在 FreeRTOS 中,调度器本身并不是一个中断或任务,它运行在 CPU空闲时 或由 SysTick 和 PendSV 中断驱动上下文切换。但我们可以从以下几个角度来理解你问的“调度器优先级”:
🔧 1. 调度相关中断优先级
FreeRTOS 使用两个关键中断来实现调度:
中断 | 作用 | 推荐优先级 | 说明 |
---|---|---|---|
SysTick_IRQn | 触发时间片中断,驱动 tick 增加 | 最低优先级(如 15 ) | 系统节拍来源 |
PendSV_IRQn | 实现任务切换(上下文切换) | 最低优先级(如 15 ) | 必须低于其他中断 |
✅ 所以我们通常手动或由 FreeRTOS 内部将这两个设置为:
NVIC_SetPriority(PendSV_IRQn, 15);
NVIC_SetPriority(SysTick_IRQn, 15);
📌 它们必须设为最低优先级,否则会干扰中断服务。
⚙️ 2. FreeRTOS 内核中配置项解释
在 FreeRTOSConfig.h
中,你配置了内核调度相关的“优先级窗口”,用于约束允许调用 FreeRTOS API 的中断优先级范围:
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
这意味着:
- 所有使用 FreeRTOS API 的中断优先级 必须为 5~15(数值越大优先级越低)
PendSV_IRQn
和SysTick_IRQn
会设置为configKERNEL_INTERRUPT_PRIORITY
(通常为15
)
✅ 3. FreeRTOS 任务优先级
这个和 NVIC 中断优先级是两个不同的体系:
概念 | 范围 | 数值越大优先级 |
---|---|---|
任务优先级 | 0 ~ configMAX_PRIORITIES - 1 | 越高(更优先被调度) |
中断优先级 | 数值越小优先级越高(STM32) | 越高(会抢占其他中断) |
例如:
vTaskCreate(..., uxPriority = 5, ...); // FreeRTOS 任务优先级为 5(调度优先)
🧠 总结:FreeRTOS 调度器相关优先级一览
项目 | 优先级值(通常) | 优先级说明 |
---|---|---|
PendSV_IRQn | 15 | 最低中断优先级,切换任务用,必须最低 |
SysTick_IRQn | 15 | 时钟节拍中断,驱动调度器 tick |
configKERNEL_INTERRUPT_PRIORITY | 15 | 内核运行的最低安全中断 |
configMAX_SYSCALL_INTERRUPT_PRIORITY | 5 (可调) | 可使用 FreeRTOS API 的最高优先级 |
FreeRTOS 任务优先级 | 0 ~ configMAX_PRIORITIES-1 | 数值越大越优先执行(与中断无关) |