在裸機開發(非 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 | 數值越大越優先執行(與中斷無關) |