STM32学习笔记-STM32堆栈区(二)

STM32堆栈区(二)

STM32的分区

STM32的分区从0x2000 0000(0x2000 0000是SRAM的起始地址,由此可知,堆栈等都是在RAM中的)开始。静态区,堆,栈。所有的全局变量,包括静态变量之类的,全部存储在静态存储区。 紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区,栈在程序中存储局部变量。

先看启动文件startup_stm32f10x_md.s的定义:

;
Amount of memory (in bytes) allocated for Stack 

; Tailor this value to your application needs 

; <h> Stack Configuration 

; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> 

; </h>

Stack_Size
EQU 0x00000400

AREA
STACK, NOINIT, READWRITE, ALIGN=3 

Stack_Mem SPACE Stack_Size 

__initial_sp



; <h> Heap Configuration 

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

; </h>

Heap_Size
EQU 0x00000200

AREA
HEAP, NOINIT, READWRITE, ALIGN=3 

__heap_base 

Heap_Mem SPACE Heap_Size 

__heap_limit

这里定义了堆栈各自大小,堆:512bytes 栈1k
所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出

再看下code ro rw zi

  1. Code指存储到flash【Rom】中的程序代码。
  2. ZI英语是zero initial,就是程序中用到的变量并且被系统初始化为0的变量的字节数,keil编译器默认是把你没有初始化的变量都赋值一个0,这些变量在程序运行时是保存在RAM中的。
  3. RW是可读可写变量,就是初始化时候就已经赋值了的,RW + ZI就是你的程序总共使用的RAM字节数
  4. RO是程序中的指令和常量,这些值是被保存到Rom中的。
  5. Total ROM Size (Code +RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。为什么Rom中还要存RW,因为掉电后RAM中所有数据都丢失了,每次上电RAM中的数据是被重新赋值的,每次这些固定的值就是存储在Rom中的,为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。

实际上,ROM中的指令至少应该有这样的功能:

  1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
  2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中。

例子:

1,首先来看:栈(STACK)的问题.

函数的局部变量,都是存放在“栈”里面,栈的英文是:STACK。STACK的大小,我们可以在stm32的启动文件里面设置,在startup_stm32f10x_hd.s里面,开头就有:

Stack_Size     EQU     0x00000800

表示栈大小是0X800,也就是2048字节,这样,CPU处理任务的时候,函数局部变量过多可占用的大小就是:2048字节。注意:是所有在处理的函数,包括函数嵌套,递归,等等,都是从这个“栈”里面,来分配的。

所以,如果一个函数的局部变量过多,比如在函数里面定义一个u8 buf[512],这一下就占了1/4的栈大小了,再在其他函数里面来搞两下,程序崩溃是很容易的事情,这时候,一般你会进入到hardfault…

这是初学者非常容易犯的一个错误.切记不要在函数里面放N多局部变量,尤其有大数组的时候!

对于栈区,一般栈顶,也就是MSP,在程序刚运行的时候,指向程序所占用内存的最高地址。比如附件里面的这个程序序,内存占用如下图:
在这里插入图片描述
图中,我们可以看到,程序总共占用内存:20+2348字节=2368=0X940

那么程序刚开始运行的时候:MSP=0X2000 0000+0X940=0X2000 0940.
事实上,也是如此,如图:
在这里插入图片描述
图中,MSP就是:0X2000 0940,程序运行后,MSP就是从这个地址开始,往下给函数的局部变量分配地址。

2,再来说说,堆(HEAP)的问题.
全局变量,静态变量,以及内存管理所用的内存,都是属于“堆"区”,英文名:“HEAP”,与栈区不同,堆区,则从内存区域的起始地址开始分配给各个全局变量和静态变量。
堆的生长方向,都是向上的。在程序里面,所有的内存分为:堆+栈,只是他们各自的起始地址和增长方向不同,他们没有一个固定的界限,所以一旦堆栈冲突,系统就到了崩溃的时候了。
3,再说说,大小端的问题

大端模式:低位字节存在高地址上,高位字节存在低地址上
小端模式:高位字节存在高地址上,低位字节存在低地址上
STM32属于小端模式,简单的说,比如u32 temp=0X12345678;
假设temp地址在0X2000 0010.
那么在内存里面,存放就变成了:
地址
| HEX |

0X2000 0010 | 78 56 43 12 |

猜你喜欢

转载自blog.csdn.net/qq_34623621/article/details/97611317