stm32 memory architecture and management

stm32 memory architecture and management

Computer Memory Management

Stm32 time learning some foggy memory management, online blog also read a lot of documents, but have not made it to explain stm32 system memory architecture. So we decided to do an analysis of their own and their own understanding of stm32 memory architecture.

Before discussing the single-chip memory management, I would like to say something about computers is how memory management. According to "C ++ Primer Plus (6th Edition)" This book talking about, C ++ (on memory management in terms similar to C) There are three kinds of management data memory of the way:
①, automatic storage: 1 function defined inside a routine constant use automatic storage, the automatic variable called variable (local variable).
Generating (push) 2. When the function is called die (popping) function ends. Last in, first out (LIFO). Thus in one function block, the region will continue to
increase or decrease.
3. The area we generally referred to as the stack area.
②, static memory: 1 static storage is there a way to store the entire program during execution.
2. There are two definitions of the variable: definitions it out of the function / use keyword when declaring variables: static.
③, dynamic storage:. 1 new (malloc) and delete (free) operator (function) provides a more flexible and static variables than automatic methods.
2. They manage a memory pool, which is called in C ++ free memory space or heap (heap).
3. This is stored independently of the other two, variable generation and disappearance can be determined by the programmer.
We may be able to understand these three areas of SRAM storage area stm32.

stm32 memory architecture

stm32 a 32-bit microcontroller, the available address space up to 4GB. Of course, we only use a small part of it, to stm32f407 example, its internal Flash (ROM) size is 1M byte, SRAM size is 192Kb bytes.
We usually say the SRAM memory management is the management of dynamic memory (heap). The 4GB address space corresponds to stm32 by the following figure shows (see Source watermark):
Here Insert Picture Description
a drawing by clearly see the relationship between the Cortex-M3 and stm32, although we stm32f407 is based on the Cortex-M4 architecture, but also by the FIG see the relationship between the 4GB address space and STM32. Our program and constants are stored in Flash, debug mode can also be seen in 0X0800 0000 PC pointer is always behind the Flash area, the variable is stored in the SRAM, the SRAM is the first address 0X2000 0000. I made a architecture diagram to help you better understand the storage infrastructure stm32:
Here Insert Picture Description
where the memory address is defined in accordance with stm32f407 go, we chose to look at in addition to the main chip when it brought peripherals ADC / TIM / DAC / FSMC, but also in It depends on the size of Flash and SRAM enough of our projects.

If our compiler is Keil (of course, most people use it), then put them in a storage area subdivided into segments each area, such as we casually compile the project led by a look:
Here Insert Picture Description
Flash = Code (program code) + RO - data (and instructions stored constant const) + RW - data (initial value is not a global / static variables 0)
the SRAM RW = - data (the program running is read from the Flash) + ZI - data (initial value 0 or uninitialized global / static variables)

Ps: SRAM memory at compile time will not apply for all variables show finished, because SRAM memory is a dynamic process, so you can not see the size of SRAM meet onboard SRAM size, the program is considered to meet the hardware requirements! Of course, involve more complex stack memory, memory leaks, memory overlay, etc., the more important we say about the individual behind.

SRAM internal management

其实就我们平时写写程序就只需要知道有这么一个大小的SRAM给我们用就好了,但是如果基于操作系统OS的话,还是要更加细分SRAM区域,合理利用每一个区域去完成我们的项目,最大限度的利用单片机资源,这里我们放一张数据手册中的矩阵图:Here Insert Picture Description
我们可以看到192Kb的SRAM其实分为3部分,SRAM1,SRAM2,和64Kb的CCMRAM。查看数据手册的关于SRAM的介绍:
Seven slaves:
– Internal Flash memory ICode bus
– Internal Flash memory DCode bus
– Main internal SRAM1 (112 KB)
– Auxiliary internal SRAM2 (16 KB)
– AHB1 peripherals including AHB to APB bridges and APB peripherals
– AHB2 peripherals
– FSMC
我们可以看到SRAM1是主要的存储区,主要存放一些程序运行时产生的变量,SRAM2辅助内部存储区,主要作用于与外设数据有关的变量。而CCMRAM则比较特殊,stm32f1里没有这个东西,从矩阵图中也可以看出这个区域通过D总线直接和CPU相连,这意味着,**CPU能以最大的系统时钟和最小的等待时间从CCM中读取数据或者代码。**对于要求速度,精度高的项目我们可以尝试将变量定义在这个区域里面。定义的方法网上大概分为两种:
嫌麻烦的话就 u32 ccmTextNum attribute((at(0x10000000)))用at去定位到这个区域里面,还有一种方法分散加载文件(.sct),更为强大一些,感兴趣的可以自己去尝试一下。再Ps:CCMRAM没有与一些外设如DMA相连,说明这个区域的变量不可以通过DMA传输!

程序验证堆栈区地址及内存覆盖

说了这么多,现在大家对stm32内存架构可能会有更清晰的了解,我们现在动手验证一下我们所说的是否准确,首先我们先测试堆和栈的地址范围及容量大小(程序基于正点原子探索者):

仅验证堆栈首地址及其大小

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

//为了方便起见,STACK区(栈)我们用SRAM1来表示,HEAP区(堆)我们用SRAM2来表示,静态常量区我们用SRAM3来表示。

u8 SRAM3_Buffer[100]={0};//声明了一个初始化为0的全局数组,在静态常量区,0x2000 0000开头

int main(void)
{ 
	u8 SRAM1_i,SRAM1_j = 1,m;//i为普通的未初始化局部变量,j作为初始化的局部变量,测试可得均存在于栈区
	u8* pSRAM2 = (u8*)malloc(200);//指针pSRAM2指向堆区分配了一个u8类型200大小的数组的首地址,测试可得存在于堆区
	
	u8 SRAM1_Buffer[100] = {0};//声明了一个局部数组,存在于静态常量区。
	
	delay_init(168);		  //初始化延时函数
	LED_Init();		        //初始化LED端口
	uart_init(115200);
  
	for(m = 0;m < 100;m++)
	{
		SRAM3_Buffer[m] = m;
	}
	
	printf("未初始化局部变量SRAM1_i在栈中的地址为:0x%x\r\n",&SRAM1_i);
	printf("初始化的局部变量SRAM1_j在栈中的地址为:0x%x\r\n",&SRAM1_j);
	printf("初始化局部数组SRAM1_Buffer在栈中的地址为:0x%x\r\n",&SRAM1_Buffer);
	printf("调用malloc声明了一个在堆区的数组首地址为:0x%x\r\n",pSRAM2);
	//printf("静态常量区的数组的地址为:0x%x\r\n",SRAM3_Buffer);
	
//	printf("静态常量区的数组值为:\r\n");
//	for(m = 0;m < 100;m++)
//	{
//		printf("%d ",SRAM3_Buffer[m]);
//	}
	

	while(1)
	{
		delay_ms(500);
		
		LED1 = ~LED1;
	}
}

通过串口调试助手我们可以看到我们声明的变量的具体地址:
Here Insert Picture Description
可以看出前三个局部变量是在同一个区域,后一个动态变量在另一个区域,而这两个区域,就是我们平时说的堆栈区。堆栈区的大小我们可以从启动文件里得到:
Here Insert Picture Description
Here Insert Picture Description
从启动文件我们可以得到栈区大小为0x0000 0400(1Kb),堆区的大小为:0x0000 0200(512字节)。这里我们再放一张图,可以清楚的看到堆栈区与静态常量区的关系(出处见水印(我也看不清。。)):
Here Insert Picture Description
这里大家可能会发现我们申请的位于栈区的局部变量首地址,是位于栈顶的0x2000 06f0开始的,而位于堆区的动态变量首地址是从堆底0x200000f0开始的。这就涉及堆栈对于数据处理方式的不同,前面的文章也讲了,栈是后进先出,所以栈变量(局部变量)是从栈顶向下分配地址,而堆则相反,是先进后出,所以从堆底向上分配地址。那么有没有一种可能,栈变量我们申请的比较大,那么它就会一直向下申请内存,直到污染了HEAP和静态存储区,这就是比较可怕的内存叠加,我们在软件里模拟一下这个事件:

加上全局数组后的程序

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

//为了方便起见,STACK区(栈)我们用SRAM1来表示,HEAP区(堆)我们用SRAM2来表示,静态常量区我们用SRAM3来表示。

u8 SRAM3_Buffer[100]={0};//声明了一个初始化为0的全局数组,在静态常量区,0x2000 0000开头

int main(void)
{ 
	u8 SRAM1_i,SRAM1_j = 1,m;//i为普通的未初始化局部变量,j作为初始化的局部变量,测试可得均存在于栈区
	u8* pSRAM2 = (u8*)malloc(200);//指针pSRAM2指向堆区分配了一个u8类型200大小的数组的首地址,测试可得存在于堆区
	
	u8 SRAM1_Buffer[100] = {0};//声明了一个局部数组,存在于静态常量区。
	
	delay_init(168);		  //初始化延时函数
	LED_Init();		        //初始化LED端口
	uart_init(115200);
  
	for(m = 0;m < 100;m++)
	{
		SRAM3_Buffer[m] = m;
	}
	
	printf("未初始化局部变量SRAM1_i在栈中的地址为:0x%x\r\n",&SRAM1_i);
	printf("初始化的局部变量SRAM1_j在栈中的地址为:0x%x\r\n",&SRAM1_j);
	printf("初始化局部数组SRAM1_Buffer在栈中的地址为:0x%x\r\n",&SRAM1_Buffer);
	printf("调用malloc声明了一个在堆区的数组首地址为:0x%x\r\n",pSRAM2);
	printf("静态常量区的数组的地址为:0x%x\r\n",SRAM3_Buffer);
	
	printf("静态常量区的数组值为:\r\n");
	for(m = 0;m < 100;m++)
	{
		printf("%d ",SRAM3_Buffer[m]);
	}
	

	while(1)
	{
		delay_ms(500);
		
		LED1 = ~LED1;
	}
}

Here Insert Picture Description
这个首先我们在main函数添加了一个100位局部数组并且把0-99赋值进去,我们可以看到正常数组是位于静态存储区。这时我们声明一个位于栈区的数组,这个数组很大,大到足以污染静态存储区。

涉及内存覆盖的程序

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

//为了方便起见,STACK区(栈)我们用SRAM1来表示,HEAP区(堆)我们用SRAM2来表示,静态常量区我们用SRAM3来表示。

u8 SRAM3_Buffer[100]={0};//声明了一个初始化为0的全局数组,在静态常量区,0x2000 0000开头

int main(void)
{ 
	u8 SRAM1_i,SRAM1_j = 1,m;//i为普通的未初始化局部变量,j作为初始化的局部变量,测试可得均存在于栈区
	u8* pSRAM2 = (u8*)malloc(200);//指针pSRAM2指向堆区分配了一个u8类型200大小的数组的首地址,测试可得存在于堆区
	
	u8 SRAM1_Buffer[100] = {0};//声明了一个局部数组,存在于静态常量区。
	
	u8 SRAM2_Buffer[1500] = {0};
	
	delay_init(168);		  //初始化延时函数
	LED_Init();		        //初始化LED端口
	uart_init(115200);
  
	for(m = 0;m < 100;m++)
	{
		SRAM3_Buffer[m] = m;
	}
	
	printf("未初始化局部变量SRAM1_i在栈中的地址为:0x%x\r\n",&SRAM1_i);
	printf("初始化的局部变量SRAM1_j在栈中的地址为:0x%x\r\n",&SRAM1_j);
	printf("初始化局部数组SRAM1_Buffer在栈中的地址为:0x%x\r\n",&SRAM1_Buffer);
	printf("调用malloc声明了一个在堆区的数组首地址为:0x%x\r\n",pSRAM2);
	printf("静态常量区的数组的地址为:0x%x\r\n",SRAM3_Buffer);
	
	printf("静态常量区的数组值为:\r\n");
	for(m = 0;m < 100;m++)
	{
		printf("%d ",SRAM3_Buffer[m]);
	}
	

	while(1)
	{
		delay_ms(500);
		
		LED1 = ~LED1;
	}
}

Then we see an array SRAM1_Buffer located in static memory's value has changed, it is very terrible, stack variable area is too large to other areas such as heap area / variable value of static storage area to be affected!
Here Insert Picture Description
Of course, this means that after running the program displays the result on the serial debugging assistant, if you trouble free, you can also directly enter debug mode change in value Memory 1 display program running:
Here Insert Picture Description
To sum up, I think we have a general understanding stm32 memory architecture, there is a heap is an extension of up thing to say, but the stack is downward, and the compiler can not tell the size of the stack area when, for the operation of the stack so we must be careful, must apply for the memory delete / free fall, or will cause a memory leak, develop good programming habits! There is a local variable application is too large, leading to memory problems covered, and very likely to cause a crash program on stm32 memory architecture introduced here to.

Next, I will brief you on how we manage our memory by the program, this is my first blog, welcome attention, reproduced indicate the source can be happy Lantern Festival 2020!

Published an original article · won praise 1 · views 100

Guess you like

Origin blog.csdn.net/su_fei_ma_su/article/details/104229453