单片机学习小组
直播中

小香干

12年用户 517经验值
擅长:399938
私信 关注

如何利用STM32CubeIDE将变量定义到指定地址呢

怎样使用Keil去编写程序呢?

怎样使用STM32CubeIDE去编写程序呢?

回帖(1)

张波

2022-2-21 14:33:21
使用Keil

在使用Keil编写程序的时候我们可以很轻松的将变量定义到指定地址
uint8_t array[1024] __attribute__((at(0x20010000)));
使用STM32CubeIDE

由于编译器不同,STM32CubeIDE中是不支持 __attribute__((at()))这一属性的,所以需要另辟蹊径。在网上查找到的资料说可以使用__attribute__((section()))属性

//将array放到地址空间0x20010000中
uint8_t array[1024] __attribute__((section(".RAM_Array")));


配合修改链接文件stm32Fxxx_FLASH.ld

...
MEMORY
{
        CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
        RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
        RAM_Array_Addr    (xrw)    : ORIGIN = 0x20010000,   LENGTH = 1K
        FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 1024K
}
...
SECTIONS
{
...
...
.RAM_Array (NOLOAD):        //注意这里的 NOLOAD !
{
   . = ALIGN(4);
   *(.RAM_Array)        //这是与.c文件中声明变量时的段对应的符号
   . = ALIGN(4);
} >RAM_Array_Addr
...
...
}
这样做确实可以将array定义到内存地址0x20010000中去,但是需要注意一个问题,这个坑也是促使我第一次写博文的重要原因:

  说问题之前先普及一下知识点:
  我们的源码经过GCC编译器编译链接之后会生成一个 .elf 文件和一个 .bin 文件,二者都是二进制文件,但是 elf 文件包含符号表、汇编等信息,它的执行需要有操作系统支持,例如Linux,而bin 文件是elf 文件经过压缩,仅提取了其中的代码段 .text 和数据段.data 以及一些自定义的段(如 .RAM_Array)来做成的内存镜像,所以可以直接由机器运行,也就是我们要下载到STM32的FLASH中的东西。
  我们的源码编译后会默认的生成三个段 .text 代码段、.data数据段以及 .bss存放未初始化变量的段,还有一些自定义的段 .RAM_Array。这些段的地址等属性由MEMORY{...}中的内容控制。
  .text:代码段,存放代码
.data:数据段,存放已经初始化的变量
.bss:存放未初始化或初始化为零的变量,在编译时会直接清空这部分内存,以压缩输出文件
同时输出的bin 文件中只包含.text段和.data段以及自定义段。
我在自定义的段中定义了一个32M的大数组,放到了SDRAM中,但是未初始化,编译时内存炸了。千辛万苦找出原因发现是.bss段是在RAM中的,尝试将.bss段放到SDRAM中,但是SDRAM需要初始化,于是又失败了。所以大数组不能放到.bss段中,于是乎初始化为1,编译通过!赶紧下载试试,咦?怎么进度条一直不动呢?千辛万苦找出原因发现输出的bin文件直接 2.9G!?没错,你没看错,我也没打错,就是2.9个G!好家伙!玩呢!我一个32M的大数组愣是给我编译出了2.9G?于是乎又宣布失败。于是乎开始学习ld链接文件的语法,终于有心人天不负,让我发现了NOLOAD这个属性,就是在链接时告诉编译器,这个段我不要加载,你也别给我输出到bin文件中去了,我的小心脏受不了!,于是乎一个40KB的bin文件出来了,烧录,成功!好家伙!
举报

更多回帖

发帖
×
20
完善资料,
赚取积分