FreeRTOS 之 在Cortex-M中应用时的中断优先级设置
??由于不同的 Cortex-M 系列,其中斷優(yōu)先級是不一樣的,所以事先搞清楚所用 MCU 的中斷優(yōu)先級有幾種。在 CMSIS 庫中的頭文件中可以查看優(yōu)先級的數(shù)量 __NVIC_PRIO_BITS
?? FreeRTOS 的中斷嵌套結(jié)構(gòu)被分為兩組,一組為被屏蔽的一組為不屏蔽的。FreeRTOS Config.h 中的configMAX_SYSCALL_INTERRUPT_PRIORITY 定義了這種分組。而這個最優(yōu)值取決于上面提到的 MCU 的優(yōu)先級位數(shù),實際 CMSIS 中只要定義了 __NVIC_PRIO_BITS,移植時需要在 FreeRTOS Config.h 引入即可。
??數(shù)以千計的 FreeRTOS 應(yīng)用運行在 ARM Cortex-M 內(nèi)核上。令人驚奇的是,RTOS 與 Cortex-M 內(nèi)核組合使用,使得技術(shù)支持請求變得如此的少。大多數(shù)的問題點是由不正確的優(yōu)先級設(shè)置引起的。這個問題也是在意料之中的,因為盡管 Cortex-M 內(nèi)核的中斷模式是非常強大的,但對于那些使用傳統(tǒng)中斷優(yōu)先級架構(gòu)的工程師來說, Cortex-M 內(nèi)核中斷機制也有點笨拙(或者是說使用比較繁瑣),并且違反直覺(這個主要是因為 Cortex-M 優(yōu)先級數(shù)越大代表的優(yōu)先級反而越小)。
說明:雖然 Cortex-M 內(nèi)核的優(yōu)先級方案看上去比較復(fù)雜,但每一個官方發(fā)布的 FreeRTOS 接口包(在 .\ FreeRTOS \Source\portable文件夾中,一般為 port.c)內(nèi)都會有正確配置的演示例程,可以以此為參考。
有效優(yōu)先級
Cortex-M 硬件詳述
??首先需要清楚有效優(yōu)先級的總數(shù),這取決于微控制器制造商怎么使用 Cortex-M 內(nèi)核。所以,并不是所有的 Cortex-M 內(nèi)核微處理器都具有相同的中斷優(yōu)先級級別。
?? Cortex-M 構(gòu)架自身最多允許 256 級可編程優(yōu)先級(優(yōu)先級配置寄存器最多 8 位,所以優(yōu)先級范圍從 0x00 ~ 0xFF),但是絕大多數(shù)微控制器制造商只是使用其中的一部分優(yōu)先級。比如,TI Stellaris Cortex-M3 和 Cortex-M4 微控制器使用優(yōu)先級配置寄存器的 3 個位,能提供 8 級優(yōu)先級。再比如,NXP LPC17xx Cortex-M3 微控制器使用優(yōu)先級配置寄存器的 5 個位,能提供 32 級優(yōu)先級。STM32F1、F4 使用了其中的 4 位,能提供 16 級優(yōu)先級。
??如果你的工程包含 CMSIS 庫頭文件,則頭文件中的宏 __NVIC_PRIO_BITS 定義使用多少優(yōu)先級寄存器的位(默認(rèn)是 4 位)。
應(yīng)用到 FreeRTOS
??RTOS 中斷嵌套方案將有效的中斷優(yōu)先級分成兩組:一組可以通過 RTOS 臨界區(qū)屏蔽,另一組不受 RTOS 影響,永遠(yuǎn)都是使能的。在 FreeRTOS Config.h 中配置的 configMAX_SYSCALL_INTERRUPT_PRIORITY ,定義兩組中斷優(yōu)先級的邊界。邏輯優(yōu)先級高于此值的中斷不受 RTOS 影響。最優(yōu)值取決于微控制器使用的優(yōu)先級配置寄存器的位數(shù)。
與數(shù)值相反的優(yōu)先級值和邏輯優(yōu)先級設(shè)置
Cortex-M 硬件詳述
??有必要先解釋一下優(yōu)先級值和邏輯優(yōu)先級:在 Cortex-M 內(nèi)核中,假如有 8 級優(yōu)先級,我們說優(yōu)先級值是 0~7,但數(shù)值最大的優(yōu)先級 7 卻代表著最低的邏輯優(yōu)先級。很多使用傳統(tǒng)傳統(tǒng)中斷優(yōu)先級架構(gòu)的工程師會覺得這樣比較繞,違反直覺。以下內(nèi)容提到的優(yōu)先級要仔細(xì)區(qū)分是優(yōu)先級數(shù)值還是邏輯優(yōu)先級。
??接下來需要清楚的是,在 Cortex-M 內(nèi)核中,一個中斷的優(yōu)先級數(shù)值越低,邏輯優(yōu)先級卻越高。比如,中斷優(yōu)先級為 2 的中斷可以搶占中斷優(yōu)先級為 5 的中斷,但反過來就不行。換句話說,中斷優(yōu)先級 2 比中斷優(yōu)先級 5 的優(yōu)先級更高。這是 Cortex-M 內(nèi)核最容易讓人犯錯之處,因為大多數(shù)的非 Cortex-M 內(nèi)核微控制器的中斷優(yōu)先級表述是與之相反的。
應(yīng)用到 FreeRTOS
??以 “FromISR” 結(jié)尾的 FreeRTOS 函數(shù)是具有中斷調(diào)用保護(hù)的(執(zhí)行這些函數(shù)會進(jìn)入臨界區(qū)),但是就算是這些函數(shù),也不可以被邏輯優(yōu)先級高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中斷服務(wù)函數(shù)調(diào)用。(宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 定義在頭文件 FreeRTOS Config.h 中)。因此,任何使用 RTOS API 函數(shù)的中斷服務(wù)例程的中斷優(yōu)先級數(shù)值大于等于 configMAX_SYSCALL_INTERRUPT_PRIORITY 宏的值。這樣就能保證中斷的邏輯優(yōu)先級等于或低于 configMAX_SYSCALL_INTERRUPT_PRIORITY 。
?? Cortex-M 中斷默認(rèn)情況下有一個數(shù)值為 0 的優(yōu)先級。大多數(shù)情況下 0 代表最高級優(yōu)先級。因此,絕對不可以在優(yōu)先級為 0 的中斷服務(wù)例程中調(diào)用 RTOS API 函數(shù)。
Cortex-M 內(nèi)部優(yōu)先級概述
Cortex-M 硬件詳述
?? Cortex-M 內(nèi)核的中斷優(yōu)先級寄存器是以最高位(MSB)對齊的。比如,如果使用了 3 位來表達(dá)優(yōu)先級,則這 3 個位位于中斷優(yōu)先級寄存器的 bit5、bit6、bit7 位。剩余的 bit0~bit4 可以設(shè)置成任何值,但為了兼容,最好將他們設(shè)置成 1.
?? Cortex-M 優(yōu)先級寄存器最多有 8 位,如果一個微控制器只使用了其中的 3 位,那么這 3 位是以最高位對齊的,見下圖:
??某微控制器只使用了優(yōu)先級寄存器中的 3 位,下圖展示了優(yōu)先級數(shù)值5(二進(jìn)制101B)是怎樣在優(yōu)先級寄存器中存儲的。如果優(yōu)先級寄存器中未使用的位置 1,下圖也展示了為什么數(shù)值 5(二進(jìn)制0000 0101B)可以看成數(shù)值 191(二進(jìn)制1011 1111)的。
??某微控制器只使用了優(yōu)先級寄存器中的 4 位,下圖展示了優(yōu)先級數(shù)值 5(二進(jìn)制101B)是怎樣在優(yōu)先級寄存器中存儲的。如果優(yōu)先級寄存器中未使用的位置 1,下圖也展示了為什么數(shù)值 5(二進(jìn)制0000 0101B)可以看成數(shù)值 95(二進(jìn)制0101 1111)的。
原出處,本圖有誤,查找英文出處修訂改過
應(yīng)用到 FreeRTOS
??上文中已經(jīng)描述,那些在中斷服務(wù)例程中調(diào)用 RTOS API 函數(shù)的中斷邏輯優(yōu)先級必須低于或等于configMAX_SYSCALL_INTERRUPT_PRIORITY(低邏輯優(yōu)先級意味著高優(yōu)先級數(shù)值)。
?? CMSIS 以及不同的微控制器供應(yīng)商提供了可以設(shè)置某個中斷優(yōu)先級的庫函數(shù)。一些庫函數(shù)的參數(shù)使用最低位對齊,另一些庫函數(shù)的參數(shù)可能使用最高位對齊,所以,使用時應(yīng)該查閱庫函數(shù)的應(yīng)用手冊進(jìn)行正確設(shè)置。
??可以在 FreeRTOS Config.h 中設(shè)置宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 和 configKERNEL_INTERRUPT_PRIORITY 的值。(關(guān)于這兩個宏可以參考參數(shù)設(shè)置一章,網(wǎng)址:http://open MCU.net/post/kernel-config.html)。這兩個宏需要根據(jù) Cortex-M 內(nèi)核自身的情況進(jìn)行設(shè)置,要以最高有效位對齊。比如某微控制器使用中斷優(yōu)先級寄存器中的 3 位,設(shè)置 configKERNEL_INTERRUPT_PRIORITY 的值為 5,則代碼為:#define configKERNEL_INTERRUPT_PRIORITY (5<<(8-3))
??對于每一個官方 FreeRTOS 演示例程,這也是在FreeRTOS Config.h中要設(shè)置宏 configKERNEL_INTERRUPT_PRIORITY 為最低優(yōu)先級時,為什么要將它設(shè)置為 255(1111 1111B)的原因。使用這種方式指定這個值的原因是: FreeRTOS 內(nèi)核是直接在 Cortex-M 內(nèi)核硬件上運行的(沒有使用第三方接口庫函數(shù)),要比大多數(shù)庫函數(shù)先運行。
臨界區(qū)
Cortex-M 硬件詳述
??RTOS 內(nèi)核使用 Cortex-M 內(nèi)核的 BASEPRI 寄存器來實現(xiàn)臨界區(qū)(注:BASEPRI 為優(yōu)先級屏蔽寄存器,優(yōu)先級數(shù)值大于或等于該寄存器的中斷都會被屏蔽,優(yōu)先級數(shù)值越大,邏輯優(yōu)先級越低,但是為零時不屏蔽任何中斷)。這允許 RTOS 內(nèi)核可以只屏蔽一部分中斷,因此可以提供一個靈活的中斷嵌套模式。
??那些需要在中斷調(diào)用時保護(hù)的 API 函數(shù), FreeRTOS 使用寄存器 BASEPRI 實現(xiàn)中斷保護(hù)臨界區(qū)。當(dāng)進(jìn)入臨界區(qū)時,將寄存器BASEPRI 的值設(shè)置成 configMAX_SYSCALL_INTERRUPT_PRIORITY,當(dāng)退出臨界區(qū)時,將寄存器 BASEPRI 的值設(shè)置成 0。很多 Bug 反饋都提到,當(dāng)退出臨界區(qū)時不應(yīng)該將寄存器設(shè)置成 0,應(yīng)該恢復(fù)它之前的狀態(tài)(之前的狀態(tài)不一定是 0)。但是 Cortex-M NVIC 決不會允許一個低優(yōu)先級中斷,去打斷當(dāng)前正在執(zhí)行的高優(yōu)先級中斷,不管 BASEPRI 寄存器中是什么值。與進(jìn)入臨界區(qū)前先保存 BASEPRI 的值,退出臨界區(qū)再恢復(fù)的方法相比,退出臨界區(qū)時將 BASEPRI 寄存器設(shè)置成 0 的方法可以獲得更快的執(zhí)行速度。
應(yīng)用到RTOS kernel
??RTOS 內(nèi)核通過寫 configMAX_SYSCALL_INTERRUPT_PRIORITY 的值到 BASEPRI 寄存器的方法創(chuàng)建臨界區(qū)。中斷優(yōu)先級 0(具有最高的邏輯優(yōu)先級)不能被 BASEPRI 寄存器屏蔽,因此,configMAX_SYSCALL_INTERRUPT_PRIORITY 絕不可以設(shè)置成 0。
鳴謝
原文地址:https://www.douban.com/note/548730851/,感謝原作者。轉(zhuǎn)載時可能有部分改動。
總結(jié)
以上是生活随笔為你收集整理的FreeRTOS 之 在Cortex-M中应用时的中断优先级设置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LwIP 之三 操作系统隔离接口 sys
- 下一篇: LwIP 之四 超时处理/定时器(tim