0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

在STM32F407单片机上使用多块不连续空间实现堆的软件方法介绍

麦克泰技术 来源:嵌入式系统专家之声 2024-03-20 10:43 次阅读

0 引言

嵌入式系统设计中,需要根据系统的功能需求选择相应的单片机。笔者参与开发的一款中央空调主控制板选用了意法半导体公司STM32F407 单片机,这一系列的单片机具有高集成度、高性能、嵌入式存储器和外设,适合作为主控制板的核心单片机使用。STM32F407 主要特征如下:提供了工作频率为 168 MHz 的 Cortex-M4 内核(具有浮点单元)的性能,在168MHz 频率下,从 Flash 存储器执行时,STM32F407 能够提供 210 DMIPS/566 CoreMark 性能,并且利用意法半导体的 ART 加速器实现了 Flash 零等待状态。DSP 指令和浮点单元扩大了产品的应用范围。

STM32F407产品系列具有 512 KB~1MB Flash 和 192 KBSRAM,采用尺寸小至 10 mm×10mm 的 100~ 176 引脚封装。在开发该控制板的软件时发现,由于 STM32F407 的 SRAM 地址不连续,造成动态内存分配存在问题,不能利用全部的片内 192 KB SRAM 资源,有必要深入分析并解决。

1 EWARM 7.40C/C++编译器的数据存储

笔者在开发该控制板的软件时,使用IAR公司的EWARM7.40作为 C/C++ 编译器,该编译器提供了静态内存分配与动态内存分配2种不同的内存分配机制。

1.1 简介

ARM内核可处理4GB 的连续内存,范围从0x00000000到0xFFFF FFFF。不同类型的物理内存可以放置在上述内存范围中。典型的应用程序同时具有只读存储器(ROM)和随机存取内存(RAM)。此外,内存范围的某些部分包含处理器控制寄存器和外围单元。

在典型的应用程序中,数据可以通过以下3种不同的方式存储在内存中:

(1)自动变量

除已声明为静态变量者外,所有函数的局部变量都存储在寄存器或堆栈上。这些变量在函数执行时可以使用。当函数返回到其调用者时,内存空间不再有效。

(2)全局变量、模块静态变量和声明为 static的局部变量

在这种情况下,内存的分配是一劳永逸的。在此语境中,“静态”一词表示应用程序运行时分配给此类变量的内存数量不会改变。ARM 内核有一个单一的地址空间且编译器支持完整的内存寻址。

(3)动态分配的数据

应用程序可以在堆上分配数据,此数据一直有效,直到它被应用程序显式地释放回系统。对于在应用程序执行之前不知道对象数量的场合,这种类型的内存是有用的。注意:就内存量有限的系统或预期运行很久的系统而言,存在着与使用动态分配的数据相关的潜在风险。

1.2 自动变量和参数的存储

按照 C 语言标准,函数内定义且未声明为静态的变 量被命名为自动变量。其中一些变量被放置在处理器寄存器中,其余的放在堆栈上。从语义的角度来看,这是等价的。与放在堆栈上的变量相比,主要区别在于访问寄存器更快,并且需要的内存更少。自动变量只能在函数执行时存活;当函数返回时,分配在堆栈上的内存被释放。

(1)堆栈

堆栈可以包含:未存储在寄存器中的局部变量和参数;表达式的临时结果;函数的返回值(在寄存器中传递的除外);中断期间的处理器状态;应在函数返回前恢复的处理器寄存器(被调用者保存的寄存器)。

堆栈是一个固定的内存块,分为两部分:第一部分包含为调用当前函数的函数,以及调用该函数的函数所使用而分配的内存;第二部分包含可分配的自由内存。这两个区域之间的边界线称为栈顶,由一个专门的处理器寄存器——堆栈指针来表示。通过移动堆栈指针,内存被分配到堆栈上。

函数绝不应指向包含自由内存的堆栈区域。原因是,如果发生中断,被调用的中断函数会分配、修改,当然还有在堆栈上去分配内存。

(2)优点

堆栈的主要优点是:程序不同部分的函数可以使用相同的内存空间存储其数据。不同于堆,堆栈永远不会变成碎片或出现内存泄漏。

函数可以直接或间接地调用自己(递归函数),每个调用可以在堆栈上存储自己的数据。

(3)潜在的问题

堆栈的工作方式使得臆想在函数返回后存储数据变得不可能。以下函数演示了常见的编程错误。它返回指向变量 x 的指针,该变量在函数返回后已不存在。

int * MyFunction(){

int x;

/*在此处理一些事情*/

return &.x; /* 不正确*/

}

另一个问题是堆栈耗尽的风险。这个问题在一个函数调用另一个、被调函数继续调用第3个函数等,每个函数使用堆栈的总和大于堆栈的大小时会发生。当大型数据对象存储在堆栈上或使用递归函数时,风险更高。

1.3 堆上的动态内存

分配在堆上的对象的内存将一直存在,直到对象被显式释放。这种类型的内存存储对于直到运行时才知道数据量的应用程序是非常有用的。

在 C 语言中,使用标准库函数 malloc或相关函数 calloc 和 realloc 中的一个来分配内存,使用free 来释放内存。

在 C++ 语言中,一个特殊的关键字new 分配内存和运行构造器。通过 new 分配的内存必须使用关键字 delete 来释放。

设计使用堆分配对象的应用程序时必须非常仔细,因为很容易出现无法在堆上分配对象的情形。如果你的应用程序使用过多的内存,堆可能会耗尽。如果不再使用的内存未被释放,则堆也会用完。

对于每个分配的内存块,若干字节用于管理目的的数据是必需的。对于分配大量小块的应用程序,此管理开销可能很大。

还存在碎片化的问题。这意味着在堆中,一小部分自由内存被分配对象使用的内存所分隔。如果没有一块足够大的自由内存给对象,即使自由内存大小的总和超过对象的大小,还是无法分配一个新的对象。不幸的是,随着内存的分配和释放,碎片化往往会增加。基于此,设计长时间运行的应用程序时应尽量避免使用分配在堆上的内存。

2 问题分析与解决方案

以下介绍的程序实例在编译器EWARM7.40、Fre-eRTOS 10.0.0 下验证通过。

2.1 STM32F407 的片内 SRAM

STM32F407 具有192 KB 的片内 SRAM 。片内 SRAM 可以字节、半字(16位)或全字(32位)的形式访问。读取和写人操作以 CPU 速度执行,等待状态为0。片内 SRAM 最多分为两个模块:SRAM1 和 SRAM2 映射地址0x20000000,可以被所有 AHB 主设备存取;CCM(核心耦合存储器)映射到地址0x10000000, 只能由 CPU 通过 D 总线存取。

STM32F407 的内存映射如图1所示,应用程序可以使用的系统SRAM 地址为0x20000000~0x2001 FFFF(128KB),CCM地址为0x10000000~0x1000 FFFF(64 KB)。

由于两块内存的地址不连续,使用编译器 EWARM 7.40时,new 运算符只能够在一片连续的空间分配内存,无法同时使用另外一片连续的空间。换言之,堆的实现只能在128 KB 的 SRAM 内存空间内,另外1/3的片内 SRAM 被白白浪费了,这在应用程序较为复杂时是个严重的缺陷,必须设法解决。

5282cf46-e5cb-11ee-a297-92fbcf53809c.jpg

图1 STM32F407 的内存映射

2.2 解决方案

由于编译器 EWARM7.40 的局限性,堆无法在两片不连续的内存空间实现。为了解决此问题,笔者联想到了免费的实时操作系统 FreeRTOS, 该操作系统在2014年8月发布的 V8.1.0中提供了新的内存管理文件 heap_5.c, 允许堆跨越多个不连续的内存区域。后续版本对此功能做了优化与改进。笔者尝试用此方案解决堆的实现问题,取得了成功。具体方法如下:

①把FreeRTOS源程序包中的heap_5.c添加到软件工程中。

②在头文件中定义堆的大小。

#define configTOTAL_HEAP¹_SIZE((size_t)(64*1024))

//HEAP164KB

#define configTOTAL_HEAP2_SIZE((size_t)(100*1024))

//HEAP2100KB

说明:HEAP1 使用CCM 的全部 64KB;HEAP2 使用 SRAM 的100 KB, 剩余部分留给操作系统使用。此数值可根据应用程序的需求灵活调整。

③在main.c中定义两片内存区域:

#pragmalocation=".ccmram"

uint8_tucHeapl[configTOTAL_HEAP1_SIZE];

uint8_tucHeap2[configTOTAL_HEAP2_SIZE];

constHeapRegion_txHeapRegions[]={

/*Startaddress with dummy offsets Size */

{ucHeapl,configTOTAL_HEAP¹_SIZE},

{ucHeap2,configTOTAL_HEAP2_SIZE},

{NULL,0}

};

④ 在 main.c 中重载new 和delete:

void *operator new(size_t size){

void *p=0;

p=pvPortMalloc(size); //调用FreeRTOS 的内存分配函数

return p;

void operator delete(void *p){

vPortFree(p); // 调用 FreeRTOS 的内存释放函数

经过上述改进后,应用程序可以使用的堆的大小为 164KB, 彻底摆脱了编译器 EWARM7.40 的局限性,满足了复杂应用程序的需求。

3 结语

本文详细介绍了使用多块不连续内存空间实现堆的软件方法,以及在 STM32F407 单片机上的软件实现方法。使用该技术可以在多块不连续内存空间实现堆,更好 地实现了内存的动态分配。使用该软件的控制器产品至今已在现场稳定运行18个月。



审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3563

    浏览量

    129203
  • 加速器
    +关注

    关注

    2

    文章

    795

    浏览量

    37740
  • Flash存储器
    +关注

    关注

    3

    文章

    104

    浏览量

    25708
  • STM32F407
    +关注

    关注

    15

    文章

    187

    浏览量

    29364
  • 静态变量
    +关注

    关注

    0

    文章

    13

    浏览量

    6643

原文标题:使用多块不连续空间实现堆的软件方法

文章出处:【微信号:麦克泰技术,微信公众号:麦克泰技术】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    国产优秀替代_APM32F407替代STM32F407记录

    前言 最近一段时间玩极海的APM32F407系列的MCU,研究一段时间后发现其资源和意法半导体的STM32F407不相上下。通过对比两者的数据手册和参考手册,我发现APM32
    的头像 发表于 05-10 11:22 1.9w次阅读
    国产优秀替代_APM32<b class='flag-5'>F407</b>替代<b class='flag-5'>STM32F407</b>记录

    STM32F407 位带配置步骤

    介绍STM32F407位带操作方法,设置寄存器的偏移量,实现按GPIO口指定位进行读写操作,方便编程。
    的头像 发表于 07-06 14:30 1171次阅读
    <b class='flag-5'>STM32F407</b> 位带配置步骤

    STM32F407 基本定时器使用

    介绍STM32F407基本定时器的配置方法,分别介绍轮询方式、中断方式使用定时器完成定时。
    的头像 发表于 07-06 14:32 3142次阅读
    <b class='flag-5'>STM32F407</b> 基本定时器使用

    介绍一下单片机STM32F407芯片

    主要有单片机、嵌入式linux等。其中单片机以其功能强大、性价比高,物联网这一行业中占据了大半江山。4.1 初识STM32F407芯片本节介绍
    发表于 07-16 07:32

    如何实现stm32f407单片机串口通信?

    如何实现stm32f407单片机串口通信?
    发表于 12-07 06:24

    STM32F407模板

    STM32F407模板,感兴趣可以看看。
    发表于 07-25 18:52 132次下载

    STM32F407 UCOS III实验

    STM32F407 UCOS III实验,介绍基于STM32F407的UCOSIII实例,参考下
    发表于 09-22 14:08 82次下载

    如何实现STM32F407单片机的ADC转换

    ADC转换是把外面输入到引脚的电压值转换成数字信号,单片机里面有一个模拟至数字的转换模块,我们可以控制它采集引脚的电压,stm32F407可以利用void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)这个函数来控制转换。
    发表于 12-26 15:08 2.7w次阅读
    如何<b class='flag-5'>实现</b><b class='flag-5'>STM32F407</b><b class='flag-5'>单片机</b>的ADC转换

    为什么选用ST系列STM32F407单片机

    为什么选用ST系列STM32F407单片机
    发表于 11-26 14:06 7次下载
    为什么选用ST系列<b class='flag-5'>STM32F407</b><b class='flag-5'>单片机</b>

    STM32F407STM32F105 CAN通讯失败的定位解决

    STM32F407STM32F105 CAN通讯失败的定位解决问题的发现问题的现象测试过程硬件调整测试软件调整测试结论基本结论结论扩展验证问题的发现在STM32 CAN总线的应用过程
    发表于 12-02 16:51 18次下载
    <b class='flag-5'>STM32F407</b>与<b class='flag-5'>STM32F</b>105 CAN通讯失败的定位解决

    STM32F407芯片介绍

    1. 文档准备做嵌入式开发的第一步就是了解主芯片,了解STM32F407主要要关注几个文档:1. stm32F407芯片手册2. stm32F407参考手册3. Arm Cortex-M4数据手册
    发表于 12-04 13:21 109次下载
    <b class='flag-5'>STM32F407</b>芯片<b class='flag-5'>介绍</b>

    基于stm32f407的MNIST数字识别

    基于stm32f407的MNIST数字识别本文是将数字识别模型应用到stm32的实例,利用X-CUBE-AI将模型导入单片机进行调试开发环境操作系统:Windows模型训练
    发表于 12-17 18:36 37次下载
    基于<b class='flag-5'>stm32f407</b>的MNIST数字识别

    STM32F407原理图下载

    STM32F407原理图下载
    发表于 01-17 13:44 420次下载

    stm32f407原理图

    stm32f407原理图
    发表于 07-14 16:07 205次下载

    RM0090_STM32F405/415, STM32F407/417, STM32F427/437和STM32F429/439单片机参考手册

    RM0090_STM32F405/415, STM32F407/417, STM32F427/437和STM32F429/439单片机参考手
    发表于 11-23 08:24 15次下载
    RM0090_<b class='flag-5'>STM32F</b>405/415, <b class='flag-5'>STM32F407</b>/417, <b class='flag-5'>STM32F</b>427/437和<b class='flag-5'>STM32F</b>429/439<b class='flag-5'>单片机</b>参考手册