1.FreeRTOS的系统配置文件为FreeRTOSConfig.h,在此配置文件中可以完成FreeRTOS的裁剪和配置。
在官方的demo中,每个工程都有一个该文件。
2.先说一下”INCLUDE_”开始的宏
使用“INCLUDE_”开头的宏用来表示使能或除能FreeRTOS中的相应API函数,作用就是用来配置FreeRTOS中的可选API函数。
(1)INCLUDE_xSemaphoreGetMutexHolder
如果要使用函数xSemaphoreGetMutexHolder(),则宏INCLUDE_xSemaphoreGetMutexHolder必须定义为1。
(2)INCLUDE_xTaskAbortDelay
如果要使用函数xTaskAbortDelay(),则宏INCLUDE_xTaskAbortDelay定义为1。
(3)INCLUDE_vTaskDelay
如果要使用函数vTaskDelay(),则宏INCLUDE_vTaskDelay定义为1。
(4)INCLUDE_vTaskDelayUntil
如果要使用函数vTaskDelayUntil(),则宏INCLUDE_vTaskDelayUntil定义为1。
(5)INCLUDE_vTaskDelete
如果要使用函数vTaskDelete(),则宏INCLUDE_vTaskDelete定义为1。
(6)INCLUDE_xTaskGetCurrentTaskHandle
如果要使用函数xTaskGetCurrentTaskHandle(),则宏INCLUDE_xTaskGetCurrentTaskHandle定义为1。
(7)INCLUDE_xTaskGetHandle
如果要使用函数xTaskGetHandle(),则宏INCLUDE_xTaskGetHandle定义为1。
(8)INCLUDE_xTaskGetIdleTaskHandle
如果要使用函数xTaskGetIdleTaskHandle(),则INCLUDE_xTaskGetIdleTaskHandle定义为1。
(9)INCLUDE_xTaskGetSchedulerState
如果要使用函数xTaskGetSchedulerState(),则宏INCLUDE_xTaskGetSchedulerState定义为1。
(10)INCLUDE_uxTaskGetStackHighWaterMark
如果要使用函数uxTaskGetStackHighWaterMark(),则宏INCLUDE_uxTaskGetStackHighWaterMark定义为1。
(11)INCLUDE_uxTaskPriorityGet
如果要使用函数uxTaskPriorityGet(),则宏INCLUDE_uxTaskPriorityGet定义为1。
(12)INCLUDE_vTaskPrioritySet
如果要使用函数vTaskPrioritySet(),则宏INCLUDE_vTaskPrioritySet定义为1。
(13)INCLUDE_xTaskResumeFromISR
如果要使用函数xTaskResumeFromISR(),则需要将宏INCLUDE_xTaskResumeFromISR和INCLUDE_vTaskSuspend都定义为1。
(14)INCLUDE_eTaskGetState
如果要使用函数eTaskGetState(),则宏INCLUDE_eTaskGetState定义为1。
(15)INCLUDE_vTaskSuspend
如果要使用函数vTaskSuspend()、vTaskResume()、prvTaskIsTaskSuspended()、xTaskResumeFromISR(),则宏INCLUDE_vTaskSuspend定义为1。
如果要使用函数xTaskResumeFromISR(),则宏INCLUDE_xTaskResumeFromISR和INCLUDE_vTaskSuspend都必须定义为1。
(16)INCLUDE_xTimerPendFunctionCall
如果要使用函数xTimerPendFunctionCall()和xTimerPendFunctionCallFromISR(),则宏INCLUDE_xTimerPendFunctionCall和configUSE_TIMERS都必须定义为1。
3.再来说一下config开始的宏
(1)configAPPLICATION_ALLOCATED_HEAP
该宏与系统的堆内存的分配相关,在heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5中都有定义。当该宏为1时,需要用户自行堆内存ucHeap,否则就由编译器来分配。
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif
(2)configASSERT
断言类似C语言中的assert()函数。
该宏需要在FreeRTOSConfig.h中定义。
#define configASSERT((x)) if ((x) == 0) vAssertCalled(__FILE_, __LINE__)
注意:vAssertCalled()函数需要自行定义。
#define vAssertCalled(char, int) printf("Error: %s, %d\r\n", char, int)
断言会导致开销增大,一般在调试阶段使用,调试完成后去掉。
(3)configCHECK_FOR_STACK_OVERFLOW
该宏设置堆栈溢出检测。
每一个任务都有一个任务栈,使用函数vTaskCreate()创建任务时,任务栈是自动从FreeRTOS的堆(ucHeap)中分配的;而xTaskCreateStatic()创建任务时,任务站时由用户分配的。
任务栈的检测方式有两种,当该宏为1时使用第1种方式,当该宏为2时,使用第2中方式,两种方式的不同不再描述。
(4)configCPU_CLOCK_HZ
设置CPU的频率
(5)configSUPPORT_DYNAMIC_ALLOCATION
定义为1–在创建FreeRTOS内核对象时,需要的RAM就会从FreeRTOS的堆中动态的获取;定义为0–所需的RAM就需要用户自行提供。默认为1。
(6)configENABLE_BACKWARD_COMPATIBILITY
FreeRTOS.h中有一些数据类型名字的宏定义 。
#if configENABLE_BACKWARD_COMPATIBILITY == 1
#define eTaskStateGet eTaskGetState
#define portTickType TickType_t
#define xTaskHandle TaskHandle_t
#define xQueueHandle QueueHandle_t
#define xSemaphoreHandle SemaphoreHandle_t
#define xQueueSetHandle QueueSetHandle_t
#define xQueueSetMemberHandle QueueSetMemberHandle_t
#define xTimeOutType TimeOut_t
#define xMemoryRegion MemoryRegion_t
#define xTaskParameters TaskParameters_t
#define xTaskStatusType TaskStatus_t
#define xTimerHandle TimerHandle_t
#define xCoRoutineHandle CoRoutineHandle_t
#define pdTASK_HOOK_CODE TaskHookFunction_t
#define portTICK_RATE_MS portTICK_PERIOD_MS
#define pcTaskGetTaskName pcTaskGetName
#define pcTimerGetTimerName pcTimerGetName
#define pcQueueGetQueueName pcQueueGetName
#define vTaskGetTaskInfo vTaskGetInfo
/* Backward compatibility within the scheduler code only - these definitions
are not really required but are included for completeness. */
#define tmrTIMER_CALLBACK TimerCallbackFunction_t
#define pdTASK_CODE TaskFunction_t
#define xListItem ListItem_t
#define xList List_t
#endif
宏configENABLE_BACKWARD_COMPATIBILITY默认为1。
(7)configGENERATE_RUN_TIME_STATS
设置为1开启时间统计功能,则相应的API函数会被编译;为0则关闭时间统计功能。
(8)configIDLE_SHOULD_YIELD
此宏定义了与空闲任务(idle Task)出于同等优先级的其他用户任务的行为。为0,表示空闲任务不会为其他处于同等优先级的任务让出CPU使用权;为1,则空闲任务为处于同等优先级的用户让出CPU使用权。
一般建议关闭这个功能。
(9)configKERNEL_INTERRUPT_PRIORITY、configMAX_SYSCALL_INTERRUPT_PRIORITY、configMAX_API_CALL_INTERRUPT_PRIORITY
这3个宏和FreeRTOS的中断配置有关,后面会有专门的章节来讲解。
(10)configMAX_CO_ROUTINE_PRIORITIES
设置可以分配给协程的最大优先级,也就是协程的优先级数。
0是最低优先级,configMAX_CO_ROUTINE_PRIORITIES-1为最高的优先级。
(11)configMAX_PRIORITIES
设置任务的优先级数量,设置好以后任务就可以使用从0~configMAX_PRIORITIES-1的优先级。
0时最低优先级,configMAX_PRIORITIES-1是最高优先级。
(12)configMAX_TASK_NAME_LEN
设置任务名的最大长度
(13)configMINIMAL_STACK_SIZE
设置空闲任务的任务栈的最小值。
注意:这里以字为单位,不是字节。
(14)configNUM_THREAD_LOCAL_STORAGE_POINTERS
设置每个任务的本地存储指针数组大小。
任务控制块中有本地存储数组指针,用户应用程序可以在这些本地存储中存入一些数据。
(15)configQUEUE_REGISTRY_SIZE
设置可以注册的队列和信号量的最大数量。使用内核调试器查看信号量和队列的是否需要设置此宏,不使用内核调试器时此宏设置为0即可。
(16)configSUPPORT_STATIC_ALLOCATION
此宏定义为1时,在创建一些内核对象的时候需要用户指定RAM;为0时,则自动使用heap.c中的动态内存管理函数来申请RAM。
若定义为1,需要实现两个函数vApplicationGetIdleTaskMemory()和vApplicationGetTimerTaskMemory()。
(17)configTICK_RATE_HZ
设置FreeRTOS的系统时钟节拍频率,单位为Hz。
此频率是系统滴答定时器的中断频率。
(18)configTIMER_QUEUE_LENGTH
此宏与软件定时器相关,用来设置软件定时器的命令队列的长度。
(19)configTIMER_TASK_PRIORITY
设置软件定时器任务的任务优先级。
(20)configTIMER_TASK_STACK_DEPTH
设置定时器任务的任务栈的大小。
(21)configTOTAL_HEAP_SIZE
用来设置堆大小。
如果使用动态内存管理,则FreeRTOS在创建任务、信号量、队列等的时候就会使用heap_x.c(x为1~5)中的内存申请函数来申请内存。
(22)configUSE_16_BIT_TICKS
设置系统节拍计数器变量的数据类型,系统节拍计数器变量类型为TickType_t。
configUSE_16_BIT_TICKS为1时,TickType_t是16位的;configUSE_16_BIT_TICKS为0时,TickType_t是32位的。
(23)configUSE_APPLICATION_TASK_TAG
此宏设置为1时,函数configUSE_APPLICATION_TASK_TAGF()和xTaskCallApplicationTaskHook()就会被编译。
(24)configUSE_CO_ROUTINES
此宏为1时开启协程。
协程可以节省开销,但是功能有限,现在的CPU性能已经很强大了,建议关闭协程。
(25)configUSE_COUNTING_SEMAPHORES
设置为1时启用计数型信号量,相关的API函数就会被编译。
(26)configUSE_DAEMON_TASK_STARTUP_HOOK
当宏configUSE_TIMERS和configUSE_DAEMON_TASK_STARTUP_HOOK都为1时需要定义函数vApplicationDaemonTaskStartupHook()。
函数原型:void vApplicationDaemonTaskStartupHook(void)
(27)configUSE_IDLE_HOOK
为1时使用空闲任务钩子函数,用户需要实现空闲任务钩子函数,函数的原型为:void vApplicationIdleHook(void)
(28)configUSE_MALLOC_FAILED_HOOK
为1时使用内存分配函数失败钩子函数,用户需要实现内存分配失败钩子函数,函数原型为:void vApplicationMallocFailedHook(void)
(29)configUSE_MUTEXES
为1时使用互斥信号量,相关的API函数会被编译。
(30)configUSE_PORT_OPTIMISED_TASK_SELECTION
FreeRTOS有两种方法来选择下一个要运行的任务:一个是通用的方法,另外一个是特殊的方法,也就是硬件方法,使用MCU自带的硬件指令来实现。
为0,使用通用方法计算下一个要运行的任务;为1,使用硬件方法计算下一个要运行的任务。
(31)configUSE_PREEMPTION
为1时,使用抢占式调度器;为0时,使用协程。
如果使用抢占式调度器,则内核会在每个时钟节拍中断中进行任务切换;使用协程时会在如下的地方进行任务切换:任务调用了函数taskYIELD()、任务调用了可以使任务进入阻塞态的API函数、应用程序明确定义了在中断中执行上下文切换。
(32)configUSE_QUEUE_SETS
为1时,启用队列集功能。
(33)configUSE_RECURSIVE_MUTEXES
为1时使用递归互斥信号量,相关的API函数会被编译。
(34)configUSE_STATS_FORMATTING_FUNCTIONS
宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS都为1时,函数vTaskList()和vTaskGetRunTimeStats()会被编译。
(35)configUSE_TASK_NOTIFICATIONS
为1时使用任务通知功能,相关的API函数会被编译。开启了此功能的话,每个任务会多消耗8个字节。
(36)configUSE_TICK_HOOK
为1时使能时间片钩子函数,用户需要实现时间片钩子函数,函数原型如下:void vApplicationTickHook(void)
(37)configUSE_TICKLESS_IDLE
为1时使能低功耗tickless模式。
(38)configUSE_TIMERS
为1时使用软件定时器,相关的API函数会被编译。
当宏configUSE_TIMERS为1的话,宏configTIMER_TASK_PRIORITY、configTIMER_QUEUE_LENGTH和configTIMER_TASK_STACK_DEPTH必须定义。
(39)configUSE_TIME_SLICING
默认情况下,FreeRTOS使用抢占式调度器,这意味着调度器永远都在执行已经就绪了的最高优先级的任务,优先级相同的任务在时钟节拍中断中进行切换。当宏configUSE_TIME_SLICING为0时,不会在时钟节拍中断中执行相同优先级任务的任务切换。默认情况下宏configUSE_TIME_SLICING为1。
(40)configUSE_TRACE_FACILITY
为1时启用可视化跟踪调试,则会增加一些结构体成员和API函数。
4.条件编译后说
FreeRTOS中的裁剪和配置就是用这种条件编译的方法来实现的,很多协议栈、RTOS系统和GUI库等也都是使用条件编译的方法来完成配置和裁剪的。
条件编译的好处就是节省空间,不需要的功能就不编译,这样可以根据实际需求来减少系统占用的ROM和RAM大小,根据自己使用的MCU来调整系统功耗,降低成本。