ROM/RAM太小,因此要對系統進行剪裁;
相關文章
【FreeRTOS實戰匯總】小白博主的RTOS學習實戰快速進階之路(持續更新)
文章目錄
- 1 系統的剪裁
- 2 FreeRTOSConfig.h
- 3 應用相關配置
- configUSE_PREEMPTION
- configMAX_PRIORITIES
- configMINIMAL_STACK_SIZE
- configUSE_16_BIT_TICKS
- configUSE_CO_ROUTINES
- configMAX_CO_ROUTINE_PRIORITIES
- 4 內存管理配置
- configSUPPORT_STATIC_ALLOCATION
- configSUPPORT_DYNAMIC_ALLOCATION
- configTOTAL_HEAP_SIZE
- configAPPLICATION_ALLOCATED_HEAP
- 5 hook 鈎子函數
- configUSE_TICK_HOOK
- configUSE_IDLE_HOOK
- configUSE_MALLOC_FAILED_HOOK
- configUSE_DAEMON_TASK_STARTUP_HOOK
- 6 功能選配
- 7 總結
1 系統的剪裁
嵌入式系統通常都支持用戶自定義進行剪裁,比較常見的Linux
系統通過Kbuild
在構建系統的時候進行剪裁,同樣,國產的RT-Thread
也支持Kbuild
,可以很方便地通過menuconfig
進行內核的剪裁,具體如下所示;
另外也支持通過對config
文件進行配置,Linux的內核構建過程可以參考文章《探索Linux內核:Kconfig / kbuild的秘密》;
FreeRTOS
支持使用FreeRTOSConfig.h
配置文件進行定制,下面有幾點需要注意的地方;
- 每個FreeRTOS應用程序的預處理器必須包含頭文件
FreeRTOSConfig.h
; FreeRTOSConfig.h
是根據用戶需求而進行定制產生的文件,它應位於應用程序的目錄中,而不是RTOS
內核代碼的目錄;FreeRTOS
源碼中的每一個demo
程序都有屬於自己的FreeRTOSConfig.h
文件,如果一下配置選項被省略,那這些設置為默認值;- 用戶通過修改
FreeRTOSConfig.h
頭文件中的宏定義,從而刪減系統的模塊,設置任務棧空間大小,設置系統分配的堆大小等等,下面配合源碼進行詳細解析。
2 FreeRTOSConfig.h
這里先找到文件FreeRTOSConfig.h
,這個FreeRTOS
工程是通過CubeIDE
進行快速整合的,具體可以參考《【FreeRTOS學習01】CubeIDE快速整合FreeRTOS創建第一個任務》;工程結構如下圖所示;
本文的FreeRTOSConfig.h
頭文件是根據集成在CubeIDE
中的CubeMX
插件自動生成的,源碼如下所示;
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* Ensure definitions are only used by the compiler, and not by the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
void xPortSysTickHandler(void);
#endif
#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0 //
#define configUSE_TICK_HOOK 0 //
#define configCPU_CLOCK_HZ ( SystemCoreClock ) //輸入以Hz為單位的CPU頻率:例如 72Mb->72000000
#define configTICK_RATE_HZ ((TickType_t)1000) //輸入以Hz為單位的滴答中斷頻率
#define configMAX_PRIORITIES ( 7 ) //應用程序任務可用的優先級數
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configTOTAL_HEAP_SIZE ((size_t)15360)
#define configMAX_TASK_NAME_LEN ( 16 ) //創建任務時,任務的名稱允許的最大長度
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1 //使用互斥功能
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 0
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
/* The highest interrupt priority that can be used by any interrupt service routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Normal assert() semantics without relying on the provision of an assert.h header file. */
/* USER CODE BEGIN 1 */
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
/* USER CODE END 1 */
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick, to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
/* #define xPortSysTickHandler SysTick_Handler */
#endif /* FREERTOS_CONFIG_H */
下面將對某些額外需要注意的進行另外注釋;
3 應用相關配置
configUSE_PREEMPTION
這個宏定義來選擇當前系統任務之間的調度算法;
- 設置為
1
,則表示選擇RTOS為搶占式調度; - 設置為
0
,則表示調度算法為時間片調度;
通常這里需要設置為搶占式調度,一般設置為
1
configMAX_PRIORITIES
應用程序任務可用 的優先級數,任意數量的任務可以共享相同的優先級。協同例程(Co-routines
)分別進行優先級排序,可以參考configMAX_CO_ROUTINE_PRIORITIES
;
每個可用的優先級都會消耗RTOS內核中的RAM,因此該值不應設置為高於應用程序實際需要的值;
configMINIMAL_STACK_SIZE
空閑任務使用的堆棧大小;通常,不應將此值從演示應用程序隨附的FreeRTOSConfig.h文件中為您所使用的端口設置的值中減少。
xTaskCreate()
和 xTaskCreateStatic()
函數的堆棧大小參數一樣,堆棧大小以字而不是字節,如果放在堆棧上的每個單元都是32位,堆棧大小100則表示400字節,4bytes等於32bit;
configUSE_16_BIT_TICKS
- 設置為
1
:TickType_t被定義(類型定義)為無符號的16位類型; - 設置為
0
:TickType_t被定義(類型定義)為無符號的32位類型;
當系統是8位或16位的結構時,使用這個設置,可以提高能;
configUSE_CO_ROUTINES
- 設置為
1
可在構建中包括協同例程功能; - 設置為
0
可從構建中省略協同例程功能;
要包含協例程,必須在項目中包含
croutine.c
configMAX_CO_ROUTINE_PRIORITIES
應用程序協同例程可用的優先級數。任意數量的協同例程可以共享相同的優先級。任務分別進行優先級排序-請參閱configMAX_PRIORITIES
4 內存管理配置
configSUPPORT_STATIC_ALLOCATION
- 設置為
1
:則可以使用程序中預先分配好的RAM
創建RTOS
對象; - 設置為
0
:只能使用從FreeRTOS
堆分配的RAM
創建RTOS
對象;
如果未定義configSUPPORT_STATIC_ALLOCATION,則默認為0
如果將configSUPPORT_STATIC_ALLOCATION設置為1,則應用程序編寫器還必須提供兩個回調函數:- -
vApplicationGetIdleTaskMemory()
:用於提供RTOS空閑任務的內存;vApplicationGetTimerTaskMemory()
:用於提供RTOS守護程序/計時器服務任務(如果configUSE_TIMERS設置為1)的內存: 。
這個在移植的時候可能也會遇到,具體如下所示;
/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an implementation of vApplicationGetIdleTaskMemory() to provide the memory that is used by the Idle task. */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
/* If the buffers to be provided to the Idle task are declared inside this function then they must be declared static – otherwise they will be allocated on the stack and so not exists after this function exits. */
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
/* Pass out a pointer to the StaticTask_t structure in which the Idle task’s state will be stored. */
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
/* Pass out the array that will be used as the Idle task’s stack. */
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. Note that, as the array is necessarily of type StackType_t, configMINIMAL_STACK_SIZE is specified in words, not bytes. */
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
/*———————————————————–*/
/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the application must provide an implementation of vApplicationGetTimerTaskMemory() to provide the memory that is used by the Timer service task. */
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
/* If the buffers to be provided to the Timer task are declared inside this function then they must be declared static – otherwise they will be allocated on the stack and so not exists after this function exits. */
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
/* Pass out a pointer to the StaticTask_t structure in which the Timer task’s state will be stored. */
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
/* Pass out the array that will be used as the Timer task’s stack. */
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. Note that, as the array is necessarily of type StackType_t, configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
configSUPPORT_DYNAMIC_ALLOCATION
- 設置為
1
:則可以使用從FreeRTOS堆自動分配的RAM創建RTOS對象; - 設置為
0
:則只能使用應用程序編寫器提供的RAM創建RTOS對象;
如果未定義configSUPPORT_DYNAMIC_ALLOCATION,則默認為1;
configTOTAL_HEAP_SIZE
設置FreeRTOS
中堆可用的RAM總量;
僅當configSUPPORT_DYNAMIC_ALLOCATION
設置為1;且使用FreeRTOS
源代碼下載中提供的示例內存分配方案(heap_1.c
,heap_2.c
,heap_3.c
,heap_4.c
,heap_5.c
)時,才會配置這個值;
configAPPLICATION_ALLOCATED_HEAP
- 設置為
0
:FreeRTOS
堆由FreeRTOS
聲明,並由鏈接器放置在內存中; - 設置為
1
:可以使堆改為由用戶程序進行設置,允許將堆放置在內存中任意位置;
如果使用
heap_1.c
,heap_2.c
或heap_4.c
,並且configAPPLICATION_ALLOCATED_HEAP
設置為1
,那么應用程序編寫器必須提供一個uint8_t數組,其名稱和維數如下所示。
uint8_t ucHeap [configTOTAL_HEAP_SIZE];
該數組將被作為FreeRTOS的堆來使用。如何將數組放置在特定的內存位置取決於所使用的編譯器–請參閱編譯器的文檔。
5 hook 鈎子函數
鈎子函數的本質就是回調函數,有下面四個函數;
configUSE_TICK_HOOK
;configUSE_IDLE_HOOK
;configUSE_MALLOC_FAILED_HOOK
;configUSE_DAEMON_TASK_STARTUP_HOOK
;
具體參考hook函數;
configUSE_TICK_HOOK
程序必須為hook函數提供以下原型:
void vApplicationTickHook( void );
configUSE_IDLE_HOOK
configUSE_IDLE_HOOK設置為1,才會調用IDLE_HOOK,設置此選項后,應用程序必須為hook函數提供以下原型:
void vApplicationIdleHook(void);
configUSE_MALLOC_FAILED_HOOK
程序必須為hook函數提供以下原型:
void vApplicationMallocFailedHook( void );
configUSE_DAEMON_TASK_STARTUP_HOOK
RTOS守護程序任務與計時器服務任務相同。有時將其稱為守護程序任務,因為該任務現在不僅用於維護計時器,還用於更多任務。
將configUSE_DAEMON_TASK_STARTUP_HOOK
設置為1,則在守護程序任務首次開始執行時,將立即調用守護程序任務啟動鈎子函數。應用程序的初始化代碼如果需要放在該鈎子函數中,則該功能將很有用,這將允許初始化代碼利用RTOS功能。
應用程序編寫器必須使用以下名稱提供原型的“守護程序任務”啟動掛鈎函數的實現。
void vApplicationDaemonTaskStartupHook( void );
6 功能選配
如果以下函數沒有被使用到,已經設置為0
,使其不被包含到應用程序中,從而減少程序的應用空間;
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 0
#define INCLUDE_xTaskAbortDelay 0
#define INCLUDE_xTaskGetHandle 0
#define INCLUDE_xTaskResumeFromISR 1
7 總結
如果是學習FreRTOS的初期,只需要了解幾個比價關鍵的配置即可,隨着后期對該系統功能了解的深入,在系統的剪裁,RAM和ROM的優化上就可以進一步的了解,另外也可以參考https://www.freertos.org/a00110.html,