如何在STM32上实现程序从RAM运行并禁用Flash?
第一步:修改STM32WB55的GCC链接脚本
找到项目中后缀为.ld的链接脚本,按如下规则修改:
- 先修改MEMORY区域定义,明确Flash加载域和RAM运行域的地址范围:
MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1M /* 按你实际Flash容量调整 */ RAM (xrw) : ORIGIN = 0x20000008, LENGTH = 196604 - 8 /* 前8字节预留,避免栈指针越界 */ }
- 新增段规则,指定代码、只读数据的加载地址为Flash,运行地址为RAM,同时导出拷贝需要的符号:
/* 代码+只读数据段:加载在Flash,运行在RAM */ .text : { . = ALIGN(4); _stext = .; /* RAM中代码段起始地址 */ *(.text) *(.text*) *(.rodata) *(.rodata*) . = ALIGN(4); _etext = .; /* RAM中代码段结束地址 */ } >RAM AT> FLASH /* 可读写数据段 */ .data : { . = ALIGN(4); _sdata = .; *(.data) *(.data*) . = ALIGN(4); _edata = .; } >RAM AT> FLASH /* 零初始化段 */ .bss (NOLOAD) : { . = ALIGN(4); _sbss = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; } >RAM /* 导出Flash中代码段的加载起始地址,启动拷贝用 */ _sidata = LOADADDR(.text);
第二步:修改启动汇编代码
找到项目中startup_stm32wb55xx.s启动文件,修改Reset_Handler复位处理函数,在系统初始化前完成Flash到RAM的代码拷贝:
Reset_Handler: /* 拷贝代码段从Flash到RAM */ ldr r0, =_sidata /* Flash中代码起始地址 */ ldr r1, =_stext /* RAM中代码目标起始地址 */ ldr r2, =_etext /* RAM中代码目标结束地址 */ b copy_text_loop copy_text_loop: cmp r1, r2 ittt lt ldrlt r3, [r0], #4 strlt r3, [r1], #4 blt copy_text_loop /* 拷贝数据段从Flash到RAM */ ldr r0, =_sidata + (_etext - _stext) ldr r1, =_sdata ldr r2, =_edata b copy_data_loop copy_data_loop: cmp r1, r2 ittt lt ldrlt r3, [r0], #4 strlt r3, [r1], #4 blt copy_data_loop /* 清BSS段,原有逻辑保留即可 */ ldr r0, =_sbss ldr r1, =_ebss mov r2, #0 b clear_bss_loop clear_bss_loop: cmp r0, r1 itt lt strlt r2, [r0], #4 blt clear_bss_loop /* 重映射中断向量表到RAM地址 */ ldr r0, =0xE000ED08 /* SCB->VTOR寄存器地址 */ ldr r1, =_stext str r1, [r0] /* 跳转到RAM中的初始化函数执行,后续所有代码均运行在RAM */ ldr r0, =SystemInit blx r0 ldr r0, =main blx r0 b Infinite_Loop
第三步:添加Flash禁用逻辑
在main.c中添加Flash禁用函数,注意必须在跳转到RAM运行之后再调用,放在main函数第一行即可:
#include "stm32wbxx_hal.h" void disable_flash(void) { // 等待Flash所有操作完成 while(READ_BIT(FLASH->SR, FLASH_SR_BSY) != 0); // 关闭Flash预取、缓存 CLEAR_BIT(FLASH->ACR, FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN); // 开启运行、睡眠模式下Flash自动断电 SET_BIT(FLASH->ACR, FLASH_ACR_SLEEP_PD | FLASH_ACR_RUN_PD); } int main(void) { disable_flash(); // 后续原有业务逻辑保留 HAL_Init(); SystemClock_Config(); // ... USART初始化、延时发送逻辑不变 }
第四步:修改CMake配置避免下载报错
在项目CMakeLists.txt中添加OpenOCD下载参数,跳过Flash校验(因为运行地址和烧录地址不一致会触发默认校验失败):
set(OPENOCD_DOWNLOAD_FLAGS "verify disable")
注意事项
- 程序仍需烧写到Flash中,上电后BootROM会读取Flash前8字节的栈指针和复位向量,跳转到复位处理函数后才会完成RAM拷贝
- 调试断点需匹配RAM地址的符号,不要选择Flash地址的符号
- 禁止在Flash运行状态下调用禁用Flash的函数,会直接导致程序跑飞
内容的提问来源于stack exchange,提问作者Paul Jon
相关产品推荐
相关产品推荐

