在编译固件的时候,如何将函数或者数据编译到指定位置?

发布于:2024-06-28 ⋅ 阅读:(15) ⋅ 点赞:(0)

在设计微控制器的程序时,有时候希望将一部分函数或者数据放在指定的区域,而不是由编译器自动处理。比如有些STM32包含多个SRAM,这时希望一部分数据放置在RAM2中,而其它的数据存放在RAM1中。或者具有CCM RAM的STM32,为了提高代码的运行速度,想要将代码放在CCM RAM中,而不是Flash中。像这些情况要怎么做呢?

这里以Keil IDE为例,使用STM32L431系列芯片。该系列芯片包含64KB的SRAM,这个SRAM是由48KB的SRAM1和16KB的SRAM2组成。

在这里插入图片描述

其中的SRAM2有一些新的特性,比如SRAM2在待机模式(standby)能够保持数据。这样的话,当STM32从待机模式唤醒的时候,SRAM2的数据不会丢失。

下面介绍3种方法,将指定数据保存到SRAM2中。

方法一 使用KEIL源文件属性

首先在建立的STM32L431的工程文件中,在工程的options->target里,其定义了2个IRAM区域,分别对应的是SRAM1和SRAM2。(注意,SRAM2的起始地址是0x10000000,但是STM32也将其映射到了0x2000C000地址上了,因此这两个地址都可以访问SRAM2)

在这里插入图片描述

当我们想将某个源文件里的所有数据都放到IRAM2里时,比如创建一个test.c源文件,在里面创建2个数组,如下图所示。

在这里插入图片描述

在源文件上右键选择”options for File xxx”,设置test.c的属性。

在这里插入图片描述

然后在Memory Assignment中将”Zero Initialized Data”和”Other Data”选择到IRAM2中。这两项对应的是ZI和RW数据,即初始化为0和初始化不为0的全局变量。

在这里插入图片描述

此时再编译的时候,就会发现该文件中的所有全局变量都被放置在IRAM2的区域中了。如下面2图所示,在上面的图中,数组a和b都在IRAM1中,而通过设置后,下面图中数组a和b都在IRAM2中。

在这里插入图片描述
在这里插入图片描述

方法二 使用编译器的属性 attribute((at()))

使用编译器的属性 __attribute__((at())) 也同样可以实现将函数或者数据存放在指定位置。

将test.c进行如下改写:

在这里插入图片描述

编译之后,可以看到数组a和b也放入到了地址0x10000000。

在这里插入图片描述

方法三 修改分散表(scatter file),使用属性 attribute((section(“”)))

这个方法比较复杂,但是使用起来更加灵活,需要单独的一篇文章进行。在这里先简要的介绍一下。
首先使用属性__attribute__((section(""))) 修饰数据或者函数,如下面的例子:

在这里插入图片描述

然后在scatter file中放置一个命名的区域,如上例中section的名字是foo,那么在scatter file中也要有名字是foo的section。修改方法如下:

  1. 在工程的options->Linker里去掉勾选”Use Memory Layout from Target”,然后点击”Edit”按键;

在这里插入图片描述

  1. 在弹出的文件”xxx.sct”中,按照如下进行修改,这句的意思是将任意输入文件里的foo section的内容放到IRAM2区域中。

在这里插入图片描述

经过如上修改后,重新编译能够看到变量a也被编译到0x10000000地址了。

在这里插入图片描述

在这里插入图片描述