如何在STM32链接脚本中为参数段填充至指定16KB大小
问题背景
我使用的STM32F4 MCU拥有512KB Flash存储器,首个16KB分区分配给Bootloader,第二个16KB计划用作调参参数存储区(硬复位后参数不丢失),剩余区域为主应用区。
目前Bootloader已单独编译,并通过以下objcopy命令填充至0x08004000:
COMMAND ${CMAKE_OBJCOPY} -O binary --pad-to 0x08004000 --gap-fill 0xff $<TARGET_FILE:${BOOTLOADER}> ${BOOTLOADER}.bin
主应用通过链接脚本加载在Bootloader之后。现在的问题是:如何将参数段恰好填充至16KB,避免擦写参数时(Flash需整片擦除)损坏其他代码段。
当前链接脚本的text段如下:
SECTIONS { .text : { KEEP(*(.bootloader_section)) /* 16 KB */ KEEP(*(.parameters_section)) /* 16 KB HOW??? */ /* Main application: should start from 0x8008000 = 32KB offset from flash base */ *(.vectors) /* Vector table */ KEEP(*(.firmware_info)) *(.text*) /* Program code */ . = ALIGN(4); *(.rodata*) /* Read-only data */ . = ALIGN(4); } >rom }
项目中定义参数的parameters.c文件:
__attribute__((section(".parameters_section"))) Parameters_t param = { .tuning.value1 = 0x4, .tuning.value2 = 0x3, .tuning.value3 = 0x2, .tuning.value4 = 0x3, .reserved4 = 0xaaaaaaaa, .reserved5 = 0xaaaaaaaa, .reserved6 = 0xaaaaaaaa, .reserved7 = 0xaaaaaaaa, .reserved8 = 0xaaaaaaaa, .reserved9 = 0xaaaaaaaa, .reserved10 = 0xaaaaaaab, .reserved11 = 0xaa0aaaaa, .reserved12 = 0xaaaaaaaa, .reserved13 = 0xaaaaaaaa, .reserved14 = 0xaaaaaaaa, .reserved15 = 0xaaaaaaaa, .reserved16 = 0xaaaaaaaa, .reserved17 = 0xaaaaaaaa, .reserved18 = 0xaaaaaaaa, .reserved19 = 0xaaaaaaaa, };
请问是否需要单独编译parameters.c并通过objcopy填充,还是有其他实现方法?
解决方案
不需要单独编译parameters.c,推荐以下两种更高效的实现方式:
方法一:链接脚本直接定义参数分区并填充
修改链接脚本,明确划分各分区的起始地址和大小,用FILL(0xff)自动填充剩余空间:
SECTIONS { /* Bootloader分区:0x08000000 ~ 0x08003FFF,16KB */ .bootloader : ORIGIN(0x08000000), LENGTH(16K) { KEEP(*(.bootloader_section)) /* 填充Bootloader分区剩余空间 */ . = ORIGIN(.bootloader) + LENGTH(.bootloader); } >rom /* 参数分区:0x08004000 ~ 0x08007FFF,16KB */ .parameters : ORIGIN(0x08004000), LENGTH(16K) { KEEP(*(.parameters_section)) /* 用0xff填充至16KB */ . = ORIGIN(.parameters) + LENGTH(.parameters); FILL(0xff); } >rom /* 主应用分区:从0x08008000开始 */ .text : ORIGIN(0x08008000) { *(.vectors) /* Vector table */ KEEP(*(.firmware_info)) *(.text*) /* Program code */ . = ALIGN(4); *(.rodata*) /* Read-only data */ . = ALIGN(4); } >rom }
这种方式的优势:
- 链接阶段直接完成分区对齐和填充,无需额外编译步骤
- 分区边界清晰,彻底避免代码或参数越界覆盖
方法二:单独生成参数二进制并拼接
如果需要单独更新参数,可以选择这种方式:
- 单独编译parameters.c为目标文件:
arm-none-eabi-gcc -c parameters.c -o parameters.o -mcpu=cortex-m4 -mthumb
- 生成填充至16KB的参数二进制:
arm-none-eabi-objcopy -O binary --pad-to 0x1000 --gap-fill 0xff parameters.o parameters.bin
- 拼接Bootloader、参数、主应用的二进制文件,生成完整Flash镜像:
cat bootloader.bin parameters.bin app.bin > full_flash.bin
额外注意事项
- STM32F4的16KB分区对应一个Flash扇区,确保参数段完全落在该扇区内,擦写时不会影响其他分区
- 建议在代码中添加参数区的宏定义,方便后续维护:
#define PARAMS_FLASH_START 0x08004000 #define PARAMS_FLASH_SIZE 0x4000 // 16KB
内容的提问来源于stack exchange,提问作者mehdi
相关产品推荐
相关产品推荐

