FreeRTOS——配置文件

FreeRTOS 基础系列文章

 基本对象
  FreeRTOS——任务
  FreeRTOS——队列
  FreeRTOS——信号量
  FreeRTOS——互斥量
  FreeRTOS——任务通知
  FreeRTOS——流和消息缓冲区
  FreeRTOS——软件定时器
  FreeRTOS——事件组

 内存管理
  FreeRTOS——静态与动态内存分配
  FreeRTOS——堆内存管理
  FreeRTOS——栈溢出保护

 代码组织
  FreeRTOS——源代码组织
  FreeRTOS——创建新的项目
  FreeRTOS——配置文件


FreeRTOS——配置文件

  • 定制
  • “config”参数
  • “INCLUDE”参数

定制

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

/* 这里是包含整个应用程序所需的头文件的好地方。*/
#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 /* 已弃用!*/ 
#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 configSTACK_DEPTH_TYPE                   uint16_t
#define configMESSAGE_BUFFER_LENGTH_TYPE         size_t

/* 内存分配相关定义。*/ 
#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

/* 钩子函数相关定义。*/ 
#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 configGENERATE_RUN_TIME_STATS            0
#define configUSE_TRACE_FACILITY                 0
#define configUSE_STATS_FORMATTING_FUNCTIONS     0

/* 协程相关定义。*/ 
#define configUSE_CO_ROUTINES                    0
#define configMAX_CO_ROUTINE_PRIORITIES          1

/* 软件计时器相关定义。*/ 
#define configUSE_TIMERS                         1
#define configTIMER_TASK_PRIORITY                3
#define configTIMER_QUEUE_LENGTH                 10
#define configTIMER_TASK_STACK_DEPTH             configMINIMAL_STACK_SIZE

/* 中断嵌套行为配置。*/ 
#define configKERNEL_INTERRUPT_PRIORITY          [依赖于处理器] 
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     [依赖于处理器和应用程序] 
#define configMAX_API_CALL_INTERRUPT_PRIORITY    [依赖于处理器和应用程序]

/* 定义在开发过程中捕获错误。*/ 
#define configASSERT ( ( x ) ) if( ( x ) == 0 )调用 vAssert( __FILE__, __LINE__ )

/* FreeRTOS MPU 特定定义。*/ 
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
#define configTOTAL_MPU_REGIONS                                 8 /* 默认值。*/ 
#define configTEX_S_C_B_FLASH                                   0x07UL /* 默认值。*/ 
#define configTEX_S_C_B_SRAM                                    0x07UL /* 默认值。*/ 
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY             1

/* 可选函数 - 大多数链接器无论如何都会删除未使用的函数。*/ 
#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

/* 这里可以包含定义跟踪宏的头文件。*/

#endif /* FREERTOS_CONFIG_H */

“config”参数


configUSE_PREEMPTION

设置为 1 以使用抢占式 RTOS 调度程序,或设置为 0 使用协作式 RTOS 调度程序。


configUSE_PORT_OPTIMISED_TASK_SELECTION

某些 FreeRTOS 端口有两种选择要执行的下一个任务的方法 —— 通用方法和特定于该端口的方法。

通用方法

  • 当 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 0 或未实现特定于端口的方法时使用。
  • 可用于所有 FreeRTOS 端口。
  • 完全用 C 编写,使其效率低于特定于端口的方法。
  • 不对可用优先级的最大数量施加限制。

端口特定的方法

  • 并非适用于所有端口。
  • 当 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 1 时使用。
  • 依赖于一个或多个特定于体系结构的汇编指令(通常是计数前导零 [CLZ] 或等效指令),因此只能与专门为其编写的体系结构一起使用。
  • 比泛型方法更有效。
  • 通常将可用优先级的最大数量限制为 32。


configUSE_TICKLESS_IDLE

将 configUSE_TICKLESS_IDLE 设置为 1 以使用低功耗无滴答模式,或设置为 0 以保持滴答中断始终运行。并非所有 FreeRTOS 端口都提供低功耗无滴答实现。


configUSE_IDLE_HOOK

如果您希望使用空闲钩子,请设置为 1 ,或者设置为 0 以省略空闲钩子。


configUSE_MALLOC_FAILED_HOOK

每次创建任务、队列或信号量时,内核都会调用 pvPortMalloc() 从堆中分配内存。为此,官方 FreeRTOS 下载包括 5 个示例内存分配方案。这些方案分别在 heap_1.c、heap_2.c、heap_3.c、heap_4.c 和 heap_5.c 源文件中实现。configUSE_MALLOC_FAILED_HOOK 仅在使用这 5 个示例方案之一时才有用。

malloc() 失败的钩子函数是一个钩子(或回调)函数,如果定义和配置,将在 pvPortMalloc() 返回 NULL 时调用。仅当 FreeRTOS 堆内存不足以使请求的分配成功时,才会返回 NULL。

如果 configUSE_MALLOC_FAILED_HOOK 设置为 1,则应用程序必须定义 malloc() 失败的钩子函数。如果 configUSE_MALLOC_FAILED_HOOK 设置为 0,则 malloc() 失败的钩子函数将不会被调用,即使定义了。malloc() 失败的钩子函数必须具有如下所示的名称和原型。

void vApplicationMallocFailedHook( void );


configUSE_DAEMON_TASK_STARTUP_HOOK

如果 configUSE_TIMERS 和 configUSE_DAEMON_TASK_STARTUP_HOOK 都设置为 1,那么应用程序必须定义一个钩子函数,它具有如下所示的确切名称和原型。当 RTOS 守护进程任务(也称为计时器服务任务)第一次执行时,钩子函数将被调用一次 。任何需要运行 RTOS 的应用程序初始化代码都可以放在钩子函数中。

void void vApplicationDaemonTaskStartupHook( void );


configUSE_TICK_HOOK

如果您希望使用滴答钩子,请设置为 1 ,或者设置为 0 以省略滴答钩子。


configCPU_CLOCK_HZ

输入以 Hz 为单位的内部时钟频率,它是驱动用于生成滴答中断的外设的运行频率 —— 这通常是驱动内部CPU时钟的同一时钟。该值是正确配置定时器外设所必需的。


configSYSTICK_CLOCK_HZ

仅适用于 ARM Cortex-M 端口的可选参数。

默认情况下,ARM Cortex-M 端口从 Cortex-M SysTick 定时器生成 RTOS 滴答中断。大多数 Cortex-M MCU 以与 MCU 本身相同的频率运行 SysTick 计时器 —— 在这种情况下,不需要 configSYSTICK_CLOCK_HZ 并且应该保持未定义。如果 SysTick 计时器以与 MCU 内核不同的频率计时,则正常设置 configCPU_CLOCK_HZMCU 时钟频率,并将 configSYSTICK_CLOCK_HZ 设置为 SysTick 时钟频率


configTICK_RATE_HZ

RTOS 滴答中断的频率。

滴答中断用于测量时间。因此,更高的滴答频率意味着可以以更高的分辨率测量时间。然而,高滴答频率也意味着 RTOS 内核将使用更多的 CPU 时间,因此效率较低。RTOS 演示应用程序都使用 1000Hz 的滴答率。这用于测试 RTOS 内核,并且高于通常所需的值。

多个任务可以共享相同的优先级。RTOS 调度程序将通过在每个 RTOS 滴答期间在任务之间切换来在相同优先级的任务之间共享处理器时间。因此,高滴答频率也将具有减少给予每个任务的“时间片”的效果。


configMAX_PRIORITIES

应用程序任务可用的优先级数。任意数量的任务可以共享相同的优先级。协程单独确定优先级 —— 请参阅 configMAX_CO_ROUTINE_PRIORITIES。

每个可用的优先级在 RTOS 内核中消耗少量 RAM,因此不应将此值设置为高于应用程序实际需要的值。

如果 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 1,则最大允许值将受到限制。


configMINIMAL_STACK_SIZE

空闲任务使用的栈大小。通常,这不应从随您正在使用的端口的演示应用程序提供的 FreeRTOSConfig.h 文件中设置的值中减少。

xTaskCreate()xTaskCreateStatic() 函数的堆栈大小参数一样,栈大小以字而不是字节指定。如果放置在栈上的每个项目都是 32 位,那么栈大小为 100 意味着 400 字节(每个 32 位栈项目消耗 4 个字节)。


configMAX_TASK_NAME_LEN

创建任务时赋予任务的描述性名称的最大允许长度。长度以包括 NULL 终止字节在内的字符数指定。


configUSE_TRACE_FACILITY

如果您希望包含额外的结构成员和函数以帮助执行可视化和跟踪,请设置为 1。


configUSE_STATS_FORMATTING_FUNCTIONS

configUSE_TRACE_FACILITYconfigUSE_STATS_FORMATTING_FUNCTIONS 设置为 1 以在构建中包含 vTaskList()vTaskGetRunTimeStats() 函数。将任一设置为 0 将从构建中省略 vTaskList() 和 vTaskGetRunTimeStates()。


configUSE_16_BIT_TICKS

时间以“滴答”来衡量 —— 这是自 RTOS 内核启动以来滴答中断执行的次数。滴答计数保存在 TickType_t 类型的变量中。

将 configUSE_16_BIT_TICKS 定义为 1 会导致 TickType_t 被定义为无符号 16 位类型。将 configUSE_16_BIT_TICKS 定义为 0 会导致 TickType_t 被定义为无符号 32 位类型。

使用 16 位类型将大大提高 8 位和 16 位体系结构的性能,但将最大可指定时间段限制为 65535 个“滴答”。因此,假设滴答频率为 250Hz,使用 16 位计数器时任务可以延迟或阻塞的最长时间为 262 秒,而使用 32 位计数器时为 17179869 秒。


configIDLE_SHOULD_YIELD

此参数控制处于空闲优先级的任务的行为。它仅在以下情况下有效:

  1. 正在使用抢占式调度程序。
  2. 应用程序创建以空闲优先级运行的任务。

如果 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

将 configUSE_TASK_NOTIFICATIONS 设置为 1(或保持 configUSE_TASK_NOTIFICATIONS 未定义)将在构建中包含直接到任务通知功能及其关联的 API。

将 configUSE_TASK_NOTIFICATIONS 设置为 0 将从构建中排除直接到任务通知功能及其关联的 API。

当构建中包含直接到任务通知时,每个任务都会消耗 8 个额外字节的 RAM。


configTASK_NOTIFICATION_ARRAY_ENTRIES

每个 RTOS 任务都有一个任务通知数组。configTASK_NOTIFICATION_ARRAY_ENTRIES 设置数组中的索引数。

在 FreeRTOS V10.4.0 之前,任务只有一个通知值,而不是一组值,因此为了向后兼容,configTASK_NOTIFICATION_ARRAY_ENTRIES 如果未定义则默认为 1。


configUSE_MUTEXES

设置为 1 以在构建中包含互斥量功能,或设置为 0 以从构建中省略互斥量功能。读者应该熟悉互斥量和二进制信号量两者在 FreeRTOS 功能方面的区别。


configUSE_RECURSIVE_MUTEXES

设置为 1 以在构建中包含递归互斥量功能,或设置为 0 以从构建中省略递归互斥量功能。


configUSE_COUNTING_SEMAPHORES

设置为 1 以在构建中包括计数信号量功能,或设置为 0 以从构建中省略计数信号量功能。


configUSE_ALTERNATIVE_API

设置为 1 以在构建中包含“替代”队列函数,或设置为 0 以从构建中省略“替代”队列函数。queue.h 头文件中描述了替代 API。 替代 API 已弃用,不应在新设计中使用


configCHECK_FOR_STACK_OVERFLOW

该参数的使用方法请参见“FreeRTOS——堆栈溢出保护”页面。


configQUEUE_REGISTRY_SIZE

队列注册表有两个目的,这两个目的都与 RTOS 内核感知调试相关联:

  1. 它允许将文本名称与队列相关联,以便在调试 GUI 中轻松识别队列。
  2. 它包含调试器定位每个注册队列和信号量所需的信息。

除非您使用 RTOS 内核感知调试器,否则队列注册表没有任何用途。
configQUEUE_REGISTRY_SIZE 定义了可以注册的队列和信号量的最大数量。只需要注册您想要使用 RTOS 内核感知调试器查看的那些队列和信号量。有关更多信息,请参阅 vQueueAddToRegistry() 和 vQueueUnregisterQueue() 的 API 参考文档。


configUSE_QUEUE_SETS

设置为 1 以包括队列集功能(在多个队列和信号量上阻塞或挂起的能力),或设置为 0 以省略队列集功能。


configUSE_TIME_SLICING

默认情况下(如果 configUSE_TIME_SLICING 未定义,或者 configUSE_TIME_SLICING 定义为 1)FreeRTOS 使用优先级抢占式调度时间切片。这意味着 RTOS 调度程序将始终运行处于就绪状态的最高优先级任务,并会在每个 RTOS 滴答中断时在同等优先级的任务之间切换。如果 configUSE_TIME_SLICING 设置为 0,那么 RTOS 调度程序仍将运行处于就绪状态的最高优先级任务,但不会仅仅因为发生滴答中断而在同等优先级的任务之间切换。


configUSE_NEWLIB_REENTRANT

如果 configUSE_NEWLIB_REENTRANT 设置为 1,那么将为每个创建的任务分配一个 newlib 重入结构体。

注意 Newlib 支持已被大众需求包含在内,但 FreeRTOS 维护者自己并未使用。FreeRTOS 不对 newlib 操作产生的结果负责。用户必须熟悉 newlib 并且必须提供必要存根的系统范围的实现。请注意(在撰写本文时)当前的 newlib 设计实现了必须提供锁的系统范围的 malloc()。


configENABLE_BACKWARD_COMPATIBILITY

FreeRTOS.h 头文件包含一组 #define 宏,这些宏将 8.0.0 版之前的 FreeRTOS 版本中使用的数据类型名称映射到 FreeRTOS 8.0.0 版中使用的名称。宏允许应用程序代码将它们构建的 FreeRTOS 版本从 8.0.0 之前的版本更新到 8.0.0 之后的版本,无需修改。在 FreeRTOSConfig.h 中将 configENABLE_BACKWARD_COMPATIBILITY 设置为 0 会从构建中排除宏,这样做可以验证没有使用 8.0.0 之前的名称。


configNUM_THREAD_LOCAL_STORAGE_POINTERS

设置每个任务的线程本地存储数组中的索引数 。


configSTACK_DEPTH_TYPE

设置用于在调用 xTaskCreate() 时指定栈深度的类型 ,以及其他各种使用栈大小的地方(例如,当返回栈高水位线时)。

旧版本的 FreeRTOS 使用 UBaseType_t 类型的变量指定堆栈大小,但发现这在 8 位微控制器上过于严格。configSTACK_DEPTH_TYPE 通过使应用程序开发人员能够指定要使用的类型来消除该限制。


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 个字节。


configSUPPORT_STATIC_ALLOCATION

如果 configSUPPORT_STATIC_ALLOCATION 设置为 1,则可以使用应用程序编写者提供的 RAM 创建 RTOS 对象。

如果 configSUPPORT_STATIC_ALLOCATION 设置为 0,则只能使用从 FreeRTOS 堆分配的 RAM 创建 RTOS 对象。

如果 configSUPPORT_STATIC_ALLOCATION 未定义,它将默认为 0。

如果 configSUPPORT_STATIC_ALLOCATION 设置为 1,则应用程序编写器还必须提供两个回调函数:vApplicationGetIdleTaskMemory() 提供给 RTOS 空闲任务使用的内存,以及(如果 configUSE_TIMERS 设置为 1)vApplicationGetTimerTaskMemory() 提供给 RTOS 守护进程/计时器服务任务使用的内存。下面提供了示例。

/* configSUPPORT_STATIC_ALLOCATION被设置为1,因此应用程序必须提供
   vApplicationGetIdleTaskMemory() 的实现来提供Idle任务使用的内存。 */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
                                    StackType_t **ppxIdleTaskStackBuffer,
                                    uint32_t *pulIdleTaskStackSize )
{
/* 如果要提供给Idle任务的缓冲区是在这个函数中声明的,那么它们必须声明为
   static —— 否则它们将被分配到栈上,因此在这个函数退出后不存在。 */
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];

    /* 传递一个指向StaticTask_t结构体的指针,Idle任务的状态将存储在该
       结构体中。 */
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;

    /* 传递将用作空闲任务栈的数组。 */
    *ppxIdleTaskStackBuffer = uxIdleTaskStack;

    /* 传递*ppxIdleTaskStackBuffer所指向的数组的大小。注意,由于数组
       的类型必须是StackType_t,configMINIMAL_STACK_SIZE 以字而不是
       字节指定。 */
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
/*-----------------------------------------------------------*/

/* configSUPPORT_STATIC_ALLOCATION 和 configUSE_TIMERS 都被设置为 1,
   因此应用程序必须提供 vApplicationGetTimerTaskMemory() 的实现来提供
   计时器服务任务使用的内存。 */
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
                                     StackType_t **ppxTimerTaskStackBuffer,
                                     uint32_t *pulTimerTaskStackSize )
{
/* 如果要提供给Timer任务的缓冲区是在函数内部声明的,那么它们必须声明为
   static —— 否则它们将被分配到栈上,因此在函数退出后不存在。 */
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];

    /* 传递一个指向StaticTask_t结构体的指针,定时器任务的状态将存储在该
       结构体中。 */
    *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;

    /* 传递将用作定时器任务堆栈的数组。 */
    *ppxTimerTaskStackBuffer = uxTimerTaskStack;

    /* 传递*ppxTimerTaskStackBuffer所指向的数组的大小。注意,由于数组
       的类型必须是StackType_t,configTIMER_TASK_STACK_DEPTH 以字而
       不是字节指定。 */
    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

更多详细信息,请参阅FreeRTOS——静态与动态内存分配页面。


configSUPPORT_DYNAMIC_ALLOCATION

如果 configSUPPORT_DYNAMIC_ALLOCATION 设置为 1,则可以使用从 FreeRTOS 堆自动分配的 RAM 创建 RTOS 对象。

如果 configSUPPORT_DYNAMIC_ALLOCATION 设置为 0,则只能使用应用程序编写者提供的 RAM 创建 RTOS 对象。

如果 configSUPPORT_DYNAMIC_ALLOCATION 未定义,它将默认为 1。

更多详细信息,请参阅FreeRTOS——静态与动态内存分配页面。


configTOTAL_HEAP_SIZE

FreeRTOS 堆中可用的 RAM 总量。

仅当 configSUPPORT_DYNAMIC_ALLOCATION 设置为 1 并且应用程序使用 FreeRTOS 源代码下载中提供的示例内存分配方案之一时,才会使用此值。更多详细信息,请参阅FreeRTOS——堆内存管理页面。


configAPPLICATION_ALLOCATED_HEAP

默认情况下,FreeRTOS 堆由 FreeRTOS 声明并由链接器放置在内存中。将 configAPPLICATION_ALLOCATED_HEAP 设置为 1 允许应用程序编写者声明堆,这允许应用程序编写者将堆放在内存中他们喜欢的任何位置。

如果使用 heap_1.cheap_2.cheap_4.c,并且 configAPPLICATION_ALLOCATED_HEAP 设置为 1,则应用程序编写者必须提供具有确切名称和维度的 uint8_t 数组,如下所示。该数组将用作 FreeRTOS 堆。数组如何放置在特定的内存位置取决于所使用的编译器 —— 请参阅编译器的文档。

uint8_t ucHeap[configTOTAL_HEAP_SIZE];


configSTACK_ALLOCATION_FROM_SEPARATE_HEAP

如果 configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 设置为 1,则使用 xTaskCreatexTaskCreateRestricted API创建的任何任务的栈使用 pvPortMallocStack 分配并使用 vPortFreeStack 函数释放。用户需要提供 pvPortMallocStack 和 vPortFreeStack 函数的线程安全实现。这使用户能够从单独的内存区域(可能是不同于 FreeRTOS 堆的另一个堆)为任务分配栈。

如果 configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 未定义,它将默认为 0。

pvPortMallocStack 和 vPortFreeStack 函数的示例实现如下:

void * pvPortMallocStack( size_t xWantedSize ) 
{ 
    /* 分配一个大小为 xWantedSize 的内存块。
     * 用于分配内存的函数必须是线程安全的。*/
    return MyThreadSafeMalloc( xWantedSize ); 
} 

void vPortFreeStack( void * pv ) 
{ 
    /* 释放之前使用 pvPortMallocStack 分配的内存。
     * 该用于释放内存的函数必须是线程安全的。*/ 
    MyThreadSafeFree( pv ); 
}


configGENERATE_RUN_TIME_STATS

运行时间统计页面描述了该参数的使用。


configUSE_CO_ROUTINES

设置为 1 以在构建中包含协程功能,或设置为 0 以从构建中省略协程功能。要包含协程 croutine.c 必须包含在项目中。


configMAX_CO_ROUTINE_PRIORITIES

应用程序协程可用的优先级数。任意数量的协程可以共享相同的优先级。任务被单独划分优先级 —— 请参阅 configMAX_PRIORITIES


configUSE_TIMERS

设置为 1 以包括软件计时器功能,或设置为 0 以省略软件计时器功能。有关完整说明,请参阅FreeRTOS——软件计时器页面。


configTIMER_TASK_PRIORITY

设置软件计时器服务/守护程序任务的优先级。有关完整说明,请参阅FreeRTOS——软件计时器页面。


configTIMER_QUEUE_LENGTH

设置软件计时器命令队列的长度。有关完整说明,请参阅FreeRTOS——软件计时器页面。


configTIMER_TASK_STACK_DEPTH

设置分配给软件计时器服务/守护程序任务的栈深度。有关完整说明,请参阅FreeRTOS——软件计时器页面。


configKERNEL_INTERRUPT_PRIORITY
configMAX_SYSCALL_INTERRUPT_PRIORITY
configMAX_API_CALL_INTERRUPT_PRIORITY

包含 configKERNEL_INTERRUPT_PRIORITY 设置的端口包括 ARM Cortex-M3PIC24dsPICPIC32SuperHRX600。包含 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置的端口包括 PIC32RX600ARM Cortex-AARM 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,则在每个优先级可以做什么和不能做什么,如下所示:

FreeRTOS——配置文件_第1张图片

示例中断优先级配置


这些配置参数允许非常灵活的中断处理:

  • 可以编写中断处理“任务”,并且可以像系统中任何其他任务一样的赋予优先级。这些任务由中断唤醒。中断服务程序 (ISR) 本身应该写得尽可能短——它只抓取数据,然后唤醒高优先级的处理程序任务。然后 ISR 直接返回到已唤醒的处理程序任务中——因此中断处理在时间上是连续的,就像它是在 ISR 本身中完成的一样。这样做的好处是,在处理程序任务执行时,所有中断都保持启用状态。

  • 实现 configMAX_SYSCALL_INTERRUPT_PRIORITY 的端口更进一步——允许完全嵌套的模型,其中 RTOS 内核中断优先级和 configMAX_SYSCALL_INTERRUPT_PRIORITY 之间的中断可以嵌套并且可以使用合适的 API 调用。RTOS 内核活动永远不会延迟优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断。

  • 运行在最大系统调用优先级之上的 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

configASSERT() 宏的语义与标准 C assert() 宏相同。如果传入 configASSERT() 的参数为零,则触发断言。

在整个 FreeRTOS 源文件中调用 configASSERT() 以检查应用程序如何使用 FreeRTOS。强烈建议在开发 FreeRTOS 应用程序时定义 configASSERT() 。

示例定义 (显示在文件的顶部并在下面复制) 调用 vAssertCalled(),传入触发 configASSERT() 调用的文件名和行号(__FILE____LINE__ 是大多数编译器提供的标准宏)。这仅用于演示,因为 vAssertCalled() 不是 FreeRTOS 函数,可以定义 configASSERT() 采取应用程序编写者认为合适的任何操作。

通常会以阻止应用程序进一步执行的方式定义 configASSERT() 。这有两个原因:在断言点停止应用程序可以调试断言的起因;不管怎样,在触发断言之后执行都可能导致崩溃。

注意,定义 configASSERT() 将增加应用程序代码的大小和执行时间。当应用程序稳定时,额外的开销可以通过简单地注释掉 FreeRTOSConfig.h 中的 configASSERT() 定义来消除。

/* 定义configASSERT()在断言失败时调用vAssertCalled()。如果传入
   configASSERT()的参数值等于零,则断言失败。 */
#define configASSERT ( x )     if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )

如果在调试器的控制下运行 FreeRTOS,那么 configASSERT() 可以被定义为仅仅禁用中断并处于循环中,如下所示。这样做的效果是停止 assert 测试失败的那一行代码 —— 暂停调试器将立即将您带到出错的行,以便您可以看到它失败的原因。

/* 定义configASSERT()以禁用中断并驻留在循环中。 */
#define configASSERT ( x )     if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }


configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS

configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 仅由 FreeRTOS MPU 使用。

如果 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 )
{
	/* 陈述函数被调用时处理器的特权级别。 */
	BaseType_t xRunningPrivileged = prvRaisePrivilege();

    /* 调用库函数,该函数现在可以访问所有RAM。 */
    debug_printf( pcMessage );

    /* 将处理器特权级别重置为初始值。 */
    portRESET_PRIVILEGE( xRunningPrivileged );
}

这种技术应该只在开发期间使用,而不是部署期间,因为它绕过了内存保护。


configTOTAL_MPU_REGIONS

ARM Cortex-M4 微控制器的 FreeRTOS MPU(内存保护单元)端口,支持具有 16 个 MPU 区域的设备。对于具有 16 个 MPU 区域的设备,将 configTOTAL_MPU_REGIONS 设置为 16。如果未定义,则默认为 8。


configTEX_S_C_B_FLASH

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。


configTEX_S_C_B_SRAM

TEX、可共享 (S)、可缓存 (C) 和可缓冲 (B) 位定义了内存类型。并在必要时定义 MPU 区域的可缓存和可共享属性。configTEX_S_C_B_SRAM 允许应用程序编写者覆盖包含 RAM 的 MPU 区域的 TEX、可共享 (S)、可缓存 (C) 和可缓冲 (B) 位的默认值。如果未定义,它默认为0x07UL,这意味着TEX=000, S=1, C=1, B=1。


configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY

configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 可以定义为 1 以防止任何源自内核代码外部的权限提升(除了在进入中断时由硬件本身执行的提升)。当 FreeRTOSConfig.h 中的configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 设置为 1 时,变量 __syscalls_flash_start___syscalls_flash_end__ 需要从链接器脚本中导出,以分别指示系统调用内存的开始地址和结束地址。建议将其定义为 1 以获得最大的安全性。


“INCLUDE”参数

以“INCLUDE”开头的宏允许那些不被你的应用程序使用的实时内核的组件被排除在你的构建之外。这可确保 RTOS 不会使用任何超出特定嵌入式应用程序所需的 ROM 或 RAM。

每个宏的形式是……

INCLUDE_FunctionName

……其中 FunctionName 表示可以选择排除的 API 函数 (或一组函数)。要包含 API 函数,将宏设置为1;要排除函数,将宏设置为0。例如,要包含 vTaskDelete() API函数,请使用:

#define INCLUDE_vTaskDelete    1

要从构建中排除 vTaskDelete(),请使用:

#define INCLUDE_vTaskDelete    0

你可能感兴趣的:(FreeRTOS,freertos,操作系统)