FeeRTOS在STM32中是如何使用内存的

STM32内存结构

STM32的数据在物理上分别储存在RAM和Flash中。RAM可读可写,掉电清零。Flash可读可写,但是读写时间很长,能掉电储存,并且一般空间比RAM大很多。

在关于如何使用RAM和Flash的问题上,STM32的内存又有了6个储存数据段和3种储存属性区的概念。
在这里插入图片描述

STM32 Stack_Size和Heap_Size大小设置的意义

其中STACK_SIZE和HEAP_SIZE在STM32的启动文件startup_stm32fxx.s中都有定义,这两个值一般的工程都不需要调整,足够使用。

Stack_Size      EQU     0x400
 
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp
                                                  
; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
 
Heap_Size       EQU     0x200
 
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3

在使用STM32编程时,一般情况下我们不会关注堆栈空间的大小,因为在STM32的启动文件中,已经帮我们预先设置好了堆栈空间的大小。如下图所示的启动代码中,Stack栈的大小为:0x400(1024Byte),Heap堆的大小为:0x200(512Byte)。

1,Stack Size,一般小工程0X400足够,所以默认无需设置太大,确实需要调整,可根据实际需求手动修改。
2,Heap Size,如果没有用到标准库的malloc,就是废物,纯属浪费内存,所以直接设置为0即可。

FreeRTOS中的堆

FreeRTOS中的堆也属于ZI区,但是它与STM32内存结构中的堆并不占用相同的空间,两个堆同时存在。以下出现的堆(heap)表示FreeRTOS堆,另外在STM32启动文件中定义大小的堆称为系统堆。
(这一点可以同过分别修改startup_stm32fxx.s文件中的Heap_Size值,Stack_Size值,FreeRTOSConfig.h中的configTOTAL_HEAP_SIZE值,然后观察编译结束后Program Size的变化来验证。)
在这里插入图片描述

FreeRTOS有5种heap的实现方式,在STM32CubeMX中默认为heap_4.c。这种方式可以满足大部分使用需求,暂时不用关注其实现细节。

这一个堆的大小定义在FreeRTOSConfig.c中:

#define configTOTAL_HEAP_SIZE ((size_t)3072)

FreeRTOS创建任务时默认的任务栈大小为128字,在32位系统中即为128*4=512Byte,再加上TCB块占用84Byte,一共596Byte。而大小为3072Byte的堆允许创建3个这样的任务,占用约1800Byte。堆中剩余的部分则存放了系统内核、信号量、队列、任务通知等数据。

需要创建更多任务时,堆的大小可自行修改。用RAM的空间减去已分配的空间,即为能给堆分配的最大空间:

Space=RAM−bss−data−SysHeap−Stack

FreeRTOS堆和任务的空间分配

FreeRTOS堆和任务栈在运行中具有很强的动态性,其大小很难估计。

我们在实际使用中,可以先把空间调整得大一些。程序正常运行后,再通过一些API查看堆栈剩余的空间大小,估算程序运行中需求内存空间的最大值。最后将这个最大值乘一个安全系数,得到最终应该分配的空间大小。安全系数推荐1.3到1.5。

查看堆(heap)剩余空间的API有:
size_t xPortGetFreeHeapSize( void );	         //获取当前未分配的内存堆大小
size_t xPortGetMinimumEverFreeHeapSize( void );	 //获取未分配的内存堆历史最小值

它们返回值的单位都是字节。

需要注意的是,xPortGetFreeHeapSize()在使用heap_3.c时不能被调用;xPortGetMinimumEverFreeHeapSize()则只能在使用heap_4.c或heap_5.c时生效。

查看任务栈剩余空间的API:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

这个函数可以获取一个任务从创建好到调用此函数时,任务栈空间的历史最小剩余值(HighWaterMark)。使用这个函数时需注意,它的返回值的单位是字(STM32里1个字长为4个字节)。

这个API默认是关闭状态,需要手动在Cubemx(或配置文件中)将宏INCLUDE_uxTaskGetStackHighWaterMark置为1。

我在使用过这些API后发现,他们本身也会占用相当的内存空间,尤其是uxTaskGetStackHighWaterMark(),会拖慢任务运行速度。所以在程序的正式版中,应该将他们删除。

运行freertos系统的大部分都是资源有限的MCU,所以对于ram我们都要考虑尽量的节省,避免资源浪费,从而也可以针对项目选择性价比更好的mcu。先看下图弄清楚freertos的heap空间和任务栈空间的不同与联系。
在这里插入图片描述

任务栈空间和FreeRTOS堆空间优化

以上关系搞清楚,那么又该如何定heap的空间大小呢,可以先进行一个粗略的计算,假设任务1分配2kbytes栈,任务2分配3kbytes栈,队列大概占1k,用户malloc大概2k,这么算一共就是8k。那么在资源有限的情况下可以先把heap空间分个15k。

通过在任务函数中加入:

size_t xPortGetFreeHeapSize( void );	         //获取当前未分配的内存堆大小
size_t xPortGetMinimumEverFreeHeapSize( void );	 //获取未分配的内存堆历史最小值
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); //查看任务栈空间的历史最小值

就可以打印出来该任务自启动起来最小剩余栈空间大小。然后我们就可以计算出最大使用的大小,一般可以再乘以1.5左右作为最终分配的值。需要注意的是该函数不像前面两个返回的是bytes,而返回的以字为单位,真实的bytes需要乘以4。所以总体的原则就是:先分大再调小最终把它确定好。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值