【FreeRTOS学习05】深度解剖FreeRTOSConfig.h实现对系统的自定义剪裁
ROM/RAM太小,因此要对系统进行剪裁;
相关文章
【FreeRTOS实战汇总】小白博主的RTOS学习实战快速进阶之路(持续更新)
文章目录
- 1 系统的剪裁
- 2 FreeRTOSConfig.h
- 3 应用相关配置
- configUSE_PREEMPTION
- configMAX_PRIORITIES
- configMINIMAL_STACK_SIZE
- configUSE_16_BIT_TICKS
- configUSE_CO_ROUTINES
- configMAX_CO_ROUTINE_PRIORITIES
- 4 内存管理配置
- configSUPPORT_STATIC_ALLOCATION
- configSUPPORT_DYNAMIC_ALLOCATION
- configTOTAL_HEAP_SIZE
- configAPPLICATION_ALLOCATED_HEAP
- 5 hook 钩子函数
- configUSE_TICK_HOOK
- configUSE_IDLE_HOOK
- configUSE_MALLOC_FAILED_HOOK
- configUSE_DAEMON_TASK_STARTUP_HOOK
- 6 功能选配
- 7 总结
1 系统的剪裁
嵌入式系统通常都支持用户自定义进行剪裁,比较常见的Linux系统通过Kbuild在构建系统的时候进行剪裁,同样,国产的RT-Thread也支持Kbuild,可以很方便地通过menuconfig进行内核的剪裁,具体如下所示;

另外也支持通过对config文件进行配置,Linux的内核构建过程可以参考文章《探索Linux内核:Kconfig / kbuild的秘密》;
FreeRTOS支持使用FreeRTOSConfig.h配置文件进行定制,下面有几点需要注意的地方;
- 每个FreeRTOS应用程序的预处理器必须包含头文件
FreeRTOSConfig.h; FreeRTOSConfig.h是根据用户需求而进行定制产生的文件,它应位于应用程序的目录中,而不是RTOS内核代码的目录;FreeRTOS源码中的每一个demo程序都有属于自己的FreeRTOSConfig.h文件,如果一下配置选项被省略,那这些设置为默认值;- 用户通过修改
FreeRTOSConfig.h头文件中的宏定义,从而删减系统的模块,设置任务栈空间大小,设置系统分配的堆大小等等,下面配合源码进行详细解析。
2 FreeRTOSConfig.h
这里先找到文件FreeRTOSConfig.h,这个FreeRTOS工程是通过CubeIDE进行快速整合的,具体可以参考《【FreeRTOS学习01】CubeIDE快速整合FreeRTOS创建第一个任务》;工程结构如下图所示;

本文的FreeRTOSConfig.h头文件是根据集成在CubeIDE中的CubeMX插件自动生成的,源码如下所示;
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* 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;
void xPortSysTickHandler(void);
#endif
#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0 //
#define configUSE_TICK_HOOK 0 //
#define configCPU_CLOCK_HZ ( SystemCoreClock ) //输入以Hz为单位的CPU频率:例如 72Mb->72000000
#define configTICK_RATE_HZ ((TickType_t)1000) //输入以Hz为单位的滴答中断频率
#define configMAX_PRIORITIES ( 7 ) //应用程序任务可用的优先级数
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configTOTAL_HEAP_SIZE ((size_t)15360)
#define configMAX_TASK_NAME_LEN ( 16 ) //创建任务时,任务的名称允许的最大长度
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1 //使用互斥功能
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* 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 0
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
/* 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: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
/* #define xPortSysTickHandler SysTick_Handler */
#endif /* FREERTOS_CONFIG_H */
下面将对某些额外需要注意的进行另外注释;
3 应用相关配置
configUSE_PREEMPTION
这个宏定义来选择当前系统任务之间的调度算法;
- 设置为
1,则表示选择RTOS为抢占式调度; - 设置为
0,则表示调度算法为时间片调度;
通常这里需要设置为抢占式调度,一般设置为
1
configMAX_PRIORITIES
应用程序任务可用 的优先级数,任意数量的任务可以共享相同的优先级。协同例程(Co-routines)分别进行优先级排序,可以参考configMAX_CO_ROUTINE_PRIORITIES;
每个可用的优先级都会消耗RTOS内核中的RAM,因此该值不应设置为高于应用程序实际需要的值;
configMINIMAL_STACK_SIZE
空闲任务使用的堆栈大小;通常,不应将此值从演示应用程序随附的FreeRTOSConfig.h文件中为您所使用的端口设置的值中减少。
xTaskCreate()和 xTaskCreateStatic()函数的堆栈大小参数一样,堆栈大小以字而不是字节,如果放在堆栈上的每个单元都是32位,堆栈大小100则表示400字节,4bytes等于32bit;
configUSE_16_BIT_TICKS
- 设置为
1:TickType_t被定义(类型定义)为无符号的16位类型; - 设置为
0:TickType_t被定义(类型定义)为无符号的32位类型;
当系统是8位或16位的结构时,使用这个设置,可以提高能;
configUSE_CO_ROUTINES
- 设置为
1可在构建中包括协同例程功能; - 设置为
0可从构建中省略协同例程功能;
要包含协例程,必须在项目中包含
croutine.c
configMAX_CO_ROUTINE_PRIORITIES
应用程序协同例程可用的优先级数。任意数量的协同例程可以共享相同的优先级。任务分别进行优先级排序-请参阅configMAX_PRIORITIES
4 内存管理配置
configSUPPORT_STATIC_ALLOCATION
- 设置为
1:则可以使用程序中预先分配好的RAM创建RTOS对象; - 设置为
0:只能使用从FreeRTOS堆分配的RAM创建RTOS对象;
如果未定义configSUPPORT_STATIC_ALLOCATION,则默认为0
如果将configSUPPORT_STATIC_ALLOCATION设置为1,则应用程序编写器还必须提供两个回调函数:- -
vApplicationGetIdleTaskMemory():用于提供RTOS空闲任务的内存;vApplicationGetTimerTaskMemory():用于提供RTOS守护程序/计时器服务任务(如果configUSE_TIMERS设置为1)的内存: 。
这个在移植的时候可能也会遇到,具体如下所示;
/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an
implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
used by the Idle task. */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
/* If the buffers to be provided to the Idle task are declared inside this
function then they must be declared static – otherwise they will be allocated on
the stack and so not exists after this function exits. */
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
/* Pass out a pointer to the StaticTask_t structure in which the Idle task’s
state will be stored. */
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
/* Pass out the array that will be used as the Idle task’s stack. */
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
Note that, as the array is necessarily of type StackType_t,
configMINIMAL_STACK_SIZE is specified in words, not bytes. */
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
/*———————————————————–*/
/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
application must provide an implementation of vApplicationGetTimerTaskMemory()
to provide the memory that is used by the Timer service task. */
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
/* If the buffers to be provided to the Timer task are declared inside this
function then they must be declared static – otherwise they will be allocated on
the stack and so not exists after this function exits. */
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
/* Pass out a pointer to the StaticTask_t structure in which the Timer
task’s state will be stored. */
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
/* Pass out the array that will be used as the Timer task’s stack. */
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
Note that, as the array is necessarily of type StackType_t,
configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
configSUPPORT_DYNAMIC_ALLOCATION
- 设置为
1:则可以使用从FreeRTOS堆自动分配的RAM创建RTOS对象; - 设置为
0:则只能使用应用程序编写器提供的RAM创建RTOS对象;
如果未定义configSUPPORT_DYNAMIC_ALLOCATION,则默认为1;
configTOTAL_HEAP_SIZE
设置FreeRTOS中堆可用的RAM总量;
仅当configSUPPORT_DYNAMIC_ALLOCATION设置为1;且使用FreeRTOS源代码下载中提供的示例内存分配方案(heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c)时,才会配置这个值;
configAPPLICATION_ALLOCATED_HEAP
- 设置为
0:FreeRTOS堆由FreeRTOS声明,并由链接器放置在内存中; - 设置为
1:可以使堆改为由用户程序进行设置,允许将堆放置在内存中任意位置;
如果使用
heap_1.c,heap_2.c或heap_4.c,并且configAPPLICATION_ALLOCATED_HEAP设置为1,那么应用程序编写器必须提供一个uint8_t数组,其名称和维数如下所示。
uint8_t ucHeap [configTOTAL_HEAP_SIZE];
该数组将被作为FreeRTOS的堆来使用。如何将数组放置在特定的内存位置取决于所使用的编译器–请参阅编译器的文档。
5 hook 钩子函数
钩子函数的本质就是回调函数,有下面四个函数;
configUSE_TICK_HOOK;configUSE_IDLE_HOOK;configUSE_MALLOC_FAILED_HOOK;configUSE_DAEMON_TASK_STARTUP_HOOK;
具体参考hook函数;
configUSE_TICK_HOOK
程序必须为hook函数提供以下原型:
void vApplicationTickHook( void );
configUSE_IDLE_HOOK
configUSE_IDLE_HOOK设置为1,才会调用IDLE_HOOK,设置此选项后,应用程序必须为hook函数提供以下原型:
void vApplicationIdleHook(void);
configUSE_MALLOC_FAILED_HOOK
程序必须为hook函数提供以下原型:
void vApplicationMallocFailedHook( void );
configUSE_DAEMON_TASK_STARTUP_HOOK
RTOS守护程序任务与计时器服务任务相同。有时将其称为守护程序任务,因为该任务现在不仅用于维护计时器,还用于更多任务。
将configUSE_DAEMON_TASK_STARTUP_HOOK设置为1,则在守护程序任务首次开始执行时,将立即调用守护程序任务启动钩子函数。应用程序的初始化代码如果需要放在该钩子函数中,则该功能将很有用,这将允许初始化代码利用RTOS功能。
应用程序编写器必须使用以下名称提供原型的“守护程序任务”启动挂钩函数的实现。
void vApplicationDaemonTaskStartupHook( void );
6 功能选配
如果以下函数没有被使用到,已经设置为0,使其不被包含到应用程序中,从而减少程序的应用空间;
#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
7 总结
如果是学习FreRTOS的初期,只需要了解几个比价关键的配置即可,随着后期对该系统功能了解的深入,在系统的剪裁,RAM和ROM的优化上就可以进一步的了解,另外也可以参考https://www.freertos.org/a00110.html,
【FreeRTOS学习05】深度解剖FreeRTOSConfig.h实现对系统的自定义剪裁的更多相关文章
- FreeRTOS Customisation -- FreeRTOSConfig.h
http://www.freertos.org/a00110.html FreeRTOS is customised using a configuration file called FreeRTO ...
- freeRTOSConfig.h文件对FreeRTOS进行系统配置
FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制.每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核.这个配置文件是针 ...
- FreeRTOS学习笔记——FreeRTOS 任务基础知识
RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习RTOS 系统的工程师或者学生主要就是为了使用RTOS 的多任务处理功能,初步上手RTOS 系统首先必须掌握的也是任务的创建 ...
- C语言深度解剖读书笔记
开始本节学习笔记之前,先说几句题外话.其实对于C语言深度解剖这本书来说,看完了有一段时间了,一直没有时间来写这篇博客.正巧还刚刚看完了国嵌唐老师的C语言视频,觉得两者是异曲同工,所以就把两者一起记录下 ...
- 【转】 C语言深度解剖读书笔记(1.关键字的秘密)
本文出处:http://blog.csdn.net/mbh_1991/article/details/10149805 开始本节学习笔记之前,先说几句题外话.其实对于C语言深度解剖这本书来说,看完了有 ...
- 【FreeRTOS学习02】源码结构/数据类型/命名规则总结
个人不是很喜欢FreeRTOS的编程风格,但是没办法,白嫖人家的东西,只能忍了,这里先简单总结一下: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 ...
- 【FreeRTOS学习03】小白都能懂的Task Management 任务管理基本概念介绍
在FreeRTOS中,线程的术语又可以被称之为任务,或许这样更加合适,本文将介绍任务的创建/删除,任务参数的使用,以及任务优先级: 1 软实时和硬实时 硬实时系统的任务运行正确性与响应时限是紧密相关的 ...
- FreeRTOS学习及移植笔记之二:在IAR和STM32F103VET上移植FreeRTOS
上一次,我们简单的测试了FreeRTOS的基于IAR EWARM v6.4和STM32F103VET6平台的Demo,对其有了一个基本认识.接下来我们开始自己移植FreeRTOS的过程. 1.创建一个 ...
- C语言深度解剖读书笔记(6.函数的核心)
对于本节的函数内容其实就没什么难点了,但是对于函数这节又涉及到了顺序点的问题,我觉得可以还是忽略吧. 本节知识点: 1.函数中的顺序点:f(k,k++); 这样的问题大多跟编译器有关,不要去刻意追求 ...
随机推荐
- sudo: 在加载插件“sudoers_policy”时在 /etc/sudo.conf 第 0 行出错 sudo: /usr/lib/sudo/sudoers.so 必须只对其所有者可写 sudo: 致命错误,无法加载插件
解决办法: su root chmod 644 /usr/lib/sudo/sudoers.so chown -R root /usr/lib/sudo 千万不要给 /usr 赋全部权限!!! ...
- 百度云虚拟空间(BCH)
百度云虚拟空间(BCH)上的一些默认配置 :first-child { margin-top: 0;}blockquote > :last-child { margin-bottom: 0;}i ...
- 替换字符串sql
update [表名] set 字段名 = replace(与前面一样的字段名,'原本内容','想要替换成什么') UPDATE `zjl_III_hei_zlj_20151111`.`ctrl_ne ...
- 【集群实战】sersync
1. sersync介绍 sersync功能: 实时同步: sersync组成: sersync==inotify+rsync inotify: 监控某个目录下面"文件/目录"是否 ...
- JavaScript面向对象的作用域链(转载)
JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕... 一.“JavaScript中无块级作用域” 在Java或C# ...
- nodejs实现定时爬取微博热搜
The summer is coming " 我知道,那些夏天,就像青春一样回不来. - 宋冬野 青春是回不来了,倒是要准备渡过在西安的第三个夏天了. 废话 我发现,自己对 coding 这 ...
- vue中递归组件的使用
2019独角兽企业重金招聘Python工程师标准>>> 递归 简单来讲就是程序自己调用自身. vue中的递归组件就是,组件自身调用自身. 父组件 <template> & ...
- FastJson踩坑:@JsonField在反序列化时失效
问题描述 一个对象(某个字段为枚举类型,为了不采用默认的序列化过程,用@JSONField指定了序列化器和反序列器,过程见旧博文),将其放到JSONArray中再序列化JSONArray对象,用得到的 ...
- puppet报告系统Dashboard部署及配置详解
Puppet Dasshboard是由支持Puppet开发的公司Puppetlabs创建的,是Ruby on Rails程序.可以作为一个ENC(外部节点分类器)以及一个报告工具,并且正在逐渐成为一个 ...
- 【COCOS2DX-LUA 脚本开发之四】使用tolua++编译pk创建自定义类
此篇基本[COCOS2DX(2.X)_LUA开发之三]在LUA中使用自定义精灵(LUA脚本与自创建类之间的访问)及LUA基础讲解 在Lua第三篇中介绍了,如何在cocos2dx中使用Lua创建自定义类 ...