用GCC编译STM32工程时,想和在MDK中修改scatter文件的方式一样将某些代码的变量分配到外部SRAM中,搜索了一些方法发现都是用加变量属性__attribute__((section(xxx)))的方式,感觉每个变量都要加太麻烦,而且一些使用的第三方库(比如FatFs)并不想修改,所以研究了一下怎么能直接把整个文件链接到指定的内存中去。
首先要先修改.ld文件,在MEMORY中加入外部SRAM,如下:
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
XRAM(xrw) : ORIGIN = 0x6C000000, LENGTH = 1024K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
}
之后在SECTION中加入外部SRAM使用的.data段和.bss段,分别放在原.data段和.bss段之后,其中aaa.o和bbb.o为工程某路径下名为aaa和bbb的目标文件,ccc/*.o为子目录ccc下的所有文件。在xram对应段中指定了目标文件后,为避免重复,需要在内部RAM的对应段中使用EXCLUDE_FILE排除这些文件。
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(EXCLUDE_FILE(*aaa.o *bbb.o *ccc/*.o) .data .data*)
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_sixdata = LOADADDR(.xdata);
/* XRAM data section
*/
.xdata :
{
. = ALIGN(4);
_sxdata = .; /* create a global symbol at xram data start */
*(.xdata)
*(.xdata*)
*aaa.o(.data .data*)
*bbb.o(.data .data*)
*ccc/*.o(.data .data*)
. = ALIGN(4);
_exdata = .; /* create a global symbol at xram data end */
} >XRAM AT> FLASH
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(EXCLUDE_FILE(*aaa.o *bbb.o *ccc/*.o) .bss .bss *)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* XRAM bss section
*/
.xbss :
{
. = ALIGN(4);
_sxbss = .; /* create a global symbol at xram bss start */
*(.xbss)
*(.xbss*)
*aaa.o(.bss.bss*)
*bbb.o(.bss.bss*)
*ccc/*.o(.bss.bss*)
. = ALIGN(4);
_exbss = .; /* create a global symbol at xram bss end */
} >XRAM
修改完.ld文件后,还有修改启动文件,加入.xdata和.xbss的初始化指令,保证分配到这些段的变量能被正确初始化,首先在文件开头引入刚刚定义的段地址
/* start address for the initialization values of the .xdata section.
defined in linker script */
.word _sixdata
/* start address for the .xdata section. defined in linker script */
.word _sxdata
/* end address for the .xdata section. defined in linker script */
.word _exdata
/* start address for the .xbss section. defined in linker script */
.word _sxbss
/* end address for the .xbss section. defined in linker script */
.word _exbss
之后在设置程序入口之前加入初始化代码
/* Copy the xdata segment initializers from flash to SRAM */
ldr r0, =_sxdata
ldr r1, =_exdata
ldr r2, =_sixdata
movs r3, #0
b LoopCopyXDataInit
CopyXDataInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyXDataInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyXDataInit
/* Zero fill the xbss segment. */
ldr r2, =_sxbss
ldr r4, =_exbss
movs r3, #0
b LoopFillZeroxbss
FillZeroxbss:
str r3, [r2]
adds r2, r2, #4
LoopFillZeroxbss:
cmp r2, r4
bcc FillZeroxbss
修改完成后编译就可以发现.map文件中对应的文件中的所有变量都已经被分配到了外部SRAM中了
参考资料:
Putting Code of Files into Special Section with the GNU Linker | MCU on Eclipse
链接脚本(Linker Scripts)语法和规则解析(自官方手册) - BSP-路人甲 - 博客园 (cnblogs.com)