STM32 内存分配、堆栈以及变量存储位置理解与分析

大部分参考自以下链接,并结合自己的实践与理解形成本文:
1、博客园
2、正点原子论坛

1、STM32内存(FLASH和RAM)

  一般来说单片机的内存指的是FLASH和RAM,当在程序中定义了全局变量、局部变量、只读变量等参数时都是会存放到对应的FLASH或者是RAM中。具体对单片机FLASH和RAM的介绍之后再写,这里只对单片机内存分配,对堆和栈以及变量的存储做一个梳理和记录。

2、FLASH

  FLASH主要是存放代码和数据的。下面是将 flash 内部进行细分之后的一张图。(图来源于1、博客园
在这里插入图片描述
  STM32的flash是从地址0x0800 0000开始的,是向上增长的。Flash又可以细分为这么几个部分,分别是文本段 (Text),其中文本段中又包含可执行代码 (Executable Code)和常量 (Literal Value),在文本段之后就是只读数据区域 (Read Only Data),只读数据段后面接着的就是数据复制段 (Copy of Data Section),这个段充当的作用是存放程序中初始化为非 0 值的全局变量的初始值,之所以要将初始值存放到这里,是因为全局变量是存放在 RAM 上的,RAM 上的值掉电便丢失,每次上电后这些变量是要进行重新赋值的,而重新赋的值就存放在这里。
  可以看到STM32的flash中存放了代码、常量、只读数据和数据复制段。
  如何理解这些我们来做个实验。简单写一个点亮LED的测试工程,定义由const修饰的一个常量TEST_DATA1,和一个有初始值的全局变量TEST_DATA2。

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "usart.h"	

const int TEST_DATA1= 4660; //一个常量

int TEST_DATA2=0x1112;//一个有初始值的全局变量

int main(void)
{ 
	delay_init(168);		  //初始化延时函数
	LED_Init();		        //初始化LED端口
	uart_init(115200);

	printf("%p\r\n",&TEST_DATA1);
	printf("%p\r\n",&TEST_DATA2);
	while(1)
	{
	  GPIO_ResetBits(GPIOF,GPIO_Pin_9);  //LED0对应引脚GPIOF.9拉低,亮  等同LED0=0;
	  GPIO_SetBits(GPIOF,GPIO_Pin_10);   //LED1对应引脚GPIOF.10拉高,灭 等同LED1=1;
	  delay_ms(500);  		   //延时300ms
	  GPIO_SetBits(GPIOF,GPIO_Pin_9);	   //LED0对应引脚GPIOF.0拉高,灭  等同LED0=1;
	  GPIO_ResetBits(GPIOF,GPIO_Pin_10); //LED1对应引脚GPIOF.10拉低,亮 等同LED1=0;
	  delay_ms(500);                     //延时300ms
	}
}

验证过程
  1、通过代码里printf把TEST_DATA1和TEST_DATA2的地址打印出来,通过串口助手可以看到:
在这里插入图片描述
  TEST_DATA1存放在flash的0x0800 0d4c中,而TEST_DATA2存在ram中。这里解释一下,TEST_DATA1是一个常量存放在flash中是没错的,而TEST_DATA2是一个有初始值的全局变量,应该和上面说的一样存放在flash中然后在上电时把值搬到ram中,但是为什么打印出来是在ram呢?原因应该是它已经搬完了。接下来进一步去flash中找这两个值。
  2、在MAP文件中查找,通过双击“LED”,会跳转到MAP文件,我们使用快捷键“ctrl+f”在MAP中查找TEST_DATA变量,如下图

在这里插入图片描述
在这里插入图片描述

在这里依然是串口里打印出来的地址,那再换一种方式。
  3、通过ST-LINK Utility软件直接查看芯片的flash。先定位到TEST_DATA1所在的0x0800 0d4c:

在这里插入图片描述

在flash的0x0800 0d4c处找到了定义的常量TEST_DATA1:4660(0x1234),通过全局搜索定义的TEST_DATA2:0x1112,在flash的最后找到了这个全局变量的初始值0x1112。

在这里插入图片描述

  这里已经验证过这两个值就是定义的TEST_DATA1和TEST_DATA2,还想测试的话可以多定义几个,结果是一样的。
  这就是flash中变量的存储,除了代码外,还存在一些常量、只读变量以及有初始值的全局变量。

3、RAM

  相对对flash来说,ram主要就是用来存储数据了,如下是STM32中ram的分区(图来源于1、博客园
在这里插入图片描述
  ram中包含了如下几个部分:
    1、data : 存放初始化为非 0 值的全局变量
    2、bss : 存放未初始化或者是初始化为 0 的全局变量
    3、堆 (heap) : 由 malloc 申请,由 free 释放
    4、栈 (Stack) : 存放局部变量和函数调用时的返回地址
  其中data和bss比较好理解就是一些全局变量。堆和栈的空间可以由我们来自由设定如下图所示,只要这些部分加起来不超过STM32的RAM空间。
在这里插入图片描述

  在STM32的启动文件(.s)中,刚开头就有对堆和栈空间的定义描述。如图定义了栈的大小是(0x400),堆的大小是(0x200)。里面存放的是一些函数执行时的局部变量、中断入口等,函数执行结束时这些存储单元自动被释放。是程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。再来看一下MAP文件,如下图

在这里插入图片描述
  可以看到在整个ram空间(0x2000 0000起)依次存放了data、bss、HEAP、STACK,其中堆和栈的大小和我们定义的是一致的。
  在ram中值得关注的是堆和栈的空间,堆是向上增长的而栈是向下生长的,如果一个函数运行的时候有大量的局部变量(栈向下增长),同时程序在整个过程中malloc申请了大量的堆空间而没有释放(堆向上增长),造成堆和栈空间的冲突,一旦堆栈冲突,系统就崩溃了。
  特别说明一下,我使用了很多正点原子的工程,他们里面使用的自定义的mymalloc函数(区别于C的malloc)存放在bss字段里而不是HEAP字段里,使用的时候别搞混了。
  综上就是STM32内存分配、堆栈以及变量存储位置的理解。

  • 30
    点赞
  • 148
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值