赞
踩
目录
在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称之为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。在对于RAM紧缺的嵌入式系统中,是缺少MMU内存管理单元的。因此在一些嵌入式系统中,比如常用的STM32来讲,内存映射被划分为闪存段(也被称为Flash,用于存储代码和只读数据)和RAM段,用于存储读写数据。
STM32的Flash和RAM地址范围
标题中所说的内存是指STM32的Flash和RAM,下图是ARM Cortex M3的地址映射
从图中我们可以看出,RAM地址是从0x2000 0000开始的,Flash地址是从0x8000 0000开始的。
代码和数据是存放在Flash中的,下面是将Flash内部进行细分之后的一张图,图中表明了代码段,数据段以及常量在Flash中的位置。
如上图所示,Flash又可以分为这么几个部分。分别是文本段(Text) ,其中文本段中又包含可执行代码(Executable Code)和常量(Literal Value),在文本段之后就是只读数据区域(Read Only Data),当然并不是所有架构的单片机都满足这样一个排布规律,这里只针对于ARM Cortex M3系列的,只读数据段后面接着的就是数据复制段(Copy of Data Section),第一次遇见这个概念的朋友看到数据复制可能会有疑惑,其实这个段充当的作用是存放程序中初始化为非0值得全局变量的初始值,之所以要将初始值存放到这里,是因为全局变量是存放在RAM上的,RAM上的值掉电便丢失,每次上电之后这些变量是要重新赋值的,而重新赋值的值就存放在这里。那为什么不存放初始化为0的全局变量的初始值呢,原因也很简单,既然是初始化为0,那么在上电之后统一对存放初始化为0的全局变量的那块区域清0就好。
下面举一个例子,分析各个变量在上述中的存储位置:
- #include <stdio.h>
-
- const int read_only_variable = 2000;
-
- int data = 500;
-
- void my_function(void)
- {
- int x=200;
-
- char *str = 'string';
-
- }
在上述代码中,read_only_variable是一个用const修饰的全局变量,它是只读的,存放在flash中的只读数据区域,编译器会给read_only_variable分配一个地址,并将2000这个数据存放到这个位置。data这个变量将存放到RAM中的RW区域中(后面将会详细讲解),但是data后面的初始值500 将会被存放到数据复制区域中,也就是上图中的从下往上的第三个区域,在my_function中的变量x将会被存放到RAM中的堆栈中,将x赋值为200,200将被存储到Flash的Text的常量区中,str是一个char型的指针变量,它指向的是字符串第一个字符存放的位置,然而对于字符串string来讲,它是存放在Text常量区的,所以指针变量指向这个区域的一个地址,但是它终归是局部变量,它指向Flash的一个地址,但是其本身还是存放于RAM中的堆栈上的。
STM32单片机的片内RAM会被链接文件“分区”,为如下几个段:
如上图所示,RAM中包含了如下几个部分,栈(Stack):存放局部变量和函数调用时返回的地址
堆(heap):由malloc申请,free释放
bss:存放未初始化或者是初始化为0的全局变量
data:存放初始化为非0的全局变量
下面举一个简单的例子来说明变量在各个段中的存储位置:
- #include <stdio.h>
-
- int data_var = 500;
-
- int bss_var0;
-
- int bss_var1 = 0;
-
- static int static_var;
-
- void my_function(void)
- {
- static int static_var1 = 0;
-
- int stack = 0;
-
- char *buffer;
-
- const int value =1;
-
- buffer = malloc(10);
- }
上述变量的命名已经很清楚的表明了变量处于RAM中的哪一个段,data var是已经初始化的全局变量,存放在RAM的data区,bssvar0和bssvar1是未初始化和初始化为0的全局变量,它们都存放于RAM中的bss段,由static修饰的staticvar和static_var1都存放于bss段,区别只在于两个变量的作用域不同。stack是在函数内部的局部变量,其存放于RAM的栈区域,用const修饰的局部变量value,虽然它是只读的,但是它是存储于RAM中的栈中的,这里也说明一点,并不是所有用const修饰的变量都是存放于只读变量区的。buffer指针变量用malloc函数申请了10字节的内存空间,那这10字节的内存空间位于堆中。
如果程序运行过程中,堆得空间也一直在消耗,同时栈的空间也在增加,这时堆和栈如果碰到一起,那么就会造成堆栈溢出,从而导致程序跑飞。
STM32的map文件分析
在用keil编译STM32工程之后,我们会得到一个map文件,map文件的最底部有这么一个信息:
图中的各个段是和上文所述的能够进行对应起来的,正如下面这张表所示
Code | RO Data | RW Data | ZI Data |
Executable Code | Read Only Data | data | bs |
对于RAM和FLASH空间都有限的MCU来讲,了解各个变量在内存中的存储位置很有必要,它能够很好的帮助我们解决很多问题。
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。