单片机内存及运行
内存
一般单片机内存分为RAM和FLASH。 比如STM32F103ZET6
/* Memories definition */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K }
RAM
随机存取存储器(英语:Random Access Memory,缩写:RAM),也叫主存,是与CPU直接交换数据的内部存储器。它可以随时读写(刷新时除外),而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储介质。
FLASH
快闪存储器(英语:flash memory),是一种电子式可清除程序化只读存储器的形式,允许在操作中被多次擦或写的存储器。
关键字
RAM可随时读写 FLASH只读。 这里说的读写是针对CPU的。
程序
1 int gvar_x;
2 int main(void)
3 {
4
5 while (1)
6 {
7 gvar_x = gvar_x + 1;
8 }
9}
在代码7行,分别对变量gvar_x进行了写入操作。根据上面RAM、FLASH的介绍,写入操作只能在RAM中进行。 打开MAP文件,会发现:
.text.main 0x8000268 0x28 ./Core/Src/main.o
0x8000268 main
.data.gvar_x 0x20000000 0x4 ./Core/Src/main.o
0x20000000 gvar_x
可以看出gvar_x作为可写的变量被放到了RAM区域,而main函数作为只读的代码指令放到了只读的FLASH区域。
gvar_x = gvar_x+1;
8000278: 4b02 ldr r3, [pc, #8] ; (8000284 <main+0x1c>)
800027a: 681b ldr r3, [r3, #0]
800027c: 3301 adds r3, #1
800027e: 4a01 ldr r2, [pc, #4] ; (8000284 <main+0x1c>)
8000280: 6013 str r3, [r2, #0]
8000282: e7f9 b.n 8000278 <main+0x10>
8000284: 20000000 .word 0x20000000
再来分析下汇编。
- 在地址8000278处,指令ldr r3, [pc, #8]意味着将PC+8处的数据加载到r3寄存器,从汇编可以看出PC+8=8000284,即将20000000加载到r3寄存器。
- 然后CPU继续运行来到800027a处,指令ldr r3, [r3, #0]意味着将r3+0处的数据加载到r3,而这时候r3的内容是20000000,也就是将20000000里面的数据加载到r3寄存器里面,这时候r3寄存器里面才是变量gvar_x的值。
- 在地址800027c处,指令adds r3, #1意味着对r3寄存器加1,也就是gvar_x+1。
- 到这一步就完成了,先取变量gvar_x的值,然后对变量gvar_x加1。
- 在地址800027e处,指令ldr r2, [pc, #4]意味着将PC+4,也就是8000284处的数据加载到r2寄存器里面,这里和第1步一样,先拿到变量gvar_x的地址。只不过r3已经被占用了,所以使用了r2寄存器,这里CPU自有一套标准选择使用的寄存器。
- 来到8000280处,指令str r3, [r2, #0]意味着将r3寄存器里的值设置到r2+0地址处,也就是20000000这个地址里面。
从上面流程可以看出,为什么不写到8000284处,还要绕一圈写道到20000000处,就是因为8000284属于FLASH,只可读,20000000属于RAM可读可写。如果FLASH里面的可写,那对程序来说就是一场灾难。 所以这就是单片机里面为什么要有只读的FLASH和可读可写的RAM。 从上面分析也可以看出,CPU执行代码指令是直接从FLASH里面直接取代码指令去执行。
RAM扩展
RAM里面有全局变量、静态变量、堆、栈。 当你编译完后,你写的代码指令和数据都在一个hex文件里面,而这个hex的起始地址是80000000开始的,也就是当你烧录程序时候,不会把变量烧录到20000000后面的地址。 那变量是什么时候到20000000里面的呢? 就在程序启动之前,CPU会先把属于RAM的数据变量都加载到RAM里面。 这就涉及VMA、LMA。也就是运行内存地址和加载内存地址。 这就是为什么当你的单片机掉电后,运行数据都丢失的原因。 如果你想保存这些数据,就需要单片机的外设FLASH模块了。而CPU是不能直接将数据写入到FLASH里面的。
栈
_Min_Stack_Size = 0x400 ; /* required amount of stack */
栈里面就是存储的局部变量,当然栈是有大小的,这里最小设置的1KBytes。 假如堆+全局变量+静态变量使用了63K,那你栈只能使用1K空间,如果这时候你有个局部变量数据,大小是2K,那你就去HardFault里面呆着吧。
堆
_Min_Heap_Size = 0x200 ; /* required amount of heap */
堆就是你程序在跑的过程中使用malloc开辟的空间。 假如栈+全局变量+静态变量使用了63K,而你又要开辟了一个2K的堆空间,那这时候就会内存泄漏。程序跑哪我也不知道了。
|