1、编译失败时
很多人从事嵌入式单片机开发,不怎么关心内存分配问题。尤其是现在STM32大行其道之时,型号众多,可选择性大,而且RAM也是极大的增加,不像开发51单片机那样要仅仅盯着RAM的分配及使用情况。对于简单的项目应用,功能单一的情况下,不用过于操心RAM的使用情况。随着功能的增多,模块增多之后,尤其编译时提示内存不足之时,如下图所示
内存RAM不足编译失败
发生这种情况,就要左看看右看看,这边减少一些那边减少一些,或者做刚做的改动调整一下,做出妥协的做法了。
2、弄清RAM使用情况
作为一个认真执着的开发工程师(码农)对于RAM的使用情况是否需要弄清它呢?怎么样弄清它呢?有没有一个方法可以让程序自动告诉我们RAM用来多少?还剩余多少呢?答案是有的。
2.1、RAM结构
RAM结构很简单,如下图所示。
已STM32F103RB为例
在实践中,变量得需要时动态增加或者减少的,因此上述分区基本不变,变化的是具体区域的地址;我们只要拿捏住芯片RAM大小与堆栈区的大小及栈定的地址就可以很方便地知道其他区域的使用情况了。那么我们怎么知道栈顶地址呢?做过STM32应用编程(IAP)的朋友应该很容易想到,它就保存在0x08000000地址处(对此不清楚的朋友可以查下相关资料)。题外话:系统是怎么知道堆栈(上图红线)越界了呢?知道的朋友可以留言告诉我一下,谢谢。
2.2、验证栈顶地址
验证栈顶地址的方法有3种,
第一是看项目的map文件,如下图所示。
map文件查找栈顶地址
第二是仿真看MSP寄存器,如下图所示。
软件仿真查看MSP,仅启动仿真功能不运行
第三种是查看BIN文件的第一个字,如下图所示。
生成工程BIN文件查看第一个字,这是IAP功能的基础
通过上面三中方法验证了栈顶地址是一致的。但是这些我能只能人工去做,现在就让软件自动告诉我们RAM分配清单。
3、让软件自动输出RAM分配清单
关键点:一是,到.s文件查看堆与栈分配的大小,定义如下图所示。
定义芯片RAM内存相关信息
当更改S文件中的堆栈配置时这里的宏定义也要跟着改变(要是有知道在C文件中引用S文件定义的朋友请留言告诉作者,谢谢)。
下面简单地写一个测试公共变量得函数,测试堆内存得函数,同时实现写一个输出RAM分配清单函数,如下:
#define App_START_ADDRESS 0x08000000 //开始地址(栈顶地址)
#define RAM_START_ADDRESS 0x20000000 //RAM开始地址
#define APP_STACK_SIZE 0x1000 //栈大小(字节数量)4KB
#define APP_HEAP_SIZE 0x1000 //堆大小(字节数量)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); //从堆区申请内存
p1=p2;
memcpy(p2,buff,BUFF_SIZE); //将公共变量的值拷贝到申请的内存中
p1=p2;
for(i=0;i<BUFF_SIZE;i++) //计算申请内存中值的和
{
sum+=*p2++;
}
return sum; //返回计算和
}
// --------------------------------------------------
void TellAboutRam()
{
unsigned int StackTopAddr=(*(__IO u32*)APP_START_ADDRESS); //获取栈顶地址
unsigned int HeapTopAddr=StackTopAddr-APP_STACK_SIZE; //获取堆顶/栈底地址
unsigned int GlobalVarSize=HeapTopAddr-APP_HEAP_SIZE-RAM_START_ADDRESS; //计算公共变量区域大小
unsigned int RamFreeSize=MCU_RAM_SIZE-(StackTopAddr-RAM_START_ADDRESS); //计算空闲区大小
printf ("栈 顶t=t%08XH n",StackTopAddr);
printf ("堆 顶t=t%08XH n",HeapTopAddr);
printf ("未分配区t=t%d Byten",RamFreeSize);
printf ("栈 区t=t%d Byten",APP_STACK_SIZE);
printf ("堆 区t=t%d Byten",APP_HEAP_SIZE);
printf ("公共变量区t=t%0d Byten",GlobalVarSize);
}
// --------------------------------------------------
int main (void)
{
SER_Init ();
printf ("------------- Hello World ------------n");
printf ("测试公共变量t=t%d tn",GetGloablVarSum());
printf ("测 堆区t=t%d tn",GetHeapVarSum());
TellAboutRam();
while (1)
{
;
}
}
仿真输出如下图所示:
总之弄清RAM分配情况很简单,首先抓住栈地址特别是0x08000000这个地址得值,其次是弄清S文件中堆与栈的大小。还有什么好方法欢迎留言。