【GD32 MCU入门教程】 七、分散加载说明

[复制链接]
3750|6
 楼主| 聚沃科技 发表于 2024-8-28 09:37 | 显示全部楼层 |阅读模式
本帖最后由 聚沃科技 于 2024-9-18 17:36 编辑

分散加载说明以GD32F103ZE为例,分别用Keil、IAR和Embedded Builder工具实现:将函数放置某个地址、将常量放置某个地址、将函数放在RAM中运行的三种效果。
1、将led_toggle()函数放在0x08040000地址后。
2、将tempbuf[1024]常量放在0x08020000地址后。
3、将void led_flow(void) 函数在RAM中运行,放在0x20008000地址后面。
1.Keil IDE example1.1.将函数放置某个地址
生成.sct 文件
单击 MDK 的 Option -> linker 取消勾选“Use memory layout from target Dialog”。
单击“Scatter file”中的“Edit” ,keil 工程会出现“.sct”文件。
1.png
修改.sct 文件,将 512k flash 分成 LR_IROM1 和 LR_IROM2 两个加载区域,分别为 256K 的 flash。
2.png
将 void led_toggle(void)函数添加到 LR_IROM2 地址内。
led.o 表示 led.c 文件生成的.o 文件。led_toggle 表示所添加的函数。
3.png
void led_toggle(void)函数需要添加“attribute”,代码如下。
void led_toggle(void) attribute((section ("led_toggle")));其中“led_toggle”名称可以任意。
4.png
双击工程名“Tartget1” 生成.map 文件,查看是否加载成功。
5.png
查看.map 文件。led_toggle 函数 在地址 0x08040000 后。说明加载成功。
6.png
1.2.将常量放置某个地址
将 tempbuf[1024]放置到 0x08020000,添加如下代码。此时可以不用修改.sct 文件。const uint8_t tempbuf [1024] attribute((at(0x08020000))) = {0};
7.png
查看.map 文件。常量 tempbuf[1024]在地址 0x08020000 后。说明加载成功。
8.png
1.3.将函数放置 RAM 中运行
在 led.c 文件将 led_flow(void)申明,代码添加如下。
void led_flow(void) attribute((section ("led_flow")));
9.png
修改.sct 文件,将 mcu 的 64K RAM 分成 RW_IRAM1 和 RW_IRAM2 两个区,分别32K 大小 。在 LR_IROM2 增加 RW_IRAM2 执行区域和 led_flow 函数,如图。
10.png
查看.map 文件,led_flow 函数在地址 0x20008000 后。说明加载成功。
11.png
1.4.将程序中所有 const 快速放置在 data 区域
专门划分出一块区域 0x08040000-0x08080000 放置 const 数据
12.png
修改 sct 文件如下:
13.png
代码编译出来效果如下:
14.png
2.IAR IDE example2.1.将函数放置某个地址
打开配置文件.icf
Option -> linker -> config 勾选“override default”。单击“Edit”进行修改。
1.png
修改 icf 文件,将 512K flash 分成 ROM 和 ROM1,各 256K 加载区,添加代码如下:
  1. define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
  2. define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
  3. define symbol __ICFEDIT_region_ROM1_start__ = 0x08040000;
  4. define symbol __ICFEDIT_region_ROM1_end__ = 0x0807FFFF;
  5. define region ROM1_region=mem:[from__ICFEDIT_region_ROM1_start__to
  6. __ICFEDIT_region_ROM1_end__]

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

3.png
在 led.c 文件中添加函数属性。添加代码如下。
void led_toggle(void)@ “led_toggle”其中“led_toggle”名称可以任意。
4.png
生成.map 文件,查看是否加载成功。在 IAR 中 Option -> linker -> List 勾选“generate linker map file”。
5.png
查看.map 文件。led_toggle 函数 在地址 0x08040000 后。说明加载成功。
6.png
2.2.将常量放置某个地址
将tempbuf[1024]放置到0x08020000,添加如下代码。此时可以不用修改.icf 文件。const uint8_t tempbuf [1024] attribute((at(0x08020000))) = {0};
7.png
查看.map 文件。函数 tempbuf 在地址 0x08020000 后。说明加载成功。
8.png
2.3.将函数放在 RAM 中运行
在 led.c 文件设置 led_flow 属性,添加代码如下。void led_flow(void) @"led_flow";
9.png
修改.sct 文件,将 MCU 的 64K RAM 分成 RAM 和 RW_IRAM1 两个 区,分别 32K 大小。
10.png
将函数从 flash copy 到 RAM 中,添加代码如下。
initialize by copy { readwrite,section led_flow };
11.png
将 void led_flow(void)函数放置地址 0x20008000 后,需要增加如下函数。如图。
  1. place at address mem:0x20008000 { section led_flow };

12.png
查看.map 文件,函数 led_flow 在地址 0x20008000 后说明加载成功。
13.png
2.4. 将程序中的 const data 快速的放置到某个区域
相关语法如下:place at address mem:0x08040000 { section .rodata };
14.png
运行效果如下:
15.png
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”下打开编辑, 代码下图所示:
1.png
3.1.将函数放置某个地址
将 led_toggle()函数放置在 flash 的 0x08003400 位置
2.png
3.2.将常量放置某个地址
将常量数组放置在 flash 的 0x08003000 地址,
3.png
在 gd32f10x_flash.ld 中 添加如下语句
4.png
3.3.将函数放置 RAM 中运行
将函数 gd_eval_led_toggle 放在 SRAM 中运行,在 gd32f10x_flash.ld 添加如下代码
  1. /* memory map */
  2. MEMORY
  3. {
  4. FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
  5. RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
  6. RAM1 (xrw) : ORIGIN = 0x20000400, LENGTH = 1K
  7. }
  8. ENTRY(Reset_Handler)
  9. SECTIONS
  10. {
  11. __stack_size = DEFINED(__stack_size) ? __stack_size : 2K;

  12. /* ISR vectors */
  13. .vectors :
  14. {
  15. . = ALIGN(4);
  16. KEEP(*(.vectors))
  17. . = ALIGN(4);
  18. __Vectors_End = .;
  19. __Vectors_Size = __Vectors_End - __gVectors;
  20. } >FLASH

  21. /* Load .sram1_text and gd32f4xx_it.o to RAM1 starting address */
  22. _ram1_text = 0x08003500;
  23. .ram1_text : AT(_ram1_text)
  24. {
  25. . = ALIGN(4);
  26. _sram1_text = .;
  27. *(.sram1_text)
  28. *(.sram1_text*)
  29. *gd32f10x_it.o(.text .text.*)
  30. . = ALIGN(4);
  31. _erma1_text = .;
  32. } > RAM1

上述代码将.sram1_text 段和 gd32f10x_it.o 文件加载到 RAM1(0x20005000)起始地址处,在启动文件startup_gd32f10x_md.S 中加入如下汇编代码
  1. CopyData3:
  2. ldr r3, =_ram1_text
  3. ldr r3, [r3, r1]
  4. str r3, [r0, r1]
  5. adds r1, r1, #4
  6. b LoopCopyDataInit2
  7. LoopCopyDataInit2:
  8. ldr r0, =_sram1_text
  9. ldr r3, =_erma1_text
  10. adds r2, r0, r1
  11. cmp r2, r3
  12. bcc CopyData3

上述汇编代码完成将.sram1_text 段和 gd32f10x_it.o 文件由 flash 搬运到指定的 ram 地址中。
在函数前加上attribute ((section(".sram1_text")))。
  1. /*!
  2. \brief toggle selected led
  3. \param[in] lednum: specify the led to be toggled
  4. \arg LED2
  5. \arg LED3
  6. \arg LED4
  7. \arg LED5
  8. \param[out] none
  9. \retval none
  10. */
  11. __attribute__ ((section(".sram1_text")))
  12. void gd_eval_led_toggle(led_typedef_enum lednum)
  13. {
  14. gpio_bit_write(GPIO_PORT[lednum], GPIO_PIN[lednum],
  15. (bit_status)(1-gpio_input_bit_get(GPIO_PORT[lednum], GPIO_PIN[lednum])));
  16. }

调试运行验证函数地址
5.png


教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462


4.png
tpgf 发表于 2024-9-2 15:23 | 显示全部楼层
分散加载主要用于嵌入式系统开发,特别是涉及复杂内存映射和多种类型内存设备的场合
wakayi 发表于 2024-9-7 07:59 | 显示全部楼层
分散加载是一项强大的技术,允许开发者精确控制程序代码和数据的内存布局,从而满足嵌入式系统中复杂的内存管理和性能优化需求
renzheshengui 发表于 2024-9-8 08:24 | 显示全部楼层
分散加载脚本使用一种特殊的脚本语言,有自己的语法规则
paotangsan 发表于 2024-9-9 15:03 | 显示全部楼层
在不使用自定义分散加载文件时,Keil MDK工程的默认程序布局可能不满足特定需求
heimaojingzhang 发表于 2024-9-11 17:11 | 显示全部楼层
在一个MCU的Flash里同时摆放引导程序和用户程序,需要调整分散加载文件以实现同一Flash中放置两个不同程序
keaibukelian 发表于 2024-9-12 13:41 | 显示全部楼层
如果要把外扩的存储用于运行代码或扩展RW数据段等用途,需要分散加载配合
您需要登录后才可以回帖 登录 | 注册

本版积分规则

170

主题

190

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部