stm32的存储器结构


首先,先看一下stm32的存储器结构。

FlashSRAM寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。可访问的存储器空间被分成8个主要块,每个块为512MBFLASH存储下载的程序,FLASH是ROM的一种。SRAM是存储运行程序中的数据,SRAM是RAM的一种。所以,只要你不外扩存储器,写完的程序中的所有东西也就会出现在这两个存储器中。


1.     STM32中的堆栈

        首先要说明的是单片机是一种集成电路芯片,集成CPURAMROM、多种I/O口和中断系统、定时器/计数器等功能。CPU中包括了各种总线电路,计算电路,逻辑电路,还有各种寄存器。Stm32有通用寄存器R0R15 以及一些特殊功能寄存器,其中包括了堆栈指针寄存器。当stm32正常运行程序的时候,来了一个中断,CPU就需要将寄存器中的值压栈到RAM里,然后将数据所在的地址存放在堆栈寄存器中。等中断处理完成退出时,再将数据出栈到之前的寄存器中,这个在C语言里是自动完成的。


2.     STM32的堆栈大小

 定义大小在startup_stm32f2xx.s

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp


; Heap Configuration
;     Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base

 

 

3.     STM32的堆栈位置

通过MAP文件可知(在目标工程栏-->>双击工程名,就会在keil文件显示框出现map文件)

 HEAP                                     0x200106f8   Section      512  startup_stm32f2xx.o(HEAP)
 STACK                                   0x200108f8   Section     1024  startup_stm32f2xx.o(STACK)

 __heap_base                         0x200106f8   Data           0  startup_stm32f2xx.o(HEAP)
 __heap_limit                           0x200108f8   Data           0  startup_stm32f2xx.o(HEAP)
 __initial_sp                             0x20010cf8   Data           0  startup_stm32f2xx.o(STACK)

 

         显然 Cortex-m3资料可知:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)显然堆和栈是相邻的。

 

4.     STM32的堆和栈的空间分配

栈:向低地址扩展

堆:向高地址扩展

显然如果依次定义变量

先定义的栈变量的内存地址比后定义的栈变量的内存地址要大

先定义的堆变量的内存地址比后定义的堆变量的内存地址要小 



5.     编程中的堆栈。

在编程中很多时候会提到堆栈这个东西,准确的说这个就是RAM中的一个区域。我们先来了解几个说明:

(1) 程序中的所有内容最终只会出现在flashram里(不外扩)。

(2) 段的划分,是将类似数据种类存储在一个区域里,方便管理,但正如上面所说,不管什么段的数据,都是最终在flashram里面。

重点分析一下STM32以及在MDK里面段的划分。

MDKCode,RO-data,RW-data,ZI-data这几个段:

Code是存储程序代码的。

RO-data是存储const常量和指令。

RW-data是存储初始化值不为0的全局变量。

ZI-data是存储未初始化的全局变量或初始化值为0的全局变量。

Flash=Code + RO-Data + RW-Data;

RAM= RW-data+ZI-data;

        这个是MDK编译之后能够得到的每个段的大小,也就能得到占用相应的FLASHRAM的大小,但是还有两个数据段也会占用RAM,但是是在程序运行的时候,才会占用,那就是堆和栈。在stm32的启动文件.s文件里面,就有堆栈的设置,其实这个堆栈的内存占用就是在上面RAM分配给RW-data+ZI-data之后的地址开始分配的。

这里为什么在FLASH中加了RW-Data还要在RAM中加上呢,原因是在初始化时RW-data从flash拷贝到RAM中,掉电后数据依然是在FLASH中的


:是编译器调用动态内存分配的内存区域。

:是程序运行的时候局部变量的地方,所以局部变量用数组太大了都有可能造成栈溢出。

        堆栈的大小在编译器编译之后是不知道的,只有运行的时候才知道,所以需要注意一点,就是别造成堆栈溢出了。。。不然就等着hardfault找你吧。


举例:


Flash=4164+336+56=0x11CC

RAM=56+1832=0x760

那么:堆栈指针指向的位置就是0x20000760



6.     OS中的堆栈及其内存管理。

        嵌入式系统的堆栈,不管是用什么方法来得到内存,感觉他的方式都和编程中的堆差不多。目前我知道两种获得内存情况:

(1)用庞大的全局变量数组来圈住一块内存,然后将这个内存拿来进行内存管理和分配。这种情况下,堆栈占用的内存就是上面说的:如果没有初始化数组,或者数组的初始化值为0,堆栈就是占用的RAM的ZI-data部分;如果数组初始化值不为0,堆栈就占用的RAM的RW-data部分。这种方式的好处是容易从逻辑上知道数据的来由和去向。

(2)​就是把编译器没有用掉的RAM部分拿来做内存分配,也就是除掉RW-data+ZI-data+编译器堆+编译器栈后剩下的RAM内存中的一部分或者全部进行内存管理和分配。这样的情况下就只需要知道内存剩下部分的首地址和内存的尾地址,然后要用多少内存,就用首地址开始挖,做一个链表,把内存获取和释放相关信息链接起来,就能及时的对内存进行管理了。内存管理的算法多种多样,不详说,这样的情况下:OS的内存分配和自身局部变量或者全局变量不冲突,之前我就在这上面纠结了很久,以为函数里面的变量也是从系统的动态内存中得来的。这种方式感觉更加能够明白自己地址的开始和结束。

这两种方法我感觉没有谁更高明,因为只是一个内存的获取方式,高明的在于内存的管理和分配。


7.     STM32的堆栈生长方向和存储模式。

大端格式(Big-endian)

小端格式(Little-endian)

数据0x12345678存储格式

      大端格式

低地址<----0x12|0x34|0x56|0x78---->高地址

      小端格式

低地址<----0x78|0x56|0x34|0x12---->高地址

stm32是向下生长,采用的是小端存储。



你可能感兴趣的:(STM32)