1. 程式人生 > >FreeRTOS 任務棧大小確定及其溢出檢測

FreeRTOS 任務棧大小確定及其溢出檢測

發送 創建 lock art 消息 阻塞 image img mage

FreeRTOS 的任務棧設置
不管是裸機編程還是 RTOS 編程,棧的分配大小都非常重要。 局部變量,函數調用時的現場保護和返
回地址,函數的形參,進入中斷函數前和中斷嵌套等都需要棧空間,棧空間定義小了會造成系統崩潰。
裸機的情況下,用戶可以在這裏配置棧大小:
技術分享

技術分享

為什麽是堆中的?因為我們采用的就是動態創建任務的方式。如果靜態創建,就和我們自己開辟的空間有關,通常靜態創建任務用數組作為容器,但是通常靜態創建的方式我們都不使用。

FreeRTOS 的系統棧設置
上面跟大家講解了什麽是任務棧,這裏的系統棧又是什麽呢?裸機的情況下,凡是用到棧空間的地方
都是在這裏配置的棧空間:

技術分享

在 RTOS 下,上面兩個截圖中設置的棧大小有了一個新的名字叫系統棧空間

,而任務棧是不使用這裏的空間的。 任務棧不使用這裏的棧空間,哪裏使用這裏的棧空間呢?答案就在中斷函數和中斷嵌套。

? 由於 Cortex-M3 和 M4 內核具有雙堆棧指針,MSP 主堆棧指針和 PSP 進程堆棧指針,或者叫 PSP
任務堆棧指針也是可以的。在 FreeRTOS 操作系統中,主堆棧指針 MSP 是給系統棧空間使用的,進
程堆棧指針 PSP 是給任務棧使用的。 也就是說,在 FreeRTOS 任務中,所有棧空間的使用都是通過
PSP 指針進行指向的。 一旦進入了中斷函數以及可能發生的中斷嵌套都是用的 MSP 指針。這個知識
點要記住它,當前可以不知道這是為什麽,但是一定要記住。
? 實際應用中系統棧空間分配多大,主要是看可能發生的中斷嵌套層數,下面我們就按照最壞執行情況
進行考慮,所有的寄存器都需要入棧,此時分為兩種情況

? 64 字節
對於 Cortex-M3 內核和未使用 FPU(浮點運算單元)功能的 Cortex-M4 內核在發生中斷時需
要將 16 個通用寄存器全部入棧,每個寄存器占用 4 個字節,也就是 16*4 = 64 字節的空間。
可能發生幾次中斷嵌套就是要 64 乘以幾即可。 當然,這種是最壞執行情況,也就是所有的寄存
器都入棧。
註:任務執行的過程中發生中斷的話,有 8 個寄存器是自動入棧的,這個棧是任務棧,進入中
斷以後其余寄存器入棧以及發生中斷嵌套都是用的系統棧
? 200 字節
對於具有 FPU(浮點運算單元)功能的 Cortex-M4 內核,如果在任務中進行了浮點運算,那麽
在發生中斷的時候除了 16 個通用寄存器需要入棧,還有 34 個浮點寄存器也是要入棧的,也就是


(16+34)*4 = 200 字節的空間。當然,這種是最壞執行情況,也就是所有的寄存器都入棧。
註:任務執行的過程中發送中斷的話,有 8 個通用寄存器和 18 個浮點寄存器是自動入棧的,
這個棧是任務棧,進入中斷以後其余通用寄存器和浮點寄存器入棧以及發生中斷嵌套都是用的系
統棧

FreeRTOS 的任務狀態
FreeRTOS 的運行支持以下四種狀態:
? Running—運行態
當任務處於實際運行狀態被稱之為運行態,即 CPU 的使用權被這個任務占用。
? Ready—就緒態
處於就緒態的任務是指那些能夠運行(沒有被阻塞和掛起) ,但是當前沒有運行的任務,因為同優先
級或更高優先級的任務正在運行。
? Blocked—阻塞態
由於等待信號量,消息隊列,事件標誌組等而處於的狀態被稱之為阻塞態,另外任務調用延遲函數也
會處於阻塞態。
? Suspended—掛起態
類似阻塞態,通過調用函數 vTaskSuspend()對指定任務進行掛起,掛起後這個任務將不被執行,只
有調用函數 xTaskResume()才可以將這個任務從掛起態恢復。
使用如下函數即可啟動 FreeRTOS:
? vTaskStartScheduler();
函數原型:
void vTaskStartScheduler( void );
函數描述:
函數 vTaskStartScheduler 用於啟動 FreeRTOS 調度器,即啟動 FreeRTOS 的多任務執行。
使用這個函數要註意以下幾個問題:
1. 空閑任務和可選的定時器任務是在調用這個函數後自動創建的。
2. 正常情況下這個函數是不會返回的,運行到這裏極有可能是用於定時器任務或者空閑任務的 heap 空
間不足造成創建失敗,此時需要加大 FreeRTOSConfig.h 文件中定義的 heap 大小:
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
技術分享

FreeRTOS 的任務恢復

使用如下函數可以實現 FreeRTOS 的任務恢復:
? xTaskResume()

使用如下函數可以實現 FreeRTOS 的任務恢復(中斷方式):
? xTaskResumeFromISR()

未完待續。。。

FreeRTOS 任務棧大小確定及其溢出檢測