FreeRTOS学习笔记——系统配置

FreeRTOS的系统配置文件是“FreeRTOSConfig.h”,通过此文件可以对系统进行裁剪和配置。FreeRTOS的配置基本都是通过“FreeRTOSConfig.h”中的#define语句来定义宏定义实现的。

一、“INCLUDE_”开始的宏

使用“INCLUDE_”开始的宏表示使能或除能对应的FreeRTOS的API函数,作用就是用来配置FreeRTOS的可选API函数。比如当宏INCLUDE_vTaskPrioritySet配置为0的时候不能表示不能使用vTaskPrioritySet()函数。如图所示:

 

 只有当宏INCLUDE_vTaskPrioritySet配置为1的时候,vTaskPrioritySet()函数才会被编译。不止FreeRTOS这么干,其他的很多协议栈、GUI库和RTOS系统也都是使用条件编译来实现配置和剪裁的

,条件编译的好处就是节省空间,不需要的功能就不用编译,根据实际需求减少系统占用的RAM和ROM大小,根据自己使用的MCU来调整系统消耗,降低成本。

其他的几个INCLUDE_开头的宏也是相同的道理:

 

 二、“config”开始的宏

1.configAPPLICATION_ALLOCATED_HEAP

“config”开始的宏也是用来完成FreeRTOS配置和裁剪的,例如,configAPPLICATION_ALLOCATED_HEAP定义为1的话,堆内存可以由用户自行配置,堆内存在heap1.c、heap2.c、heap3.c、heap4.c和heap5.c中有定义,具体在哪一个文件,取决于选择的内存管理方式。例如我们使用了heap4.c,在heap4.c中就有如图所示的定义:

 

 当宏configAPPLICATION_ALLOCATED_HEAP配置为1的时候,需要用户自行配置堆内存ucHeap,否则由编译器分配。

 

2.configASSERT

断言,类似C库中的assert()函数,调试代码的时候判断传入的参数是否合理。FreeRTOS内核中的关键点都会调用configASSERT(x),当x=0的时候说明有错误发生,使用断言的话会导致开销加大,一般用于调试阶段。如图所示:

 

 调试结束后,尽量将断言去掉,防止开销增大。

 3.configCHECK_FOR_STACK_OVERFLOW

设置堆栈溢出检测,使用xTaskCreat()函数创建一个任务的话,任务的堆栈是自动从FreeRTOS的堆(ucHeap)中分配的,堆栈的大小由usStackDepth来决定。如果使用函数xTaskCreateStatic()创建任务的话任务堆栈是由用户设置的,参数pxStackBuffer为任务堆栈,一般是一个数组。当宏configCHECK_FOR_STACK_OVERFLOW不为0时,使能堆栈检测功能,必须提供一个钩子函数(回调函数),当内核检测到堆栈溢出的时候就会调用这个函数,此钩子函数原型为:

void vApplicationStackOverflowHook( TaskHandle_t xTask,
                                               char * pcTaskName )

  参数xTask是任务句柄,pcTaskName是任务名字。要注意的是堆栈溢出情况太严重的话,可能会损毁这两个参数,如果发生了这种情况可以直接查看变量pxCurrentTCB来确定是哪个任务发生了堆栈溢出,有些处理器可能在堆栈溢出的时候发生一个fault中断来提示这种错误,另外 ,堆栈溢检测会增加上下文切换的开销,建议在调试的时候使用。

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

configCHECK_FOR_STACK_OVERFLOW==2,使用堆栈溢出检测方法2。

使用方法二的话在创建任务的时候会向任务堆栈填充一个已知的标记值,方法二会一直检测堆栈后面的几个bytes(标记值)是否被改写,如果被改写的话就会调用堆栈溢出钩子函数,方法二也会使用方法一中的机制!方法二比方法一要慢一些,但是对用户而言还是很快的!方法二能检测到几乎所有的堆栈溢出,但是也有一些情况检测不到,比如溢出值和标记值相同的时候。

 4.configCPU_CLOCK_HZ

设置CPU频率

 5.configSUPPORT_DYNAMIC_ALLOCATION

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

6.configENABLE_BACKWARD_COMPATIBILITY

FrecRTOS.h中由一些列的#define宏定义,这些宏定义都是一些数据类型名字,如下图3.2.2所示:

 

 7.configGENERATE_RUN_TIME_STATS

设置为1开启时间统计功能,相应的API函数会被编译,为0时关闭时间统计功能。如果宏configGENERATE_RUN_TIME_STATS为1的话还需要定义表3.2.1中的宏。

 

 8、configIDLE_SHOULD_YIELD

 此宏定义了与空闲任务(idle Task)处于同等优先级的其他用户任务的行为,当为0的时候空闲任务不会为其他处于同优先级的任务让出CPU使用权。当为1的时候空闲任务就会为处于同等优先级的用户任务让出CPU使用权,除非没有就绪的用户任务,这样花费在空闲任务上的时间就会很少,但是这种方法也带了副作用,见图3.2.3。

 

 图3.2.3中有三个用户任务:A、B、C,还有一个空闲任务I,用户任务和空闲任务处于同一优先级,任务切换发生在TO~T7时刻。T0~T1之间的时间为一个时间片,从图中可以看出一开始任务B、C都执行了一个完成的时间片,在T2时刻空闲任务Ⅰ开始执行,1任务运行了一段时间以后被A任务抢走了CPU使用权,A任务运行到T3时刻发生任务切换,B任务开始运行。可以看出其实任务Ⅰ和任务A一起使用了一个时间片,所以任务A运行的时间就比其他任务少!

 一般建议大家关闭这个功能,毕竟空闲任务用不了多少时间,而且现在的MCU性能都很强!

9、 configKERNEL_INTERRUPT_PRIORITY、configMAX_sYSCALL_INTERRUPT_PRIORITY、configMAX_APl_CALL_INTERRUPT_PRIORITY

这三个宏跟FreeRTOS的中断配置有关。

10、configMAX_CO_ROUTINE_PRIORITIES

 

 设置可以分配给协程的最大优先级,也就是协程的优先级数。设置号以后协程的优先级可以从0 到configMAX_CO_ROUTINE_PRIORITIES-1 ,其中 0是最低的优先级﹐configMAx_CO_ROUTINE_PRIORITIES-1为最高的优先级。

 11、configMAX PRIORITIES

设置任务的优先级数量,设置好以后任务就可以使用从0到configMAX_PRIORITIES-1的优先级,其中0是最低优先级,configMAX_PRIORITIES-1是最高优先级。注意和UCOS的区别,UcoS中0是最高优先级!

12、configMINIMAL_STACK_SIZE

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

13、configNUM_THREAD_LOCAL_STORAGE_POINTERS

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

 14、configQUEUE_REGISTRY_SIZE

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

15、configSUPPORT_STATIC_ALLOCATION

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

16、configTICK_RATE_HZ
设置FreeRTOS的系统时钟节拍频率,单位为HZ,此频率就是滴答定时器的中断频率,需要使用此宏来配置滴答定时器的中断,前面在讲delay.c文件的时候已经说过了。为了兼容ST最新的HAL库,我们将此宏设置为1000,周期就是1ms.


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


18、configTIMER_TASK_PRIORITY
设置软件定时器任务的任务优先级。


19、configTIMER_TASK_STACK_DEPTH

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

 20、configTOTAL_HEAP_SIZE

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

21、configUSE_16_BIT_TICKS

 设置系统节拍计数器变量数据类型,系统节拍计数器发重尖型闪11CKIype_t,=configUSE_16_BIT_TICKS为1的时候TickType_t就是16位的,当configUSE_16_BIT_TICKS为0的话TickType_t就是32位的。

 22、configUSE_APPLICATION_TASK_TAG

 此宏设置为1的 话﹐函数configUSE_APPLICATION_TASK_TAGF()和xTaskCallApplicationTaskHook()就会被编译。

 23、configUSE_CO_ROUTINES

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

 24、configUSE_COUNTING_SEMAPHORES

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

25、configUSE_DAEMON_TASK_STARTUP_HOOK

当宏configUSE_TIMERS和 configUSE_DAEMON_TASK_STARTUP_HOOK都为Ⅰ的时需要定义函数vApplicationDaemonTaskStartupHook(),函数原型如下: :void vApplicationIdleHook( void )

 26、configUSE_IDLE_HOOK

 为1时使用空闲任务钩子函数,用户需要实现空闲任务钩子函数,函数的原型如下:void vApplicationIdleHook( void )

27、configUSE_MALLOC_FAILED_HOOK

为1时使用内存分配失败钩子函数,用户需要实现内存分配失败钩子函数,函数原型如下;void vApplicationMallocFailedHook( void )

28、configUSE_MUTEXES

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

29、configUSE_PORT_OPTIMISED_TASK_SELECTION

FreeRTOS有两种方法来选择下一个要运行的任务,一个是通用的方法,另外一个是特殊的方法,也就是硬件方法,使用MCU自带的硬件指令来实现。

通用方法:

  • 当宏configuSE_PORT_OPTIMISED_TASK_SELECTION为0,或者硬件不支持的时候。
  • 希望所有硬件通用的时候。
  • 全部用c语言来实现,但是效率比特殊方法低。
  • 不限制最大优先级数目的时候。

特殊方法:

  • 不是所有的硬件都支持。
  • 当宏configuSE_PORT_OPTIMISED_TASK_SELECTION为1的时候。
  • 硬件拥有特殊的指令,比如计算前导零(CLZ)指令。
  • 比通用方法效率高。
  • 会限制优先级数目,一般是32个。

STM32有计算前导零的指令,所以我们可以使用特殊方法,即将宏configUSE_PORT_OPTIMISED_TASK_SELECTION定义为1。计算前导零的指令在UCOSIII也用到了,也是用来查找下一个要运行的任务的。

30、configUSE_PREEMPTION

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

31、configUSE_QUEUE_SETS

为1时启用队列集功能。

32、configUSE_RECURSIVE_MUTEXES

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

33、configUSE_STATS_FORMATTING_FUNCTIONS

宏configUSE_TRACE_FACILITY和 configUSE_STATS_FORMATTING_FUNCTIONS都为1的时候函数vTaskList()和 vTaskGctRunTimeStats()会被编译。 

 

34、configUSE_TASK_NOTIFICATIONS

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

35、configUSE_TICK_HOOK

为1时使能时间片钩子函数,用户需要实现时间片钩子函数,函数的原型如下:void vApplicationTickHook( void )

36、configUSE_TICKLESS_IDLE

为1时使能低功耗tickless模式。

37、configUSE_TIMERS

为1时使用软件定时器,相关的API函数会被编译,当宏configUSE_TIMERS为1的话,那么宏configTIMER_TASK_PRIORITY , configTIMER_QUEUE_LENGTH和configTIMER_TASK_STACK_DEPTH必须定义。

38、configUSE_TIME_SLICING

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

39、configUSE_TRACE_FACILITY

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

FreeRTOS的配置文件基本就这些,还有一些其他的配置宏由于使用的比较少这里并没有列出来,这些配置具体使用到的时候在具体查看就行了。

PS:

11、configMAX_TASK_NAME_LEN

设置任务名最大长度。

本文参考正点原子的《STM32F429FreeRTOS开发手册》

 

posted @ 2021-10-03 00:21  沙河淘金  阅读(757)  评论(0编辑  收藏  举报