- FreeRTOS内核剪裁配置文件是FreeRTOSConfig.h
- FreeRTOSConfig.h前部分是一些CPU、调度算法等配置,后部分是中断配置
- FreeRTOSConfig.h的中断配置使得FreeRTOS系统可以理会和不理会某些中断
1. configUSE_PREEMPTION
为 1 时RTOS使用抢占式调度器,即当进程位于内核空间时,有一个更高优先级的任务出现时,如果当前内核允许抢占,则可以将当前任务挂起,执行优先级更高的进程;为 0 时RTOS使用协作式调度器(时间片)高优先级的进程不能中止正在内核中运行的低优先级的进程而抢占CPU运行。。
2. configUSE_PORT_OPTIMISED_TASK_SELECTION
某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:通用方法和特定于硬件的方法。
通用方法:
configUSE_PORT_OPTIMISED_TASK_SELECTION设置为 0 或者 没有实现端口特定方法时,将显式或者隐式使用***通用方法***。
可以用于所有FreeRTOS支持的硬件。
完全用C实现,效率略低于特殊方法。
不强制要求限制最大可用优先级数量。
特定硬件方法:并非所有硬件都支持。
必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为 1 。
依赖于一个或多个架构特定汇编指令(通常为计数前导零(CLZ)或等效指令),因此只能与其专门编写的体系结构一起使用。
比通用方法更有效率。
一般强制限定最大可用优先级数目为32。
3. configUSE_TICKLESS_IDLE
设置configUSE_TICKLESS_IDLE为 1,使能低功耗tickless模式;为 0 保持系统节拍(SysTick)中断一直运行。
4. configUSE_IDLE_HOOK
设置为1使用空闲钩子(类似于回调函数),0忽略空闲钩子。
5. configUSE_MALLOC_FAILED_HOOK
每当一个任务、队列、信号量被创建时,内核使用一个名为pvPortMalloc()的函数来从堆中分配内存。官方的下载包中包含5个简单内存分配策略,分别保存在源文件heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c中。
仅当使用以上这五个简单策略之一时,这个宏才有意义。
如果定义并正确配置malloc()失败钩子函数,则这个函数会在pvPortMalloc()函数返回NULL时被调用。只有FreeRTOS在响应内存分配请求时发现堆内存不足才会返回NULL。
如果宏configUSE_MALLOC_FAILED_HOOK设置为1,那么必须定义一个malloc()失败钩子函数,如果宏configUSE_MALLOC_FAILED_HOOK设置为0,malloc()失败钩子函数不会被调用,即便已经定义了这个函数。malloc()失败钩子函数的函数名和原型必须如下所示:
void vApplicationMallocFailedHook( void);
6. configUSE_DAEMON_TASK_STARTUP_HOOK
如果configUSE_TIMERS和configUSE_DAEMON_TASK_STARTUP_HOOK都设置为1,那么应用程序必须定义一个钩子函数,其名称和原型如下所示:
void void vApplicationDaemonTaskStartupHook( void );
当RTOS守护程序任务(也称为定时器服务任务)第一次执行时,钩子函数将被精确调用一次。 需要RTOS运行的任何应用程序初始化代码都可以放在hook函数中。
7. configUSE_TICK_HOOK
设置为1使用时间片钩子(Tick Hook),0忽略时间片钩子。
8. configCPU_CLOCK_HZ
写入实际的CPU内核时钟频率,也就是CPU指令执行频率,通常称为Fcclk。配置此值是为了正确的配置系统节拍中断周期。
例如,在STM32中时,常用#define configCPU_CLOCK_HZ ( SystemCoreClock )
9. configTICK_RATE_HZ
RTOS 系统自己的节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度。
10. configMAX_PRIORITIES
配置应用程序有效的优先级数目。任何数量的任务都可以共享一个优先级,使用协程可以单独的给与它们优先权。见configMAX_CO_ROUTINE_PRIORITIES。
在RTOS内核中,每个有效优先级都会消耗一定量的RAM,因此这个值不要超过你的应用实际需要的优先级数目。
11. configMINIMAL_STACK_SIZE
定义空闲任务使用的堆栈大小。通常此值不应小于对应处理器演示例程文件FreeRTOSConfig.h中定义的数值。
就像xTaskCreate()和xTaskCreateStatic()函数的堆栈大小参数一样,堆栈大小不是以字节为单位而是以字为单位的,比如在32位架构下,栈大小为100表示栈内存占用400字节的空间。
12.configMAX_TASK_NAME_LEN
调用任务函数时,需要设置描述任务信息的字符串,这个宏用来定义该字符串的最大长度。这里定义的长度包括字符串结束符'\0'。
13.configUSE_TRACE_FACILITY
设置成1表示启动可视化跟踪调试,会激活一些附加的结构体成员和函数。
该配置通常在调试时才会使用,在真正发布程序时必须将其关闭,因为其对于FreeRTOS的性能是有影响的。
14.configUSE_STATS_FORMATTING_FUNCTIONS
设置宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS为1会编译vTaskList()和vTaskGetRunTimeStats()函数。如果将这两个宏任意一个设置为0,上述两个函数将被忽略。通常也是在调试时才使用,用来观察各任务。
15.configUSE_16_BIT_TICKS
时间是以“ticks”来衡量的 - 这是自RTOS内核启动以来tick事件中断已执行的次数。 tick计数保存在TickType_t类型的变量中。
将configUSE_16_BIT_TICKS定义为 1 会使TickType_t为无符号的16位类型定义(typedef’ed)。 将configUSE_16_BIT_TICKS定义为 0 会使TickType_t为无符号32位类型定义(typedef’ed)。
使用16位类型将大大提高8位和16位架构的性能,但将最大可指定时间限制为65535个“ticks”。 因此,假设节拍频率为250Hz,当使用16位计数器时,任务可以延迟或阻塞的最大时间为262秒,而使用32位计数器时为17179869秒。
16.configIDLE_SHOULD_YIELD
- 使用抢占式内核调度
- 用户任务使用空闲优先级。
通过时间片共享同一个优先级的多个任务,如果共享的优先级大于空闲优先级,并假设没有更高优先级任务,这些任务应该获得相同的处理器时间。
但如果共享空闲优先级时,情况会稍微有些不同。当configIDLE_SHOULD_YIELD为1时,其它共享空闲优先级的用户任务就绪时,空闲任务立刻让出CPU,用户任务运行,这样确保了能最快响应用户任务。处于这种模式下也会有不良效果(取决于你的程序需要),描述如下:
图中描述了四个处于空闲优先级的任务,任务A、B和C是用户任务,任务I是空闲任务。上下文切换周期性的发生在T0、T1…T6时刻。当用户任务运行时,空闲任务立刻让出CPU,但是,空闲任务已经消耗了当前时间片中的一定时间。这样的结果就是空闲任务I和用户任务A共享一个时间片。用户任务B和用户任务C因此获得了比用户任务A更多的处理器时间。
可以通过下面方法避免:
- 如果合适的话,将处于空闲优先级的各单独的任务放置到空闲钩子函数中;
- 创建的用户任务优先级大于空闲优先级;
- 设置IDLE_SHOULD_YIELD为0;
设置configIDLE_SHOULD_YIELD为0将阻止空闲任务为用户任务让出CPU,直到空闲任务的时间片结束。这确保所有处在空闲优先级的任务分配到相同多的处理器时间,但是,这是以分配给空闲任务更高比例的处理器时间为代价的。
17.configUSE_TASK_NOTIFICATIONS
设置宏configUSE_TASK_NOTIFICATIONS为1(或不定义宏configUSE_TASK_NOTIFICATIONS)将会开启任务通知功能,有关的API函数也会被编译。设置宏configUSE_TASK_NOTIFICATIONS为0则关闭任务通知功能,相关API函数也不会被编译。默认这个功能是开启的。
开启后,每个任务多增加8字节RAM。
18.configUSE_MUTEXES
设置为 1 表示使用互斥量,设置成0表示忽略互斥量。读者应该了解在FreeRTOS中互斥量和二进制信号量的区别。
关于互斥量和二进制信号量简单说:
互斥型信号量必须是同一个任务申请,同一个任务释放,其他任务释放无效。
二进制信号量,一个任务申请成功后,可以由另一个任务释放。
互斥型信号量是二进制信号量的子集。
19.configUSE_RECURSIVE_MUTEXES
设置成1表示使用递归互斥量,设置成0表示不使用。
20.configUSE_COUNTING_SEMAPHORES
设置成1表示使用计数信号量,设置成0表示不使用。
21.configUSE_ALTERNATIVE_API
设置成1表示使用“替代”队列函数(‘alternative’ queue functions),设置成0不使用。“替代”API在queue.h头文件中有详细描述。
22. configCHECK_FOR_STACK_OVERFLOW
每个任务维护自己的栈空间,任务创建时会自动分配任务需要的占内存,分配内存大小由创建任务函数(xTaskCreate())的一个参数指定。堆栈溢出是设备运行不稳定的最常见原因,因此FreeeRTOS提供了两个可选机制用来辅助检测和改正堆栈溢出。配置宏configCHECK_FOR_STACK_OVERFLOW为不同的常量来使用不同堆栈溢出检测机制。
注意,这个选项仅适用于内存映射未分段的微处理器架构。并且,在RTOS检测到堆栈溢出发生之前,一些处理器可能先产生故障(fault)或异常(exception)来反映堆栈使用的恶化。如果宏configCHECK_FOR_STACK_OVERFLOW没有设置成0,用户必须提供一个栈溢出钩子函数,这个钩子函数的函数名和参数必须如下所示:
void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName );
参数xTask和pcTaskName为堆栈溢出任务的句柄和名字。请注意,如果溢出非常严重,这两个参数信息也可能是错误的!在这种情况下,可以直接检查pxCurrentTCb变量。
推荐仅在开发或测试阶段使用栈溢出检查,因为堆栈溢出检测会增大上下文切换开销。
方法一:
任务切换出去后,该任务的上下文环境被保存到自己的堆栈空间,这时很可能堆栈的使用量达到了最大(最深)值。在这个时候,RTOS内核会检测堆栈指针是否还指向有效的堆栈空间。如果堆栈指针指向了有效堆栈空间之外的地方,堆栈溢出钩子函数会被调用。
这个方法速度很快,但是不能检测到所有堆栈溢出情况(比如,堆栈溢出没有发生在上下文切换时)。设置configCHECK_FOR_STACK_OVERFLOW为 1 会使用这种方法。
方法二:
当堆栈首次创建时,在它的堆栈区中填充一些已知值(标记)。当任务切换时,RTOS内核会检测堆栈最后的16个字节,确保标记数据没有被覆盖。如果这16个字节有任何一个被改变,则调用堆栈溢出钩子函数。
这个方法比第一种方法要慢,但也相当快了。它能有效捕捉堆栈溢出事件(即使堆栈溢出没有发生在上下文切换时),但是理论上它也不能百分百的捕捉到所有堆栈溢出(比如堆栈溢出的值和标记值相同,当然,这种情况发生的概率极小)。
使用这个方法需要设置configCHECK_FOR_STACK_OVERFLOW为 2 .
23.configQUEUE_REGISTRY_SIZE
通过此定义来设置可以注册的信号量和消息队列个数。队列记录有两个目的,都涉及到RTOS内核的调试:
- 注册队列的时候,可以给队列起一个名字,当使用调试组件的时候,通过名字可以很容易的区分不同队列。
- 包含调试器需要的每一个记录队列和信号量定位信息;
除了进行内核调试外,队列记录没有其它任何目的。
24.configUSE_QUEUE_SETS
设置成1使能队列集功能(可以阻塞、挂起到多个队列和信号量),设置成0取消队列集功能。
25.configUSE_TIME_SLICING
默认情况下,该宏会被定义为1。1 表示:FreeRTOS使用基于时间片的优先级抢占式调度器。这意味着FreeRTOS调度器总是运行处于最高优先级的就绪任务,在每个FreeRTOS 系统节拍中断时在相同优先级的多个任务间进行任务切换。 如果configUSE_TIME_SLICING设置为0,那么RTOS调度程序仍将运行处于就绪状态的最高优先级任务,但是不会因为发生滴答中断而在相同优先级的任务之间切换。
26.configUSE_NEWLIB_REENTRANT
设置为1,每一个创建的任务会分配一个newlib(一个嵌入式C库)reent结构。
27.configENABLE_BACKWARD_COMPATIBILITY
头文件FreeRTOS.h包含一系列#define宏定义,用来映射版本V8.0.0和V8.0.0之前版本的数据类型名字。这些宏可以确保RTOS内核升级到V8.0.0或以上版本时,之前的应用代码不用做任何修改。在FreeRTOSConfig.h文件中设置宏configENABLE_BACKWARD_COMPATIBILITY为0会去掉这些宏定义,并且需要用户确认升级之前的应用没有用到这些名字。
就是为了兼容之前的版本用的宏。例如:在之前的版本中,FreeRTOS的各种类型均为xAAA(如xSemaphoreHandle),在最新版中,均使用AAA_t(如SemaphoreHandle_t)。因此,在新项目中,最好使用FreeRTOS的最新的各种类型定义。具体如下:
#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 */
28. configNUM_THREAD_LOCAL_STORAGE_POINTERS
设置每个任务的线程本地存储指针数组大小。关于这部分的说明,详细参考Thread Local Storage Pointers