FLASH
1.FLASH主要是存放代码和只读数据的,细分图如下:
如上图所示,Flash又可以细分为文本段、只读数据段、数据复制段。其中文本段包含代码和代码中的常量部分,只读数据区通常存放程序中以const关键字修饰的数据,数据复制段存放的则是程序中初始化不为0的全局变量的数据,在每次单片机复位后要对这些变量重新赋值。
RAM
RAM主要用来存储数据,如下是STM32的RAM分区:
data段:存放初始化非0的全局变量;
bss段:存放未初始化或初始化为0的全局变量;
Heap(堆)段:由程序员通过malloc/free申请和释放;
Stack(栈)段:存放局部变量和函数的入口地址;
其中栈的方向是由栈顶自上而下的,堆的方向则是自下而上的,如果RAM空间有限而且一个程序中局部变量较多或申请的堆空间过大,便会造成堆和栈冲突,并造成系统崩溃(堆栈溢出)。
栈,也叫堆栈,是一种先进后出,插入和删除操作都在栈顶操作的线性表。栈的作用通常是保存函数返回地址及保存局部变量。每个函数在运行时都有自己的栈空间,局部变量越多,占空间占用越大,函数间调用越深,栈空间也越大。CPU将打断前的程序运行到的地址、寄存器的值保存到栈中,即保护现场;当打断执行完以后,又从栈中读取之前保存的值,即恢复现场。
map文件
Code:代码,也就是编译之后产生的机器指令。
RO_data:Read Only data,只读数据域,指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能修改其内容。C语言中const关键字定义的变量就是典型的RO-data。这部分在程序运行过程中不能被更改,因此在运行时只需要来读取即可,无需占用 RAM 空间。
RW_data:Read Write data,可读写数据域,指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。C语言中定义的全局变量,且定义时赋予“非0值”给该变量进行初始化。
ZI_data:Zero Initialie data,即0初始化数据,它指初始化为“0值”的可读写数据域。它与RW-data的区别是程序刚运行时这些数据初始值全都为 0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。例如C语言中使用定义的全局变量,且定义时赋予“ 0 值”给该变量进行初始化(若定义该变量时没有赋予初始值,编译器会把它当ZI-data来对待,初始化为 0);
想要让一个程序正常运行。
芯片的 Flash 大小 要大于 Code + RO-data + RW-data 的大小;
芯片的 RAM 大小 要大于 RW-data + ZI_data 的大小
stm32xxxxx_flash.icf文件
定义FLASH分区的文件为stm32l476xxx_flash.icf
每个芯片开发商都会针对每款芯片来编写一个.icf文件就是传说中的链接文件。对于基本的应用,这个.icf文件足以满足你的工程需要。但有时也会需要改动,比如当你的项目要添加外部RAM时就要修改一下icf。
1、Icf到底干了啥呢?
- 定义了芯片存储空间的大小。
- 定义ROM的大小和起始、结束地址。
- 定义RAM的大小和起始、结束地址。
当然这些都是最基本的,你也可以设置以下的东西来匹配你的具体项目。
- 链接时是否保存位块与符号
- 设置你的启动过程
- 设置你的堆与栈的大小和对齐方式
- 修改编译器默认的初始化过程。
- 关于默认库的处理等。。。
2、下面我简单介绍几个功能,详细请参考 EWARM_DevelopmentGuide
2.1 添加额外的region
比如我要添加另一个名为ROM2的ROM区域,大小是256bytes,起始地址是0x80000.
define region ROM = Mem:[from 0x80000 size 0x100];
2.2 教你怎样放置SECTION
如果你要把你的只读常量放置在你指定的域而不是编译器默认的位置,你就得按如下操作了:
define region CONST_region = Mem:[from 0x100 size 0x100];
place in CONST_region{readonly section .rodata}
2.3 把一个段放置在指定位置
place at address Mem:[0] {readonly section .intvec} //--将向量表放置在地址0处。
Note:之前在看启动代码时,老在想这个向量表示怎么放到地址0处的呢,查了一下reference
__vector_table是编译器专有字符,表示出处开始放置向量表。
在代码开始处就声明了此段为.intvec。链接的时候在依据icf把它放到地址0处。
2.4 将需要从RAM中运行的代码搬到RAM中
Initialize by copy {section .textrw}
二、下面是我对generic_cortex.icf的注解
三、总结
在分配ROM空间时要尽量保持代码空间和备份升级的代码空间对称相等,这样可以避免因程序修改导致的升级失败现象。(代码超出空间直接编译失败)
要有建立flash空间分配文件的良好习惯。