声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。
本专栏博客参考《STM32Cube高效开发教程(高级篇)》,有意向的读者可以购买正版书籍辅助学习,本书籍由王维波老师、鄢志丹老师、王钊老师倾力打造,书籍内容干货满满。
一、 FreeRTOS的文件组成
在STM32Cube高效开发教程<高级篇><FreeRTOS>(一)-----FreeRTOS基础示例中,与FreeRTOS相关的程序文件主要分为可修改的用户程序文件和不可修改的FreeRTOS源程序文件。上一篇博客中介绍的freertos.c是可修改的用户程序文件,FreeRTOS中任务、信号量等对象的创建,用户任务函数都在这个文件里实现。项目中FreeRTOS的源程序文件都在目录\Middlewares\ThirdParty\FreeRTOS\Source下,这些是针对选择的MCU型号做好了移植的文件。使用CubeMX生成代码时,用户无须关心FreeRTOS的移植问题,所需的源程序文件也为用户组织好了。
虽然无须自己进行程序移植和文件组织,但是了解FreeRTOS的文件组成以及主要文件的功能,对于掌握FreeRTOS的原理和使用还是有帮助的。FreeRTOS的源程序文件大致可以分为5类,如下图所示:
1.1 用户配置和程序文件
用户配置和程序文件包括如下2个文件,用于对FreeRTOS进行各种配置和功能裁剪,以及实现用户任务的功能。
- 文件FreeRTOSConfig.h:是对FreeRTOS进行各种配置的文件,FreeRTOS的功能裁剪就是通过这个文件里的各种宏定义实现的。
- 文件feertos.c:包含FreeRTOS对象初始化函数MXFREERTOS_InitO和任务函数,是编写用户代码的主要文件。
1.2 FreeRTOS通用功能文件
这些是实现FreeRTOS的任务、队列、信号量、软件定时器、事件组等通用功能的文件。这些功能与硬件无关。源程序文件在\Source目录下,头文件在\Source\Include目录下。这两个目录下的源程序文件和头文件如下图所示。
这些通用功能文件及其功能如下表。在一个嵌入式操作系统中,任务管理是必需的,某些功能是在用到时才需要加入的,如事件组、软件定时器、信号量、流缓冲区等。CubeMX在生成代码时,将这些文件全部复制到了项目里,但是它们不会被全部编译到最终的二进制文件里。用户可以对FreeRTOS的各种参数进行配置,实现功能裁剪这些参数配置实际就是各种条件编译的条件定义。
文件 | 功能 |
---|---|
croutine.h/.c | 实现协程(co-routine)功能的程序文件,协程主要用于内存非常小的MCU,现在已经很少使用 |
event_groups.h/.c | 实现事件组功能的程序文件 |
list.h/list.c | 实现链表功能的程序文件,FreeRTOS的任务调度器用到链表 |
queue.h/queue.c | 实现队列功能的程序文件 |
semphr.h | 实现信号量功能的文件,信号量是基于队列的,信号量操作的函数都是宏函数,其实现都是调用队列处理的函数 |
task.h/tasks.c | 实现任务管理功能的程序文件 |
timers.h/timers.c | 实现软件定时器功能的程序文件 |
stream_buffer.h/stream_buffer.c | 实现l流缓冲区功能的程序文件。流缓冲区是一种优化的进程间通信机制,是在V10版本中才引入的功能 |
message_buffer.h | 实现消息缓冲区的文件。实现消息缓冲区功能的所有函数都是宏函数,因为消息缓冲区是基于流缓冲区实现的,都调用流缓冲区的函数。消息缓冲区是在V10版本中才引入的功能 |
mpu_prototypes.h | MPU(内存保护单)功能的头文件。该文件定义的函数是在标准函数前面增加前缀“MPU”,当应用程序使用MPU功能时,FreeRTOSmpu wrappers.h内核会优先执行此文件中的函数 |
1.3 FreeRTOS通用定义文件
目录\Source\include下有几个与硬件无关的通用定义文件。
(1)文件FreeRTOS.h。这个文件包含FreeRTOS的默认去定义、数据类型定义、接口函数定义等。FreeRTOS.h中有一些默认的用于FreoRTOS功能裁剪的宏定义,例如:
#ifndef configIDLE_SHOULD_YIELD#define configIDLE_SHOULD_YIELD 1
#endif
#ifndef INCLUDE_vTaskDelete#define INCLUDE_yTaskDelete 0
#endif
FreeRTOS的功能裁剪就是通过这些宏定义实现的,这些用于配置的宏定义主要分为如下两类
- 前缀为“config”的宏表示某种参数设置,一般地,值为1表示开启此功能,值为0表示禁用此功能,如configIDLE_SHOULD_YIELD表示空闲任务是否对同优先级的任务让出处理器使用权。
- 前缀为“INCLUDE_”的宏表示是否编译某个函数的源代码,例如,宏INCLUDE_vTaskDelete的值为1,就表示编译函数vTaskDelete()的源代码,值为0就表示不编译函数vTaskDelete()的源代码。
在FreeRTOS中,这些宏定义通常称为参数,因为它们决定了系统的一些特性。文件FreeRTOS.h包含系统默认的一些参数的宏定义,不要直接修改此文件的内容。用户可修改的配置文件FreeRTOSConfigh,这个文件也包含大量前缀为“config”和“INCLUDE”的宏定义。如果文件FreeRTOSConfig.h中没有定义宏,就使用文件FreeRTOS.h中的默认定义。
FreeRTOS的大部分功能配置都可以通过CubeMX可视化设置完成,并生成文件FreeRTOSConfig.h中的宏定义代码。
(2)文件projdefs.h。这个文件包含FreeRTOS中的一些通用定义,如错误编号宏定义,逻
辑值的宏定义等。文件projdef.h中常用的几个宏定义及其功能见下表。
宏定义 | 值 | 功能 |
---|---|---|
PdFALSE | 0 | 表示逻辑值false |
pdTRUE | 1 | 表示逻辑值true |
pdFAIL | 0 | 表示逻辑值false |
pdPASS | 1 | 表示逻辑值true |
pdMS_TO_TICKS(xTimelnMs) | - | 这是个宏函数,其功能是将xTimelnMs表示的毫秒数转换xTimelnMs为时钟节拍数,因为延时函数vTaskDelayO的输入参数是节拍数 |
(3)文件stack_macros.h和StackMacros.h。这两个文件的内容完全一样,只是为了向后兼容,才出现了两个文件。这两个文件定义了进行栈溢出检查的函数,如果要使用栈溢出检查功能,需要设置参数configCHECKFOR_STACK_OVERFLOW的值为1或者2。
1.4 CMSIS-RTOS标准接口文件
目录ISource\CMSIS_RTOS_V2下是CMSIS-RTOS标准接口文件,如下图所示。这些文件里的宏定义、数据类型、函数名称等的前缓都是”os”。原理上来说,这些函数和数据类型的名称与具体的RTOS无关,它们是CMSIS-RTOS标准的定义。在具体实现上,这些前缀为“os”的函数调用具体移植的RTOS的实现函数,例如,若移植的是FreeRTOS,“os”函数就调用FreeRTOS的
实现函数,若移植的是uC/OS-Ⅱ,“os”函数就调用uC/OS-Ⅱ的实现函数。
本系列博客使用的是FreeRTOS,所以这些“os”区函数调用的都是FreeRTOS的函数。例如,CMSIS-RTOS的延时函数.osDelay()的内部就是调用了FreeRTOS的延时函数vTaskDelay()。
在上一篇博客示例中,使用过一些类似的函数:osThreadNew()的内部调用
xTaskCreate()或福xTaskCreateStatic()创建任务;osKernelStart()的内部调用vTaskStartScheduler()启动FreeRTOS内核运行
从原理上来说,如果在程序中使用这些CMSIS-RTOS标准接口函数和类型定义,可以减少与具体RTOS的关联。例如,一个应用程序原先是使用FreeRTOS写的,后来要改为使用uC/OS-II,则只需改RTOS移植部分的程序,而无须改应用程序。但是这种情况可能极少。
在本博客中,为了讲解FreeRTOS的使用,后面在编写用户功能代码时,将尽量直接使用FreeRTOS的函数,而不使用CMSIS-RTOS接口函数。但是CubeMX自动生成的代码使用的基本都是CMSIS-RTOS接口函数,这些是不需要去更改的,明白两者之间的关系即可。
1.5 硬件相关的移植文件
硬件相关的移植文件就是需要根据硬件类型进行改写的文件,一个移植好的版本称为一个端口(port),这些文件在目录\Source\portable下,又分为架构与编译器、内存管理两个部分,如下图所示:
(1)处理器架构和编译器相关文件。处理器架构和编译器部分有2个文件,即portmacro.h和port.c。这两个文件里是些与硬件相关的基础数据类型、宏定义和函数定义。因为某些函数的功能实现涉及底层操作,其实现代码甚至是用汇编语言写的,所以与硬件密切相关。
FreeRTOS需要使用一个基础数据类型定义头文件stdint.h,这个头文件定义的是uint8_t、uint32_t等基础数据类型,STM32的HAL库包含这个文件。
在文件pormacro.h中,我们重新定义了一些基础数据类型的类型符号,定义的代码如下。Cortex-M4是32位处理器,这些类型定义对应的整数或浮点数类型见注释。
#define PortCHAR char //int8t
#define PortFLOAT float //4字节浮点数
#define portDOUBLE double //8字节浮点数
#define PortLONG long //int32t
#define portSHORT short //int16t
#define portSTACK_TYPE uint32_t //栈数据类型
#define PortBASE_TYPE long //int32_t
typedef PortSTACK_TYPE StackType_t; //栈数据类型stackType_t,是uint32_t
typedef long BaseType_t; //基础数据类型Baserype_t,是int32_t
typedef unsigned long UBaseType_t; //基础数据类型UBaserype_t,是uint32_
typedef uint32_t Tickrype_t; //节拍数类型TickType_t,是uint32_t
重新定义的4个数据类型符号是为了移植方便,它们的等效定义和意义如下表所示。
数据类型符号 | 等效定义 | 意义 |
---|---|---|
BaseType_t | int32_t | 基础数据类型,32位整数 |
UBaseType_t | uint32_t | 基础数据类型,32位无符号整数 |
StackType_t | uint32_t | 栈数据类型,32位无符号整数 |
Tickrype_t | uint32_t | 基础时钟节拍数类型,无符号整数 |
(2)内存管理相关文件。内存管理涉及内存动态分配和释放等操作,与具体的处理器密切相关。FreeRTOS提供5种内存管理方案,即heap_1至heap_5,在CubeMX里设置FreeRTOS参数时,选择1种即可。在上图中,内存管理文件是heap_4.c,这也是默认的内存管理方案。
文件heap_4.c实现了动态分配内存的函数pvPorMalloc(),释放内存的函数vPortFree(),以及其他几个函数。heap_4.c以目录\Sourcelinclude下的portable.h文件为头文件。
二、 FreeRTOS的编码规则
FreeRTOS的核心源程序文件遵循一套编码规则,其变量命名、函数命名、宏定义命名等都有规律,知道这些规律有助于理解函数名、宏定义的意义。
2.1 变量名
变量名使用类型前缀。通过变量名的前缓,用户可以知道变量的类型
- 对于stdinth中定义的各种标准类型整数,前缀“c”表示char类型变量,前“s”表示it16_t(short)类型变量,前缀1表示inf32-类型变量。对于无符号(unsigned)整数,再在前面增加前缀“u”,如“uc”表示uint8类型,“us”表示uint16t,“ul”表示uint32t类型。
- BaseTypet和所有其他非标准类型的变量名,如结构体变量、任务句板、队列句柄等都用前缀"x"。
- UBaseTypet类型的变量使用前缀"ux"。
- 指针类型变量在前面再增加一个“p”,例如,“pc”表示Char*类型。
2.2 函数名
函数名的前缀由返回值类型和函数所在文件组成,若返回值为void类型,则类型前缀是"v",举例如下。
- 函数xTaskCreate(),其返回值为BaseTyPe类型,在文件task.h中定义。
- 函数vQueueDelete(),其返回值为void,在文件queue.h中定义。
- 函数pcTimerGetName(),其返回值为char *,在文件timer.h中定义。
- 函数pvPortMalloc(),其返回值为void *,在文件portable.h中定义。
如果函数是用static声明的文件内使用的有函数则其前级为prv”.例如,tasks.c文件中的函数prvAddNewTaskToRegdyListO,因为私有函数不会被外部调用,所以函数名中就不用包括返回值类型和所在文件的前缀了。
CMSIS-RTOS相关文件中定义的函数前都是“os”,不包括返回值类型和所在文件的前缀。例如,cmsis_os2.h中的函数osThreadNew()、osDelay()等。
2.3 宏名称
宏定义和宏函数的名称一般用大写字母,并使用小写字母前缀表示宏的功能分组。FreeRTOS中常用的宏名称前级见下表。
前缀 | 意义 | 所在文件 | 实例 |
---|---|---|---|
config | 用于系统功能配置的宏 | FreeRTOSConfig、EreeRTOS.h | configUSE_MUTEXES、configTICK_RATE_HZ |
INCLUDE_ | 条件编译某个函数的宏 | FreeRTOSConfig.h、FreeRTOS.h | INCLUDE_vTaskDelay、INCLUDE_vTaskDelete |
task | 任务相关的宏 | task.h、task.c | taskENTER_CRITICAL()、taskIDLE_PRIORITY |
queue | 队列相关的宏 | queue.h | queueQUEUE_TYPE_MUTEX |
pd | 项目通用宏定义 | projdefs.h | PdTRUE,pdFALSE |
port | 修植接口文件定义的宏 | portablc.h、portmacro.h、port.c | portBYTE_ALIGNMENT_MASK、portCHAR、portMAX_24_BIT_NUMBER |
tmr | 软件定时器相关的宏 | timer.h | tmrCOMMAND_START |
os | CMSIS-RTO3接口相关的宏 | cmsis_os.h、cmsis_os2.h | osFeature_SysTick、osFlagsWaitAll |
三、FreeRTOS的配置和功能裁剪
FreeRTOS的配置和功能裁剪主要是通过文件FeoRTOSConfig.h和FreeRTOS.h中的一些宏定义实现的,前缀为“config”的宏用于配置FreeRTOS的一些参数,前级为“INCLUDE_”的宏用于控制是否编译某些函数的源代码。文件FreeRTOS.h中的宏定义是系统默认的宏定义,请勿直接修改。FeeRTOSConfig.h是用户可修改的配置文件,如果一个宏没有在文件
FeeRTOSConfig.h中重新定义,就使用文件FreeRTOS.h中的默认定义。
在CubeMX中,FreeRTOS的配置界面中有Config parameters和Includ eparameters两个页面,用于对这两类宏进行设置。在本节中,我们介绍CubeMX中设置的这些宏的意义,但很多概念需要在后面才会具体讲到,如果读者对这些概念不工解也没关系,在后面的博客中会详细介绍。
3.1 “config”类的宏
前缀为“config”的宏用于对FreeRTOS的一些参数进行配置。上一博客中的示例完全使用了FreeRTOS的默认配置,例如,文件FeeRTOSConfig.h中部分这类宏定义代码如下:
#define configENABLE_FPU 0
#define configENABLE_MPU 0#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES ( 56 )
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configTOTAL_HEAP_SIZE ((size_t)15360)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256
在CubeMX中修改了值的参数都会在文件FreeRTOSConfig.h中生成语句。有默认值的宏
定义在文件FreeRTOS.h中,例如,文件FreeRTOS.h中有如下的定义:
#ifndef configIDLE_SHOULD_YIELD#define configIDLE_SHOULD_YIELD 1
#endif
默认情况下,文件FreeRTOSConfig.h中没有定义宏configIDLE_SHOULD_YIELD,就使用
文件FreeRTOS.h中的默认定义。如果通过CubeMX修改了这个参数,在FreeRTOSConfig.h中
生成了如下的宏定义,那么就使用FreeRTOSConfig.h中的定义。
#define configIDLE_SHOULD_YIELD 0
在CubeMX中,FreeRTOS参数配置的ConfigParameters页面的参数,分为好几组,这些参数对应于文件FreoRTOSConfig.h和FreeRTOS.h中相应的宏,下面我们分别介绍这几组参数设置的内容。
(1)MPU/FPU。这组有两个参数,用于设置是否使用内存保护单元MPU和浑点数单元FPU,如下图所示。
- ENABLE_MPU,使用MPU功能。虽然MCU硬件支持MPU,但是需要FreeRTOS的本地代码支持。
- ENABLE_FPU,是否在FreeRTOS中使用FPU功能。STM32F4系列MCU是有FPU的。
(2)Kernel settings,内核设置。这组是FreeRTOS内核的一些参数,设置的具体参数及其默认值如下图所示。某些参数是不允许修改的,就显示为灰色字体。某些参数只能选择一个参数值,例如,USE_MUTEXES只能选择Enabled。
上图中所示的参数与文件FreeRTOSConfig.h或FreeRTOS.h中的宏是对应的,只是去掉
了前缀“config”,如USE_PREEMPTION对应的宏是configUSE_PREEMPTION。界面中逻辑型参数的可选值是Enabled和Disabled,对应于宏定义的值是1和0,这些宏一般是条件编译的条件,用于条件编译某段代码。上图中的这些参数的意义和默认值见下表。
配置参数 | 默认值 | 意义 |
---|---|---|
USE_PREEMPTION | Enabled | Enabled 表示使用抢占式(pie-cmpivc)任务调Enabled度器:Disabled表示使用合作式(co-operative)任务调度器 |
CPU_LCLOCK_HZ | SystemCorcClock | 系统核心时钟,即MCU的HCLK时钟 |
TICK_RATE_HZ | 1000 | 系统响哈时控频率,设置范围为1至1000,默认为1000Hz所以周期建1ms |
MAX_PRIORITIES | 56 | 任务的最多优先级个数,这里固定为56,不可修改 |
MINIMAL_STACK_SIZE | 128 Words | 系统空闲任务的栈空间的最小值,设置范围为64至3840。在FreeRTOS中,栈空间的大小单位是字,在Corex-M架构中,一个字是4字节 |
MAX_TASK_NAME_LEN | 16 | 任务名称字符串的最大长度,设置范围为12至255 |
USE_16_BIT_TICKS | Disabled | 决定文件portmacro.h中定义的节拍数据类型TickType_t的具体类型,若这个值是Disabled,则TickType_t是uin32_类型,否则,是uint16类型。Cortex-M架构上TickType_t是uint32类型 |
IDLE_SHOULD_YIELD | Enabled | 空闲任务是否对同众先级的任务主动让出CPU使用权 |
USE_MUTEXES | Enabled | 是否使用互斤量,只能选择Enabled |
USE_RECURSIVE_MUTEXES | Enabled | 是否使用递归互斤量,只能选择Enabled |
USE_COUNTING_SEMAPHORES | Enabled | 是否使用计数信号量,只能选择Enabled |
QUEUE_REGISTRY_SIZE | 8 | 可注册的队列和信号量的最大数量,设置范围为0至255。使用内核调试器查看信号量和队列时,需要先注册队列和信号量 |
USE_APPLICATION_TASK_TAG | Disabled | 是否使用应用程序的任务标(tag),若对应的宏是1,则会编译一些代码段,特别是文件tasks.c中的3个相关函数:vTaskSetApplicationTaskTag()、xTaskGetApplicationTaskTag()、xTaskCallApplicationTaskHook() |
ENABLE_BACKWARD_COMPATIBILITY | Bnabled | 是否向后兼容旧的版本 |
USE_PORT_OPTIMISED_TASK_SELECTION | Disabled | 任务调度时,选择下一个运行任务的方法。表示使用通用的方法,不依赖于具体的硬件。在使用Cortex-MO或CMSIS-RTOS V2时,只能是Disabled |
USE_TICKLESS_IDLE | Disabled | 是否使用无节拍(tickless)的低功耗模式。若Disabled设置为Enabled,可自动进入低功耗模式降低系统功耗 |
USE_TASK_NOTIFICATIONS | Enabled | 是否使用任务通知功能。若设置为Enabled,则编译相关的函数,每个任务的栈多消耗8字节空间 |
RECORD_STACK_HIGH ADDRESS | Disabled | 是否将栈的起始地址保存到每个任务的任务控制块中(假设找是向下生长的) |
(3)Memorymanagemcutseties,内存管理设置。内存管理的参数设置界面如下图所示,只有3个参数。
- MemoryAllocation,内存分配方式,固定为Dynamic/Static,也就是同时支持动态分配和静态分配。这个参数对应于文件]FreeRTOSConfig.h中的两个宏。这个参数的值不能在CubeMX里修改,但可以在文件FreeRTOSConfig.h里修改,便FreeRTOS同时支持动态分配和静态分配,或只支持一种内存分配方式。
#define configSUPPORT_STATIC_ALLOCATION 1#define configSUPPORT_DYNAMIC_ALLOCATION 1
- TOTAL_HEAP_SIZE,FreeRTOS总的堆空间大小,设置范围为512B~128KB。FreeRTOS中创建的所有对象,如任务、队列、软件定时器、信号量、互序量等,都需要从FreeRTOS的堆空间分配内存。在CubeMX中,FreeRTOS Heap Usage页面显示了当前配置下,FreeRTOS的堆空间使用情况,如下图所示。界面中显示了剩余的可用内存,以及各个任务、各种对象使用的内存量。
- MemoryManagementscheme,内存管理方案。有5种可选的内存管理方案,从heap_1到heap_5,使用哪种方案,就在文件FreeRTOSConfig.h中生成对应那种方案的宏定义。例如,使用方案heap_4,生成的宏定义如下:
#define USE_FreeRTOS_HEAP_4
内存管理是与硬件密切相关的,每一种内存管理方案对应一个源程序文件,如heap_4.c,这些文件在目录\Source\portable\MemMang下。
FreeRTOS的5种内存管理方案各有特点和适用场合,其详细介绍可参考文献Mastering the FreeRTOS Real Time Kernel的第2章。heap_4是献认的内存管理方案,它使用第一匹配(first fit)算法分配内存,能将紧邻的空白内存块整合成一个大的空白内存块,降低产生内存碎片的风险,且速度比标准库中的函数mallocO和fteeQ要快。
(4) Hook function related definitions,钩子函数相关定义。钩子函数类似于回调函数,就是在某个功能或函数执行时要调用的一个函数。钩子函数的代码由用户编写,用于实现一些自定义的处理。
钩子函数的设置界面如下图所示。默认情况下,这些参数值都是Disabled,也就是不实现相应的钩子函数。如果设置为Enabled,CubeMX会在文件freertos.c中自动生成相应钩子函数的函数框架。
下图中各个参数的意义以及设置为Enabled时对应的钩子函数名称见下表,表中只列出了函数名称,省略了函数参数。
钩子函数配置参数 | 调用场合 | 对应的钩子函数名称 |
---|---|---|
USE_IDLE_HOOK | 空闲任务里调用 | vApplicationldleHook() |
USE_TICK_HOOK | 滴嗒定时器虫断服务函数里调用 | vApplicationTickHook() |
USE_MALLOC_FAILED_HOOK | 使用pvPortMalloc0分配内存失败时调用 | vApplicationMallocFailedHook() |
USE_DAEMON_TASK_STARTUP_HOOK | 守护Daemon任务启动时调用 | vApplicationDaemonTaskStartupHook() |
CHECK_FOR_STACK_OVERFLOW | 栈溢出时调用 | vApplicationStackOverflowHook() |
CHBCKFORSTACK_OVERFLOW的选项比较特殊,它提供Option1和Option2两个选项,对应于FreeRTOS内部两种不同的栈溢出处理方法,但是对应的钩子函数名称是相同的。
(5)Runtime and task stats gathering related definitions,运行时间和任务状态收集相关定义。FreeRTOS可以收集任务运行时间和任务状态信息,相关参数的设置界面如下图所示。
- GENERATE_RUNTIME_STATS,若设置为Enabled,则会启动任务运行时间统计功能,并可以通过函数vTaskGetRunTimeStats()读取这些信息。
- USE_TRACE_FACILITY,若设置为Enabled,则会增加一些结构体成员和函数,用于可视化和跟踪调试。
- USE_STATS_FORMATTING_FUNCTIONS,若USE_TRACE_FACILITY和这个参数都设置为Enabled,则会编译函数vTaskList()和yTaskGetRunTimeStats()两个参数中只要有一个设置为Disabled,就不会编译这两个函数。
(6)Co-routine related definitions,协程相关定义,使用协程可以节省内存,主要用于功能有限、内存很小的MCU,现在的MCU内存一般比较充足,就很少使用协程了,所以禁用此功能即可,如下图所示。
(7)Software timer definitions,软件定时器定义。FreeRTOS可以创建软件定时器,其功能类似于高级语言(如C++)中的软件定时器。软件定时器相关参数的设置界面如下图所示。在后面会介绍软件定时器的使用。
- USE_TIMERS,是否使用软件定时器,默认设置为Enabled,且不可修改。
- TIMER_TASK_PRIORITY,定时器服务任务的优先级,默认值是2,属于比较低的优先级。设置范围是0到55,因为总的优先级个数是56。
- TIMER_QUEUE_LENGTH,定时器指令队列的长度,设置范围是1到255。
- TIMER_TASK_STACK_DEPTH,定时器服务任务的栈空间大小,默认值256个字,设置范围是128到32768个字。注意,栈空间的单位是字,而不是字节。
(8) Interruptiheshng behaviour configuration,中断嵌套行为配置。如下图所示,这两个参数与硬件中断相关,在后面会有介绍。
- LIBRARY_LOWEST_INTERRUPT_PRIORITY,最低中断优先级,设置范围是1到15,默认值是15。因为CubeMX使用FreeRTOS时,优先级分组方案中4位都用作抢占优先级,所以最低优先级是15。
- LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY,系统能管理的最高中断优先级,设置范围是1到15,默认值是5。在中断服务函数中,只能调用FreeRTOSAPI函数的中断安全版本,如果一个中断的优先级高于这个值,就不能在此中断的ISR里调用FreeRTOS的中断安全API函数。
(9)Addedwith10.2.1support,V10.2.1版本中新增支持的参数。下图所示的是FreeRTOSV10.2.1版本中新增支持的两个参数。
- MESSAGE_BUFFER_LENGTH_TYPE,消息缓冲区长度类型。消息缓冲区的相关内容在后面会介绍。
- USE_POSIX_ERRNO,使用POSIX标准的错误编号。POSIX(Portable Operating System Interface)即可移植操作系统接口,是操作系统设计的一种接口标准。
ConfigParameters页面中这几组参数,覆盖了文件FreeRTOSConfig.h和FreeRTOS.h中一些主要的可配置的宏定义,还有一些其他的参数就保持默认值。
3.2 "INCLUDE_"类的宏
前缀为“INCLUDE”的宏,用作一些函数的条件编译的条件,控制是否编译这些函数的源代码,从而实现对FreeRTOS的功能裁剪。不编译应用程序中用不到的FreeRTOS API函数,可以使最终编译出的程序尽量小。
在文件FeeRTOSConfig.h和FreeRTOS.h虫,都有有“INCLUDE_”类的宏定义。与"config_"
类的宏定义一样,文件FreeRTOS.h中的是默认的宏定义例如,文件FreeRTOS.h中有如下的定义:
#ifndef INCLUDE_vTaskDelete#define INCLUDE_vTaskDelete 0
#endif
这表示如果没有定义宏INCLUDE_vTaskDelete,就将这个宏定义为0。文件FreeRTOS.h中的定义是默认定义,请勿直接修改文件FreeRTOS.h里的内容。
文件FeeRTOSConfig.h是用户可修改的配置文件,在CubeMX里设置的“INCLUDE_”参数会在这个文件里生成例如,文件FeeRTOSConfig.h中部分“INCLUDE_”类的宏定义如下,其中就有宏定义INCLUDE_vTaskDelete,其值定义为1:
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xQueueGetMutexHolder 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_eTaskGetState 1
前缀为“INCLUDE_”的宏一般用于函数代码的条件编译,例如,函数vTaskDelete()的源代码就有如下的条件编译,这表示当参数INCLUDE_vTaskDelete值为1时,才编译函数vTaskDelete():
#if (INCLUIDE_vTaskDelete == 1)void vTaskDelete(TaskHandle_t xTaskToDelete){/* 省略了函数具体代码*/}
#endif
有些函数代码的编译条件还是多个参数的组合,例如,函数eTaskGetState()的编译条件如下:
#if((INCLUDE_eTaskGetstate==1)||(configUSE_TRACE_FACILITY == 1)||(INCLUDE_xTaskAbortDelay == 1))eTaskstate eTaskGetstate(TaskHandle_t xTask){/*省略了函数具体代码*/}
#endif
在CubeMX的JFreeRTOS配置部分,Includeparameters页面用于设置“INCLUDE_”类宏的值,如下图所示。
在上图所示的界面上,每个参数对应于一个"INCLUDE_"宏,一般也对应于一个函数。例如,参数vTaskPrioritySet对应于宏IINCLUDE_vTaskPrioritySet,用作函数vTaskPrioritySet()的编译条件参数vTaskDelete对应于宏INCLUDEv_vTaskDelete,用作函数vTaskDelete()的编编译条件。
五、往期回顾
STM32Cube高效开发教程<高级篇><FreeRTOS>(一)-----FreeRTOS基础