MCU如何将常量和函数放在Code Flash/ROM指定地址

strongerHuang 2026-05-26 11:35

来源 | 瑞萨嵌入式小百科


前言


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


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


由于瑞萨电子RA系列开发基于FSP(Flexible Software Package),因此项目的构建均基于FSP生成的代码,对于第三方集成开发环境(IDE)像IAR EW for Arm和Keil MDK,则依赖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(8000h),因此两个section大小均设定为0x8000。


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


一、GNU编译器


首先,我们介绍在e2studio中使用GNU编译器时的操作步骤。


在e2studio中找到以下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存储数据,用于其它内容Link的地址空间需要在此基础上去掉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文件的变动参考下图:


MCU如何将常量和函数放在Code Flash/ROM指定地址图1

memory_regions_new.ld变更内容


第二步,修改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


MCU如何将常量和函数放在Code Flash/ROM指定地址图2

fsp_gen_new.ld变更内容


第三步,修改源码,将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));


MCU如何将常量和函数放在Code Flash/ROM指定地址图3


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图4

fsp_new.ld变更点


最后一步,在e2studio中设置Linker Script File为fsp_new.ld。


MCU如何将常量和函数放在Code Flash/ROM指定地址图5

更新Linker Script File为fsp_new.ld



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


MCU如何将常量和函数放在Code Flash/ROM指定地址图6

***.map文件中常量和函数的编译地址


二、LLVM编译器


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


在e2studio中找到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,文件变动参考下图:


MCU如何将常量和函数放在Code Flash/ROM指定地址图7

memory_regions_new.lld变更内容


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图8

fsp_gen_new.lld变更内容


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


左右滑动查看完整内容

constuint8_t test_data_0[8] BSP_PLACE_IN_SECTION(".mydata") = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};constuint8_t test_data_1[8] BSP_PLACE_IN_SECTION(".mydata") = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
uint32_ttest_function_fibonacci(uint32_t num)BSP_PLACE_IN_SECTION(".mytext") __attribute__((noinline));inttest_function_is_prime(int num)BSP_PLACE_IN_SECTION(".mytext") __attribute__((noinline));


左右滑动查看完整内容

MCU如何将常量和函数放在Code Flash/ROM指定地址图9


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图10

fsp_new.lld变更点


最后一步,在e2studio中设置Linker Script File为fsp_new.lld


MCU如何将常量和函数放在Code Flash/ROM指定地址图11

更新Linker Script File为fsp_new.lld



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


MCU如何将常量和函数放在Code Flash/ROM指定地址图12

***.map文件中常量和函数的编译地址


三、IAR编译器


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


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


  • script\fsp.icf →[JX1] [JW2] script\fsp_new.icf

  • memory_regions.icf → memory_regions_new.icf

  • fsp_gen.icf → fsp_gen_new.icf


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图13

memory_regions_new.icf变更内容


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图14


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图15

代码中增加变量和函数声明


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图16

fsp_new.icf变更点


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图17

更新Linker Script File为fsp_new.icf


特别提醒

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



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


MCU如何将常量和函数放在Code Flash/ROM指定地址图18

***.map文件中常量和函数的编译地址


四、Arm Compiler



对于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,文件变动参考下图:


MCU如何将常量和函数放在Code Flash/ROM指定地址图19

memory_regions_new.scat变更内容


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


找到关键字“LOAD_REGION_OPTION_SETTING_OFS0”在该段落前增加.my_data_setion和.my_text_section两个section。


MCU如何将常量和函数放在Code Flash/ROM指定地址图20

fsp_gen_new.scat变更内容


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


左右滑动查看完整内容

MCU如何将常量和函数放在Code Flash/ROM指定地址图21


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图22

fsp_new.scat变更点


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


MCU如何将常量和函数放在Code Flash/ROM指定地址图23

更新Linker Script File为fsp_new.scat



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


MCU如何将常量和函数放在Code Flash/ROM指定地址图24

***.map文件中常量和函数的编译地址



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


理论讲清楚了,接下来就是实操环节啦。


这里也准备了对应的示例工程,方便直接验证:


示例工程

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


1

END

1





声明:内容取材于网络,仅代表作者观点,如有内容违规问题,请联系处理。 
MCU
more
G32A汽车专用MCU家族扩容丨G32A1085/1065/1045系列正式量产发布
如何在基于MCU的边缘AI应用场景中实现高性能、低功耗推理!
边缘AI趋势下,德州仪器升级MCU的策略
汽车高端MCU,远征与迷雾
不靠 MCU,用 FPGA + DAC 实现可调信号源
最高涨幅85%!MCU芯片掀涨价潮,谁能抓住机遇?
创始团队退出?云途半导体被传“卖身”矽力杰,MCU市场风云突变!
后量子加密时代拉开帷幕,这些MCU已经准备好了
【RISC-V Now!亮点解析】先楫半导体:高性能MCU如何开启嵌入式新生态?
分享一个提高MCU计算能力的神器!
Copyright © 2025 成都区角科技有限公司
蜀ICP备2025143415号-1
  
川公网安备51015602001305号