STM32メモリアーキテクチャと管理

STM32メモリアーキテクチャと管理

コンピュータのメモリ管理

いくつかの霧のメモリ管理を学習STM32時間は、オンラインのブログでも、文書をたくさん読んで、それはSTM32システムメモリアーキテクチャを説明するために行っていません。だから我々は、自分自身の分析とSTM32メモリアーキテクチャの独自の理解を行うことを決めました。

シングルチップのメモリ管理について説明する前に、私はコンピュータについての何かがどのようにメモリ管理であると言いたいです。「C ++プライマープラス(第6版)」の話をこの本、C ++(Cと同様の条件で、メモリ管理上の)道の管理データメモリの3種類がありますによると:
①、自動ストレージ:1関数は、ルーチン内で定義されました一定の使用自動ストレージ、自動変数は、変数(ローカル変数)と呼ばれます。
生成機能がダイ(ポッピング)関数が終了すると呼ばれている(プッシュ)2。最終では、最初に出(LIFO)。したがって、一つの機能ブロックには、領域がし続ける
増減します。
3.私たちは、一般的にスタック領域と呼ばれるエリア。
②、静的メモリ:1静的ストレージは、実行時にプログラム全体を格納する方法があります。
機能/使用キーワードの定義はそれを変数宣言:静的の2変数の二つの定義があります。
③、動的記憶:. 1(malloc関数)新しい及び削除(フリー)演算子(関数)自動方法よりも柔軟で静的変数を提供します。
2.彼らは、C ++空きメモリ領域やヒープ(ヒープ)に呼び出されたメモリプールを管理します。
3.これは、他の2つの独立して格納され、変数生成と消滅は、プログラマによって決定することができます。
私たちは、SRAM記憶領域STM32のこれら三つの領域を理解することができるかもしれません。

STM32メモリアーキテクチャ

STM32 32ビット・マイクロコントローラ、最大4GB利用可能なアドレス空間。もちろん、我々はそれだけの小さな部分を使用し、stm32f407例に、その内部のフラッシュ(ROM)サイズは1Mバイトで、SRAMのサイズは192KBがバイトです。
私たちは通常、SRAMのメモリ管理は、ダイナミックメモリ(ヒープ)の管理であると言います。次の図に示すことにより、STM32に4GBのアドレス空間の対応は、(ソース・ウォーターマークを参照してください):
ここに画像を挿入説明
はっきりによる描画がのCortex-M3とSTM32の間の関係を参照してください、私たちがでものCortex-M4アーキテクチャに基づいているが、stm32f407図は、4GBのアドレス空間とSTM32の間の関係を参照してください。私たちのプログラムや定数はフラッシュに保存され、デバッグモードは、PCポインタ0000 0x0800でも見ることができるフラッシュ領域の後ろに常にある、変数はSRAMに格納され、SRAMは、最初のアドレス0x2000で0000です。:私は、あなたがより良いストレージ・インフラストラクチャのSTM32理解するためのアーキテクチャ図を作った
ここに画像を挿入説明
、我々はそれがADC / TIM / DAC / FSMC、だけでなく、中に周辺機器をもたらしたとき、メインチップに加えて、見に選んだ行くのメモリアドレスがstm32f407に従って定義されますそれは私たちのプロジェクトのフラッシュとSRAM十分の大きさに依存します。

私たちのコンパイラはKeil社(もちろん、ほとんどの人がそれを使用する)である場合には、セグメントに分割記憶領域に入れ、各エリア、我々が何気なく見率いるプロジェクトをコンパイルなど:
ここに画像を挿入説明
フラッシュ=コード(プログラムコード)+ RO -データ(および命令を記憶された定数CONST)+ RW -データ(初期値ではない0グローバル/静的変数)
データ(プログラム実行をフラッシュから読み出される)+ ZI - -データ(初期値0または初期化されていないSRAM RWは=グローバル/静的変数)

シモンズ:SRAMメモリは動的なプロセスであるので、あなたがSRAMサイズオンボードSRAM会うの大きさを見ることができないので、コンパイル時にSRAMメモリはすべての変数に対して適用されるわけではない、完成を示し、プログラムは、ハードウェア要件を満たしていると考えられています!もちろん、我々は個々の後ろについて言うより重要なのなど、より複雑なスタックメモリ、メモリリーク、メモリ・オーバーレイを伴います。

SRAM内部管理

其实就我们平时写写程序就只需要知道有这么一个大小的SRAM给我们用就好了,但是如果基于操作系统OS的话,还是要更加细分SRAM区域,合理利用每一个区域去完成我们的项目,最大限度的利用单片机资源,这里我们放一张数据手册中的矩阵图:ここに画像を挿入説明
我们可以看到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;
	}
}

通过串口调试助手我们可以看到我们声明的变量的具体地址:
ここに画像を挿入説明
可以看出前三个局部变量是在同一个区域,后一个动态变量在另一个区域,而这两个区域,就是我们平时说的堆栈区。堆栈区的大小我们可以从启动文件里得到:
ここに画像を挿入説明
ここに画像を挿入説明
从启动文件我们可以得到栈区大小为0x0000 0400(1Kb),堆区的大小为:0x0000 0200(512字节)。这里我们再放一张图,可以清楚的看到堆栈区与静态常量区的关系(出处见水印(我也看不清。。)):
ここに画像を挿入説明
这里大家可能会发现我们申请的位于栈区的局部变量首地址,是位于栈顶的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;
	}
}

ここに画像を挿入説明
这个首先我们在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;
	}
}

その後、我々は、スタティックメモリの値であり、配列SRAM1_Bufferが変更されている、それは非常に恐ろしいであることがわかり、スタック変数の領域は、このような影響を受けるための静的格納領域のヒープエリア/変数の値などの他の分野に大きすぎます!
ここに画像を挿入説明
あなたがトラブルのない場合は、シリアルデバッグアシスタントにプログラムが表示に結果を実行した後、あなたはまた、直接値メモリー1表示プログラム実行中にデバッグモードの変更を入力することができますもちろん、この手段があること:
ここに画像を挿入説明
まとめるために、私たちは一般的な理解を持っていると思いますSTM32メモリアーキテクチャは、ヒープが事は言うまでの拡張であり、しかし、スタックは下向きであり、我々は注意しなければならないので、スタックの操作のために、メモリを申請しなければならない場合、コンパイラはスタック領域のサイズを伝えることはできません自由落下は/削除、またはメモリリークが発生します、良いプログラミング習慣を開発します!ローカル変数アプリケーションは、メモリの問題につながるが大きすぎる覆われており、非常に可能性の高いSTM32メモリアーキテクチャ上のクラッシュプログラムはこちらを紹介引き起こすことがあります。

次に、私たちは私たちのプログラムでメモリを管理方法について簡単に説明しますが、これは私の最初のブログ、歓迎注目され、ソースが幸せランタンフェスティバル2020ことができることを示し再現!

出版元の記事 ウォンの賞賛1 ビュー100

おすすめ

転載: blog.csdn.net/su_fei_ma_su/article/details/104229453