stm32内存到底是如何分配的,基于.map文件分析
Posted ycpkbql
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stm32内存到底是如何分配的,基于.map文件分析相关的知识,希望对你有一定的参考价值。
一直以来本人对MCU的FLASH和SRAM(RAM存储器一种)是如何分配的只是知道个大概,而不尽祥。不是非常了解内存分配大多数时候对我们进行裸机程序编写是没有太大影响的。
但一旦上升到使用嵌入式操作系统,这个问题就难以回避,因为操作系统没有任何应用编译之后都要占用至少10几KB,这对RAM紧张的MCU来说是致命的,
我们要想尽办法来省RAM,而办法是基于你知道内存是怎么分配的。
ps:有些只有10KB RAM的单片机就不要打OS的主意了,还是老老实实的用时间片轮询吧,效率也是不错的。
以下偏重RAM的分析
一、已经了解的
如图是MDK编译之后的消息
从中知道
占用的FLASH = Code + RO-data + RW-data
stm32 FLASH的起始地址是0x08000000,当然也可以自定义起始地址,不过记得在main函数中定义变量后加一句SCB->VTOR=FLASH_BASE | OFFSET;OFFSET是想要偏移的量,可宏定义或直接0xXX。
当然也可以调用库函数 NVIC_SetVectorTable()进行偏移,效果一样。IAP升级这样用的多。
占用的SRAM = RW-data + ZI-data
stm32 SRAM的起始地址是0x20000000。看MDK的魔法棒设置target选项也是可以设置RAM起始地址和大小的,不过一般我不动RAM。
我一般是这样记忆的,前面3个是给FLASH,后面2个是给SRAM。
含义:
Code :代码
RO-data :只读数据,字符串常量(const修饰的)
RW-data:可读可写数据,已经初始化的全局变量 或者 static修饰的变量(不管局部变量还是全局变量,没有显示地初始化的话会初始化为0)
ZI-data :没有进行初始化的全局变量
二、基于.map文件的分析,我逐个试出来的结果如下,右边是.map文件的内容。
PAD是垫子、卫生巾的意思,占用两个字节,姑且理解为隔开各个段吧。
宏定义、结构体、联合体、枚举类型等都属于代码。RAM只存放变量。但FLASH不只是存放代码,还有变量。就是和RAM都有的交集。MDK生成的 RW-data (全局变量、static变量)
这么多的变量,他们是怎么排列在RAM中的呢,看上面.map文件中的地址就知道了。就是已初始化的变量在前面,然后跟着是未初始化的全局变量,然后是堆,最后是栈。
也就是说栈和堆的起始地址是不可控的,是根据我们程序的全局变量多少计算出来的,一句话,吃剩下的。
三、裁剪栈和堆的大小
1.当我们程序运行到一个函数中莫名其妙的就崩了,进入HardFault_Handler,数组也没有越界啊。
其中可能的一个原因就是局部变量过多,栈溢出,不够用了,需要我们Tailor(裁剪)一下RAM。ps:数组越界也属于栈溢出。在启动文件中进行裁剪。HardFault_Handler网上也有很多分析方法。
2.例如,如下启动文件我们可以吧Stack_Size从0x400(1KB)改到0x800(2KB)一般就不会出现崩溃了,如果还崩,那要找找其他原因(是不是函数使用了非法的指针(即非法地址,0xE0000000之类的MCU不认,不能访问的地址))等等。
3.当然有时候栈加上其他的,大小超过了RAM总大小,编译器就会提示不够,就要一点一点加着试。
这时大小超过了RAM总大小,也能从一定程度说明程序设计存在不合理,几乎用光了RAM。比如全局变量设置的过大,实际没用这么多,也设置这么多,一般多实际最大使用量加2个字节都没问题。大型的全局变量(即结构体全局变量、联合体全局变量)过多,重复繁杂,共用率不高。就要逐个文件删繁就简,砍掉能砍的全局变量,缩小能缩的结构体,字节对齐,各种看家本领使出来。砍到不能再砍只能考虑砍功能或者换芯片了。
四、以后再增加对FREERTOS的内存管理分析
。。。
以上是关于stm32内存到底是如何分配的,基于.map文件分析的主要内容,如果未能解决你的问题,请参考以下文章
通过map文件了解堆栈分配(STM32MDK5)--避免堆栈溢出