STM32内存结构介绍和FreeRTOS内存分配技巧

2023-05-16

概述

        这是我第一次使用FreeRTOS构建STM32的项目,踩了好些坑,又发现了我缺乏对于操作系统的内存及其空间的分配的知识,故写下文档记录学习成果。

文章最后要解决的问题是,如何恰当地分配FreeRTOS中的堆、任务栈的空间。但是在概念的理解上,也需要知道STM32内存的相关知识。所以首先大致介绍一下STM32的内存结构。

一、STM32内存结构

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

但需要注意的是,堆栈空间不能分配到Flash上,所以对于内存模型来说Flash实际上是不可写的。对于Flash的更多介绍可以参看这篇博客​​​​​​​。

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

6个储存数据段

data

数据段,储存已初始化的,且初始化不为0的全局变量和静态变量。

bss

Block Started by Symbol。储存未初始化的,或初始化为0的全局变量和静态变量。

text

代码段,储存程序代码。

constdata

储存只读常量。

heap

堆,存放进程运行中被动态分配的内存段。其可用大小定义在启动文件startup_stm32fxx.s中,由程序员使用malloc()free()函数进行分配和释放。

stack

栈,其大小定义在启动文件startup_stm32fxx.s中,由系统自动分配和释放。可存放局部变量、函数的参数和返回值,中断发生时能保存现场。但是static声明的局部静态变量不储存在栈中,而是放在data数据段。

3种储存属性区

RO(Read Only)

烧写到Flash中,可以长久保存。text代码段和constdata都属于RO。由于需要掉电储存,RO里也保存了一份data的数据。

RW(Read Write)

储存在RAM中。data属于此区。上电时单片机会将Flash中保存的data类型数据复制到RAM中,以供读写使用。

ZI(Zero Init)

零初始化区,同样储存在RAM里。系统上电时会把此区域的数据进行0初始化。bss,heap,stack均属于这个区域。

小结

STM32的RAM上有RW和ZI两个属性区,里边包含了data,bss,堆(heap),栈(stack)这几个数据段。这里是程序运行的所在。

Flash中有RO区,包含了text、constdata和data三个段,这里则是程序本体所在。

二、FreeRTOS中的堆

FreeRTOS中的堆也属于ZI区,但是它与STM32内存结构中的堆并不占用相同的空间,两个堆同时存在。以下出现的堆(heap)表示FreeRTOS堆,另外在STM32启动文件中定义大小的堆称为系统堆。

FreeRTOS内核主要使用的内存管理函数为:

void *pvPortMalloc( size_t xSize );	//申请内存
void vPortFree( void *pv );	        //释放内存

以上函数控制的是FreeRTOS堆;系统堆则应使用malloc()free()来分配和释放。

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−StackSpace

三、FreeRTOS堆和任务空间分配技巧

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

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

查看堆(heap)剩余空间的API有:

size_t xPortGetFreeHeapSize( void );	         //获取当前未分配的内存堆大小
size_t xPortGetMinimumEverFreeHeapSize( void );	 //获取未分配的内存堆历史最小值

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

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

FreeRTOS中也有查看任务栈剩余空间的API:

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32内存结构介绍和FreeRTOS内存分配技巧 的相关文章

  • 云的几种部署模式

    云的几种部署模式 定义 xff1a 特点云的部署模式 定义 xff1a 云 是一种计算模式 xff0c 利用互联网技术把大量可扩展和弹性的IT相关能力作为 一种服务提供给多个客户 特点 服务化 弹性 多租户 云的部署模式 公有云 混合云 内
  • 通过git 上传本地代码至码云

    实验步骤 1 配置ssh xff08 1 xff09 在本地生成sshkey xff0c 打开git命令终端 git bash 窗口 ssh keygen t rsa C 34 xxxxx 64 xxxxx com 34 你的邮箱 xff0
  • git常见命令

    常见命令 1 初始化本地仓库 git init 2 需要与码云保持一致 git config global user name 34 用户姓名 34 git config global user email 34 用户邮箱 34 3 设置远
  • 【python】详解threading模块:lock、Rlock的使用(二)

    在之前的 python 详解threading模块 xff1a 基本概念 join阻塞和setDaemon守护主线程 xff08 一 xff09 一文中 xff0c 是有对多线程进行一个详细的梳理的 其中就提到了线程锁这一功能 主要基于Rl
  • 定位导航——旋转矩阵,IMU,左右乘

    我们先明确一下这里所说的一些概念 IMU IMU全称Inertial Measurement Unit xff0c 惯性测量单元 xff0c 主要用来检测和测量加速度与旋转运动的传感器 起初只是用来测量角度的 xff0c 后来随着其他传感器
  • scp命令详解

    相关知识 scp是secure copy的简写 xff0c 用于在Linux下进行远程拷贝文件的命令 xff0c 和它类似的命令有cp xff0c 不过cp只是在本机进行拷贝不能跨服务器 xff0c 而且scp传输是加密的 可能会稍微影响一
  • H3C命令详解(笔记)

    1 常用命令 lt gt xff1a 用户视图模式 xff0c 仅仅能配置基本参数 xff0c 调试命令 xff0c 权限较小 xff1a 系统视图模式 xff0c 可以做高级配置 system view 进入系统视图 quit 退出当前模
  • 解决Ubuntu18.04 安装ROS中 sudo rosdep init 和 rosdep update 失败问题

    解决Ubuntu18 04 安装ROS中 sudo rosdep init 和 rosdep update 失败问题 目录 解决Ubuntu18 04 安装ROS中 sudo rosdep init 和 rosdep update 失败问题
  • GD32F303 移植freertos 中断管理设定。。。。

    之前做项目时 xff0c 使用GD32F303并移植了freertos 移植过程网上有很多教程 xff0c 根据这些教程移植就可以 移植完后注意FreeRTOSConfig h中关于RTOS中断管理的设置 我移植时在官网下的是当时最新的RT
  • ros自建功能包操作

    功能包改名 假定功能包原名Apkg xff0c 要改成Bpkg 把Apkg功能包文件夹名改为Bpkg 把CMakeLists txt中project Apkg 改为project Bpkg 把Package xml文件中 lt name g
  • Jacobian矩阵和梯度矩阵

    记号标识 标量 xff1a 常规小写字母 xff1b 向量 xff1a 加粗的小写字母 x 61 x 1
  • 一份还热乎的蚂蚁金服面经(已拿Offer)!附答案!!

    本文转自 xff1a https mp weixin qq com s MzmdxqukOZ6rUta9nkGGw 本文来自我的知识星球的球友投稿 xff0c 他在最近的校招中拿到了蚂蚁金服的实习生Offer xff0c 整体思路和面试题目
  • arduino 自平衡小车3\对mpu6050获得的X轴角度和角速度进行卡尔曼滤波

    对mpu6050获得的X轴角度和角速度进行卡尔曼滤波 mpu6050得到的角度值有些值的偏差较大 xff0c 为了使平衡小车更加稳定 xff0c 需要对获得的角度进行优化 xff0c 使用 卡尔曼滤波 xff0c 代码如下 xff1a in
  • nginx CPU 100 跑满问题定位

    1 确定连接数是不是达到了上限 2 确定是不是开启了gzip压缩 xff0c 确定压缩等级 xff0c 小于1kb的不要压缩 xff1b 图片 xff0c 大文件 xff0c 大压缩文件等不要压缩 3 单个CPU占用100 原因的定位 xf
  • 虚拟串口及其在串口转以太网中的应用

    本文介绍虚拟串口的概念 xff0c 以及如何在串口转以太网中利用该技术 1 虚拟串口的概念 虚拟串口是用操作系统的虚拟驱动技术产生的串口 xff08 COM口 xff09 xff0c 相对于计算机本身的硬件串口 xff08 COM1等 xf
  • 机器学习——PCA降维

    参考文章 xff1a https zhuanlan zhihu com p 77151308 PCA xff08 Principal Component Analysis xff09 是一种常见的数据分析方式 xff0c 常用于高维数据的降
  • C++命名规则--简明即查即用版(Windows开发环境)

    目录 前言 1 类名 2 函数名 3 参数 4 变量 5 常量 6 静态变量 7 全局变量 8 类的成员变量 前言 Microsoft推出的命名规则匈牙利法是 在变量和函数名中加入前缀以增进人们对程序的理解 xff0c 但如此一来太为繁琐
  • STM32中的FreeRTOS-#1(入门)

    写在前面 xff1a 我一直觉得 xff0c 如果我能把一点知识说给别人听 xff0c 并且别人能听懂 xff0c 大概率我自己真的学会了 记录的过程也是自己梳理的过程 xff0c 本系列我把它称为 教程 xff0c 是想把它写得系统且有条
  • 信号量 与 互斥量的区别

    原文来源 https blog csdn net ZhipingXi article details 78031307 信号量 与 互斥量 xff08 锁 xff09 的区别 一 概念和定义 信号量 xff1a 多线程同步使用的 xff1b
  • opencv版本问题,引起的vins视觉结果漂移

    最近在根据vins代码进行改写 xff0c 实验发现 当opencv为3 4 12版本时 xff08 core imgproc imgcodecs这几个库 xff09 xff0c vins 优化结果会非常飘 如果vins结果比较离谱 xff

随机推荐