學(xué)RTOS從配置文件開(kāi)始!
最近有小伙伴問(wèn):學(xué)RTOS從哪里開(kāi)始?這個(gè)問(wèn)題說(shuō)簡(jiǎn)單也簡(jiǎn)單,說(shuō)難也難,因為每個(gè)人掌握的基礎不同,自然,從哪里開(kāi)始學(xué)起也各有不同。首先你要去了解RTOS相關(guān)的一些基礎知識,然后再下載源碼實(shí)踐運行,跑起來(lái)!接下來(lái)真正入門(mén)的第一步,大概率還得從“配置”文件開(kāi)始,這里的配置,可以理解為大家說(shuō)的“裁剪系統”及相關(guān)的一些配置。
本文引用地址:http://dyxdggzs.com/article/202412/465754.htm比如 FreeRTOS 中“FreeRTOSConfig.h”配置文件:
當然,配置文件是你已經(jīng)具備一定基礎知識,上手源碼第一步要掌握的內容。不僅僅是 FreeRTOS,其他μCOS、RT-Thread,甚至Linux都是從配置開(kāi)啟第一步的。
可能會(huì )有老鐵說(shuō),使用STM32CubeMX配置FreeRTOS,就不用修改(配置)FreeRTOSConfig.h文件?這么說(shuō)吧,第三方工具圖形化配置,也會(huì )牽涉到配置文件,而且僅僅是基礎的配置,你要做項目還是會(huì )修改配置文件。通過(guò)第三方配置工具,你不會(huì )真正掌握RTOS底層原理,后期做項目你會(huì )發(fā)現很困難。
FreeRTOS配置文件常見(jiàn)內容
本文結合流程的FreeRTOS給大家講講其中配置文件的內容。FreeRTOS配置文件看起來(lái)有點(diǎn)多,但它都有分類(lèi),多了解一下,你會(huì )發(fā)現理解起來(lái)也不是很難。
通用配置
通用配置基本配置,就是需要我們定義的一些配置,也是比較重要的配置。
1.configUSE_PREEMPTION調度模式配置
配置為0:合作式調度,即時(shí)間片輪流執行;
配置為1:搶占式調度,即優(yōu)先級高的任務(wù)搶先執行;
由于我們要求實(shí)時(shí)響應,就配置為1,使用搶占式調度方式。否則就發(fā)揮不到實(shí)時(shí)操作系統的作用。
2.configCPU_CLOCK_HZ
CPU時(shí)鐘,就是我們常說(shuō)的主頻。注意:?jiǎn)挝皇荋z。
如:STM32F407主頻為168M
#define configCPU_CLOCK_HZ (168000000)
3.configTICK_RATE_HZ
系統滴答,即系統每秒鐘滴答的次數,可以說(shuō)是系統的心跳,但需要和主頻區分開(kāi)來(lái)。系統滴答的值要根據CPU主頻來(lái)看,一般主頻越高,取值相對越大,一般在100至1000之間。
簡(jiǎn)單舉例:系統滴答決定vTaskDelay。
比如:
#define configTICK_RATE_HZ (1000)
則:vTaskDelay(1000),表示延時(shí)1S。
4.configMAX_PRIORITIES
系統最大優(yōu)先級值:我們創(chuàng )建任務(wù)是,配置的優(yōu)先級值不能超過(guò)這個(gè)最大值。
xTaskCreate(vAppTask1, "Task1", TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, NULL);
提示:
a.系統優(yōu)先級和中斷優(yōu)先級原理類(lèi)似,高優(yōu)先級的會(huì )搶在低優(yōu)先級的前面,但需要區分系統和中斷優(yōu)先級的應用場(chǎng)景。
b.FreeRTOS中優(yōu)先級數值越大,優(yōu)先級越高。而UCOS則相反。
5.configMINIMAL_STACK_SIZE
最小堆棧值:在系統中,一般用于空閑、定時(shí)等一些系統任務(wù)中,當然,我們有些地方也可以使用這個(gè)定義的堆棧值。
注意數值的單位,一般在A(yíng)RM中為4個(gè)字節。
6.configTOTAL_HEAP_SIZE
系統總共堆(棧)大?。何覀冃枰鶕枰褂玫那闆r定義這個(gè)值。不能定義太小,太小內存容易溢出;也不能定義太大,有些芯片RAM本身就不大(有些就只有幾K),如果太大我們就沒(méi)法定義太多全局變量,或分配其他堆??臻g。
7.configMAX_TASK_NAME_LEN
任務(wù)名稱(chēng)最大長(cháng)度:也就是創(chuàng )建任務(wù)定義任務(wù)名稱(chēng)的字符串長(cháng)度。
xTaskCreate(vAppTask1, "Task1", TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, NULL);
提示:結束符 '?'也包含在內。
8.configUSE_16_BIT_TICKS
是否使用16位滴答計數值
配置為0:則使用32位的滴答計數值,一般在32位處理器中都是配置為0;
配置為1:則使用16位的滴答計數值,一般8位或者16位處理器中配置為1。
9.configIDLE_SHOULD_YIELD
是否讓空閑任務(wù)“放棄”搶占:也就是說(shuō)在執行與空閑任務(wù)相同優(yōu)先級的任務(wù)過(guò)程中,空閑任務(wù)是否具有搶占的機會(huì )。
配置為0:不放棄搶占;
配置為1:放棄搶占;
10.configUSE_MUTEXES
是否使用互斥鎖
配置為0:不使用
配置為1:使用
提示:互斥鎖也叫互斥信號量,也就是說(shuō)對資源“加鎖”。它的作用是實(shí)現多任務(wù)間共享資源的獨占式處理。簡(jiǎn)單的說(shuō),就是某個(gè)資源在某一時(shí)刻只允許一個(gè)任務(wù)處理,處理完之后才允許其他任務(wù)處理該資源。
比如:A任務(wù)優(yōu)先級高,B任務(wù)優(yōu)先級低;AB任務(wù)都會(huì )使用一個(gè)串口發(fā)送指令數據,(即每次必須發(fā)送完成,不能發(fā)送到一半就被打斷)。
當B任務(wù)正在發(fā)送數據時(shí),A任務(wù)處于就緒狀態(tài)(要打斷B任務(wù))。那么B任務(wù)就需要使用互斥鎖占有該串口(加鎖,占有該資源),等發(fā)送完指令,就釋放該串口(開(kāi)鎖,釋放該資源)。一旦釋放了該資源,A任務(wù)就可以使用該串口(資源)了。
11.configUSE_RECURSIVE_MUTEXES
是否使用遞歸互斥鎖
配置為0:不使用
配置為1:使用
13.configQUEUE_REGISTRY_SIZE(*)
可添加(或登記)隊列名的數量:這個(gè)配置信息不好翻譯,它主要結合vQueueAddToRegistry與vQueueUnregisterQueue這兩個(gè)函數使用。
直接上函數接口:
void vQueueAddToRegistry(QueueHandle_t xQueue, const char *pcQueueName); void vQueueUnregisterQueue(QueueHandle_t xQueue);
從函數接口可以知道,一個(gè)函數是登記(已經(jīng)創(chuàng )建的)隊列的名稱(chēng);一個(gè)函數是注銷(xiāo)隊列的名稱(chēng);其實(shí),主要目的就是給(已經(jīng)創(chuàng )建的)隊列取名,方便調試查找。
提示:很多初學(xué)者理解為“可創(chuàng )建隊列的最大數”,這個(gè)配置參數與其完全不一樣的概念。
14.configUSE_QUEUE_SETS(*)
是否使用消息隊列“SET”功能
配置為0:不使用
配置為1:使用
15.configUSE_TIME_SLICING
是否使用時(shí)間片進(jìn)行調度:這個(gè)參數結合上面第1各配置參數configUSE_PREEMPTION一起使用。這個(gè)配置參數是在后面新版本增加的,好像在V7版本之前是沒(méi)有這個(gè)配置參數。所以,在FreeRTOSConfig.h配置文件中默認是沒(méi)有的,而是定義在FreeRTOS.h中。
#ifndef configUSE_TIME_SLICING #define configUSE_TIME_SLICING 1 #endif
HOOK配置
1.configUSE_IDLE_HOOK
是否定義IDLE空閑任務(wù)HOOK函數
配置為0:不定義
配置為1:定義
configUSE_IDLE_HOOK是系統設計之初就有的,必須在“FreeRTOSConfig.h”中宏定義。不像有些宏定義可以不在“FreeRTOSConfig.h”中定義,因為它們在“FreeRTOS.h”有判斷是否定義了,如果沒(méi)有定義,會(huì )有一個(gè)默認的定義。
比如:“configUSE_MUTEXES”可以不在“FreeRTOSConfig.h”中定義,而在“FreeRTOS.h”中可以看到如下一段代碼:
#ifndef configUSE_MUTEXES #define configUSE_MUTEXES 0 #endif
也就是說(shuō),如果沒(méi)有定義,它會(huì )默認給你定義。
回來(lái)說(shuō)configUSE_IDLE_HOOK,在task.c文件中,有如下一段代碼:
#if (configUSE_IDLE_HOOK == 1) { extern void vApplicationIdleHook(void); vApplicationIdleHook(); } #endif
意思是說(shuō):如果你配置configUSE_IDLE_HOOK為1,那么你就必須要實(shí)現“vApplicationIdleHook()”這個(gè)函數,否則編譯會(huì )出錯。初學(xué)者默認不定義該函數。
2.configUSE_TICK_HOOK
是否定義TICK滴答HOOK函數
配置為0:不定義
配置為1:定義
在task.c文件中的xTaskIncrementTick函數下可以看見(jiàn)如下代碼:
#if (configUSE_TICK_HOOK == 1) { if(uxPendedTicks == (UBaseType_t) 0U) { vApplicationTickHook(); } else { mtCOVERAGE_TEST_MARKER(); } } #endif
提示:xTaskIncrementTick函數是在PendSV_Handler中斷函數中被調用的。因此,vApplicationTickHook()函數執行的時(shí)間必須很短才行。
3.configCHECK_FOR_STACK_OVERFLOW
是否定義棧溢出HOOK函數
配置為0:不定義
配置為1:定義
這個(gè)配置比較關(guān)鍵和重要,特別對于復雜的系統設計,代碼量比較大那種工程,使用該功能,可以幫你分析是否有內存越界的情況。
4.configUSE_MALLOC_FAILED_HOOK
是否定義內存分配失敗HOOK函數
配置為0:不定義
配置為1:定義
我們創(chuàng )建任務(wù)、信號量、隊列等都需要耗費系統堆棧,如果我們對系統總共分配堆棧不夠多,在創(chuàng )建多個(gè)任務(wù)或隊列時(shí)容易分配失敗,這個(gè)時(shí)候就起到一個(gè)提示作用。
5.configUSE_DAEMON_TASK_STARTUP_HOOK
是否定義守護進(jìn)程HOOK函數
配置為0:不定義
配置為1:定義
通過(guò)分析軟件源代碼可以發(fā)現,這個(gè)HOOK函數是在TIMER任務(wù)下面實(shí)現的,所以需要配置configUSE_TIMERS為1。
TIMERS配置
TIMER即定時(shí)器,在RTOS中的TIMER屬于軟件定時(shí)。FreeRTOS的定時(shí)器精度不高,會(huì )隨著(zhù)定時(shí)的增加而改變,特別是TIMER任務(wù)優(yōu)先級較低,高優(yōu)先級占用資源的情況下。
若要使用高精度的定時(shí),還是最后使用硬件的定時(shí)器(現在處理器一般都有多個(gè)硬件TIMER)。
1.configUSE_TIMERS是否使用軟件定時(shí)器
配置為0:不使用
配置為1:使用
其他許多相關(guān)的功能都需要結合該配置才能使用,使用時(shí)需要注意是否關(guān)聯(lián)。
2.configTIMER_TASK_PRIORITY
軟件定時(shí)器任務(wù)優(yōu)先級:軟件定時(shí)器其實(shí)也是需要創(chuàng )建一個(gè)任務(wù),創(chuàng )建方式和我們常規的一樣,只是它是有系統內核完成,不用我們自己寫(xiě)創(chuàng )建任務(wù)代碼。
這里的這個(gè)優(yōu)先級就是定時(shí)器任務(wù)的優(yōu)先級。
3.configTIMER_QUEUE_LENGTH
軟件定時(shí)器命令隊列長(cháng)度:關(guān)于TIMER的命令隊列牽涉的知識相對復雜點(diǎn),后期進(jìn)一步講述,可看下圖:
4.configTIMER_TASK_STACK_DEPTH
分配給軟件定時(shí)器的堆??臻g
CO_ROUTINES配置
CO_ROUTINES這個(gè)不好翻譯,網(wǎng)上都叫協(xié)同程序,或者合作程序,理解為協(xié)同一起使用的程序,后期結合應用講述。
1.configUSE_CO_ROUTINES
是否使用CO_ROUTINES
配置為0:不使用
配置為1:使用
2.configMAX_CO_ROUTINE_PRIORITIES
CO_ROUTINE優(yōu)先級
MEMORY配置
內存分配相關(guān)的配置,這里的配置與heap_x.c有關(guān),后面會(huì )再次進(jìn)行講述。
1.configSUPPORT_STATIC_ALLOCATION
是否支持靜態(tài)分配
配置為0:不支持
配置為1:支持
2.configSUPPORT_DYNAMIC_ALLOCATION
是否支持動(dòng)態(tài)分配
配置為0:不支持
配置為1:支持
3.configTOTAL_HEAP_SIZE
分配給系統的堆棧:創(chuàng )建任務(wù),堆棧,靜態(tài)、動(dòng)態(tài)都分配的內存都來(lái)自這里。
4.configAPPLICATION_ALLOCATED_HEAP
APP使用哪里分配的堆
配置為0:使用系統分配的堆
配置為1:使用外部分配的堆
#if(configAPPLICATION_ALLOCATED_HEAP == 1 ) extern uint8_t ucHeap[configTOTAL_HEAP_SIZE]; #else static uint8_t ucHeap[configTOTAL_HEAP_SIZE]; #endif
RUN_TIME_STATS配置
運行時(shí)信息統計配置
1.configGENERATE_RUN_TIME_STATS
是否生成統計信息
配置為0:否
配置為1:是
2.configUSE_TRACE_FACILITY
是否協(xié)助執行可視化和跟蹤
配置為0:否
配置為1:是
這里會(huì )添加額外的結構體來(lái)實(shí)現。
3.configUSE_STATS_FORMATTING_FUNCTIONS
是否統計相關(guān)的功能
配置為0:否
配置為1:是
設置宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS為1會(huì )編譯vTaskList()和vTaskGetRunTimeStats()函數。如果將這兩個(gè)宏任意一個(gè)設置為0,上述兩個(gè)函數不會(huì )被編譯。
其他配置
這里簡(jiǎn)單綜合講述一下各項配置
1.configASSERT
斷言配置
2.Interrupt相關(guān)
configKERNEL_INTERRUPT_PRIORITY:內核中斷優(yōu)先級
configMAX_SYSCALL_INTERRUPT_PRIORITY:系統調用最大的優(yōu)先級
configMAX_API_CALL_INTERRUPT_PRIORITY:API調用的最大優(yōu)先級
這一節與(Cortex)內核硬件中斷有關(guān)。
3.INCLUDE配置
#define INCLUDE_vTaskPrioritySet #define INCLUDE_uxTaskPriorityGet #define INCLUDE_vTaskDelete
這里給大家分享了常見(jiàn)的一些配置內容,要深入理解并掌握,還是需要自己多動(dòng)手修改代碼驗證才行。
評論