FreeRTOS学习笔记—配置文件


🎀 文章作者:二土电子

🌸 关注文末公众号获取其他资料和工程文件!

🐸 期待大家一起学习交流!


FreeRTOS是可以配置裁剪的,需要什么功能就可以使能什么功能,需要什么配置也可以更改。FreeRTOS 的配置基本是通过在 FreeRTOSConfig.h 中使用“#define”这样的语句来定义宏定义实现的。

一、“INCLUDE”开头的宏定义

1.1 “INCLUDE”开头的宏定义功能

使用“INCLUDE”开头的宏定义,作用是使能或使能 FreeRTOS 中相应的 API 函数。其实这个的实现方法就是我们在之前开发时使用的条件编译。这里可以看一下“task.c”文件中的一段代码

#if ( INCLUDE_vTaskPrioritySet == 1 )

	void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
	{
		// ...
	}
	
#endif

当宏INCLUDE_vTaskPrioritySet 设置为0时,不能使用函数 vIaskPrioritySet0)。当设置为 1 时,可以使用函数vIaskPrioritySet0。

FreeRTOS 中的裁剪和配置就是这种用条件编译的方法来实现的。利用条件编译的方法,不需要的功能就不再编译,可以节省空间,减少系统占用的 ROM 和 RAM 大小。

以“INCLUDE”开头的宏定义的使用方法比较简单,需要使用某些特定函数时,需要将对应的以“INCLUDE”开头的宏定义设置为1。修改位置如下

修改以“INCLUDE开头的宏定义”

1.2 一些“INCLUDE”开头的宏定义

这里简单标注一下各个以“INCLUDE”开头的宏定义对应的函数

/***************************************************************************************************************/
/*                                FreeRTOS可选函数配置选项                                                      */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState   1   // 使用函数 xTaskGetSchedulerState()
#define INCLUDE_vTaskPrioritySet         1   // 使用函数 vTaskPrioritySet()
#define INCLUDE_uxTaskPriorityGet        1   // 使用函数 uxTaskPriorityGet()
#define INCLUDE_vTaskDelete				       1   // 使用函数 vTaskDelete()
#define INCLUDE_vTaskSuspend			       1   // 使用函数vTaskSuspend(),vTaskResume(),prvTaskIsTaskSuspended(),xTaskResumeFromISR()
#define INCLUDE_vTaskDelayUntil			     1   // 使用函数 vTaskDelayUntil()
#define INCLUDE_vTaskDelay				       1   // 使用函数 vTaskDelay()
#define INCLUDE_eTaskGetState			       1   // 使用函数 eTaskGetState()
#define INCLUDE_xTimerPendFunctionCall	 1   // 使用函数 xTimerPendFunctionCall()和xTimerPendFunctionCallFromISR()

二、“config”开始的宏定义

“config”开始的宏和“INCLUDE_”开始的宏一样,都是用来完成 FreeRTOS 的配置和裁剪的。

2.1 configAPPLICATION_ALLOCATED_HEAP

FreeRTOS的堆内存默认是由编译器来分配的。如果将configAPPLICATION_ALLOCATED_HEAP 定义为 1 的话,堆内存就可以由用户自行设置。堆内存在 heap_1.c、heap_2.c、heap_3.c、heap_4.c 和 heap_5.c 中有定义,我们选用的是“heap_4.c”,在“heap_4.c”中可以修改该宏定义。

/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
	/* The application writer has already defined the array used for the RTOS
	heap - probably so it can be placed in a special segment or address. */
	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */

2.2 configASSERT

//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

断言。类似于C语言中的“assert()”。断言的意思是对某种假设条件进行检测,如果条件成立就不进行任何操作,如果条件不成立就捕捉到这种错误,并打印出错误信息,终止程序执行。在这里,如果x为0,说明发生了错误。

使用断言虽然方便在程序调试时发现错误,但是会导致程序编译后的目标代码体积变大,降低最终发布的程序效率。断言只会报告程序是错误的,而不会对错误进行相应的处理。因此,断言一般只适合用在调试阶段。

vAssertCalled()函数需要用户自行去定义,既可以将错误信息显示到显示器件上,也可以是通过串口打印出来。上面的vAssertCalled()函数是当参数 x 错误是,会通过串口打印出发生错误的文件名和错误所在的行号。

2.3 configCHECK_FOR_STACK_OVERFLOW

设置堆栈溢出检测。每个任务都有一个任务堆栈,如果使用函数 xTaskCreate()创建一个任务的话那么这个任务的堆栈是自动从 FreeRTOS 的堆(ucHeap)中分配的,堆栈的大小是由函数xTaskCreate)的参数 usStackDepth 来决定的。如果使用函数 xTaskCreateStatic0创建任务的话任务堆栈是由用户设置的,参数 pxStackBuffer 为任务堆栈,一般是一个数组。

堆栈溢出是导致应用程序不稳定的主要因素,FreeRTOS 提供了两种可选的机制来帮助检测和调试堆栈溢出,不管使用哪种机制都要设置宏 configCHECK FOR STACK OVERFLOW。不管使用哪种检测机制,都需要事先定义好一个钩子函数(回调函数)。当检测到有堆栈溢出时,会调用这个钩子函数。

vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName );

参数 xTask 是任务句柄,pcTaskName 是任务名字,要注意的是堆栈溢出太严重的话可能会损毁这两个参数,如果发生这种情况的话可以直接查看变量 pxCurrentTCB 来确定哪个任务发生了堆栈溢出。堆栈溢出检测一般也只是在调试阶段使用。

2.3.1 堆栈溢出检测方法一

上下文切换时需要保存现场,而现场是保存在堆栈中的,这个时候任务堆栈使用率很可能达到量大值。方法一就是不断的检测任条堆栈指针是否指向有效空间,如果指向了无效空旧的话就会调用钩子函数。该方法的优点就是快,但是不能检测全部类型的堆栈溢出。

2.3.2 堆栈溢出检测方法二

方法二在创建任务时,会向任务堆栈填充一个已知的标记值,方法二会一直检测堆栈后面的几个bvtes(标记值)是否被改写,如果被改写的话就会调用堆栈溢出钩子函数。方法二虽然比方法一慢一点。但是方法二能检测到几乎所有的堆栈溢出。但是也有一些情况检测不到,比如溢出值和标记值相同的时候。

2.4 configCPU_CLOCK_HZ

设置CPU频率

2.5 configSUPPORT_DYNAMIC_ALLOCATION

该宏定义为1时,创建 FreeRTOS 的内核对象所需要的 RAM 会从 FreeRTOS 的堆中动态的获取。如果为 0 ,所需的 RAM 就需要用户自行提供,默认情况下为1。

2.6 configENABLE_BACKWARD_COMPATIBILITY

开启数据类型宏定义的条件编译。在“FreeRTOS.h”文件中定义了一些数据类型,当configENABLE_BACKWARD_COMPATIBILITY为1时,使能这些数据类型的定义。

#if configENABLE_BACKWARD_COMPATIBILITY == 1
	#define eTaskStateGet eTaskGetState
	#define portTickType TickType_t
	#define xTaskHandle TaskHandle_t
	#define xQueueHandle QueueHandle_t
	#define xSemaphoreHandle SemaphoreHandle_t
	#define xQueueSetHandle QueueSetHandle_t
	#define xQueueSetMemberHandle QueueSetMemberHandle_t
	#define xTimeOutType TimeOut_t
	#define xMemoryRegion MemoryRegion_t
	#define xTaskParameters TaskParameters_t
	#define xTaskStatusType	TaskStatus_t
	#define xTimerHandle TimerHandle_t
	#define xCoRoutineHandle CoRoutineHandle_t
	#define pdTASK_HOOK_CODE TaskHookFunction_t
	#define portTICK_RATE_MS portTICK_PERIOD_MS
	#define pcTaskGetTaskName pcTaskGetName
	#define pcTimerGetTimerName pcTimerGetName
	#define pcQueueGetQueueName pcQueueGetName
	#define vTaskGetTaskInfo vTaskGetInfo

	/* Backward compatibility within the scheduler code only - these definitions
	are not really required but are included for completeness. */
	#define tmrTIMER_CALLBACK TimerCallbackFunction_t
	#define pdTASK_CODE TaskFunction_t
	#define xListItem ListItem_t
	#define xList List_t
#endif /* configENABLE_BACKWARD_COMPATIBILITY */

2.7 configGENERATE_RUN_TIME_STATS

设置为 1 开启时间统计功能,相应的 API 函数会被编译,为 0 时关闭时间统计功能。如果设置为1,还需要再配置下面两个宏定义

时间统计功能对应宏定义

2.8 configIDLE_SHOULD_YIELD

当configIDLE_SHOULD_YIELD为0时,处于空闲状态的任务不会将CPU使用权让给同等优先级的其他就绪状态任务。当configIDLE_SHOULD_YIELD为1时,处于空闲状态的任务会将CPU使用权让给其他同等优先级的就绪状态任务,除非没有处于就绪状态的任务。这样会减少在空闲任务上花费的时间。但是,当把configIDLE_SHOULD_YIELD设置为1时,也会带来副作用。

任务运行图

图中T0~T1为一个时间片。任务A,B,C,I是三个同等优先级的任务。但是I是一个空闲任务。任务B和任务C执行完成后,执行任务I。此时,任务A处于就绪状态。由于configIDLE_SHOULD_YIELD设置为1。所以任务I会将CPU使用权让给任务A。任务A执行一段时间后继续执行其他任务。可以看出,任务A的执行时间会比其他两个任务少。通常我们现在使用的CPU性能都比较强,所以一般都会关闭这个功能。

2.9 configMAX_CO_ROUTINE_PRIORITIES

设置可以分配给协程的最大优先级,也就是协程的优先级数。设置完成后,协程的优先级可以从 0 到 configMAX CO ROUTINE PRIORITIES-1,其中0是最低的优先级configMAX CO ROUTINE PRIORITIES1 为最高的优先级协程,英文Coroutines,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。协程不是被操作系统内核所管理,而完全是由程序所控制。

2.10 configMAX_PRIORITIES

设置任务的优先级数量。设置完成后,任务就可以使用从 0 到 configMAX_PRIORITIES-1 的优先级,其中 0 是最低优先级configMAX_PRIORITIES-1 是最高优先级

2.11 configMAX_TASK_NAME_LEN

设置任务名最大长度

2.12 configMINIMAL_STACK_SIZE

设置空闲任务的最小任务堆栈大小以字为单位,不是字节。比如在 STM32 上设置为 100的话,那么真正的堆栈大小就是 100*4=400 字节。

2.13 configNUM_THREAD_LOCAL_STORAGE_POINTERS

设置每个任务的本地存储指针数组大小,任务控制块中有本地存储数组指针,用户应用程序可以在这些本地存储中存入一些数据。

2.14 configQUEUE_REGISTRY_SIZE

设置可以注册的队列和信号量的最大数量,在使用内核调试器查看信号量和队列的时候需要设置此宏,而且要先将消息队列和信号量进行注册,只有注册了的队列和信号量才会再内核调试器中看到,如果不使用内核调试器的话此宏设置为 0 即可。

2.15 configSUPPORT_STATIC_ALLOCATION

当此宏定义为1,在创建一些内核对象的时候需要用户指定 RAM,当为0的时候就会自使用 heap.c 中的动态内存管理函数来自动的申请 RAM。

2.16 configTICK_RATE_HZ

设置 FreeRTOS 的系统时钟节拍频率,单位为 HZ,这个频率就是滴答定时器的中断频率,需要使用此宏定义来配置滴答定时器的中断。

2.17 configTIMER_QUEUE_LENGTH

配置 FreeRTOS 软件定时器,FreeRTOS 的软件定时器 API函数会通过命令队列向软件定时器任务发送消息,此宏用来设置这个软件定时器的命令队列长度。

2.18 configTIMER_TASK_PRIORITY

设置软件定时器任务的任务优先级

2.19 configTIMER_TASK_STACK_DEPTH

设置定时器服务任务的任务堆栈大小

2.20 configTOTAL_HEAP_SIZE

设置堆大小,如果使用了动态内存管理的话,FreeRTOS 在创建任务、信号量、队列等的时候就会使用 heap x.cx 为 1~5)中的内存申请函数来申请内存。这些内存就是从堆ucHeap[configTOTAL HEAP SIZE]中申请的,堆的大小由 configTOTAL HEAP SIZE 来定义。

2.21 configUSE_16_BIT_TICKS

设置系统节拍计数器变量数据类型,系统节拍计数器变量类型为 TickIype t,当configUSE 16 BIT TICKS 为1 的时候 TickType t 就是 16 位的,当 configUSE 16 BIT TICKS为 0的话 TickType t就是 32 位的。

2.22 configUSE_APPLICATION_TASK_TAG

此宏设置为1的话函数configUSE APPLICATION TASK TAGFO 和xTaskCallApplicationTaskHook(就会被编译。

2.23 configUSE_CO_ROUTINES

此宏为 1的时候启用协程,协程可以节省开销,但是功能有限,现在的 MCU 性能已经非常强大了,建议关闭协程

2.24 configUSE_COUNTING_SEMAPHORES

设置为 1的时候启用计数型信号量,相关的 API 函数会被编译。

2.25 configUSE_DAEMON_TASK_STARTUP_HOOK

当宏 configUSE TIMERS 和 configUSE DAEMON TASK STARTUP HOOK 都为1时,需要定义函数 VApplicationDaemonTaskStartupHook()

void vApplicationDaemonTaskStartupHook( void );

2.26 configUSE_IDLE_HOOK

为 1 时使用空闲任务钩子函数,用户需要实现空闲任务钩子函数

void vApplicationIdleHook( void );

2.27 configUSE_MALLOC_FAILED_HOOK

为 1 时使用内存分配失败钩子函数,用户需要实现内存分配失败钩子函数

void vApplicationMallocFailedHook( void );

2.28 configUSE_MUTEXES

为 1 时使用互斥信号量,相关的 API 函数会被编译。

2.29 configUSE_PORT_OPTIMISED_TASK_SELECTION

FreeRTOS 有两种方法来选择下一个要运行的任务,一个是通用的方法,另外一个是特殊的方法,也就是硬件方法,使用 MCU自带的硬件指今来实现。该宏定义设置为0时,为通用方法。设置为1时,为特殊方法。

2.30 configUSE_PREEMPTION

为1时使用抢占式调度器,为 0 时使用协程。如果使用抢占式调度器的话,内核会在每个时钟节拍中断中进行任务切换。当使用协程的话,会在如下地方进行任务切换

  • 一个任务调用了函数 taskYIELD()
  • 一个任务调用了可以使任务进入阻塞态的 API 函数
  • 应用程序明确定义了在中断中执行上下文切换

2.31 configUSE_QUEUE_SETS

为 1 时启用队列集功能

2.32 configUSE_RECURSIVE_MUTEXES

为 1 时使用递归互斥信号量,相关的 API 函数会被编译。

2.33 configUSE_STATS_FORMATTING_FUNCTIONS

宏 configUSE TRACE FACILITY 和 configUSE STATS FORMATTING FUNCTIONS 都为1的时候函数 vTaskList0和 vTaskGetRunTimeStats0会被编译。

2.34 configUSE_TASK_NOTIFICATIONS

为1的时候使用任务通知功能,相关的 API函数会被编译,开启了此功能的话每个任务会多消耗8 个字节

2.35 configUSE_TICK_HOOK

为 1时使能时间片钩子函数,用户需要实现时间片钩子函数

void vApplicationTickHook( void );

2.36 configUSE_TICKLESS_IDLE

为1时使能低功耗 tickless 模式

2.37 configUSE_TIMERS

为1时使用软件定时器,相关的 API 函数会被编译,当宏 configUSE TIMERS 为1的话那 么 宏configTIMER TASK PRIORITYconfigTIMER OUEUE LENGTH和configTIMER TASK STACK DEPTH 必须定义。

2.38 configUSE_TIME_SLICING

默认情况下,FreeRTOS 使用抢占式调度器,这意味着调度器永远都在执行已经就绪了的最高优先级任务,优先级相同的任务在时钟节拍中断中进行切换。当宏 configUSE TIME SLICING为 0 时,不会在时钟节拍中断中执行相同优先级任务的任务切换,默认情况下宏configUSE TIME SLICING 为1。

2.39 configUSE_TRACE_FACILITY

为 1 启用可视化跟踪调试,会增加一些结构体成员和 API 函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二土电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值