分散加载说明以GD32F103ZE为例,分别用Keil、IAR和Embedded Builder工具实现:将函数放置某个地址、将常量放置某个地址、将函数放在RAM中运行的三种效果。
1、将led_toggle()函数放在0x08040000地址后。
2、将tempbuf[1024]常量放在0x08020000地址后。
3、将void led_flow(void) 函数在RAM中运行,放在0x20008000地址后面。
1.Keil IDE example
1.1.将函数放置某个地址
生成.sct 文件
单击 MDK 的 Option -> linker 取消勾选“Use memory layout from target Dialog”。
单击“Scatter file”中的“Edit” ,keil 工程会出现“.sct”文件。

修改.sct 文件,将 512k flash 分成 LR_IROM1 和 LR_IROM2 两个加载区域,分别为 256K 的 flash。

将 void led_toggle(void)函数添加到 LR_IROM2 地址内。
led.o 表示 led.c 文件生成的.o 文件。led_toggle 表示所添加的函数。

void led_toggle(void)函数需要添加“attribute”,代码如下。
void led_toggle(void) attribute((section ("led_toggle")));其中“led_toggle”名称可以任意。

双击工程名“Tartget1” 生成.map 文件,查看是否加载成功。

查看.map 文件。led_toggle 函数 在地址 0x08040000 后。说明加载成功。

1.2.将常量放置某个地址
将 tempbuf[1024]放置到 0x08020000,添加如下代码。此时可以不用修改.sct 文件。const uint8_t tempbuf [1024] attribute((at(0x08020000))) = {0};

查看.map 文件。常量 tempbuf[1024]在地址 0x08020000 后。说明加载成功。

1.3.将函数放置 RAM 中运行
在 led.c 文件将 led_flow(void)申明,代码添加如下。
void led_flow(void) attribute((section ("led_flow")));

修改.sct 文件,将 mcu 的 64K RAM 分成 RW_IRAM1 和 RW_IRAM2 两个区,分别32K 大小 。在 LR_IROM2 增加 RW_IRAM2 执行区域和 led_flow 函数,如图。

查看.map 文件,led_flow 函数在地址 0x20008000 后。说明加载成功。

1.4.将程序中所有 const 快速放置在 data 区域
专门划分出一块区域 0x08040000-0x08080000 放置 const 数据

修改 sct 文件如下:

代码编译出来效果如下:

2.IAR IDE example
2.1.将函数放置某个地址
打开配置文件.icf
Option -> linker -> config 勾选“override default”。单击“Edit”进行修改。

修改 icf 文件,将 512K flash 分成 ROM 和 ROM1,各 256K 加载区,添加代码如下:
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF; define symbol __ICFEDIT_region_ROM1_start__ = 0x08040000; define symbol __ICFEDIT_region_ROM1_end__ = 0x0807FFFF; define region ROM1_region=mem:[from__ICFEDIT_region_ROM1_start__to __ICFEDIT_region_ROM1_end__]

修改 icf 文件,将 void led_toggle(void)函数放置在地址 0x08040000 后,添加代码如下。
place at address mem:0x08040000 { readonly section led_toggle };

在 led.c 文件中添加函数属性。添加代码如下。
void led_toggle(void)@ “led_toggle”其中“led_toggle”名称可以任意。

生成.map 文件,查看是否加载成功。在 IAR 中 Option -> linker -> List 勾选“generate linker map file”。

查看.map 文件。led_toggle 函数 在地址 0x08040000 后。说明加载成功。

2.2.将常量放置某个地址
将tempbuf[1024]放置到0x08020000,添加如下代码。此时可以不用修改.icf 文件。const uint8_t tempbuf [1024] attribute((at(0x08020000))) = {0};

查看.map 文件。函数 tempbuf 在地址 0x08020000 后。说明加载成功。

2.3.将函数放在 RAM 中运行
在 led.c 文件设置 led_flow 属性,添加代码如下。void led_flow(void) @"led_flow";

修改.sct 文件,将 MCU 的 64K RAM 分成 RAM 和 RW_IRAM1 两个 区,分别 32K 大小。

将函数从 flash copy 到 RAM 中,添加代码如下。
initialize by copy { readwrite,section led_flow };

将 void led_flow(void)函数放置地址 0x20008000 后,需要增加如下函数。如图。
place at address mem:0x20008000 { section led_flow };

查看.map 文件,函数 led_flow 在地址 0x20008000 后说明加载成功。

2.4. 将程序中的 const data 快速的放置到某个区域
相关语法如下:place at address mem:0x08040000 { section .rodata };

运行效果如下:

3. Embedded Builder IDE example
直接使用手动编写的 ld 文件,在 Embedded Builder 中的的“ Window->ShowView->Project
Explore->ldscripts” 中 双 击 gd32f10x_flash.ld 文件或者也可到工程目录
“GD32F4xx_ScatterLoading_v1.0.0_Eclipse\ldscripts\gd32f4xx_flash.ld”下打开编辑, 代码下图所示:

3.1.将函数放置某个地址
将 led_toggle()函数放置在 flash 的 0x08003400 位置

3.2.将常量放置某个地址
将常量数组放置在 flash 的 0x08003000 地址,

在 gd32f10x_flash.ld 中 添加如下语句

3.3.将函数放置 RAM 中运行
将函数 gd_eval_led_toggle 放在 SRAM 中运行,在 gd32f10x_flash.ld 添加如下代码
/* memory map */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K RAM1 (xrw) : ORIGIN = 0x20000400, LENGTH = 1K } ENTRY(Reset_Handler) SECTIONS { __stack_size = DEFINED(__stack_size) ? __stack_size : 2K; /* ISR vectors */ .vectors : { . = ALIGN(4); KEEP(*(.vectors)) . = ALIGN(4); __Vectors_End = .; __Vectors_Size = __Vectors_End - __gVectors; } >FLASH /* Load .sram1_text and gd32f4xx_it.o to RAM1 starting address */ _ram1_text = 0x08003500; .ram1_text : AT(_ram1_text) { . = ALIGN(4); _sram1_text = .; *(.sram1_text) *(.sram1_text*) *gd32f10x_it.o(.text .text.*) . = ALIGN(4); _erma1_text = .; } > RAM1
上述代码将.sram1_text 段和 gd32f10x_it.o 文件加载到 RAM1(0x20005000)起始地址处,在启动文件startup_gd32f10x_md.S 中加入如下汇编代码
CopyData3: ldr r3, =_ram1_text ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 b LoopCopyDataInit2 LoopCopyDataInit2: ldr r0, =_sram1_text ldr r3, =_erma1_text adds r2, r0, r1 cmp r2, r3 bcc CopyData3
上述汇编代码完成将.sram1_text 段和 gd32f10x_it.o 文件由 flash 搬运到指定的 ram 地址中。
在函数前加上attribute ((section(".sram1_text")))。
/*! \brief toggle selected led \param[in] lednum: specify the led to be toggled \arg LED2 \arg LED3 \arg LED4 \arg LED5 \param[out] none \retval none */ __attribute__ ((section(".sram1_text"))) void gd_eval_led_toggle(led_typedef_enum lednum) { gpio_bit_write(GPIO_PORT[lednum], GPIO_PIN[lednum], (bit_status)(1-gpio_input_bit_get(GPIO_PORT[lednum], GPIO_PIN[lednum]))); }
调试运行验证函数地址

-
单片机
+关注
关注
6035文章
44554浏览量
634689 -
嵌入式
+关注
关注
5082文章
19107浏览量
304833 -
IAR
+关注
关注
5文章
350浏览量
36665 -
开发板
+关注
关注
25文章
5033浏览量
97377 -
keil
+关注
关注
68文章
1212浏览量
166843
发布评论请先 登录
相关推荐
GD32 MCU 入门教程】GD32 MCU 常见外设介绍(12)FMC 模块介绍

GD32单片机利用分散加载避免前后Flash速度不一致
兆易创新GD32 MCU选型手册,适用于GD32全系列MCU
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(1)使用Keil开发GD32

【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(2)使用 IAR 开发 GD32

【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(3)使用 Embedded Builder 开发 GD32

【GD32 MCU 入门教程】二、GD32 MCU 烧录说明(1)ISP 烧录

【GD32 MCU 入门教程】二、GD32 MCU 烧录说明(3)脱机烧录

【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(14)RTC 模块介绍

【GD32 MCU入门教程】GD32 MCU GPIO 结构与使用注意事项

评论