STM32CUBEIDE 如何将变量定义到指定内存地址

使用场景如下:
我需要将bootloader/APP的版本号和一些字段信息定义到指定FLASH地址.

在STM32CubeIDE中的方法:
截止当前STM32CubeIDE还没有提供图形化的针对FLASH划分定义的支持选项, 所以第一步我们需要手动更改 .ld文件 (链接文件).

原文件如下(部分):

/* Memories definition */
MEMORY
{
  CCMRAM (xrw)	: ORIGIN = 0x10000000,	LENGTH = 64K
  RAM	 (xrw)	: ORIGIN = 0x20000000,	LENGTH = 128K
  FLASH	 (rx)	: ORIGIN = 0x8000000,	LENGTH = 64K
}

修改后:

/* Memories definition */
MEMORY
{
  CCMRAM (xrw)	     : ORIGIN = 0x10000000,	LENGTH = 64K  
  RAM   (xrw)	     : ORIGIN = 0x20000000,	LENGTH = 128K 
  FLASH	(rx)	     : ORIGIN = 0x8000000,	LENGTH = 8K    
  VERSION_FLASH (rx) : ORIGIN = 0x8002000,	LENGTH = 1K   
  REMFLASH (rx)      : ORIGIN = 0x8002400,	LENGTH = 55K   
}
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data into "FLASH" Rom type memory */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } > REMFLASH

  .version_code :
  {
    *(.bl_info.ver)
    *(.bl_info.date)
    *(.bl_info.detailed);
  } > VERSION_FLASH
....略

我们重点看一下修改后的FLASH内存结构.
这里将FLASH的前8K预留出来, 用于存放中断向量表这是硬规! 所以我们不能划分FLASH的起始区域自用.
仅中断向量表是用不完8K的,因为后面还有一些其它项的分配如 .ARM.extab, .ARM 所以这里简单预留为8K.
后面的 VERSION_FLASH 用于存储我们的自定义字段. 这里划分为1K.
REMFLASH 用于存放程序代码.

具体变量定义使用如下

volatile const char __RO_BL_INFO_VERSION__[] __attribute__((section(".bl_info.ver"))) = {"XXXX_V1.0"};
volatile const char __RO_BL_INFO_DATE__[]    __attribute__((section(".bl_info.date"))) = { __DATE__ };
volatile const char __RO_BL_INFO_DETAIL__[]  __attribute__((section(".bl_info.detailed"))) = { "Hello world !" };

定义好之后, 可以通过 .map 文件查看变量具体的存储地址.

如上操作后, 正常情况下 .map 中并不会有你想要的变量. 原因是编译器给优化了.
我尝试使用了很多别的办法, 但是最终只有如下方法可行.

if (__RO_BL_INFO_VERSION__[0] == 'A' && __RO_BL_INFO_VERSION__[2] == 'A'
    &&  __RO_BL_INFO_DATE__[1] == 'A') {
    while (1);
}

如有其它更好的方法, 预防编译器优化. 请留言. 

下面是一个重要提示:
切忌不要将上文中的 VERSION_FLASH 分配到FLASH的最后. 例如:

/* Memories definition */
MEMORY
{
  CCMRAM (xrw)	     : ORIGIN = 0x10000000,	LENGTH = 64K
  RAM    (xrw)	     : ORIGIN = 0x20000000,	LENGTH = 128K
  
  FLASH	 (rx)	     : ORIGIN = 0x8000000,	LENGTH = 8K
  REMFLASH (rx)      : ORIGIN = 0x8002000,	LENGTH = 32K
  VERSION_FLASH (rx) : ORIGIN = 0x800A000,	LENGTH = 1K
}

原因是我们并不清楚(或者非常麻烦)程序到底需要占用多大的FLASH空间. 如果 REMFLASH 定义的非常大, 则最终生成的 bin 文件将非常大(中间会有空填充),
如上的具体大小为 8+32 = 40K, 而实际的有效程序可能只有18K大小(HEX无影响). 该bin文件的大小计算仅仅适用于STM32CubeIDE, 在一些其它的IDE可能会是
40K大小. 但不管计算方法如何, 最终都会造成bin体积的增大. 如果该bin用于APP程序的升级将造成很大的时间浪费.

posted @ 2020-11-10 19:22  svchao  阅读(3883)  评论(0编辑  收藏  举报