找回密码
立即注册
搜索
发回帖 发新帖

5851

积分

0

好友

804

主题
发表于 1 小时前 | 查看: 3| 回复: 0

在嵌入式系统应用中,有时需要将常量或者函数放在代码闪存(Code Flash)的指定地址,以便后续的功能扩展或代码更新。

本文基于 EK-RA4M2,详细介绍如何在不同编译器环境下实现这一目标,涵盖 GNU、LLVM、IAR 和 Arm Compiler 6 共四种编译器。

由于瑞萨电子 RA 系列开发基于 FSP(Flexible Software Package),因此项目构建均基于 FSP 生成的代码。对于 IAR EW for Arm、Keil MDK 这类第三方集成开发环境(IDE),则需要依赖 RASC(RA Smart Configurator)创建项目。

对于所有支持的编译器来说,修改流程基本一致,核心步骤如下:

  1. 在 链接脚本文件(Linker Script File)中添加新的自定义段(section),并指定地址范围(通常包括起始地址和大小)。由于 FSP 工程会在每次重新 Generate Project Content 时重写相关的 Linker Script File,因此需要先备份原始文件,重命名后再进行修改。
  2. 使用特定关键字声明需要定位的函数或常量,将其放入新增 section 中。
  3. 在 IDE 中修改配置,使更新后的 Linker Script File 生效。
  4. 编译工程,通过生成的 *.map 文件确认相应标号已正确放置在目标地址。

假定目标是在 RA4M2 Code Flash 最高地址处新增两个 section:一个用于存放函数,另一个用于存放常量。由于高地址的 Block Size 为 32K(0x8000),因此两个 section 大小均设定为 0x8000。

实际使用时可以根据自己的需求调整大小,但一定要考虑改写内容时,最小的 Erase/Program 单元都是 Block Size。

一、GNU 编译器

首先介绍在 e²studio 中使用 GNU 编译器时的操作步骤。

在 e²studio 中找到以下 3 个文件,在原始路径下复制并重命名:

  • script\fsp.ld → script\fsp_new.ld
  • Debug\memory_regions.ld → Debug\memory_regions_new.ld
  • Debug\fsp_gen.ld → Debug\fsp_gen_new.ld

第一步,编辑 Debug\memory_regions_new.ld,在文件开头增加以下内容,对标号赋值:

FLASH_USER_DATA_LENGTH = 0x8000;
FLASH_USER_TEXT_LENGTH = 0x8000;

由于已经指定 2 个 Block 存储数据,用于其它内容链接的地址空间需要在此基础上去掉这 2 个 Block,因此更新 FLASH_LENGTH,并增加存放函数的 TEXT section 和存放常量的 DATA section:

FLASH_LENGTH = 0x00080000 - FLASH_USER_DATA_LENGTH - FLASH_USER_TEXT_LENGTH;
FLASH_USER_DATA_START = FLASH_START + FLASH_LENGTH;
FLASH_USER_TEXT_START = FLASH_USER_DATA_START + FLASH_USER_DATA_LENGTH;

memory_regions_new.ld 文件的变动参考下图:

GNU memory_regions_new.ld 自定义Flash段与FLASH_LENGTH修改对比

第二步,修改 fsp_gen_new.ld 文件,在 MEMORY 中增加 FLASH_USER_DATA 和 FLASH_USER_TEXT;找到 __flash_readonly$$(READONLY)(注意:此处是两个下划线),在其后增加 .mydata 和 .mytext。

MEMORY
{
    RAM (rwx) : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
    FLASH (rx) : ORIGIN = FLASH_START, LENGTH = FLASH_LENGTH
    FLASH_USER_DATA (rx) : ORIGIN = FLASH_USER_DATA_START, LENGTH = FLASH_USER_DATA_LENGTH
    FLASH_USER_TEXT (rx) : ORIGIN = FLASH_USER_TEXT_START, LENGTH = FLASH_USER_TEXT_LENGTH
    DATA_FLASH (rx) : ORIGIN = DATA_FLASH_START, LENGTH = DATA_FLASH_LENGTH
    QSPI_FLASH (rx) : ORIGIN = QSPI_FLASH_START, LENGTH = QSPI_FLASH_LENGTH

    .mydata :
    {
        *(.rodata*)
    }> FLASH_USER_DATA

    .mytext :
    {
        *(.text*)
    }> FLASH_USER_TEXT
}

fsp_gen_new.ld 文件的变动参考下图:

GNU fsp_gen_new.ld 新增FLASH_USER_DATA/TEXT与mydata/mytext段

第三步,修改源码,将 const 类型变量和函数声明放在新增的 .mydata 和 .mytext 两个 section 中,同时增加函数定义。在 hal_entry() 中增加函数调用,避免被优化:

const uint8_t test_data[8] BSP_PLACE_IN_SECTION(".mydata") = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};

uint32_t test_function_fibonacci(uint32_t num) BSP_PLACE_IN_SECTION(".mytext") __attribute__((noinline));

GNU 源码中使用BSP_PLACE_IN_SECTION将数据和函数放入自定义段

第四步,按照以下方式更新 fsp_new.ld 文件,使改动后的 Linker Script File(memory_regions_new.ld 和 fsp_gen_new.ld)生效:

GNU fsp_new.ld 引用修改后的memory_regions_new.ld与fsp_gen_new.ld

最后一步,在 e²studio 中将 Linker Script File 设置为 fsp_new.ld:

e²studio 项目属性中设置链接脚本为fsp_new.ld

完成上述所有步骤后编译工程,目标函数和常量就已经放在指定地址了。打开 *.map 文件,用常量和函数名作为关键字搜索,可以看到以下匹配:

GNU map文件中test_data位于0x00070000、test_function_fibonacci位于0x00078000

二、LLVM 编译器

接下来介绍在 e²studio 中使用 LLVM 编译器时的操作步骤。

在 e²studio 中找到 3 个文件,在原始路径下复制并重命名:

  • script\fsp.lld → script\fsp_new.lld
  • Debug\memory_regions.lld → Debug\memory_regions_new.lld
  • Debug\fsp_gen.lld → Debug\fsp_gen_new.lld

第一步,编辑 Debug\memory_regions_new.lld,文件变动参考下图:

LLVM memory_regions_new.lld 自定义Flash段与FLASH_LENGTH修改对比

第二步,修改 fsp_gen_new.lld 文件,参考下图:

LLVM fsp_gen_new.lld 新增FLASH_USER_DATA/TEXT与mydata/mytext段

第三步,修改源码,将 const 类型变量和函数声明放在新增的 .mydata 和 .mytext 两个 section 中,同时增加函数定义。在 hal_entry() 中增加函数调用,避免被优化:

const uint8_t test_data_0[8] BSP_PLACE_IN_SECTION(".mydata") = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};

const uint8_t test_data_1[8] BSP_PLACE_IN_SECTION(".mydata") = {
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};

uint32_t test_function_fibonacci(uint32_t num) BSP_PLACE_IN_SECTION(".mytext") __attribute__((noinline));
int test_function_is_prime(int num) BSP_PLACE_IN_SECTION(".mytext") __attribute__((noinline));

LLVM 源码中使用BSP_PLACE_IN_SECTION将数据和函数放入自定义段

第四步,按照以下方式更新 fsp_new.lld 文件,使改动后的 Linker Script File(memory_regions_new.lld 和 fsp_gen_new.lld)生效:

LLVM fsp_new.lld 引用修改后的memory_regions_new.lld与fsp_gen_new.lld

最后一步,在 e²studio 中将 Linker Script File 设置为 fsp_new.lld:

e²studio 项目属性中设置链接脚本为fsp_new.lld

编译工程后,打开 *.map 文件,用常量和函数名作为关键字搜索,可以看到以下匹配:

LLVM map文件中test_data_0/test_data_1与斐波那契函数、素数函数地址

三、IAR 编译器

前面介绍的是在瑞萨 e²studio 中使用 GNU 和 LLVM 的配置步骤。对于 IAR 和 Keil MDK 这类第三方 IDE,可以利用 RASC(Renesas RA Smart Configurator)创建相应工程后再修改。

对于 IAR Project,在 workspace 路径下找到 3 个文件,在原始路径下复制并重命名:

  • script\fsp.icf → script\fsp_new.icf
  • memory_regions.icf → memory_regions_new.icf
  • fsp_gen.icf → fsp_gen_new.icf

第一步,编辑 memory_regions_new.icf,文件变动参考下图:

IAR memory_regions_new.icf 自定义Flash段与FLASH_LENGTH修改对比

第二步,修改 fsp_gen_new.icf 文件,参考下图:

IAR fsp_gen_new.icf 新增FLASH_USER_DATA/TEXT与user_data/user_text块

第三步,修改源码,将 const 类型变量和函数声明放在新增的 .user_const 和 .user_text 两个 section 中,同时增加函数定义。在 hal_entry() 中增加函数调用,避免被优化:

IAR 源码中使用#pragma location将数据和函数放入自定义段

第四步,按照以下方式更新 fsp_new.icf 文件,使改动后的 Linker Script File(memory_regions_new.icf 和 fsp_gen_new.icf)生效:

IAR fsp_new.icf 引用修改后的memory_regions_new.icf与fsp_gen_new.icf

最后一步,在 IAR EW for Arm 中将 Linker Script File 设置为 fsp_new.icf:

IAR 链接器配置中选择fsp_new.icf作为Linker configuration file

特别提醒:在 IAR 中执行 clean 操作后,该配置会恢复为默认值(fsp.icf),需要重新进行修改。

编译工程后,打开 *.map 文件,用常量和函数名作为关键字搜索,可以看到以下匹配:

IAR map文件中test_data与test_function_fibonacci位于0x00070000和0x00078001

四、Arm Compiler 6

对于 Keil MDK 工程,在工程路径下找到 3 个文件,在原始路径下复制并重命名:

  • script\fsp.scat → script\fsp_new.scat
  • memory_regions.scat → memory_regions_new.scat
  • fsp_gen.scat → fsp_gen_new.scat

第一步,编辑 memory_regions_new.scat,文件变动参考下图:

Arm Compiler 6 memory_regions_new.scat 自定义Flash段与FLASH_LENGTH修改对比

第二步,修改 fsp_gen_new.scat 文件,参考下图。找到关键字 LOAD_REGION_OPTION_SETTING_OFS0,在该段落前增加 .my_data_section 和 .my_text_section 两个 section:

Arm Compiler 6 fsp_gen_new.scat 新增LR_MY_DATA与LR_MY_TEXT加载区

第三步,修改源码,将 const 类型变量和函数声明放在新增的 .my_data_section 和 .my_text_section 两个 section 中,同时增加函数定义。在 hal_entry() 中增加函数调用,避免被优化:

Arm Compiler 6 源码中使用BSP_PLACE_IN_SECTION将数据和函数放入自定义段

第四步,按照以下方式更新 fsp_new.scat 文件,使改动后的 Linker Script File(memory_regions_new.scat 和 fsp_gen_new.scat)生效:

Arm Compiler 6 fsp_new.scat 引用修改后的memory_regions_new.scat与fsp_gen_new.scat

最后一步,在 Keil MDK 中将 Linker > Scatter File 设置为 fsp_new.scat:

Keil MDK 链接器中设置Scatter File为fsp_new.scat

编译工程后,打开 *.map 文件,用常量和函数名作为关键字搜索,可以看到以下匹配:

Keil MDK map文件中test_data_0/test_data_1与斐波那契函数、素数函数地址

小结

关于 const 变量、函数定位到 Code Flash 指定地址的方法,本文已经基于 GNU、LLVM、IAR 和 Arm Compiler 6 共四款主流编译器做了完整对比与说明。

理论讲清楚之后,接下来就是实操环节。对应的示例工程也已经准备好,方便直接验证和复用:

https://gitee.com/recn-mcu-ae/20260507rasectiongccllvmiarac6

如果需要进一步了解瑞萨 RA 系列 MCU 的更多配置细节,建议同步查阅 FSP 官方文档和对应的链接器手册。




上一篇:ChatGPT教打麻将!OpenAI智能界面实测:GPT-6重新定义AI交互
下一篇:瑞萨RA MCU开发工具怎么选?e² studio、Keil MDK还是VS Code
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-9 05:03 , Processed in 0.084240 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表