這是我第一次使用FreeRTOS構建STM32的專案,踩了好些坑,又發現了我缺乏對于作業系統的記憶體及其空間的分配的知識,故寫下檔案記錄學習成果,
文章最后要解決的問題是,如何恰當地分配FreeRTOS中的堆、任務堆疊的空間,但是在概念的理解上,也需要知道STM32記憶體的相關知識,所以首先大致介紹一下STM32的記憶體結構,
STM32記憶體結構
STM32的資料在物理上分別儲存在RAM和Flash中,RAM可讀可寫,掉電清零,Flash可讀不可寫,但能掉電儲存,并且一般空間比RAM大很多,
在關于如何使用RAM和Flash的問題上,STM32的記憶體又有了6個儲存資料段和3種儲存屬性區的概念,
6個儲存資料段
data
資料段,儲存已初始化的,且初始化不為0的全域變數和靜態變數,
bss
Block Started by Symbol,儲存未初始化的,或初始化為0的全域變數和靜態變數,
text
代碼段,儲存程式代碼,
constdata
儲存只讀常量,
heap
堆,存放行程運行中被動態分配的記憶體段,其可用大小定義在啟動檔案startup_stm32fxx.s中,由程式員使用malloc()和free()函式進行分配和釋放,
stack
堆疊,其大小定義在啟動檔案startup_stm32fxx.s中,由系統自動分配和釋放,可存放區域變數、函式的引數和回傳值,中斷發生時能保存現場,但是static宣告的區域靜態變數不儲存在堆疊中,而是放在data資料段,
3種儲存屬性區
RO(Read Only)
燒寫到Flash中,可以長久保存,text代碼段和constdata都屬于RO,由于需要掉電儲存,RO里也保存了一份data的資料,
RW(Read Write)
儲存在RAM中,data屬于此區,上電時單片機會將Flash中保存的data型別資料復制到RAM中,以供讀寫使用,
ZI(Zero Init)
零初始化區,同樣儲存在RAM里,系統上電時會把此區域的資料進行0初始化,bss,heap,stack均屬于這個區域,
小結
STM32的RAM上有RW和ZI兩個屬性區,里邊包含了data,bss,堆(heap),堆疊(stack)這幾個資料段,這里是程式運行的所在,
Flash中有RO區,包含了text、constdata和data三個段,這里則是程式本體所在,
FreeRTOS中的堆
FreeRTOS中的堆也屬于ZI區,但是它與STM32記憶體結構中的堆并不占用相同的空間,兩個堆同時存在,以下出現的堆(heap)表示FreeRTOS堆,另外在STM32啟動檔案中定義大小的堆稱為系統堆,
FreeRTOS內核主要使用的記憶體管理函式為:
void *pvPortMalloc( size_t xSize ); //申請記憶體
void vPortFree( void *pv ); //釋放記憶體
以上函式控制的是FreeRTOS堆;系統堆則應使用malloc()和free()來分配和釋放,
FreeRTOS有5種heap的實作方式,在STM32CubeMX中默認為heap_4.c,這種方式可以滿足大部分使用需求,暫時不用關注其實作細節,
這一個堆的大小定義在FreeRTOSConfig.c中:
#define configTOTAL_HEAP_SIZE ((size_t)3072)
FreeRTOS創建任務時默認的任務堆疊大小為128字,在32位系統中即為128*4=512Byte,再加上TCB塊占用84Byte,一共596Byte,而大小為3072Byte的堆允許創建3個這樣的任務,占用約1800Byte,堆中剩余的部分則存放了系統內核、信號量、佇列、任務通知等資料,
需要創建更多任務時,堆的大小可自行修改,用RAM的空間減去已分配的空間,即為能給堆分配的最大空間:
\[Space = RAM - bss - data - SysHeap - Stack \]FreeRTOS堆和任務空間分配技巧
FreeRTOS堆和任務堆疊在運行中具有很強的動態性,其大小很難估計,
我們在實際使用中,可以先把空間調整得大一些,程式正常運行后,再通過一些API查看堆疊剩余的空間大小,估算程式運行中需求記憶體空間的最大值,最后將這個最大值乘一個安全系數,得到最終應該分配的空間大小,安全系數推薦1.3到1.5,
查看堆(heap)剩余空間的API有:
size_t xPortGetFreeHeapSize( void ); //獲取當前未分配的記憶體堆大小
size_t xPortGetMinimumEverFreeHeapSize( void ); //獲取未分配的記憶體堆歷史最小值
它們回傳值的單位都是位元組,
需要注意的是,xPortGetFreeHeapSize() 在使用heap_3.c時不能被呼叫;xPortGetMinimumEverFreeHeapSize()則只能在使用heap_4.c或heap_5.c時生效,
FreeRTOS中也有查看任務堆疊剩余空間的API:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
這個函式可以獲取一個任務從創建好到呼叫此函式時,任務堆疊空間的歷史最小剩余值(HighWaterMark),使用這個函式時需注意,它的回傳值的單位是字(STM32里1個字長為4個位元組),
這個API默認是關閉狀態,需要手動在Cubemx(或組態檔中)將宏INCLUDE_uxTaskGetStackHighWaterMark置為1,
我在使用過這些API后發現,他們本身也會占用相當的記憶體空間,尤其是uxTaskGetStackHighWaterMark(),會拖慢任務運行速度,所以在程式的正式版中,應該將他們洗掉,
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/273097.html
標籤:其他
上一篇:Linux命令的應用
