STM32F407ZGT6+freertos的中断优先级

问题一:中断分为哪几类?

在 STM32F407(Cortex-M4 内核) 中,中断从系统角度可以分为几个层级和类别,既包括 内核级(系统异常),也包括 外设级(NVIC 外部中断)。

🧩 一、STM32 的中断总体分两大类:

分类说明举例
系统异常(System Exceptions)属于 Cortex-M4 内核内部的异常,不经过 NVIC 配置。优先级固定或可配置。Reset、NMI、HardFault、SysTick、SVC、PendSV 等
外设中断(Peripheral Interrupts)由 STM32 外设产生,经 NVIC 管理,可设置优先级。USART、TIM、EXTI、DMA、CAN、ETH 等

🧠 二、系统异常类中断(内核级)

这些是 CPU 自带的异常信号,响应速度最高。

异常名说明优先级可配置性
Reset复位中断(上电或复位触发)最高(固定)❌ 否
NMI(Non-Maskable Interrupt)不可屏蔽中断,最高优先级之一固定高❌ 否
HardFault硬错误(非法访问、总线错误等)固定高❌ 否
MemManage Fault内存保护错误可设置✅ 是
BusFault总线访问错误可设置✅ 是
UsageFault使用错误(未定义指令等)可设置✅ 是
SVCall(Supervisor Call)操作系统调用异常可设置✅ 是(RTOS 用)
PendSV(Pendable Service Call)可挂起的服务调用可设置✅ 是(任务切换用)
SysTick系统滴答定时器中断可设置✅ 是(RTOS心跳)

📘 FreeRTOS 在这里用到:

  • SysTick → 系统时基

  • PendSV → 任务切换(上下文切换)

  • SVCall → 初始化任务调度时使用

⚙️ 三、外设中断(NVIC 管理)

这是我们日常开发最常接触的类型——外设事件触发中断。
这些都在 NVIC(嵌套向量中断控制器)中配置优先级。

类型常见触发源示例
外部中断(EXTI)IO口电平/边沿变化EXTI0~EXTI15(按键输入)
定时器中断定时器计数溢出/比较事件TIM1~TIM14
通信中断串口、SPI、I2C 数据事件USART1~6、SPI1~3、I2C1~3
DMA中断DMA传输完成/错误DMA1_Stream0~7, DMA2_Stream0~7
ADC/DAC中断转换完成、过采样中断ADC1~3
CAN、Ethernet、USB中断通信协议事件CAN1_RX0, ETH, OTG_FS
其他控制类PVD(电源监测)、RTC、WWDG等RTC_Alarm、PVD

中断类型角色调用FreeRTOS API优先级要求
SysTickRTOS时钟心跳RTOS内部使用最低
PendSVRTOS任务切换RTOS内部使用最低
SVC系统调用RTOS内部使用普通
外设中断用户逻辑可以(但有限制)必须 ≥ configMAX_SYSCALL_INTERRUPT_PRIORITY

问题二:所以是不是外部中断优先级大于定时器中断,外部中断是不是最高中断?

🧠 一、首先明确:

❌ 外部中断(EXTI)不是天然比定时器中断优先级高。

✅ 它们在 STM32 里 属于同一层级(NVIC 管理),谁高谁低完全取决于你自己配置的优先级数值。

⚙️ 二、STM32 中断优先级的真相

STM32(以 F4 为例)内部有一张 中断向量表(IRQ Table),每一个外设中断都有一个编号(IRQn)。
比如:

中断源向量号(IRQn)默认优先级是否固定
WWDG0—可配置
PVD1—可配置
EXTI06—可配置
EXTI15_1040—可配置
TIM228—可配置
TIM430—可配置
USART137—可配置

🔹注意:
IRQn 数字只是“编号”,和优先级无关。
实际优先级完全由你调用的:

HAL_NVIC_SetPriority(IRQn, PreemptPriority, SubPriority);

来决定。


🧮 三、优先级比较规则(最重要)

STM32 的中断优先级是:
数值越小 → 优先级越高。

例如:

HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0); HAL_NVIC_SetPriority(TIM2_IRQn, 7, 0);

👉 那么:

  • EXTI0 优先级 = 5

  • TIM2 优先级 = 7

  • 结论:外部中断会打断定时器中断。

但如果你反过来写:

HAL_NVIC_SetPriority(EXTI0_IRQn, 8, 0); HAL_NVIC_SetPriority(TIM2_IRQn, 6, 0);

👉 那就是定时器更高,会打断外部中断。


⚡ 四、所以:外部中断不是“最高中断”

STM32 里没有固定谁是“最高中断”,只有系统异常(如 NMI、HardFault)是固定最高。

普通外设中断(EXTI、TIM、USART、DMA……)优先级完全由你决定。

📘 五、常规推荐配置(在 FreeRTOS 环境下)

功能中断类型推荐优先级说明
光电输入信号(高速)EXTI 或 TIM 捕获6响应快,能通知任务
定时任务调度用TIM中断7~9稍低一点
按键输入EXTI10不需要太高优先级
串口通讯USART11~12较低,后台运行
FreeRTOS 系统中断SysTick、PendSV14~15固定最低,内核用

🧭 六、总结一句话

误区事实
“外部中断优先级最高”❌ 错。除非你设成最高。
“定时器中断一定比 EXTI 慢”❌ 错。完全取决于 NVIC 配置。
“优先级高低是固定的”❌ 错。都是用户可调的。
“数值小 → 优先级高”✅ 对。STM32 永远如此。
“FreeRTOS 会改优先级”❌ 不会,只限制 API 可用范围。

✅ 七、实战建议(总结版)

如果你的系统是:

  • 光电信号触发 → 要快速反应(控制电机或停止)

  • 定时器 → 用来产生周期任务(低实时性)

  • 按键 → 低频输入

那你可以这样设置优先级:

中断源抢占优先级子优先级是否可用RTOS API
光电信号(EXTI/TIM输入捕获)60✅
定时器(周期任务)80✅
按键100✅
FreeRTOS系统150系统保留

问题三:在freertos中的中断规则是什么?

  • 数字越小 → 优先级越高(更紧急);

  • FreeRTOS 限制高优先级(数字小)中断不能调用 RTOS API。


🧠 二、FreeRTOS 的关键配置宏(在 FreeRTOSConfig.h 中)

通常你会看到这样三行宏定义:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - __NVIC_PRIO_BITS))

解释如下👇:

名称含义备注
configLIBRARY_LOWEST_INTERRUPT_PRIORITY可用的最低中断优先级(数字最大)一般 15
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY能调用 FreeRTOS API 的最高优先级(数字最小)默认 5
configKERNEL_INTERRUPT_PRIORITYFreeRTOS 内核使用的中断优先级一般等于最低(15)

⚙️ 三、规则核心一句话:

🔸 中断优先级数值 ≥ configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(通常是 5)
才能在中断中使用 FreeRTOS 的 FromISR 函数。

是否可调用 FreeRTOS API数值范围(优先级号)示例
✅ 可以5 ~ 15普通外设中断、EXTI、USART等
⚠️ 不可以0 ~ 4高实时性硬件中断,如紧急ADC采样、DMA中断等

问题四:什么时候需要去改这个#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5数值?

🧱 ① 你的系统存在“很多高优先级中断”

场景举例:

  • 有高速 ADC、PWM、DMA、CAN、Ethernet 等,需要优先级特别高(1~3)的中断。

  • 同时还有一些中断(如串口接收、外部信号输入)希望与 FreeRTOS 通信。

问题:

  • 如果高优先级中断太多(都 < 5),就导致可调用 RTOS API 的中断范围太小(5~15)。

解决:

  • 可以适当把这个宏调大,例如:

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 6

这样允许的可调用中断范围扩大到 6~15(优先级更低的部分)。

✅ 前提:
你必须同时把你的 NVIC 优先级配置都对应修改,保持一致。


⚡ ② 你的系统不需要那么多层级的中断区分

场景举例:

  • 只有几个外设中断(例如 EXTI、UART、TIM),没有高实时需求。

  • 想统一简化配置。

解决:
可以把分界线调得“更靠上”,例如:

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 3

这样就可以在优先级号 3~15 的中断里都调用 RTOS API。
但代价是:系统中断屏蔽区变大,调度响应略慢。


🧩 ③ 你有自定义的中断管理策略(多系统共存)

比如你:

  • 有 RTOS 管的任务系统;

  • 同时还有一个“裸机”模块(比如高速 ADC 或 FPGA 接口);

  • 需要严格区分“RTOS 可见中断”和“裸机中断”。

那你就可以调整这个阈值,例如:

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 4

让 0~3 的中断完全不归 RTOS 管,由裸机模块独立运行。


🚫 四、不要改的情况(99% 的工程)

场景是否需要改原因
普通 FreeRTOS 系统(STM32 + 任务 + 外设中断)❌ 不改默认 5 已经最安全
STM32CubeMX 自动生成 FreeRTOS 工程❌ 不改Cube 配置就是按 5 来生成的
系统使用 CMSIS-RTOS v2 接口❌ 不改内部调度机制已固定

📘 五、改动后需要同步的地方

如果你改了 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY,
要同步检查以下代码:

  1. 所有中断配置:

    HAL_NVIC_SetPriority(EXTI0_IRQn, 6, 0); // 必须 >= 新的阈值

  2. HAL 库内部的 SysTick 优先级设置:

    HAL_NVIC_SetPriority(SysTick_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY, 0);

  3. 检查 CubeMX 生成的 FreeRTOSConfig.h 是否自动覆盖了你手动改的值。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐