You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在STM32上实现程序从RAM运行并禁用Flash?

第一步:修改STM32WB55的GCC链接脚本

找到项目中后缀为.ld的链接脚本,按如下规则修改:

  1. 先修改MEMORY区域定义,明确Flash加载域和RAM运行域的地址范围:
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1M /* 按你实际Flash容量调整 */
  RAM (xrw)       : ORIGIN = 0x20000008, LENGTH = 196604 - 8 /* 前8字节预留,避免栈指针越界 */
}
  1. 新增段规则,指定代码、只读数据的加载地址为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 15:45:03