1-FreeRTOSConfig.h介绍
FreeRTOS中的相关定义多数都在FreeRTOSConfig.h中,整个FreeRTOS的定义调用都可以在这里定义,当然你也可以自己命名一个文件实现自定义。
下面是这个文件的内容,如下:
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* Here is a good place to include header files that are required across
your application. */
#include "something.h"
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configUSE_TICKLESS_IDLE 0
#define configCPU_CLOCK_HZ 60000000
#define configSYSTICK_CLOCK_HZ 1000000
#define configTICK_RATE_HZ 250
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE 128
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3
#define configUSE_MUTEXES 0
#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_COUNTING_SEMAPHORES 0
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE 10
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
#define configUSE_MINI_LIST_ITEM 1
#define configSTACK_DEPTH_TYPE uint16_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
#define configHEAP_CLEAR_MEMORY_ON_FREE 1
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE 10240
#define configAPPLICATION_ALLOCATED_HEAP 1
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 1
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configUSE_SB_COMPLETED_CALLBACK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 3
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
/* Define to trap errors during development. */
#define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )
/* FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
#define configTOTAL_MPU_REGIONS 8 /* Default value. */
#define configTEX_S_C_B_FLASH 0x07UL /* Default value. */
#define configTEX_S_C_B_SRAM 0x07UL /* Default value. */
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1
#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1
#define configENABLE_ERRATA_837070_WORKAROUND 1
/* ARMv8-M secure side port related definitions. */
#define secureconfigMAX_SECURE_CONTEXTS 5
/* Optional functions - most linkers will remove unused functions anyway. */
#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_uxTaskGetStackHighWaterMark2 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
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */
下面我们就来对上面的定义进行一些简单的说明。
2- 定义说明
2.1 configUSE_PREEMPTION
这个表示是否启用调度函数,1表示使用抢占式RTOS调度程序,0是表示使用协程RTOS调度程序
2.2 configUSE_PORT_OPTIMISED_TASK_SELECTION
FreeRTOS端口有两种方法来选择要执行的下一个任务——通用方法和特定于该端口的方法。
如下:
1-通用方式
- 当configUSE_PORT_OPTIMISED_TASK_SELECTION为0时使用,或者未实现特定于端口的方法时使用。
- 可以与所有FreeRTOS端口一起使用。
- 完全是用C编写的,使其效率低于特定于端口 方法
- 没有优先级最大数量的限制
2-特定方式 - 不是所有的端口都可用
- configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1时使用。
- 依赖于一个或多个特定于体系结构的汇编指令(通常是前导零计数[CLZ]或等效指令),因此只能用于专门为其编写的体系结构。
- 比通用方式更有效
- 通常对可用优先级的最大数量限制在32。
2.3 configUSE_TICKLESS_IDLE
如果configUSE_TICKLESS_IDLE设置为1,将启用无时钟低功耗模式,设置为0则是始终保持时钟周期中断运行。但是低功耗无时钟不是所有的RTOS端口都提供的。
2.4 configUSE_IDLE_HOOK
设置1表示启动钩子函数,0表示不使用
当RTOS调度器开始工作后,为了保证至少有一个任务在运行,空闲任务被自动创建,占用最低优先级(0优先级)。对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。因此,在应用中应该注意,使用vTaskDelete()函数时要确保空闲任务获得一定的处理器时间。除此之外,空闲任务没有其它特殊功能,因此可以任意的剥夺空闲任务的处理器时间。
应用程序也可能和空闲任务共享同个优先级。
空闲任务钩子是一个函数,这个函数由用户来实现,RTOS规定了函数的名字和参数,这个函数在每个空闲任务周期都会被调用。
2.5 configUSE_MALLOC_FAILED_HOOK
每次创建任务、队列或信号量时,内核都会调用pvPortMalloc()从堆中分配内存。官方的FreeRTOS为此提供了四个示例内存分配方案。这些方案分别在heap_1.c、heap_2.c、heap_3.c、heap_4.c和heap_5.c源文件中实现。configUSE_MALLOC_FAILED_HOOK仅在使用这三个示例方案之一时才有意义。
如果定义并正确配置malloc()失败钩子函数,则这个函数会在pvPortMalloc()函数返回NULL时被调用。只有FreeRTOS在响应内存分配请求时发现堆内存不足才会返回NULL。
如果宏configUSE_MALLOC_FAILED_HOOK设置为1,那么必须定义一个malloc()失败钩子函数,如果宏configUSE_MALLOC_FAILED_HOOK设置为0,malloc()失败钩子函数不会被调用,即便已经定义了这个函数。malloc()失败钩子函数的函数名和原型必须如下所示:
void vApplicationMallocFailedHook( void );
2.6 configUSE_DAEMON_TASK_STARTUP_HOOK
如果configUSE_TIMERS和configUSE_DAEMON_TASK_STARTUP_HOOK都被设置为1,那么应用程序必须定义一个具有确切名称和原型的钩子函数,如下所示。
void void vApplicationDaemonTaskStartupHook( void );
当RTOS守护任务(也称为定时器服务任务)第一次执行时,钩子函数将被精确地调用一次。任何需要运行RTOS的应用程序初始化代码都可以放在钩子函数中。
2.7 configUSE_SB_COMPLETED_CALLBACK
在构建中设置configUSE_SB_COMPLETED_CALLBACK()、xStreamBufferCreateWithCallback()和xStreamBufferCreateStaticWithCallback()(以及它们的消息缓冲区)。使用这些函数创建的流和消息缓冲区可以有自己独特的发送完整和接收完整回调,而使用xStreamBufferCreate()和xStreamBufferCreateStatic()(以及它们的消息缓冲区等效物)创建的流和消息缓冲区都共享由sbSEND_COMPLETED()和sbRECEVE_COMPLETED()宏定义的回调。configUSE_SB_COMPLETED_CALLBACK默认为0,以便向后兼容。
2.8 configUSE_TICK_HOOK
为1使用时间片钩子(Tick Hook),0不适用时间片钩子。
注:时间片钩子函数(Tick Hook Function)
时间片中断可以周期性的调用一个被称为钩子函数(回调函数)的应用程序。时间片钩子函数可以很方便的实现一个定时器功能。
只有在FreeRTOSConfig.h中的configUSE_TICK_HOOK设置成1时才可以使用时间片钩子。一旦此值设置成1,就要定义钩子函数,函数名和参数如下所示:
void vApplicationTickHook( void );
vApplicationTickHook()函数在中断服务程序中执行,因此这个函数必须非常短小,不能大量使用堆栈,只能调用以”FromISR" 或 "FROM_ISR”结尾的API函数。
在FreeRTOSVx.x.x\FreeRTOS\Demo\Common\Minimal文件夹下的crhook.c文件中有使用时间片钩子函数的例程。
2.9 configCPU_CLOCK_HZ
输入驱动用于生成tick中断的外围设备的内部时钟将执行的频率(Hz)——这通常与驱动内部CPU时钟的时钟相同。要想准确的配置系统节拍这个是必须要设置的。
2.10 configSYSTICK_CLOCK_HZ
仅用于ARM Cortex-M端口。
默认情况下,ARM Cortex-M端口从Cortex-M SysTick定时器生成RTOS tick中断。大多数Cortex-M MCU以与MCU本身相同的频率运行SysTick定时器——在这种情况下,configSYSTICK_CLOCK_HZ不需要定义。如果SysTick定时器的时钟频率与MCU核心不同,则将configCPU_CLOCK_HZ设置为MCU时钟频率,正常情况下,将configSYSTICK_CLOCK_HZ设置为SysTick时钟频率。
2.11 configTICK_RATE_HZ
实时操作系统时钟周期中断的频率。
系统节拍中断用来测量时间,因此,越高的测量频率意味着可测到越高的分辨率时间。但是,高的系统节拍中断频率也意味着RTOS内核占用更多的CPU时间,因此会降低效率。RTOS演示例程都是使用系统节拍中断频率为1000HZ,这是为了测试RTOS内核,比实际使用的要高。(实际使用时不用这么高的系统节拍中断频率)
多个任务可以共享一个优先级,RTOS调度器为相同优先级的任务分享CPU时间,在每一个RTOS 系统节拍中断到来时进行任务切换。高的系统节拍中断频率会降低分配给每一个任务的“时间片”持续时间。
2.12 configMAX_PRIORITIES
配置应用程序有效的优先级数目。任何数量的任务都可以共享一个优先级,使用协程可以单独的给与它们优先权。见configMAX_CO_ROUTINE_PRIORITIES。
配置应用程序有效的优先级数目。任何数量的任务都可以共享一个优先级,使用协程可以单独的给与它们优先权。见configMAX_CO_ROUTINE_PRIORITIES。
每一个任务都会被分配一个优先级,优先级值从0~ (configMAX_PRIORITIES - 1)之间。低优先级数表示低优先级任务。空闲任务的优先级为0(tskIDLE_PRIORITY),因此它是最低优先级任务。
FreeRTOS调度器将确保处于就绪状态(Ready)或运行状态(Running)的高优先级任务比同样处于就绪状态的低优先级任务优先获取处理器时间。换句话说,处于运行状态的任务永远是高优先级任务。
处于就绪状态的相同优先级任务使用时间片调度机制共享处理器时间。
2.13 configMINIMAL_STACK_SIZE
定义空闲任务使用的堆栈大小。通常此值不应小于对应处理器演示例程文件FreeRTOSConfig.h中定义的数值。
就像xTaskCreate()函数的堆栈大小参数一样,堆栈大小不是以字节为单位而是以字为单位的,比如在32位架构下,栈大小为100表示栈内存占用400字节的空间(每32位消耗4个字节,一个字节等于8位)。
2.14 configMAX_TASK_NAME_LEN
调用任务函数时,需要设置描述任务信息的字符串,这个宏用来定义该字符串的最大长度。这里定义的长度包括字符串结束符’\0’。
2.15 configUSE_TRACE_FACILITY
设置成1表示启动可视化跟踪调试,会激活一些附加的结构体成员和函数。
2.16 configUSE_STATS_FORMATTING_FUNCTIONS
设置宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS为1会编译vTaskList()和vTaskGetRunTimeStats()函数。如果将这两个宏任意一个设置为0,上述两个函数不会被编译。
2.17 configUSE_16_BIT_TICKS
定义系统节拍计数器的变量类型,即定义TickType_t是表示16位变量还是32位变量。
定义configUSE_16_BIT_TICKS为1意味着TickType_t被定义为16位无符号整形,定义configUSE_16_BIT_TICKS为0意味着TickType_t被定义为32位无符号整形。
使用16位类型可以大大提高8位和16位架构微处理器的性能,但这也限制了最大时钟计数为65535个’Tick’。因此,如果Tick频率为250HZ(4MS中断一次),对于任务最大延时或阻塞时间,16位计数器是262秒,而32位是17179869秒。
2.18 configIDLE_SHOULD_YIELD
这个参数控制任务在空闲优先级中的行为。仅在满足下列条件后,才会起作用。
- 使用抢占式内核调度
- 用户任务使用空闲优先级。
通过时间片共享同一个优先级的多个任务,如果共享的优先级大于空闲优先级,并假设没有更高优先级任务,这些任务应该获得相同的处理器时间。
但如果共享空闲优先级时,情况会稍微有些不同。当configIDLE_SHOULD_YIELD为1时,其它共享空闲优先级的用户任务就绪时,空闲任务立刻让出CPU,用户任务运行,这样确保了能最快响应用户任务。处于这种模式下也会有不良效果(取决于你的程序需要),如下所示:
图中描述了四个处于空闲优先级的任务,任务A、B和C是用户任务,任务I是空闲任务。上下文切换周期性的发生在T0、T1…T6时刻。当用户任务运行时,空闲任务立刻让出CPU,但是,空闲任务已经消耗了当前时间片中的一定时间。这样的结果就是空闲任务I和用户任务A共享一个时间片。用户任务B和用户任务C因此获得了比用户任务A更多的处理器时间。
这种情况可以通过以下方式避免:
1-创建的用户优先级大于空闲任务的优先级。
2-如果可以的话,使用空闲钩子函数将处于空闲优先级的各独立任务进行代替。
3-configIDLE_SHOULD_YIELD设置为0。
设置configIDLE_SHOULD_YIELD为0将阻止空闲任务为用户任务让出CPU,直到空闲任务的时间片结束。这确保所有处在空闲优先级的任务分配到相同多的处理器时间,但是,这是以分配给空闲任务更高比例的处理器时间为代价的。
2.19 configUSE_TASK_NOTIFICATIONS
设置宏configUSE_TASK_NOTIFICATIONS为1(或不定义宏configUSE_TASK_NOTIFICATIONS)将会开启任务通知功能,有关的API函数也会被编译。设置宏configUSE_TASK_NOTIFICATIONS为0则关闭任务通知功能,相关API函数也不会被编译。默认这个功能是开启的。开启后,每个任务多增加8字节RAM。
每个RTOS任务具有一个32位的通知值,RTOS任务通知相当于直接向任务发送一个事件,接收到通知的任务可以解除任务的阻塞状态(因等待任务通知而进入阻塞状态)。相对于以前必须分别创建队列、二进制信号量、计数信号量或事件组的情况,使用任务通知显然更灵活。更好的是,相比于使用信号量解除任务阻塞,使用任务通知可以快45%(使用GCC编译器,-o2优化级别)。
2.20 configTASK_NOTIFICATION_ARRAY_ENTRIES
每个RTOS任务都有一个任务通知数组。configTASK_NOTIFICATION_ARRAY_ENTRIES设置数组中索引的数量。
在FreeRTOS V10.4.0之前,任务只有一个通知值,而不是一个值数组,因此为了向后兼容,如果不定义configTASK_NOTIFICATION_ARRAY_ENTRIES,则默认为1。
2.21 configUSE_MUTEXES
设置为1表示使用互斥量,设置成0表示忽略互斥量。读者应该了解在FreeRTOS中互斥量和二进制信号量的区别。
关于互斥量和二进制信号量简单说:
互斥型信号量必须是同一个任务申请,同一个任务释放,其他任务释放无效。
二进制信号量,一个任务申请成功后,可以由另一个任务释放。
互斥型信号量是二进制信号量的子集
2.22 configUSE_RECURSIVE_MUTEXES
设置成1表示使用递归互斥量,设置成0表示不使用。
2.23 configUSE_COUNTING_SEMAPHORES
设置成1表示使用计数信号量,设置成0表示不使用。
2.24 configUSE_ALTERNATIVE_API
设置为1表示在构建中包含计数信号量功能,设置为0表示在构建中忽略计数信号量功能。
需要注意:可代替的API已弃用,不应在新设计中使用
2.25 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 );
具体的前面已经介绍过这两种方法请查看:堆栈溢出保护
2.26 configQUEUE_REGISTRY_SIZE
队列记录有两个目的,都涉及到RTOS内核的调试:
- 它允许在调试GUI中使用一个队列的文本名称来简单识别队列;
- 包含调试器需要的每一个记录队列和信号量定位信息;
除了进行内核调试外,队列记录没有其它任何目的。
configQUEUE_REGISTRY_SIZE定义可以记录的队列和信号量的最大数目。如果你想使用RTOS内核调试器查看队列和信号量信息,则必须先将这些队列和信号量进行注册,只有注册后的队列和信号量才可以使用RTOS内核调试器查看。查看API参考手册中的vQueueAddToRegistry() 和vQueueUnregisterQueue()函数获取更多信息。
2.27 configUSE_QUEUE_SETS
设置成1使能队列集功能(可以阻塞、挂起到多个队列和信号量),设置成0取消队列集功能。
2.28 configUSE_TIME_SLICING
默认情况下(宏configUSE_TIME_SLICING未定义或者宏configUSE_TIME_SLICING设置为1),FreeRTOS使用基于时间片的优先级抢占式调度器。这意味着RTOS调度器总是运行处于最高优先级的就绪任务,在每个RTOS 系统节拍中断时在相同优先级的多个任务间进行任务切换。如果宏configUSE_TIME_SLICING设置为0,RTOS调度器仍然总是运行处于最高优先级的就绪任务,但是当RTOS 系统节拍中断发生时,相同优先级的多个任务之间不再进行任务切换。
2.29 configUSE_NEWLIB_REENTRANT
如果configUSE_NEWLIB_REENTRANT设置为1,那么将为每个创建的任务分配一个newlib结构。注意Newlib支持已经被广泛的需求所包含,但是FreeRTOS维护者自己并没有使用它。FreeRTOS不负责产生的newlib操作。用户必须熟悉newlib,并且必须提供必要存根的系统范围实现。请注意(在撰写本文时)当前的newlib设计实现了一个系统范围的malloc(),必须为其提供锁。
2.30 configENABLE_BACKWARD_COMPATIBILITY
头文件FreeRTOS.h包含一系列#define宏定义,用来映射版本V8.0.0和V8.0.0之前版本的数据类型名字。这些宏可以确保RTOS内核升级到V8.0.0或以上版本时,之前的应用代码不用做任何修改。在FreeRTOSConfig.h文件中设置宏configENABLE_BACKWARD_COMPATIBILITY为0会去掉这些宏定义,并且需要用户确认升级之前的应用没有用到这些名字。
2.31 configNUM_THREAD_LOCAL_STORAGE_POINTERS
设置每个任务的线程本地存储指针数组大小。
后面会介绍。
2.32 configUSE_MINI_LIST_ITEM
MiniListItem_t用于FreeRTOS列表中的开始和结束标记节点,ListItem_t用于FreeRTOS列表中的所有其他节点。当configUSE_MINI_LIST_ITEM设置为0时,minilisttem_t和ListItem_t都是相同的。当configUSE_MINI_LIST_ITEM设置为1时,minilisttem_t包含的字段比ListItem_t少3个,这节省了一些RAM,但代价是违反了一些编译器用于优化的严格别名规则。如果未定义,configUSE_MINI_LIST_ITEM默认为1,以便向后兼容。
2.33 configSTACK_DEPTH_TYPE
设置用于在调用xTaskCreate()时指定堆栈深度的类型,以及使用堆栈大小的各种其他位置(例如,当返回堆栈高水位标记时)。旧版本的FreeRTOS使用UBaseType_t类型的变量指定堆栈大小,但发现这在8位微控制器上限制太大。configSTACK_DEPTH_TYPE允许应用程序开发人员指定要使用的类型,从而消除了这种限制。
2.34 configMESSAGE_BUFFER_LENGTH_TYPE
FreeRTOS消息缓冲区使用configMESSAGE_BUFFER_LENGTH_TYPE类型的变量来存储每个消息的长度。如果configMESSAGE_BUFFER_LENGTH_TYPE没有定义,那么它将默认为size_t。如果存储在消息缓冲区中的消息永远不会超过255字节,那么定义configMESSAGE_BUFFER_LENGTH_TYPE为uint8_t将在32位微控制器上为每条消息节省3字节。同样,如果存储在消息缓冲区中的消息永远不会超过65535字节,那么定义configMESSAGE_BUFFER_LENGTH_TYPE为uint16_t将在32位微控制器上为每条消息节省2字节。
2.35 configSUPPORT_STATIC_ALLOCATION
如果configSUPPORT_STATIC_ALLOCATION设置为1,则可以使用应用程序编写人员提供的RAM创建RTOS对象。如果configSUPPORT_STATIC_ALLOCATION设置为0,那么RTOS对象只能使用从FreeRTOS堆分配的RAM创建。如果configSUPPORT_STATIC_ALLOCATION未定义,它将默认为0。如果configSUPPORT_STATIC_ALLOCATION设置为1,那么应用程序编写器还必须提供两个回调函数:vApplicationGetIdleTaskMemory()为RTOS空闲任务提供内存,以及(如果configUSE_TIMERS设置为1)vApplicationGetTimerTaskMemory()为RTOS守护进程/定时器服务任务提供内存。示例如下。
/* 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;
}
Examples of the callback functions that must be provided by the application to
supply the RAM used by the Idle and Timer Service tasks if configSUPPORT_STATIC_ALLOCATION
is set to 1.
2.36 configSUPPORT_DYNAMIC_ALLOCATION
如果configSUPPORT_DYNAMIC_ALLOCATION设置为1,那么可以使用从FreeRTOS堆中自动分配的RAM创建RTOS对象。如果configSUPPORT_DYNAMIC_ALLOCATION设置为0,那么RTOS对象只能使用应用程序编写者提供的RAM创建。如果configSUPPORT_DYNAMIC_ALLOCATION未定义,它将默认为1。
2.37 configTOTAL_HEAP_SIZE
FreeRTOS堆中可用的RAM总量。当configSUPPORT_DYNAMIC_ALLOCATION被设置为1。会启用堆得设置,当然前提是必须使用FreeRTOS库中那5个内存分配之一中的一个。
2.38 configAPPLICATION_ALLOCATED_HEAP
默认情况下,FreeRTOS堆由FreeRTOS声明,并由链接器放置在内存中。将configAPPLICATION_ALLOCATED_HEAP设置为1允许由应用程序编写器声明堆,这允许应用程序编写器将堆放置在内存中的任何位置。如果heap_1.c, heap_2.c或heap_4.c被使用,并且configAPPLICATION_ALLOCATED_HEAP被设置为1,那么应用程序作者必须提供一个精确的uint8_t数组,其名称和尺寸如下所示。该数组将被用作FreeRTOS堆。
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
2.39 configSTACK_ALLOCATION_FROM_SEPARATE_HEAP
如果configSTACK_ALLOCATION_FROM_SEPARATE_HEAP设置为1,则使用xTaskCreate或xTaskCreateRestricted API创建的任何任务的堆栈将使用pvPortMallocStack分配,并使用vPortFreeStack函数释放。用户需要提供pvPortMallocStack和vPortFreeStack函数的线程安全实现。这使得用户可以从一个单独的内存区域(可能是另一个不同于FreeRTOS堆的堆)为任务分配堆栈。如果configSTACK_ALLOCATION_FROM_SEPARATE_HEAP未定义,它将默认为0。pvPortMallocStack和vPortFreeStack函数的实现示例如下:
void * pvPortMallocStack( size_t xWantedSize )
{
/* Allocate a memory block of size xWantedSize. The function used for
* allocating memory must be thread safe. */
return MyThreadSafeMalloc( xWantedSize );
}
void vPortFreeStack( void * pv )
{
/* Free the memory previously allocated using pvPortMallocStack. The
* function used for freeing the memory must be thread safe. */
MyThreadSafeFree( pv );
}
2.40 configGENERATE_RUN_TIME_STATS
1- 设置宏configGENERATE_RUN_TIME_STATS为1使能运行时间统计功能。一旦设置为1,则下面两个宏必须被定义:
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():用户程序需要提供一个基准时钟函数,函数完成初始化基准时钟功能,这个函数要被define到宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()上。这是因为运行时间统计需要一个比系统节拍中断频率还要高分辨率的基准定时器,否则,统计可能不精确。基准定时器中断频率要比统节拍中断快10~100倍。基准定时器中断频率越快,统计越精准,但能统计的运行时间也越短(比如,基准定时器10ms中断一次,8位无符号整形变量可以计到2.55秒,但如果是1秒中断一次,8位无符号整形变量可以统计到255秒)。
2-portGET_RUN_TIME_COUNTER_VALUE():用户程序需要提供一个返回基准时钟当前“时间”的函数,这个函数要被define到宏portGET_RUN_TIME_COUNTER_VALUE()上。
2.41 configUSE_CO_ROUTINES
设置成1表示使用协程,0表示不使用协程。如果使用协程,必须在工程中包含croutine.c文件。
注:协程(Co-routines)主要用于资源发非常受限的嵌入式系统(RAM非常少),通常不会用于32位微处理器。
在当前嵌入式硬件环境下,不建议使用协程,FreeRTOS的开发者早已经停止开发协程。
2.42 configMAX_CO_ROUTINE_PRIORITIES
应用程序协程(Co-routines)的有效优先级数目,任何数目的协程都可以共享一个优先级。使用协程可以单独的分配给任务优先级。见configMAX_PRIORITIES。
2.43 configUSE_TIMERS
设置成1使用软件定时器,为0不使用软件定时器功能。详细描述见FreeRTOS software timers 。
2.44 configTIMER_TASK_PRIORITY
设置软件定时器服务/守护进程的优先级。详细描述见FreeRTOS software timers 。
2.45 configTIMER_QUEUE_LENGTH
设置软件定时器命令队列的长度。详细描述见FreeRTOS software timers。
2.46 configTIMER_TASK_STACK_DEPTH
2.47 configKERNEL_INTERRUPT_PRIORITY、configMAX_SYSCALL_INTERRUPT_PRIORITY 、configMAX_API_CALL_INTERRUPT_PRIORITY
Cortex-M3、PIC24、dsPIC、PIC32、SuperH和RX600硬件设备需要设置宏configKERNEL_INTERRUPT_PRIORITY;PIC32、RX600和Cortex-M硬件设备需要设置宏configMAX_SYSCALL_INTERRUPT_PRIORITY。
configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY,这两个宏是等价的,后者是前者的新名字,用于更新的移植层代码。
注意下面的描述中,在中断服务例程中仅可以调用以“FromISR”结尾的API函数。
仅需要设置configKERNEL_INTERRUPT_PRIORITY的硬件设备(也就是宏configMAX_SYSCALL_INTERRUPT_PRIORITY不会用到):configKERNEL_INTERRUPT_PRIORITY用来设置RTOS内核自己的中断优先级。调用API函数的中断必须运行在这个优先级;不调用API函数的中断,可以运行在更高的优先级,所以这些中断不会被因RTOS内核活动而延时。
configKERNEL_INTERRUPT_PRIORITY和configMAX_SYSCALL_INTERRUPT_PRIORITY都需要设置的硬件设备:configKERNEL_INTERRUPT_PRIORITY用来设置RTOS内核自己的中断优先级。因为RTOS内核中断不允许抢占用户使用的中断,因此这个宏一般定义为硬件最低优先级。configMAX_SYSCALL_INTERRUPT_PRIORITY用来设置可以在中断服务程序中安全调用FreeRTOS API函数的最高中断优先级。优先级小于等于这个宏所代表的优先级时,程序可以在中断服务程序中安全的调用FreeRTOS API函数;如果优先级大于这个宏所代表的优先级,表示FreeRTOS无法禁止这个中断,在这个中断服务程序中绝不可以调用任何API函数。
通过设置configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级级别高于configKERNEL_INTERRUPT_PRIORITY可以实现完整的中断嵌套模式。这意味着FreeRTOS内核不能完全禁止中断,即使在临界区。此外,这对于分段内核架构的微处理器是有利的。请注意,当一个新中断发生后,某些微处理器架构会(在硬件上)禁止中断,这意味着从硬件响应中断到FreeRTOS重新使能中断之间的这段短时间内,中断是不可避免的被禁止的。
不调用API的中断可以运行在比configMAX_SYSCALL_INTERRUPT_PRIORITY高的优先级,这些级别的中断不会被FreeRTOS禁止,因此不会因为执行RTOS内核而被延时。
例如:假如一个微控制器有8个中断优先级别:0表示最低优先级,7表示最高优先级(Cortex-M3和Cortex-M4内核优先数和优先级别正好与之相反,后续文章会专门介绍它们)。当两个配置选项分别为4和0时,下图描述了每一个优先级别可以和不可做的事件:
这些配置参数允许非常灵活的中断处理:
在系统中可以像其它任务一样为中断处理任务分配优先级。这些任务通过一个相应中断唤醒。中断服务例程(ISR)内容应尽可能的精简—仅用于更新数据然后唤醒高优先级任务。ISR退出后,直接运行被唤醒的任务,因此中断处理(根据中断获取的数据来进行的相应处理)在时间上是连续的,就像ISR在完成这些工作。这样做的好处是当中断处理任务执行时,所有中断都可以处在使能状态。
中断、中断服务例程(ISR)和中断处理任务是三码事:当中断来临时会进入中断服务例程,中断服务例程做必要的数据收集(更新),之后唤醒高优先级任务。这个高优先级任务在中断服务例程结束后立即执行,它可能是其它任务也可能是中断处理任务,如果是中断处理任务,那么就可以根据中断服务例程中收集的数据做相应处理。
configMAX_SYSCALL_INTERRUPT_PRIORITY接口有着更深一层的意义:在优先级介于RTOS内核中断优先级(等于configKERNEL_INTERRUPT_PRIORITY)和configMAX_SYSCALL_INTERRUPT_PRIORITY之间的中断允许全嵌套中断模式并允许调用API函数。大于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断优先级绝不会因为执行RTOS内核而延时。
运行在大于configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级中断是不会被RTOS内核所屏蔽的,因此也不受RTOS内核功能影响。这主要用于非常高的实时需求中。比如执行电机转向。但是,这类中断的中断服务例程中绝不可以调用FreeRTOS的API函数。
为了使用这个方案,应用程序要必须符合以下规则:调用FreeRTOS API函数的任何中断,都必须和RTOS内核处于同一优先级(由宏configKERNEL_INTERRUPT_PRIORITY设置),或者小于等于宏configMAX_SYSCALL_INTERRUPT_PRIORITY定义的优先级。
2.48 configASSERT
configASSERT()宏的语义与标准的C assert()宏相同。如果传递给configASSERT()的参数为零,则会触发断言。configASSERT()在整个FreeRTOS源文件中被调用,以检查应用程序如何使用FreeRTOS。强烈建议在开发FreeRTOS应用程序时定义configASSERT()。示例定义(显示在文件顶部并在下面复制)调用vAssertCalled(),传入触发configASSERT()调用的文件名和行号(__FILE__和__LINE__是大多数编译器提供的标准宏)。这只是为了演示,因为vAssertCalled()不是一个FreeRTOS函数,可以定义configASSERT()来执行应用程序作者认为合适的任何操作。通常以这样一种方式定义configASSERT(),它将阻止应用程序进一步执行。这有两个原因;在断言点停止应用程序允许对断言的原因进行调试,并且在触发断言之后执行可能会导致崩溃。注意,定义configASSERT()将增加应用程序代码大小和执行时间。当应用程序稳定时,可以通过注释掉FreeRTOSConfig.h中的configASSERT()定义来消除额外的开销。
/* Define configASSERT() to call vAssertCalled() if the assertion fails. The assertion
has failed if the value of the parameter passed into configASSERT() equals zero. */
#define configASSERT ( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )
如果在调试器的控制下运行FreeRTOS,则可以将configASSERT()定义为仅禁用中断并处于循环中,如下所示。这将有停止在断言测试失败的行上的代码的效果-暂停调试器将立即带您到有问题的行,以便您可以看到它失败的原因。
/* Define configASSERT() to disable interrupts and sit in a loop. */
#define configASSERT ( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
2.49 configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS
configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS只被FreeRTOSMPU使用。如果configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS设置为1,那么应用程序编写器必须提供一个名为“application_defined_privileged_functions.h”的头文件,在这个头文件中,应用程序编写器需要在特权模式下执行的函数可以实现。注意,尽管头文件的扩展名是.h,但它应该包含C函数的实现,而不仅仅是函数的原型。在"application_defined_privileged_functions.h"中实现的函数必须分别使用prvRaisePrivilege()函数和portRESET_PRIVILEGE()宏保存和恢复处理器的特权状态。例如,如果提供打印函数的库访问的RAM不在应用程序编写人员的控制范围内,因此不能分配给受内存保护的用户模式任务,则可以使用以下代码将打印函数封装在特权函数中:
void MPU_debug_printf( const char *pcMessage )
{
/* State the privilege level of the processor when the function was called. */
BaseType_t xRunningPrivileged = prvRaisePrivilege();
/* Call the library function, which now has access to all RAM. */
debug_printf( pcMessage );
/* Reset the processor privilege level to its original value. */
portRESET_PRIVILEGE( xRunningPrivileged );
}
2.50 configTOTAL_MPU_REGIONS
用于ARM Cortex-M4微控制器的FreeRTOS MPU(内存保护单元)端口支持16个MPU区域的设备。对于有16个MPU区域的设备,将“configTOTAL_MPU_REGIONS”设置为“16”。如果未定义,则默认为8。
2.51 configTEX_S_C_B_FLASH
TEX, Shareable (S), Cacheable ©和buffable (B)位定义了内存类型,必要时还定义了MPU区域的可缓存和可共享属性。configTEX_S_C_B_FLASH允许应用程序编写者重写用于MPU区域覆盖Flash的for TEX,共享(S),可缓存©和可缓冲(B)位的默认值。如果未定义,它默认为0x07UL,这意味着TEX=000, S=1, C=1, B=1。
2.52 configTEX_S_C_B_SRAM
TEX, Shareable (S), Cacheable ©和buffable (B)位定义了内存类型,必要时还定义了MPU区域的可缓存和可共享属性。configTEX_S_C_B_SRAM允许应用程序编写人员覆盖覆盖RAM的MPU区域的for TEX,可共享(S),可缓存©和可缓冲(B)位的默认值。如果未定义,它默认为0x07UL,这意味着TEX=000, S=1, C=1, B=1。
2.53 configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
configenfort_system_calls_from_kernel_only可以定义为1,以防止任何来自内核代码外部的特权升级(当进入中断时由硬件本身执行的升级除外)。当FreeRTOSConfig.h中的configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY设置为1时,需要从链接器脚本中导出变量__syscalls_flash_start__和__syscalls_flash_end__,分别表示系统调用内存的起始地址和结束地址。为了获得最大的安全性,建议将其定义为1。
2.54 configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS
ARMv7-M MPU端口(ARM Cortex-M3/4/7)。设置为0以防止非特权应用程序任务使用taskENTER_CRITICAL()宏创建临界区。将该常量设置为1,或不定义,以允许特权任务和非特权任务创建临界区。注意:建议将此常量定义为0以获得最大的安全性;因此,如果常量未定义,则会输出编译器警告。
2.55 configENABLE_ERRATA_837070_WORKAROUND
仅支持Cortex-M4d的MPU。
当使用Cortex-M7 r0p0/r0p1内核上的Cortex-M4 MPU端口时,将configENABLE_ERRATA_837070_WORKAROUND设置为1,以确保ARM errata 837070所需的workaround处于激活状态。
2.56 configHEAP_CLEAR_MEMORY_ON_FREE
如果设置为1,则使用pvPortMalloc()分配的内存块将在使用vPortFree()释放时被清除。如果未定义,为了向后兼容性,configHEAP_CLEAR_MEMORY_ON_FREE默认为0。为了更好的安全性,我们建议将configHEAP_CLEAR_MEMORY_ON_FREE设置为1。
2.57 secureconfigMAX_SECURE_CONTEXTS
仅限ARMv8-M安全侧端口。从ARMv8-M MCU的非安全端(ARM Cortex-M23, Cortex-M33和Cortex-M55)调用安全函数的任务有两个上下文——一个在非安全端,一个在安全端。在FreeRTOS v10.4.5之前,ARMv8-M安全端端口在运行时分配了引用安全端上下文的结构。从FreeRTOS V10.4.5开始,结构是在编译时静态分配的。secureconfigMAX_SECURE_CONTEXTS设置静态分配的安全上下文的数量。如果未定义,secureconfigMAX_SECURE_CONTEXTS默认为8。仅在ARMv8-M微控制器的非安全端使用FreeRTOS代码的应用程序,例如在安全端运行第三方代码的应用程序,不需要此常量。
2.58 INCLUDE Parameters
以’INCLUDE’开头的宏允许将应用程序未使用的实时内核组件从构建中排除。这确保RTOS不会使用超出特定嵌入式应用程序所需的ROM或RAM。
每个宏以这样的形式出现:
INCLUDE_FunctionName
在这里FunctionName表示一个你可以控制是否编译的API函数。如果你想使用该函数,就将这个宏设置成1,如果不想使用,就将这个宏设置成0。比如,对于API函数vTaskDelete():
#define INCLUDE_vTaskDelete 1
表示希望使用vTaskDelete(),允许编译器编译该函数
#define INCLUDE_vTaskDelete 0