1、編譯失敗時
很多人從事嵌入式單片機(jī)開發(fā),不怎么關(guān)心內(nèi)存分配問題。尤其是現(xiàn)在STM32大行其道之時,型號眾多,可選擇性大,而且RAM也是極大的增加,不像開發(fā)51單片機(jī)那樣要僅僅盯著RAM的分配及使用情況。對于簡單的項目應(yīng)用,功能單一的情況下,不用過于操心RAM的使用情況。隨著功能的增多,模塊增多之后,尤其編譯時提示內(nèi)存不足之時,如下圖所示
內(nèi)存RAM不足編譯失敗
發(fā)生這種情況,就要左看看右看看,這邊減少一些那邊減少一些,或者做剛做的改動調(diào)整一下,做出妥協(xié)的做法了。
2、弄清RAM使用情況
作為一個認(rèn)真執(zhí)著的開發(fā)工程師(碼農(nóng))對于RAM的使用情況是否需要弄清它呢?怎么樣弄清它呢?有沒有一個方法可以讓程序自動告訴我們RAM用來多少?還剩余多少呢?答案是有的。
2.1、RAM結(jié)構(gòu)
RAM結(jié)構(gòu)很簡單,如下圖所示。
已STM32F103RB為例
在實踐中,變量得需要時動態(tài)增加或者減少的,因此上述分區(qū)基本不變,變化的是具體區(qū)域的地址;我們只要拿捏住芯片RAM大小與堆棧區(qū)的大小及棧定的地址就可以很方便地知道其他區(qū)域的使用情況了。那么我們怎么知道棧頂?shù)刂纺兀孔鲞^STM32應(yīng)用編程(IAP)的朋友應(yīng)該很容易想到,它就保存在0x08000000地址處(對此不清楚的朋友可以查下相關(guān)資料)。題外話:系統(tǒng)是怎么知道堆棧(上圖紅線)越界了呢?知道的朋友可以留言告訴我一下,謝謝。
2.2、驗證棧頂?shù)刂?/h1>
驗證棧頂?shù)刂返姆椒ㄓ?種,
第一是看項目的map文件,如下圖所示。
map文件查找棧頂?shù)刂?/p>
第二是仿真看MSP寄存器,如下圖所示。
軟件仿真查看MSP,僅啟動仿真功能不運行
第三種是查看BIN文件的第一個字,如下圖所示。
生成工程BIN文件查看第一個字,這是IAP功能的基礎(chǔ)
通過上面三中方法驗證了棧頂?shù)刂肥且恢碌摹5沁@些我能只能人工去做,現(xiàn)在就讓軟件自動告訴我們RAM分配清單。
3、讓軟件自動輸出RAM分配清單
關(guān)鍵點:一是,到.s文件查看堆與棧分配的大小,定義如下圖所示。
定義芯片RAM內(nèi)存相關(guān)信息
當(dāng)更改S文件中的堆棧配置時這里的宏定義也要跟著改變(要是有知道在C文件中引用S文件定義的朋友請留言告訴作者,謝謝)。
下面簡單地寫一個測試公共變量得函數(shù),測試堆內(nèi)存得函數(shù),同時實現(xiàn)寫一個輸出RAM分配清單函數(shù),如下:
#define App_START_ADDRESS 0x08000000 //開始地址(棧頂?shù)刂罚?#define RAM_START_ADDRESS 0x20000000 //RAM開始地址
#define APP_STACK_SIZE 0x1000 //棧大小(字節(jié)數(shù)量)4KB
#define APP_HEAP_SIZE 0x1000 //堆大小(字節(jié)數(shù)量)4KB
#define MCU_RAM_SIZE 0x5000 //20KB
// --------------------------------------------------
#define BUFF_SIZE 1024 //定義公共大小
char buff[BUFF_SIZE]; //定義公共變量
int GetGloablVarSum(void)
{
int i,sum=0; //局部變量
for(i=0;i<BUFF_SIZE;i++) //公共變量初始化
{
buff[i]=i;
sum+=buff[i]; //計算功能變量的和
}
return sum; //返回計算和
}
// --------------------------------------------------
int GetHeapVarSum(void)
{
int i,sum=0; //定義公共變量
char *p1,*p2=(char*)malloc(BUFF_SIZE); //從堆區(qū)申請內(nèi)存
p1=p2;
memcpy(p2,buff,BUFF_SIZE); //將公共變量的值拷貝到申請的內(nèi)存中
p1=p2;
for(i=0;i<BUFF_SIZE;i++) //計算申請內(nèi)存中值的和
{
sum+=*p2++;
}
return sum; //返回計算和
}
// --------------------------------------------------
void TellAboutRam()
{
unsigned int StackTopAddr=(*(__IO u32*)APP_START_ADDRESS); //獲取棧頂?shù)刂? unsigned int HeapTopAddr=StackTopAddr-APP_STACK_SIZE; //獲取堆頂/棧底地址
unsigned int GlobalVarSize=HeapTopAddr-APP_HEAP_SIZE-RAM_START_ADDRESS; //計算公共變量區(qū)域大小
unsigned int RamFreeSize=MCU_RAM_SIZE-(StackTopAddr-RAM_START_ADDRESS); //計算空閑區(qū)大小
printf ("棧 頂t=t%08XH n",StackTopAddr);
printf ("堆 頂t=t%08XH n",HeapTopAddr);
printf ("未分配區(qū)t=t%d Byten",RamFreeSize);
printf ("棧 區(qū)t=t%d Byten",APP_STACK_SIZE);
printf ("堆 區(qū)t=t%d Byten",APP_HEAP_SIZE);
printf ("公共變量區(qū)t=t%0d Byten",GlobalVarSize);
}
// --------------------------------------------------
int main (void)
{
SER_Init ();
printf ("------------- Hello World ------------n");
printf ("測試公共變量t=t%d tn",GetGloablVarSum());
printf ("測 堆區(qū)t=t%d tn",GetHeapVarSum());
TellAboutRam();
while (1)
{
;
}
}
仿真輸出如下圖所示:
總之弄清RAM分配情況很簡單,首先抓住棧地址特別是0x08000000這個地址得值,其次是弄清S文件中堆與棧的大小。還有什么好方法歡迎留言。