在ARM CORTEX-M內核上運行FreeRTOS

英文原文:http://www.freertos.org/RTOS-Cortex-M3-M4.html


注意

文章中關於中斷嵌套的信息僅適用於Cortex-M3,Cortex-M4,Cortex-M4F和Cortex-M7,文章不適用於CORTEX-M0和CORTEX-M0+內核,因爲CORTEX-M0和CORTEX-M0+內核沒有BASEPRI寄存器。


簡介

數以千計的使用了FreeRTOS的應用運行在ARM CORTEX-M內核的CPU上,然而令人驚訝的是,對於FreeRTOS+ARM CORTEX-M CPU這個組合的技術支持卻少的可憐。錯誤的中斷優先級設置是主要原因。儘管ARM CORTEX-M內核使用的中斷模型非常強大,但是對那些用慣了使用符合常理的中斷優先級的工程師來說,這樣的中斷模型依然顯示有些傻逼和違背常理。這篇文章致力於描述ARM CORTEX-M內核的中斷優先級機制,以及在使用FreeRTOS的時候該怎樣配置中斷優先級。

記住,雖然ARM CORTEX-M3內核提供的優先級機制看起來比較複雜,但是FreeRTOS官方的每一個應用案例都提供了正確的配置以供參考。另外FreeRTOS從V7.5.0版本開始引進了configASSERT()調用用來捕獲ARM CORTEX-M中斷控制器的錯誤配置。請確保開發過程中configASSERT配置項是打開的。


可用的有效優先級

CORTEX_M內核的硬件描述

由於並不是所有的ARM CORTEX-M微控制器都提供相同數量的中斷優先級,所以對於一款使用了ARM CORTEX-M內核的微控制器,首先需要知道的是製造商總共實現了多少數量有效的中斷優先級。ARM CORTEX-M架構本身最多允許256個不同的優先級(0~0xFF共256個),但是大多是情況下,如非必要,微控制器並不會實現這麼多數量的中斷優先級。比如,TI Stellaris系列的CORTEX-M3和CORTEX-M4微控制器使用了三個比特共能提供八個不同的優先級,NXP的LPC17xx系列的CORTEX-M3微控制器使用了五個比特共能提32個不同的優先級。如果你的項目使用了CMSIS庫,請檢查CMSIS頭文件中的__NVIC_PRIO_BITS宏定義查看微控制器使用了幾個比特來實現不同的優先級。

與FreeRTOS的關聯

FreeRTOS的中斷嵌套機制將有效的中斷優先級分爲兩組:可被FreeRTOS臨界區屏蔽的中斷和不可被FreeRTOS臨界區屏蔽的中斷。FreeRTOSConfig.h中的configMAX_SYSCALL_INTERRUPT_PRIORITY宏定義了這兩個組的邊界,宏的最佳取值取決於微控制器的優先級由多少比特實現。


搶佔優先級與子優先級

CORTEX_M內核的硬件描述

8比特寬度的優先級寄存器被分爲兩個部分:搶佔優先級和子優先級,每部分佔的比特寬度可配置。搶佔優先級定義了中斷是否可以打斷另一個正在執行的中斷,子優先級決定了當同一時刻相同搶佔優先級的兩個中斷同時發生的時候哪個中斷先運行。

與FreeRTOS的關聯

推薦將所有的有效優先級比特位分配給搶佔優先級,子優先級不分配比特位。任何其他的配置將使configMAX_SYSCALL_INTERRUPT_PRIORITY的設置和分配給外設中斷的優先級複雜化。很多系統默認便是這種期望的配置,然而STM32驅動庫確實一個例外。如果你使用STM32微控制器並且使用了STM32驅動庫,請在FreeRTOS開始運行之前確保所有的有效優先級比特位分配給搶佔優先級,你可以通過調用函數NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4)來實現這一目的。


優先級的設定值和邏輯優先級的逆向關係

CORTEX_M內核的硬件描述

關於ARM CORTEX-M內核接下來需要知道的事情是,優先級取值越低代表的邏輯優先級越高。比如,一個取值爲2的中斷的優先級高於一個取值爲5的中斷的優先級,換句話說,中斷優先級2大於中斷優先級5,中斷優先級爲2的中斷可以打斷正在執行的中斷優先級爲5的中斷,但中斷優先級爲5的中斷不可以打斷正在執行的中斷優先級爲2的中斷。這是ARM Cortex-M中斷優先級中最違背常理的一方面,它和大多數非ARM Cortex-M內核的微控制器恰好相反。

與FreeRTOS的關聯

FreeRTOS中以“FromISR”結尾的函數是中斷安全的,但是即使這些函數不能從中斷中調用,它們仍然擁有一個大於configMAX_SYSCALL_INTERRUPT_PRIORITY設置值的邏輯優先級。因此,任何使用了FreeRTOS API的中斷服務程序必須設置自己的優先級值,十七在數值上大於等於configMAX_SYSCALL_INTERRUPT_PRIORITY的值。CORTEX-M中斷的默認優先級值是0,0是最高邏輯優先級。因此,不要讓使用了FreeRTOS 中斷安全API的中斷優先級使用默認值。


CORTEX-M內部優先級的表示方式

CORTEX_M內核的硬件描述

ARM CORTEX-M內核將中斷優先級值存儲在八比特寬度的中斷優先級寄存器的最高有效位,比如,如果一個ARM CORTEX-M內核的微控制器使用了三個比特來實現優先級,這三個比特將會被分別的傳送至bit5,bit6和bit7的位置。bit0~4可以是任意值,考慮到未來的兼容性,bit0~4最好設置爲1。


ARM CORTEX-M內部優先級的表示方式如上圖所示:CORTEX-M優先級寄存器最大寬度是8bit,假設一個微控制器使用了三個比特來表示優先級,那麼上圖展示了這三個比特的使用情況。


對於一個使用了三個比特來表示優先級的微控制器,上圖展示優先級值爲5(二進制101)時在優先級寄存器中的存儲形式,上圖也展示了當三個比特被移到需要的位置且保留位被設置爲1時,爲什麼值5(二進制0000 0101)也可以被寫爲191(二進制1011 1111)。


對於一個使用了四個比特來表示優先級的微控制器,上圖展示優先級值爲5(二進制101)時在優先級寄存器中的存儲形式,上圖也展示了當四個比特被移到需要的位置且保留位被設置爲1時,爲什麼值5(二進制0000 0101)也可以被寫爲95(二進制0101 1111)。

與FreeRTOS的關聯

如上所述,中斷服務程序的基本要求是確保使用的FreeRTOS的API的邏輯優先級小於等於configMAX_SYSCALL_INTERRUPT_PRIORITY表示的邏輯優先級(低邏輯優先級意味着數值更大)。CMSIS和各個微控制器廠商提供的庫函數可以用來設置中斷的優先級,有些庫函數期望中斷優先級設置在8bit寬度字節的最低有效位,也有些庫函數期望中斷優先級設置在8bit寬度字節的最高有效位,檢查你使用的函數的文檔來確認你使用的庫函數屬於哪一種,這可以使你免受不必要的錯誤。FreeRTOSConfig.h中的configMAX_SYSCALL_INTERRUPT_PRIORITY和configKERNEL_INTERRUPT_PRIORITY的設置值應該和ARM Cortex-M內核期望的保持一致:即中斷優先級設置值在8bit寬度字節的最高有效位。這也是爲什麼在每一個官方提供的應用案例的FreeRTOSConfig.h頭文件中,可以設置configKERNEL_INTERRUPT_PRIORITY的值爲255(二進制1111 1111)來使中斷處於最低邏輯優先級。這樣設置值的原因有以下幾個:FreeRTOS內核直接訪問ARM Cortex-M的硬件資源(不經過任何第三方庫),FreeRTOS內核實現了大多數庫提供的功能,FreeRTOS使用的這種機制是ARM Cortex-M3推向市場的第一個庫的所使用的機制。


臨界區

CORTEX_M內核的硬件描述

FreeRTOS內核使用ARM Cortex-M內核的BASEPRI寄存器實現臨界區,這意味着FreeRTOS內核僅能屏蔽子中斷,因此FreeRTOS內核提供了一個靈活的中斷嵌套模型。BASEPRI是一個屏蔽位,給BASEPRI設置一個值後將使所有的邏輯優先級小於等於設置值的中斷被屏蔽,因此不可以將BASEPRI設置爲0。另外,在中斷中調用FreeRTOS函數通過使用BASEPRI寄存器來實現中斷安全臨界區是安全的,進入臨界區時BASEPRI設置爲configMAX_SYSCALL_INTERRUPT_PRIORITY定義的值,出臨界區時BASEPRI設置爲0。我們接收到的很多bug報告指出退出臨界區的時候BASEPRI應該返回它的原始值,而不僅僅是設置爲0,但是不管BASEPRI設置爲什麼值,Cortex-M NVIC永遠不會接受一個邏輯優先級低於當前正在執行中斷的中斷,在編譯器優化選項打開的前提下,將BASEPRI設置爲0的代碼執行速度要比存儲BASEPRI的值快得多。

與FreeRTOS的關聯

FreeRTOS內核通過將configMAX_SYSCALL_INTERRUPT_PRIORITY的值寫進ARM Cortex-M BASEPRI寄存器來創建一個臨界區,當中斷優先級爲0()的時候不能使用BASEPRI屏蔽,configMAX_SYSCALL_INTERRUPT_PRIORITY不可以設置爲0。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章