定制
[配置]
FreeRTOS 使用 FreeRTOSConfig.h 配置文件进行定制。 每个
FreeRTOS 应用程序必须在其预处理器的包含路径中包含 FreeRTOSConfig.h 头文件
。 FreeRTOSConfig.h 为正在构建的应用程序定制 RTOS 内核
。因此它是特定于应用程序的,而非 RTOS,并且应当
位于应用程序目录,而不是 RTOS 内核源代码目录
。
RTOS 源代码下载内容中的每个演示应用程序都有自己的
FreeRTOSConfig.h 文件。 一些演示版本比较旧,没有包含所有
可用的配置选项。 其中省略的配置选项
在 RTOS 源文件中被设置为默认值。
以下是一个典型的 FreeRTOSConfig.h 定义,后面是每个参数的解释
:
#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 */
'config' 参数
设置为 1,使用抢占式 RTOS 调度器;设置为 0,使用协同式 RTOS 调度器。
一些 FreeRTOS 移植有两种选择下一个执行任务的方法,一种是通用方法,
另一种是移植特定的方法。
通用方法:
-
在 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 0 时,或
没有实现移植特定的方法时使用。
-
可用于所有 FreeRTOS 移植。
-
完全使用 C 编写,比移植特定的方法低效
。
-
不限制可用优先级的最大数量。
移植特定的方法:
-
部分移植不可用。
-
当 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 1 时使用。
-
依赖于一种或多种架构特定的汇编指令
(通常是前导零计数 [CLZ] 指令或同等指令) ,因此
仅适用于专为其编写该指令的架构。
-
比通用方法更高效。
-
通常限制可用优先级的最大数量为 32
。
将 configUSE_滴答LESS_IDLE 设置为 1,使用
低功耗无 滴答 模式,
或设置为 0,保持 滴答 中断始终运行。 并非
所有 FreeRTOS 移植都实现了低功耗无 滴答 模式。
将其设置为 1,使用空闲钩子,
或设置为 0,忽略空闲钩子。
创建任务、队列或信号量时,内核调用 pvPortMalloc() 从堆中分配内存
。 官方 FreeRTOS 下载内容中
包括4 种内存分配方案样例。 这些方案
分别实现在 heap_1.c、heap_2.c、heap_3.c、heap_4.c 和 heap_5.c 源文件中
。 configUSE_MALLOC_FAILED_HOOK 仅在用到这3 种方案时适用。
。
malloc() 失败的钩子函数是一个钩子(或回调)函数,在
已经定义和配置的情况下,如果 pvPortMalloc() 返回 NULL ,它将被调用。
只有当 FreeRTOS 堆剩余的内存不足以分配请求的内存时,它才会返回 NULL
。
如果 configUSE_MALLOC_FAILED_HOOK 设置为 1,那么应用程序必须定义
malloc() 失败的钩子函数。 如果 configUSE_MALLOC_FAILED_HOOK 设置为 0,那么
malloc() 失败的钩子函数将不会被调用,即使定义了钩子函数。
malloc() 失败的钩子函数必须具有如下所示的名称和原型。
void vApplicationMallocFailedHook( void );
如果 configUSE_TIMERS 和 configUSE_DAEMON_TASK_STARTUP_HOOK 都设置为 1,
那么应用程序必须定义钩子函数,而且它必须和如下的函数具有相同的名称和原型
。 当
RTOS 守护进程任务(也称为
定时器服务任务)
首次执行时,钩子函数将会且只会被调用一次。 任何
需要 RTOS 运行的应用程序初始化代码,可放在钩子函数中。
void void vApplicationDaemonTaskStartupHook( void );
设置 configUSE_SB_COMPLETED_CALLBACK() 时需要设置构建中的 xStreamBufferCreateWithCallback() 和 xStreamBufferCreateStaticWithCallback()
(及其消息缓冲区等效函数)。 使用这些函数创建的流缓冲区和消息缓冲区可以有自己
唯一的发送完成回调和接收完成回调,其中通过 xStreamBufferCreate() 和
xStreamBufferCreateStatic ()(及其消息缓冲区等效函数) 创建的流缓冲区和消息缓冲区都共享 sbSEND_COMPLETED() 和
sbRECEVE_COMPLETED() 宏定义的回调。 configUSE_SB_COMPLETED_CALLBACK 默认为 0 ,以便向后兼容。
将其设置为 1,使用 滴答 钩子,
或设置为 0,忽略 滴答 钩子。
输入驱动生成 滴答 中断的外设所用的内部时钟的执行频率(以赫兹为单位)。
内部时钟通常也是
驱动内部 CPU 的时钟。 此值是
正确配置定时器外围设备所必需的。
configSYS滴答_CLOCK_HZ
仅适用于 ARM Cortex-M 移植的可选参数。
ARM Cortex-M 移植默认从 Cortex-M Sys滴答 定时器生成 RTOS 滴答 中断。大多数 Cortex-M MCU 以与 MCU 自身相同的频率运行 SysTick 定时器,如果这样,则不需要 configSYSTICK_CLOCK_HZ,而且它应保持未定义状态。如果 SysTick 定时器的频率与 MCU 核心不同,那么应将 configCPU_CLOCK_HZ 设置为正常的 MCU 时钟频率,将 configSYSTICK_CLOCK_HZ 设置为 SysTick 时钟频率。
RTOS 滴答 中断的频率。
滴答中断用于测定时间。 因此,滴答 频率越高,时间测定的分辨率越高
。 然而,滴答频率高也意味着 RTOS 内核将使用更多的 CPU 时间,因此效率会降低
。 RTOS 演示应用程序使用的 滴答 频率均为 1000 Hz。 此频率用于测试 RTOS 内核,
高于正常的频率要求。
多个任务可以共用相同的优先级。 RTOS 调度器将会
在每个 RTOS 滴答期间切换具有相同优先级的任务,让它们共享处理器时间。 因此,滴答频率高也会
减少分给每个任务的“时间切片”。
应用程序任务可用的优先级数量
。 任意数量的任务可共用相同的优先级。 协程单独分配优先级,请参阅 configMAX_CO_ROUTINE_PRIORITIES。
每个可用的优先级都消耗了 RAM 内核一些 RTOS,因此不应将该值设置得高于应用程序实际需要的优先级数量
。
如果 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 1,那么将限制最大允许值。
空闲任务使用的堆栈大小。 通常,该值不应小于 FreeRTOSConfig.h 中设置的值,
该头文件位于您使用的移植的演示应用程序。
此堆栈大小与 xTaskCreate() 和
xTaskCreateStatic() 函数的堆栈大小参数类似,
是按字指定,而不是按字节指定。 如果堆栈上的每个元素为 32 位,那么
大小为 100 元素的堆栈包含 400 字节(每个堆栈元素 32 位,消耗 4 个字节)。
创建任务时,任务描述性名称的最大允许长度。
该长度按字符数指定,
包括 NULL 终止字节。
如果想包含其他结构成员和函数来辅助执行可视化和跟踪,将其设置为 1。
将 configUSE_TRACE_FACILITY 和 configUSE_STATS_FORMATTING_FUNCTIONS 设置为 1,
包含 vTaskList() 和 vTaskGetRunTimeStats()
函数中的功能。 设置任意一个为 0,会在构建时忽略 vTaskList() 和 vTaskGetRunTimeStates()。
时间以 '滴答s' 为单位测定,这是 RTOS 内核启动后,滴答中断已经执行的次数。
滴答数存放在 滴答Type_t 类型的变量中。
将 configUSE_16_BIT_滴答S 定义为 1,会将 滴答Type_t 定义为 (typedef) 无符号的 16 位类型。
将 configUSE_16_BIT_滴答S 定义为 0,会将 滴答Type_t 定义为 (typedef) 无符号的 32 位类型。
在 8 位和 16 位架构上使用 16 位类型,将大大提高性能,但会限制最大可指定的
时间段为 65535 '滴答s'。 因此,假设滴答频率为
250 Hz,当使用 16 位计数器时,任务可以延迟或阻塞的最大时间为 262 秒,而
使用 32 位计数器时,则为 17179869 秒。
此参数控制空闲优先级任务的行为。 它仅在以下情况下有效:
- 使用抢占式调度器。
- 应用程序创建运行在空闲优先级的任务。
如果 configUSE_TIME_SLICING 设置为 1(或未定义),那么
优先级相同的任务将使用时间切片。 如果没有任务被抢占,那么可以假设每个给定优先级的任务
将分配相同的处理时间——如果优先级高于
空闲优先级,那么情况确实如此。
如果任务均为空闲优先级,其行为可能略有不同。 如果 configIDLE_SHOULD_YIELD 设置为 1,那么
如果其他空闲优先级任务准备运行,空闲任务将立即挂起。 这确保
当有应用程序任务可调度时,空闲任务花费的时间最少。 然而,这种行为可能
产生如下所示的不良效应(取决于您的应用需求):
上图显示了四个空闲优先级任务的执行模式
。 任务 A、B 和 C 是应用程序任务。 任务
I 是空闲任务。 上下文在时间 T0、T1、……、T6 定期切换。 当空闲任务挂起,任务
A 开始执行,但当前时间片已经被空闲任务消耗了一部分
。 这导致实际上任务 I 和任务 A 共用同一时间
片。 因此,应用程序任务 B 和 C 获得的处理时间多于
应用任务 A。
这种情况可以通过以下方式避免:
- 如果适当,使用空闲钩子代替
单独的空闲优先级任务。
- 以高于空闲的优先级创建所有应用程序任务。
- 将 configIDLE_SHOULD_YIELD 设置为 0。
将 configIDLE_SHOULD_YIELD 设置为 0 会阻止空闲任务让出
处理时间,直到其时间片结束。 这可以确保所有空闲优先级任务
分配相同的处理时间(如果没有
任务被抢占),但这是以分配给空闲任务更高比例的处理时间为代价的
。
将 configUSE_TASK_NOTIFICATIONS 设置为 1(或未定 configUSE_TASK_NOTIFICATIONS),将在构建中包含
直达任务通知功能及其相关的 API。
将 configUSE_TASK_NOTIFICATIONS 设置为 0,构建中将不包括直达任务通知功能及其相关的 API。
如果在构建中包含直达任务通知,每个任务将额外消耗 8 字节 RAM。
每个 RTOS 任务都有一个任务通知数组。
configTASK_NOTIFICATION_ARRAY_ENTRIES 设置数组的索引数。
在 FreeRTOS V10.4.0 之前,任务只有一个通知值,而不是通知值数组,因此
出于向后兼容考虑,如果 configTASK_NOTIFICATION_ARRAY_ENTRIES 未定义,则默认为 1。
将其设置为 1,将在构建中包含互斥功能,或设置为 0,将在构建中忽略互斥功能。 读者应熟悉
互斥锁和二进制信号量之间对于 FreeRTOS 功能的差异。
将其设置为 1,将在构建中包含递归互斥锁功能,或设置为 0,将在构建中忽略递归互斥锁功能。
将其设置为 1,将在构建中包含计数信号量功能,或设置为 0,将在构建中忽略计数信号量功能。
将其设置为 1,将在构建中包含“替代”队列函数,或设置为 0,将在构建中忽略“替代”队列函数。
替代队列 API 描述在 queue.h 头文件中。
替代队列 API 已弃用,不应用于新的设计。
堆栈溢出检测页面说明了此
参数。
队列注册表有两个目的,都与 RTOS 内核感知调试相关:
- 可以关联文本名称和队列,便于在调试 GUI 中识别队列。
- 包含调试器定位每个已注册队列和信号量所需的信息。
除非使用 RTOS 内核感知调试器,否则队列注册表没有任何用途。
configQUEUE_REGISTRY_SIZE 定义了可以注册的队列和信号量的最大数量。
只需要注册那些要使用 RTOS 内核感知调试器查看的队列和信号量。
请查阅 API 引用文档,了解更多关于 vQueueAddToRegistry()
和 vQueueUnregisterQueue() 的信息。
将其设置为 1,包含队列集合功能(
可以阻塞或挂起多个队列和信号量) ,或设置为 0,忽略队列集合功能。
默认情况下(如果 configUSE_TIME_SLICING 未定义,或者 configUSE_TIME_SLICING
定义为 1)FreeRTOS 使用带时间片的抢占式优先级调度。
这意味着 RTOS 调度器将始终运行优先级最高且处于就绪状态的任务,
并在每个 RTOS 滴答中断时,在具有相同优先级的任务之间切换
。 如果 configUSE_TIME_SLICING 设置为 0,RTOS 调度器
仍将运行优先级最高且处于就绪状态的任务,但不会
因为发生滴答中断而在具有相同优先级的任务之间切换。
如果 configUSE_NEWLIB_REENTRANT 设置为 1,那么将为每个创建的任务分配一个newlib 重入结构体
。
请注意,应大众需求已经包含 newlib 支持,但
未被 FreeRTOS 维护者使用。 FreeRTOS不是
不为由此产生的 newlib 操作负责。 用户必须熟悉
newlib,而且必须实现全系统的必要桩函数
。请注意,在撰写本文档时,当前的 newlib 设计
实现了必须提供锁的全系统 malloc()。
FreeRTOS.h 头文件包含一组 #define 宏,用于
将 FreeRTOS 8.0.0 之前的版本中使用的数据类型名称映射到
FreeRTOS 8.0.0 版本中使用的名称。 该宏可以将构建应用程序代码所依据的
FreeRTOS 版本从 8.0.0 之前的版本升级到
8.0.0 之后版本,而无需修改代码。 将
FreeRTOSConfig.h 中的 configENABLE_BACKWARD_COMPATIBILITY 设置为 0,将在构建中忽略该宏。而且这样做
可以确认没有使用 8.0.0 版本之前的名称。
设置每个任务的
线程本地存储数组攫取值。
MiniListItem_t 用于 FreeRTOS 列表中的开始和结束标记节点, ListItem_t 用于
FreeRTOS 列表中的所有其他节点。当 configUSE_MINI_LIST_ITEM 设置为 0 时, MiniListItem_t 和 ListItem_t 保持一致。当
configUSE_MINI_LIST_ITEM 设置为 1 时,MiniListItem_t 包含的字段比 ListItem_t 少 3 个,这样可以节省一些 RAM,
但代价是违反了某些编译器用于优化的严格别名规则。如果未定义,
configUSE_MINI_LIST_ITEM 默认为 1 ,以便向后兼容。
设置调用
xTaskCreate() 时用于指定堆栈深度的类型,以及许多其他
使用堆栈大小的地方(例如,返回
堆栈高水位线)。
旧版的 FreeRTOS 使用 UBaseType_t 类型变量指定堆栈大小,
但这对 8 位微控制器的限制过于严格。 configSTACK_DEPTH_TYPE
通过让应用程序开发人员指定使用的类型来解除该限制
。
FreeRTOS 消息缓冲区使用
configMESSAGE_BUFFER_LENGTH_TYPE 类型的变量存储
每个消息的长度。 如果未定义 configMESSAGE_BUFFER_LENGTH_TYPE ,
那么它将默认为 size_t。 如果存储在消息缓冲区中的消息
不会超过 255 字节,那么在 32 位微控制器上将 configMESSAGE_BUFFER_LENGTH_TYPE 定义为 uint8_t
将为每个消息节约 3 个字节。 类似地,如果
存储在消息缓冲区中的消息不会超过 65535 字节,
那么在 32 位微控制器上将 configMESSAGE_BUFFER_LENGTH_TYPE 定义为 uint16_t 将为每个消息节约 2 个字节
。
如果将 configSUPPORT_STATIC_ALLOCATION 设置为 1,那么 RTOS 对象可以
使用应用程序编写者提供的 RAM 创建。
如果将 configSUPPORT_STATIC_ALLOCATION 设置为 0,那么 RTOS 对象只能
使用从 RAM 堆中分配的 FreeRTOS 创建。
如果 configSUPPORT_STATIC_ALLOCATION 未定义,那么它默认为 0。
如果将 configSUPPORT_STATIC_ALLOCATION
设置为 1,那么应用程序编写者还必须提供两个回调函数:
vApplicationGetIdleTaskMemory() 用于提供
RTOS 空闲任务所使用的内存,以及(如果 configUSE_TIMERS 设置为 1)vApplicationGetTimerTaskMemory()
用于提供 RTOS 守护/定时器服务任务使用的内存。 示例
提供在下方。
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
*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.
请参阅静态内存分配 Vs 动态内存分配
页面,了解更多信息。
如果将 configSUPPORT_DYNAMIC_ALLOCATION 设置为 1,那么 RTOS 对象可以
使用从 RAM 堆中自动分配的 FreeRTOS 创建。
如果 configSUPPORT_DYNAMIC_ALLOCATION 设置为 0,那么 RTOS 对象只能
使用应用程序编写者提供的 RAM 创建。
如果 configSUPPORT_DYNAMIC_ALLOCATION 未定义,那么它默认为 1。
请参阅静态内存分配 Vs 动态内存分配
页面,了解更多信息。
RAM 堆中可用的 FreeRTOS 总量。
只有在 configSUPPORT_DYNAMIC_ALLOCATION 设置为 1 时,才使用该值。
而且应用程序使用
FreeRTOS 源代码下载内容中提供的一种示例内存分配方案。
请参阅内存配置部分,了解更多详细信息。
默认情况下,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 ];
如果 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 )
{
return MyThreadSafeMalloc( xWantedSize );
}
void vPortFreeStack( void * pv )
{
MyThreadSafeFree( pv );
}
pvPortMallocStack 和 vPortFreeStack 函数实现的示例
运行时间统计页面说明了此参数的使用。
将其设置为 1,将在构建中包含协程功能,或设置为 0,将在构建中忽略协程功能。 要包含协程功能,项目必须包含 croutine.c 文件
。
应用程序协程可用的优先级数量
。 任意数量的协程可共用相同的优先级。 任务单独分配优先级,请参阅 configMAX_PRIORITIES。
将其设置为 1,将包含软件定时器功能,或设置为 0,将忽略软件定时器功能。
请参阅 FreeRTOS 软件定时器页面,获取完整说明。
设置软件定时器服务/守护任务的优先级。
请参阅 FreeRTOS 软件定时器页面,获取完整说明。
设置软件定时器命令队列的长度。
请参阅 FreeRTOS 软件定时器页面,获取完整说明。
设置分配给软件定时器服务/守护任务的堆栈深度。
请参阅 FreeRTOS 软件定时器页面,获取完整说明。
configKERNEL_INTERRUPT_PRIORITY
configMAX_SYSCALL_INTERRUPT_PRIORITY 和
configMAX_API_CALL_INTERRUPT_PRIORITY
含有 configKERNEL_INTERRUPT_PRIORITY 设置的移植包括 ARM Cortex-M3、PIC24、dsPIC、PIC32、SuperH 和 RX600。
含有 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置的移植包括 PIC32、RX600、ARM Cortex-A 和 ARM Cortex-M。
ARM Cortex-M3 和 ARM Cortex-M4 用户请注意本节末尾的特别注意事项!
configMAX_API_CALL_INTERRUPT_PRIORITY 是 configMAX_SYSCALL_INTERRUPT_PRIORITY 的新名称,仅用于新版移植。 这两者是等效的。
configKERNEL_INTERRUPT_PRIORITY 应设置为最低优先级。
请注意,在下面的讨论中,只有以 "FromISR" 结尾的 API 函数才能从中断服务程序中调用。
对于仅实现 configKERNEL_INTERRUPT_PRIORITY 的移植
configKERNEL_INTERRUPT_PRIORITY 设置 RTOS 内核自身使用的中断优先级。 调用 API 函数的中断也必须执行在此
优先级。 不调用 API 函数的中断可以执行在更高的优先级,因此它们的执行不会被 RTOS 内核活动(在硬件自身的限制范围内)延迟
。
对于同时实现 configKERNEL_INTERRUPT_PRIORITY 和 configMAX_SYSCALL_INTERRUPT_PRIORITY 的移植:
configKERNEL_INTERRUPT_PRIORITY 设置 RTOS 内核自身使用的中断优先级。 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置了
调用中断安全的 FreeRTOS API 函数的最高中断优先级。
完全中断嵌套模型是通过将 configMAX_SYSCALL_INTERRUPT_PRIORITY 置于 configKERNEL_INTERRUPT_PRIORITY 之上(也就是优先级水平更高)实现的。
这意味着 FreeRTOS 内核不会完全禁用中断,即使是在临界区。 此外,这没有
分段内核架构的缺点。 但请注意,某些微控制器架构会在接受新中断时(在硬件中)禁用中断,
这意味着在硬件接受中断
和 FreeRTOS 代码重启中断的短暂期间内,中断不可避免地被禁用。
不调用 API 函数的中断可以在高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的优先级执行,因此不会被 RTOS 内核的运行延迟。
例如,假定微控制器具有8个中断优先级:0 为最低优先级,7 为最高优先级(请参阅本节末尾
ARM Cortex-M3 用户的特别注意事项)。 下面的图片描述了
如果这两个配置常数设置为 4 和 0,在各个优先级上哪些操作可以做以及哪些操作不可以做,如图所示:
中断优先级配置示例
这些配置参数可以实现非常灵活的中断处理:
-
可以根据系统中的任何其他任务编写中断处理“任务”并设置优先级。这些是被中断唤醒的任务
。中断服务程序 (ISR) 本身应该被编写得尽可能短小——它只获取数据,然后唤醒
高优先级处理程序任务。ISR 之后直接返回到唤醒的处理程序任务,因此中断处理在时间上是连续的,就像全部都是
在 ISR 中完成的。这样的好处是,在处理程序任务执行期间,所有中断都保持启用状态。
-
实现 configMAX_SYSCALL_INTERRUPT_PRIORITY 的移植更进一步——允许完全嵌套模型,优先级介于
RTOS 内核中断优先级和 configMAX_SYSCALL_INTERRUPT_PRIORITY 之间的中断可以嵌套并进行适当的 API 调用。 优先级
高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断不会被 RTOS 内核活动延迟。
-
ISR 运行在系统调用的最大优先级之上,不会被 RTOS 内核本身屏蔽,因此其响应度不会受到 RTOS 内核功能的影响。
对于时间精度要求非常高的中断(例如执行电机换向的中断)来说这很合适。
但是,此类 ISR 无法使用 FreeRTOS API 函数。
要使用这种方案,您的应用程序设计必须遵守以下规则:任何使用 FreeRTOS API 的中断其优先级都必须设置为和 RTOS 内核相同(
由 configKERNEL_INTERRUPT_PRIORITY 宏配置) ,或对于包含此功能的移植,设置为等于或低于 configMAX_SYSCALL_INTERRUPT_PRIORITY。
ARM Cortex-M3 和 ARM Cortex-M4 用户的特别注意事项:请参阅
专门介绍 ARM Cortex-M 设备中断优先级设置的页面。
您至少要记住 ARM Cortex-M3 核心使用低数值数字来表示高
优先级中断,这似乎有悖直觉,而且很容易忘记! 如果您希望将中断分配为低优先级,请不要将中断的
优先级指定为 0(或其他较小数值),因为这可能会导致中断实际上在系统中具有最高优先级 - 因此,如果该优先级
高于 configMAX_SYSCALL_INTERRUPT_PRIORITY,则可能会导致系统崩溃。
ARM Cortex-M3 核心的最低优先级实际上是 255,然而,不同的 ARM Cortex-M3 供应商采用了不同数量的优先位,
并且提供了以不同方式指定优先级的库函数。 例如,在 STM32 上,您可以在 ST 驱动函数库调用中指定的最低优先级
实际上是 15,您可以指定的最高优先级是 0。
configASSERT() 宏的语义与标准 C assert() 宏相同。 如果
传入 configASSERT() 的参数为零,则会触发断言。
configASSERT() 在整个 FreeRTOS 源文件中被调用,检查
应用程序正在如何使用 FreeRTOS。 我们强烈建议开发 FreeRTOS
应用程序时定义 configASSERT()。
示例定义(显示在文件的顶部,并
复制在下方)调用 vAssertCalled(),传入
文件名和触发 configASSERT() 调用的行号(__ FILE __ 和
__ LINE __是大多数编译器提供的标准宏)。 这只是为了演示,因为
vAssertCalled() 不是 FreeRTOS 函数, configASSERT() 可以
定义为执行应用程序编写者认为适当的任何操作。
通常情况下,会将 configASSERT() 定义为阻止
应用程序进一步执行。 这么做是出于两个原因:
在断言处停止应用程序可以对导致断言的原因进行
调试,而且触发断言后继续执行无论如何都可能导致
程序崩溃。
请注意,定义 configASSERT() 不仅会增加应用程序代码量也会增加
执行时间。 当应用程序足够稳定时,
只要将 configASSERT() 在
FreeRTOSConfig.h 中的定义注释掉,就可以消除额外的开销。
/* 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( ;; ); }
只有 FreeRTOS MPU 使用 configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS。
如果 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 );
}
这种技术只应该在开发过程中使用,而不能用于部署阶段,因为它会
绕过内存保护。
ARM Cortex-M4 微控制器的 FreeRTOS MPU(内存保护单元)移植支持具有
16 个 MPU 区域的设备。对于具有 16 个 区域的设备,应将 OTAconfigTMPUL__REGIONSMPU 设置为 16。
如果未定义,则默认为 8。
TEX、可共享 (S)、可缓存 (C) 和可缓冲 (B) 位定义了内存类型,而且如果
有需要还可以定义 MPU 区域的可缓存和可共享属性。configTEX_S_C_B_FLASH
允许应用程序编写者可以对
包含 Flash 的 MPU 区域的 TEX、可共享 (S)、可缓存 (C)、和可缓冲 (B) 位进行覆盖。如果它未定义,
那么默认为 0x07UL,即 TEX = 000、S = 1、C = 1、B = 1。
TEX、可共享 (S)、可缓存 (C) 和可缓冲 (B) 位定义了内存类型,而且如果
有需要还可以定义 MPU 区域的可缓存和可共享属性。configTEX_S_C_B_SRAM
允许应用程序编写者可以对
包含 MPU 的 RAM 区域的 TEX、可共享 (S)、可缓存 (C)、和可缓冲 (B) 位进行覆盖。如果它未定义,
那么默认为 0x07UL,即 TEX = 000、S = 1、C = 1、B = 1。
可以将 configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 定义为 1,防止任何
来自内核代码外部的特权升级(进入中断时硬件本身执行的升级除外
)。如果 configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
在 FreeRTOSConfig.h 中设置为 1,变量 __syscalls_flash_start__ 和
__syscalls_flash_end__ 需要从链接器脚本中导出,以分别表明
系统调用内存的起始和终止地址。建议将其定义为1 ,以获得最高的安全性。
仅用于 ARMv7-M MPU 移植(ARM Cortex-M3/4/7)。
将其设置为 0,防止非特权应用程序任务使用 taskENTER_CRITICAL()
宏创建
临界区。将此常量设置为 1,或未定义,会允许特权或非特权
任务创建临界区。 请注意:建议将此常量定义为 0,以获得最高的安全性。因此,
如果此常量未定义,编译器会输出警告。
仅限 Cortex-M4 MPU 移植。
在 Cortex-M7 r0p0/r0p1核心上使用 Cortex-M4 MPU 移植时,将 configENABLE_ERRATA_837070_WORKAROUND
设置为 1 ,以激活 ARM 勘误表 837070 所需的解决方法。
如果设置为 1 ,则使用 pvPortMalloc()
分配的内存块将在通过
vPortFree()
释放时清除。 如果不定义, configHEAP_CLEAR_MEMORY_ON_FREE
默认为 0,
以便向后兼容性。为了提高安全性,我们建议将 configHEAP_CLEAR_MEMORY_ON_FREE
设置为 1。
仅用于 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。 仅在 FreeRTOS 微控制器非安全端使用 ARMv8-M 代码的应用程序,例如在安全端运行第三方代码的应用程序,不需要此常量。
启用 "INCLUDE" 的宏,允许在应用程序构建过程中,不包含未使用的实时内核组件
。这确保 RTOS 不会使用任何超过特定嵌入式应用程序所需的 ROM 或 RAM
。
每个宏都具备如下形式:INCLUDE_FunctionName