关于ARM Cortex-M0分散加载文件

1. 概念

分散加载文件是MDK用来将生成的可执行文件内存分散在ARM存储器上不同位置,达到充分利用存储器的功能。分散加载文件有以下两种用法:

1.1. 通用用法

通常情况下,如果不需要分散加载文件,或者是简单的分散加载,都可以在Keil的Linker中色选Use Memory Layout from Target Dialog,然后直接在Target界面进行配置。片内ROM可以设置两段代码。
关于ARM Cortex-M0分散加载文件_第1张图片

1.2. 复杂用法

有时候需要更详细的分散加载文件,如将指定文件存放在指定存储位置上。此时就需要使用分散加载文件(Scatter-Loading Description File),即后缀为.sct的文件。sct文件是BNF标记语法,功能非常强大,一般情况下,不需要对此进行深入了解,足够使用即可。sct的基本结构如下:关于ARM Cortex-M0分散加载文件_第2张图片

2. 示例

MDK链接器的一个重要作用是重定位代码和数据在内存中的地址。
如果选择使用Scatter File,则链接时,链接器会从sct文件中读取相关信息来进行代码和变量的内存位置重定位。嵌入式开发,非常注重削减成本,而SRAM是占成本的一个大头,所以IC设计时,SRAM是能省则省的。如64K的SRAM,32K用来存放代码,32K用来存放变量。如果我算法模块比较多,整个生成的BIN文件有40K,此时怎么办呢?
这里就需要用到分散加载文件中的一个重要属性——OVERLAP。它的作用是将几个不同模块的代码编译到一个相同的位置。那么有一个Main代码,几个Brance代码,需要哪个Brance代码的功能,将对应Branch代码加载到SRAM上即可。这样就可以在比较小的SRAM上,实际非常复杂的功能。

2.1. sct文件内容

以下内容来自M0内核的工程,Use *.o to match all object files. Use * to match all object files and libraries. 示例中主要将代码分模块,以及将模块指定到相同的位置。

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x20000000 0x00007000  {    ; load region size_region
  scan.bin 0x20000000 0x00007000  {  ; load address = execution address
   *.o (RESET, +First)				; *.o是指所有目标文件,RESET复位放在最前面+First指定此区域首先加载,
   *(InRoot$$Sections)				; 系统默认的
   .ANY (+RO)						; 包括其他目标文件、库文件。.ANY作用与*类似,但是*的优先级比.ANY高。
  }
  RW_IRAM1 0x20008000 UNINIT 0x00007000  {  ; RW data
   .ANY (+RW +ZI)							; .ANY指所有目标文件、库文件。+RW +ZI为指定的section attribute。
  }
}
; 以上加载域是Keil生成的,可以作为主加载域

LR_IROM2 0x20007000 OVERLAY 0x00001000  ; 第二个加载域,指定开始开始和大小, OVERLAY指定这个域可以和其他加载域重叠,让链接器不要报错误
{    ; load region size_region
  eeprom.bin 0x20007000 OVERLAY 0x00001000 ; eeprom.bin是指定此执行域的名字,名字最长不能超过31个字符
  {  ; load address = execution address
   EEpRom.o (+RO)						   ; 指定此执行域包括的目标文件 指定+RO属性存放此处,RO即表示代码。
   SANDISK.o (*)						   ; 指定SANDISK.o此目标文件中所有代码变量均存放此执行域
  }
}

LR_IROM3 0x20007000 OVERLAY 0x0000500 
{    ; load region size_region
  Hynix.bin 0x20007000 OVERLAY 0x0000500 
  {  ; load address = execution address
   Hynix.o (+RO+RW)						; 指定此执行域包括的目标文件 指定+RO +RW属性存放此处,因为RO RW都需要存放在ROM中。
  }
   RW_IRAM3 0x20007500 UNINIT 0x00000500  {  ; RW data
   Hynix.o (+ZI)							 ; 将ZI变量单独存放,可以减少代码空间浪费
  }
}

2.2. 生成Bin文件

  • sct文件中有3个加载域,对应3个执行域名,编译链接后生成scan.afx文件
  • axf文件相当于所有.o的汇总,.axf文件包括调试信息,所以比较大。
  • 在User的Run User Program After Build/Rebuild中配置如下命令:

fromelf.exe “.\Obj\scan.axf” --bin --output “.\out”

  • –output=destination
    This option specifies the name of the output file, or the
    name of the output directory if multiple output files are created.
  • Usage with --bin:
    You can specify a single input file and a single output filename.
    If you specify many input filenames and specify an output directory, then the output
    from processing each file is written into the output directory. Each output filename is derived from the corresponding input file. Therefore,specifying an output directory in this way is the only method of converting many ELF files to a binary or hexadecimal format in a single run of fromelf.
    If you specify a pattern in parentheses to select a subset of objects from an archive, fromelf only converts the subset. All the other objects are passed through to the output archive unchanged.
  • 如果设置了多个加载区域,则–output后面的会被认为是目录名,生成的文件名主要来自于.sct文件中每个加载区域中ROM的描述名。
  • 如果只有一个加载区域,则–output后面的会被认为是文件名。

2.3. 测试结果

生成的.map文件
关于ARM Cortex-M0分散加载文件_第3张图片

U32 uTest = 0x12345678;
U32 uTest2[128] = 0;
  • 这两个变量是hynix.c中的全局变量,前者属于RW类型,后者属于ZI类型,分别生成进入对应的执行域,符合预期。
  • Ov表示OVERLAY的属性,有*的符号就表示是重叠的。
  • HAL_IIC_Start和HY_CfgEnhanceMode分别属于不同的目标文件,以这两个接口进行测试。
  • 将生成的eeprom.bin加载进入RAM,触发HY_CfgEnhanceMode函数,串口打印信息如下:
    [2020-05-19 11:17:45.646]# RECV ASCII>
    HY_CfgEnhanceMode:20007001
  • 将生成的hynix.bin加载进入RAM,触发HAL_IIC_Start函数,串口打印信息如下:
    [2020-05-19 11:17:53.577]# RECV ASCII>
    HAL_IIC_Start:2000701
  • 通过串口打印的函数名及地址可以看出,确实是重叠地,并且调用也正常。

你可能感兴趣的:(存储,嵌入式,keil,mdk)