目录
(3)文件stack_macros.h和StackMacros.h
(3)Memory management settings,内存管理设置
(7)Software timer definitions,软件定时器定义
(8)Interrupt nesting behaviour configuration,中断嵌套行为配置
(9)Added with 10.2.1 support,V10.2.1版本中新增支持的参数
一、FreeRTOS的文件组成
FreeRTOS的程序文件主要分为可修改的用户程序文件和不可修改的FreeRTOS源程序文件。freertos.c是可修改的用户程序文件,FreeRTOS中任务、信号量等对象的创建,用户任务函数都在这个文件里实现。FreeRTOS的源程序文件都在目录\Middlewares\Third_Party\FreeRTOS\Source下,这些是针对选择的MCU型号做好了移植的文件。使用CubeMX生成代码时,用户无须关心FreeRTOS的移植问题,所需的源程序文件已经为用户组织好了。
虽然无须自己进行程序移植和文件组织,但是了解FreeRTOS的文件组成以及主要文件的功能,对于掌握FreeRTOS的原理和使用还是有帮助的。FreeRTOS的源程序文件大致可以分为5类:
1、用户配置和程序文件
用户配置和程序文件包括如下2个文件,用于对FreeRTOS进行各种配置和功能裁剪,以及实现用户任务的功能。
- 文件FreeRTOSConfig.h,是对FreeRTOS进行各种配置的文件,FreeRTOS的功能裁剪就是通过这个文件里的各种宏定义实现的。
- 文件freertos.c,包含FreeRTOS对象初始化函数MX_FREERTOS_Init()和任务函数,是编写用户代码的主要文件。
2、FreeRTOS通用功能文件
是实现FreeRTOS的任务、队列、信号量、软件定时器、事件组等通用功能的文件,这些功能与硬件无关。源程序文件在\Source目录下,头文件在\Source\Include目录下。
这些通用功能文件及其功能见下表。
在一个嵌入式操作系统中,任务管理是必需的,某些功能是在用到时才需要加入的,如事件组、软件定时器、信号量、流缓冲区等。CubeMX在生成代码时,将这些文件全部复制到了项目里,但是它们不会被全部编译到最终的二进制文件里。用户可以对FreeRTOS的各种参数进行配置,实现功能裁剪,这些参数配置实际就是各种条件编译的条件定
件 |
功能 |
croutine.h/.c |
实现协程(co-routine)功能的程序文件,协程主要用于内存非常小的 |
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 |
实现流缓冲区功能的程序文件。流缓冲区是一种优化的进程间通信机 |
message_buffer.h |
实现消息缓冲区的文件。实现消息缓冲区功能的所有函数都是宏函数, |
mpu_prototypes.h |
MPU(内存保护单元)功能的头文件。该文件定义的函数是在标准函 |
3、FreeRTOS通用定义文件
目录\Source\include下有几个与硬件无关的通用定义文件。
(1)文件FreeRTOS.h
这个文件包含FreeRTOS的默认宏定义、数据类型定义、接口函数定义等。FreeRTOS.h中有一些默认的用于FreeRTOS功能裁剪的宏定义,例如:
#ifndef configIDLE_SHOULD_YIELD
#define configIDLE_SHOULD_YIELD 1
#endif
#ifndef INCLUDE_vTaskDelete
#define INCLUDE_vTaskDelete 0
#endif
FreeRTOS的功能裁剪就是通过裁剪这些宏定义实现的,这些用于配置的宏定义主要分为如下两类:
- 前缀为“config”的宏表示某种参数设置,一般地,值为1表示开启此功能,值为0表示禁用此功能,如configIDLE_SHOULD_YIELD表示空闲任务是否对同优先级的任务让出处理器使用权。
-
前缀为“INCLUDE”的宏表示是否编译某个函数的源代码,例如,宏INCLUDE_vTaskDelete的值为1,就表示编译函数vTaskDelete()的源代码,值为0就表示不编译函数vTaskDelete()的源代码。
在FreeRTOS中,这些宏定义通常称为参数,因为它们决定了系统的一些特性。FreeRTOS.h包含系统默认的一些参数的宏定义,不要直接修改此文件的内容。提供给用户可修改的配置文件是FreeRTOSConfig.h,这个文件也包含大量前缀为“config"和“INCLUDE_”的宏定义。如果文件FreeRTOSConfig.h中没有定义某个宏,就使用文件FreeRTOS.h中的默认定义。FreeRTOS的大部分功能配置都可以通过CubeMX可视化设置完成,并生成文件FreeRTOSConfig.h中的宏定义代码。
(2)文件projdefs.h
这个文件包含FreeRTOS中的一些通用定义,如错误编号宏定义,逻辑值的宏定义等。文件projdefs.h中常用的几个宏定义及其功能见表:
宏定义 |
值 |
功能 |
pdFALSE |
0 |
表示逻辑值false |
pdTRUE |
1 |
表示逻辑值true |
pdFAIL |
0 |
表示逻辑值false |
pdPASS |
1 |
表示逻辑值true |
pdMS_TO_TICKS(xTimeInMs) |
— |
这是个宏函数,其功能是将xTimeInMs表示的毫秒数转换 |
(3)文件stack_macros.h和StackMacros.h
这两个文件的内容完全一样,只是为了向后兼容,才出现了两个文件。这两个文件定义了进行栈溢出检查的函数,如果要使用栈溢出检查功能,需要设置参数configCHECK_FOR_STACK_OVERFLOW的值为1或2。
4、CMSIS-RTOS标准接口文件
目录\Source\CMSIS_RTOS_V2下是CMSIS-RTOS标准接口文件。这些文件里的宏定义、数据类型、函数名称等的前缀都是“os”。原理上来说,这些函数和数据类型的名称与具体的RTOS无关,它们是CMSIS-RTOS标准的定义。在具体实现上,这些前缀为"os"的函数调用具体移植的RTOS的实现函数,例如,若移植的是μC/OS-II,“os”函数就调用μC/OS-II的实现函数。若移植的是FreeRTOS,“os”函数就调用FreeRTOS的实现函数。例如,CMSIS-RTOS的延时函数osDelay()的内部就是调用了FreeRTOS的延时函数vTaskDelay(),其完整源代码如下:
/**该函数在cmsis_os2.h声明,在cmsis_os2.c里定义*/
osStatus_t osDelay (uint32_t ticks) {
osStatus_t stat;
if (IS_IRQ()) {
stat = osErrorISR;
}
else {
stat = osOK;
if (ticks != 0U) {
vTaskDelay(ticks);
}
}
return (stat);
}
再如,参考文件中的函数:osThreadNew()的内部调用xTaskCreate()或xTaskCreateStatic()创建任务;osKernelStart()的内部调用vTaskStartScheduler()启动FreeRTOS内核运行。
从原理上来说,如果在程序中使用这些CMSIS-RTOS标准接口函数和类型定义,可以减少与具体RTOS的关联。例如,一个应用程序原先是使用FreeRTOS写的,后来要改为使用uC/OS-II,则只需改RTOS移植部分的程序,而无须改应用程序。CubeMX自动生成的代码使用的基本都是CMSIS-RTOS接口函数,这些是不需要去更改的。
5、硬件相关的移植文件
硬件相关的移植文件就是需要根据硬件类型进行改写的文件,一个移植好的版本称为一个端口(port),这些文件在目录\Source\portable下,又分为架构与编译器、内存管理两个部分:
(1)处理器架构和编译器相关文件
处理器架构和编译器部分有2个文件,即portmacro.h和port.c。这两个文件里是一些与硬件相关的基础数据类型、宏定义和函数定义。因为某些函数的功能实现涉及底层操作,其实现代码甚至是用汇编语言写的,所以与硬件密切相关。
FreeRTOS需要使用一个基础数据类型定义头文件stdint.h,这个头文件定义的是uint8_t、uint32_t等基础数据类型。STM32的HAL库包含这个文件。
在文件portmacro.h中,FreeRTOS重新定义了一些基础数据类型的类型符号,定义的代码如下。Cortex-M4是32位处理器,这些类型定义对应的整数或浮点数类型见注释:
/* Type definitions. */
#define portCHAR char //int8_t
#define portFLOAT float //4字节浮点数
#define portDOUBLE double //8字节浮点数
#define portLONG long //int32_t
#define portSHORT short //int16_t
#define portSTACK_TYPE uint32_t //栈数据类型
#define portBASE_TYPE long //int32_t
typedef portSTACK_TYPE StackType_t; //栈数据类型StackType_t,是uint32_t
typedef long BaseType_t; //基础数据类型BaseType_t,是int32_t
typedef unsigned long UBaseType_t; //基础数据类型UBaseType_t,是uint32_t
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t; //节拍数类型TickType_t,是uint32_t
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
重新定义的4个数据类型符号是为了移植方便,它们的等效定义和意义如表:
数据类型符号 |
等效定义 |
意义 |
BaseType_t |
int32_t |
基础数据类型,32位整数 |
UBaseType_t |
uint32_t |
基础数据类型,32位无符号整数 |
StackType_t |
uint32_t |
栈数据类型,32位无符号整数 |
TickType_t |
uint32_t |
基础时钟节拍数类型,32位无符号整数 |
(2)内存管理相关文件
内存管理涉及内存动态分配和释放等操作,与具体的处理器密切相关。FreeRTOS提供5种内存管理方案,即heap_1至heap_5,在CubeMX里设置FreeRTOS参数时,选择1种即可。heap_4.c是默认的内存管理方案。
文件heap_4.c实现了动态分配内存的函数pvPortMalloc(),释放内存的函数vPortFree(),以及其他几个函数。heap_4.c以目录\Source\include下的portable.h文件为头文件。
二、FreeRTOS的编码规则
FreeRTOS的核心源程序文件遵循一套编码规则,其变量命名、函数命名、宏定义命名等都有规律,知道这些规律有助于理解函数名、宏定义的意义。
1、变量名
变量名使用类型前缀。通过变量名的前缀,用户可以知道变量的类型。
- 对于stdint.h中定义的各种标准类型整数,前缀“c”表示char类型变量,前缀“s”表示int16_t(short)类型变量,前缀“l”表示int32_t类型变量。对于无符号(unsigned)整数,再在前面增加前缀“u”,如“uc”表示uint_8类型,“us”表示uint16_t,“ul”表示uint32_t类型。
- BaseType_t和所有其他非标准类型的变量名,如结构体变量、任务句柄、队列句柄等都用前缀“x”。
- UBaseType_t类型的变量使用前缀“ux”。
- 指针类型变量在前面再增加一个“p”,例如,“pc”表示char*类型。
2、函数名
函数名的前缀由返回值类型和函数所在文件组成,若返回值为void类型,则类型前缀是“v”。举例如下。
- 函数xTaskCreate(),其返回值为BaseType_t类型,在文件task.h中定义。
- 函数vQueueDelete(),其返回值为void,在文件queue.h中定义。
- 函数pcTimerGetName(),其返回值为char*,在文件timer.h中定义。
- 函数pvPortMalloc(),其返回值为void*,在文件portable.h中定义。
如果函数是用static声明的文件内使用的私有函数,则其前缀为“prv”。例如,tasks.c文件中的函数prvAddNewTaskToReadyList(),因为私有函数不会被外部调用,所以函数名中就不用包括返回值类型和所在文件的前缀了。
CMSIS-RTOS相关文件中定义的函数前缀都是“os”,不包括返回值类型和所在文件的前缀。例如,cmsis_os2.h中的函数osThreadNew()、osDelay()等。
3、宏名称
宏定义和宏函数的名称一般用大写字母,并使用小写字母前缀表示宏的功能分组。FreeRTOS中常用的宏名称前缀见表:
前缀 |
意义 |
所在文件 |
实例 |
config |
用于系统功能配置的宏 |
FreeRTOSConfig.h |
configUSE_MUTEXES |
INCLUDE_ |
条件编译某个函数的宏 |
FreeRTOSConfig.h |
INCLUDE_vTaskDelay |
task |
任务相关的宏 |
task.h |
taskENTER_CRITICAL() |
queue |
队列相关的宏 |
queue.h |
queueQUEUE_TYPE_MUTEX |
pd |
项目通用宏定义 |
projdefs.h |
pdTRUE,pdFALSE |
port |
移植接口文件定义的宏 |
portable.h |
portBYTE_ALIGNMENT_MASK |
tmr |
软件定时器相关的宏 |
timer.h |
tmrCOMMAND_START |
os |
CMSIS-RTOS接口相关的宏 |
cmsis_os.h |
osFeature_SysTick |
三、FreeRTOS的配置和功能裁剪
FreeRTOS的配置和功能裁剪主要是通过文件FreeRTOSConfig.h和FreeRTOS.h中的一些宏定义实现的,前缀为“config”的宏用于配置FreeRTOS的一些参数,前缀为“INCLUDE”的宏用于控制是否编译某些函数的源代码。文件FreeRTOS.h中的宏定义是系统默认的宏定义,请勿直接修改。FreeRTOSConfig.h是用户可修改的配置文件,如果一个宏没有在文件FreeRTOSConfig.h中重新定义,就使用文件FreeRTOS.h中的默认定义。
在CubeMX中,FreeRTOS的配置界面中有Config parameters和Include parameters两个页面,用于对这两类宏进行设置。
1、“config”类的宏
前缀为“config”的宏用于对FreeRTOS的一些参数进行配置。参考文件示例中,完全使用了FreeRTOS的默认配置,例如,文件FreeRTOSConfig.h中部分这类宏定义代码如下:
/* USER CODE BEGIN Header */
/*
* FreeRTOS Kernel V10.3.1
* Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/* USER CODE END Header */
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* These parameters and more are described within the 'configuration' section of the
* FreeRTOS API documentation available on the FreeRTOS.org web site.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* Section where include file can be added */
/* USER CODE END Includes */
/* Ensure definitions are only used by the compiler, and not by the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#ifndef CMSIS_device_header
#define CMSIS_device_header "stm32f4xx.h"
#endif /* CMSIS_device_header */
#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
/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
/* Defaults to size_t for backward compatibility, but can be changed
if lengths will always be less than the number of bytes in a size_t. */
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256
/* The following flag must be enabled only when using newlib */
#define configUSE_NEWLIB_REENTRANT 1
/* CMSIS-RTOS V2 flags */
#define configUSE_OS2_THREAD_SUSPEND_RESUME 1
#define configUSE_OS2_THREAD_ENUMERATE 1
#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1
#define configUSE_OS2_THREAD_FLAGS 1
#define configUSE_OS2_TIMER 1
#define configUSE_OS2_MUTEX 1
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#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_xTaskGetCurrentTaskHandle 1
#define INCLUDE_eTaskGetState 1
/*
* The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
* by the application thus the correct define need to be enabled below
*/
#define USE_FreeRTOS_HEAP_4
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* USER CODE BEGIN 1 */
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
/* USER CODE END 1 */
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 0
/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
/* USER CODE END Defines */
#endif /* FREERTOS_CONFIG_H */
在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
那么,如何更新FreeRTOSConfig.h呢?就是在CubeMX可视化设置Config Parameters页面的参数。这个参数有好几组,它们对应于文件FreeRTOSConfig.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表示使用抢占式(pre-emptive)任务调度器; Disabled表示使用合作式(co-operative)任务调度器 |
CPU_CLOCK_HZ |
SystemCoreClock |
系统核心时钟,即MCU的HCLK时钟 |
TICK_RATE_HZ |
1000 |
系统嘀嗒时钟频率,设置范围为1至1000,默认为1000Hz,所以周期是1ms |
MAX_PRIORITIES |
56 |
任务的最多优先级个数,这里固定为56,不可修改 |
MINIMAL_STACK_SIZE |
128 Words |
系统空闲任务的栈空间的最小值,设置范围为64至3840。 在FreeRTOS中,栈空间的大小单位是字,在Cortex-M架构中,一个字是4字节 |
MAX_TASK_NAME_LEN |
16 |
任务名称字符串的最大长度,设置范围为12至255 |
USE_16_BIT_TICKS |
Disabled |
决定文件portmacro.h中定义的节拍数据类型TickType_t的具体类型。 若这个值是Disabled,则TickType_t是uint32_t类型,否则,是uint16_t类型。Cortex-M架构上TickType_t |
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个相关函数: |
ENABLE_BACKWARD_ |
Enabled |
是否向后兼容旧的版本 |
USE_PORT_OPTIMISED_TASK_ |
Disabled |
任务调度时,选择下一个运行任务的方法。 |
USE_TICKLESS_IDLE |
Disabled |
是否使用无节拍(tickless)的低功耗模式。若设置为Enabled,可自动进入低功耗模式,降低系统功耗 |
USE_TASK_NOTIFICATIONS |
Enabled |
是否使用任务通知功能。若设置为Enabled,则编译相关的函数,每个任务的栈多消耗8字节空间 |
RECORD_STACK_HIGH_ADDRESS |
Disabled |
是否将栈的起始地址保存到每个任务的任务控制块中(假设栈是向下生长的) |
(3)Memory management settings,内存管理设置
内存管理的参数设置只有3个参数。
- Memory Allocation,内存分配方式,固定为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的堆空间使用情况,如下图所示。界面中显示了剩余的可用内存,以及各个任务、各种对象使用的内存量。
- Memory Management scheme,内存管理方案。有5种可选的内存管理方案,从heap_1到heap_5,使用哪种方案,就在文件FreeRTOSConfig.h中生成对应那种方案的宏定义。例如,使用方案heap_4,生成的宏定义如下:
#define USE_FreeRTOS_HEAP_4
内存管理是与硬件密切相关的,每一种内存管理方案对应一个源程序文件,如heap_4.c,这些文件在目录\Source\portable\MemMang下。FreeRTOS的5种内存管理方案各有特点和适用场合,heap_4是默认的内存管理方案,它使用第一匹配(first fit)算法分配内存,能将紧邻的空白内存块整合成一个大的空白内存块,降低产生内存碎片的风险,且速度比标准库中的函数malloc()和free()要快。
(4)Hook function related definitions,钩子函数相关定义
钩子函数类似于回调函数,就是在某个功能或函数执行时要调用的一个函数。钩子函数的代码由用户编写,用于实现一些自定义的处理。
钩子函数的设置界面如图所示。默认情况下,这些参数值都是Disabled,也就是不实现相应的钩子函数。如果设置为Enabled,CubeMX会在文件freertos.c中自动生成相应钩子函数的函数框架。当设置为Enabled时对应的钩子函数名称及意义见下表,表中只列出了函数名称,省略了函数参数。
钩子函数配置参数 |
调用场合 |
对应的钩子函数名称 |
USE_IDLE_HOOK |
空闲任务里调用 |
vApplicationIdleHook() |
USE_TICK_HOOK |
嘀嗒定时器中断服务函数里调用 |
vApplicationTickHook() |
USE_MALLOC_FAILED_HOOK |
使用pvPortMalloc()分配内存失败时调用 |
vApplicationMallocFailedHook() |
USE_DAEMON_TASK_STARTUP_ |
守护(Daemon)任务启动时调用 |
vApplicationDaemonTaskStartupHook() |
CHECK_FOR_STACK_OVERFLOW |
栈溢出时调用 |
vApplicationStackOverflowHook() |
特别地,CHECK_FOR_STACK_OVERFLOW的选项比较特殊,它提供Option1和Option2两个选项,对应于FreeRTOS内部两种不同的栈溢出处理方法,但是对应的钩子函数名称是相同的。
(5)Run time and task stats gathering related definitions,运行时间和任务状态收集相关定义
FreeRTOS可以收集任务运行时间和任务状态信息。
- GENERATE_RUN_TIME_STATS,若设置为Enabled,则会启动任务运行时间统计功能,并可以通过函数vTaskGetRunTimeStats()读取这些信息。
- USE_TRACE_FACILITY,若设置为Enabled,则会增加一些结构体成员和函数,用于可视化和跟踪调试。
- USE_STATS_FORMATTING_FUNCTIONS,若USE_TRACE_FACILITY和这个参数都设置为Enabled,则会编译函数vTaskList()和vTaskGetRunTimeStats()。两个参数中只要有一个设置为Disabled,就不会编译这两个函数。
(6)Co-routine related definitions,协程相关定义
使用协程可以节省内存,主要用于功能有限、内存很小的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)Interrupt nesting behaviour configuration,中断嵌套行为配置
其中的两个参数是与硬件中断相关。
- LIBRARY_LOWEST_INTERRUPT_PRIORITY,最低中断优先级,设置范围是1到15,默认值是15。因为CubeMX使用FreeRTOS时,优先级分组方案中4位都用作抢占优先级,所以最低优先级是15。
- LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY,系统能管理的最高中断优先级,设置范围是1到15,默认值是5。在中断服务函数中,只能调用FreeRTOS API函数的中断安全版本,如果一个中断的优先级高于这个值,就不能在此中断的ISR里调用FreeRTOS的中断安全API函数。
(9)Added with 10.2.1 support,V10.2.1版本中新增支持的参数
FreeRTOS V10.2.1版本中新增支持的两个参数。
- MESSAGE_BUFFER_LENGTH_TYPE,消息缓冲区长度类型。
- USE_POSIX_ERRNO,使用POSIX标准的错误编号。POSIX(Portable Operating SystemInterface)即可移植操作系统接口,是操作系统设计的一种接口标准。
2、“INCLUDE_”类的宏
前缀为“INCLUDE_”的宏,用作一些函数的条件编译的条件,控制是否编译这些函数的源代码,从而实现对FreeRTOS的功能裁剪。不编译应用程序中用不到的FreeRTOS API函数,可以使最终编译出的程序尽量小。
在CubeMX的FreeRTOS配置部分,Include parameters页面用于设置“INCLUDE_”类宏的值。每个参数对应于一个"INCLUDE_"宏,一般也对应于一个函数。例如,参数vTaskPrioritySet对应于宏INCLUDE_vTaskPrioritySet,用作函数vTaskPrioritySet()的编译条件;参数vTaskDelete对应于宏INCLUDE_vTaskDelete,用作函数vTaskDelete()的编译条件。依此类推。
在文件FreeRTOSConfig.h和FreeRTOS.h中,都有“INCLUDE_”类的宏定义。与“config_”类的宏定义一样,文件FreeRTOS.h中的是默认的宏定义,例如,文件FreeRTOS.h中有如下的定义:
#ifndef INCLUDE_uxTaskPriorityGet
#define INCLUDE_uxTaskPriorityGet 0
#endif
#ifndef INCLUDE_vTaskDelete
#define INCLUDE_vTaskDelete 0
#endif
这表示如果没有定义这些宏,就将这个宏定义为0。文件FreeRTOS.h中的定义是默认定义,请勿直接修改文件FreeRTOS.h里的内容。
文件FreeRTOSConfig.h是用户可修改的配置文件,在CubeMX里设置的“INCLUDE_”参数,会在这个文件里生成宏定义。例如,文件FreeRTOSConfig.h中部分"INCLUDE_"类的宏定如下,其中就有宏定义INCLUDE_vTaskDelete,其值定义为1:
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#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_xTaskGetCurrentTaskHandle 1
#define INCLUDE_eTaskGetState 1
前缀为“INCLUDE_”的宏一般用于函数代码的条件编译,例如,函数vTaskDelete()的源代码就有如下的条件编译,这表示当参数INCLUDE_vTaskDelete值为1时,才编译函数vTaskDelete():
#if(INCLUDE_vTaskDelete == 1)
void vTaskDelete(TaskHandle_t xTaskToDelete)
{
/* 省略了具体代码 */
}
#endif /*INCLUDE_vTaskDelete */
有些函数代码的编译条件还是多个参数的组合,例如,函数eTaskGetState()的编译条件如下:
#if((INCLUDE_eTaskGetstate == 1)||(configUSE_TRACE_FACILITY == 1)||(INCLUDE_xTaskAbortDelay == 1))
eTaskState eTaskGetState(TaskHandle_t xTask)
{/*省略了函数具体代码*/}
#endif /*INCLUDE_eTaskGetState */
这些函数是要自己写的。
四、参考文件
一些内容还可以参考本文作者发布的其他文章:细说STM32单片机FreeRTOS基础知识及用法-CSDN博客 https://wenchm.blog.csdn.net/article/details/147040055?spm=1011.2415.3001.5331