以Keil角度分析:Flash和RAM
以Keil分析:Flash和RAM
1.芯片选型怎么评估资源?
在选择芯片类型时,我们常看到这样的参数:如STM32L451的Flash是512K,RAM是160K;512K及160K都是对应最大容量,但是Flash、Ram包含那些内容呢?实际使用时,怎样计算它们的大小?
带着这两个问题去看以写内容:
2.Keil的资源统计
使用Keil编译工程后,会有下图提示:
其中四个关键点:
-
Code为代码,本质上就是一大堆ARM指令;
-
RO为只读的数据,举个栗子:
char *pcName = “Huge”; //Huge 这四个字符就是放在Rom中,属性为RO-Data
其中“Huge”这个四个字符在RAM和Flash中各自保存一份。
- RW为非0初始化的全局和静态变量占用的RAM大小.注意:同时还要占用等量的ROM大小用于存放这些非0变量的初值;
- ZI(zero initialize):初始化为0的内存区的大小(该区域3个用途:全局和静态变量初始化为0+堆区+栈区)。
打开keil自动生成的.map文件,将文件拉到最后,可以看到以下内容:
-
Flash的占用量就是上图中ROM Size的大小,它包含了Code+RO+RW的大小【ARM指令代码+只读数据+非0初始化变量的初值】
-
RAM的占用量包含上述RW+ZI的大小,也即【非0初始化变量、0初始化RAM(又分为0初始化静态变量区+堆区+栈区)】
3. Jflash读取固件大小
使用Jflash打开编译好的hex文件或者是bin文件,注意一下前四个字节:
20000000 + 17CA0 = 20017CA0(十六进制),仔细观察这个17CA0十六进制转换为十进制干好是:97440;即:97440 = RW Size,这就证明了RAM的大小确实=RW+ZI的大小。
hex或bin文件的前4个字节为主堆栈指针MSP的初值,在STM32的启动文件(.s汇编文件)中,一开始我们会看到 Stack_Size、Heap_Size 这两个汇编宏定义。
4.设置RAM
Stack指的是栈,栈是由堆栈指针MSP/PSP自动管理的,理论上初始化时给堆栈指针赋值为RAM的最高地址即可,但是用keil编译时,keil并不是按RAM的最高地址生成的HEX前4字节(也即MSP的初值),而是按照:全局和静态变量的容量+Heap_Size+Stack_Size三者之和,作为HEX文件的前4字节。
设置STM32L451芯片的RAM的总大小,是在keil的这个地方设的
其实讲道理,我觉得keil还是把这个值+RAM起始地址(0x2000000)作为MSP的初值更好,只不过keil不是这么做的,keil仅仅是把这个值用作编译检测:检查全局和局部静态变量(含0初始化和非0初始化两部分)所占的空间+堆区+栈区,它们所占空间之和是否超过了上图红框里的这个值,如果超了就编译报错。这就是上面红框里的值唯一的作用。
根据这段理论,我们也就知道了启动文件中Stack_Size该设为多少了,只要【全局变量+局部静态变量+Heap_Size+Stack_Size】的大小不超过芯片的RAM容量即可。
keil编译时,会把C库函数支持的malloc、free所需的内存指向heap内存区,并且当我们不断的malloc吃内存堆时,malloc函数会检测程序已吃掉的内存堆是否超过了Heap_Size,超了的话就会返回NULL。
keil是这样为【全局变量 + 局部静态变量 + Heap_Size + Stack_Size】分配内存的:
上面论述的是,使用C库函数提供的mallloc时,内存堆heap的使用情形,如果我们不打算使用C库提供的动态内存分配,而打算使用自己写的内存堆管理程序,甚至干脆不打算使用动态内配功能,这些情况下,请直接把Heap_Size设为0。
5.总结
最后总结一下Stack_Size的设置方法:
-
在keil中正确设置芯片的RAM大小,
-
确定堆区Heap_Size的大小,这个值可以通过调试自己估计出来,如果不使用C库的malloc的话,直接设为0,
-
把Stack_Size设的越大越好,只要编译不报错,就把Stack_Size往尽可能大了配,否则如上图所示的内存空闲区,在整个程序运行期间,将不被使用,纯属浪费,不如让其作为栈,以增强程序稳定性。
6.扩展
- 数组内存管理:自己写的动态内存管理程序,本质上就是申请一个大数组,自己管理这个数组而已,相当于自己写一套malloc/free函数,很多操作系统中有这样的例子,比如freeRtos、ucos等,这些操作系统都提供了好多种动态内存管理方法,最简单的一种,跟切火腿似的,malloc出来之后就释放不掉了,直到把这个大数组切完拉倒,看似很low的内存管理方法,实际上在很多小型项目上却用起来很方便。
更好的内存管理程序,那自然是支持动态切,还要支持把动态释放的空间合并起来,以便把刚才合并起来的空间再次malloc,这些更好的内存管理程序,用起来更方便,但是同时,这种功能强大的内存管理程序自身也会占掉很多RAM / ROM / CPU资源,矛盾利弊共存。到底要使用简单的内存管理还是高级的内存管理,要看项目需求,一般嵌入式操作系统会提供4种以上的内存管理程序供我们选用。
更多推荐



所有评论(0)