• 正文
  • 相关推荐
申请入驻 产业图谱

如何将全部代码放在 SRAM 中运行

19小时前
363
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

部分 IAP 安全场景需求:利用 STM32 系统 Bootloader,将一段临时代码加载到 SRAM 中执行;临时代码负责解密加密 APP/IAP 固件,完成 Flash 烧写;上电复位之后 SRAM 临时代码自动消失,提升固件安全性。

STM32 默认代码在内部 Flash 执行,把全部代码、向量表、常量数据完整部署至 SRAM 运行,需要修改链接脚本、编译宏、调试初始化脚本。该模式仅调试器加载可以直接跑通;文档不介绍系统 Bootloader 跳转 SRAM 的业务逻辑。本文基于 LAT1705,分别拆解 IAR、Keil 两套工具链完整配置、验证手段、高频踩坑。

重要提醒:SRAM 空间有限,全部代码 SRAM 运行,固件总大小不能超过芯片 SRAM 总容量。

资料获取:实战经验 | LAT1705 如何将全部代码放在SRAM中运行_v1.0

1 业务场景与测试准备

典型使用场景

IAP 安全方案:串口借助 System‑Bootloader 下载解密临时代码至 SRAM;SRAM 内运行解密逻辑,把解密后固件烧入 Flash;复位后 SRAM 内容丢失,临时代码不留痕迹。

本文聚焦调试器下载调试全 SRAM 运行工程,不覆盖系统 Bootloader 加载 bin 到 SRAM 的业务实现。

测试工程准备

  1. 使用 STM32CubeMX 生成基础工程,增加 LED 翻转点灯逻辑,用于运行状态观测;
  2. 分别生成 IAR (EWARM)、Keil‑MDK‑ARM 两套工程;
  3. 原始工程先在 Flash 下编译运行,确认 LED 点灯业务逻辑正常。

2 IAR‑EWARM 工程配置(全部代码 SRAM 运行)

2.1 修改链接 icf 脚本

  1. 复制原厂stm32g431xx_flash.icf,另存为stm32g431xx_SRAM.icf;
  2. 修改内存映射:ROM(只读代码段)地址由 Flash 起始地址修改为 SRAM 起始地址0x20000000;RAM 段配置保留 SRAM 剩余空间,用于 RW/ZI、栈堆;
  3. 向量表.intvec段放置到 SRAM 起始位置。

2.2 工程 Linker 选项切换

工程选项‑>Linker,勾选Override default,指定新创建的stm32g431xx_SRAM.icf链接脚本。

2.3 预编译宏增加向量表切换

C/C++ 预处理器宏定义增加两个宏:

VECT_TAB_SRAM,USER_VECT_TAB_ADDRESS

作用:system_stm32g4xx.c的 SystemInit 函数根据宏配置,修改 SCB‑>VTOR 向量表偏移寄存器,把中断向量表指向 SRAM 地址;没有该宏,中断会依然访问 Flash 地址,程序跑飞。

2.4 验证方法

  1. 调试前将芯片 Flash 整体擦除,消除旧固件干扰;
  2. ST‑LINK 下载调试,观察 LED 翻转;汇编窗口查看 PC 程序计数器地址落在0x2000xxxxSRAM 地址区间;
  3. 手动硬件复位 MCU,程序停止运行(复位后 SRAM 数据丢失,证明代码完全运行在 SRAM)。

3. Keil MDK‑ARM 工程配置(全部代码 SRAM 运行)

Keil 配置比 IAR 复杂,需要自定义分散加载 sct 脚本、调试初始化 ini 脚本,移除 Flash 烧录算法。

3.1 编写 SRAM 分散加载脚本 *.sct

示例(NUCLEO‑G431RB),把 RO 代码段部署 SRAM 起始地址0x20000000,RW/ZI、堆栈放在 SRAM 后续空间。

#define STACKSEAL_SIZE 0x8
#define HEAP_SIZE 0x200
#define STACK_SIZE 0x400

LR_IROM1 0x20000000 0x4000
{
  ER_IROM1 0x20000000 0x4000
  {
    * (InRoot$$Sections)
    .ANY(+RO)
  }
  RW_RAM1 0x20004000 0x2000
  {
    .ANY(+RW +ZI)
  }
  ARM_LIB_HEAP  AlignExpr(+0, 8) EMPTY HEAP_SIZE {}
  ARM_LIB_STACK AlignExpr(+0, 8) EMPTY STACK_SIZE {}
  STACKSEAL +0 EMPTY STACKSEAL_SIZE {}
}

根据目标芯片 SRAM 实际起始地址、总大小修改 sct 参数。

3.2 Target‑Linker 配置

取消勾选Use Memory Layout from Target Dialog;Scatter File 选择上面编写的 SRAM 版本 sct 脚本。

3.3 C/C++ 预编译宏

同样增加宏:VECT_TAB_SRAM,USER_VECT_TAB_ADDRESS,实现 VTOR 向量表重定向。

3.4 调试初始化脚本 run.ini(关键点)

Keil 调试需要 ini 脚本完成:设置 SP 栈指针、PC 程序计数器、VTOR 寄存器、加载 axf 镜像、跳转 main。

FUNC void Setup(void){
  SP=_RDWORD(0x20000000);
  PC=_RDWORD(0x20000004);
  _WDWORD(0xE000ED08, 0x20000000);
}
FUNC void OnResetExec (void){
  Setup();
  LOAD %L INCREMENTAL
  Setup();
  g,main
}
OnResetExec();

在 Debug 选项页,Initialization File填入该 run.ini 脚本路径。

3.5 移除 Flash 下载算法

  1. Debug‑>Settings‑>Flash Download,删除全部 Flash 编程算法;
  2. Download Function 选择Do not Erase,禁止 Flash 擦除编程动作;
  3. Utilities 页面选择Use External Tool for Flash Programming,关闭内置 Flash 烧录功能。

3.6 运行验证

擦除全部 Flash,下载调试;LED 正常翻转;汇编窗口确认 PC 指针处于 0x2000xxxx 地址;硬件复位,程序停止执行。

4. 工程落地排查清单

  1. 下载成功,一进中断程序直接崩溃 HardFault
    • 核查预编译宏是否添加VECT_TAB_SRAM;没有该宏 VTOR 仍然指向 Flash,中断向量访问非法地址;
    • 检查链接脚本,确认向量表段正确放置 SRAM 起始地址。
  2. 编译链接报错:SRAM 空间不足
    • 全部代码 + 常量 + RW+ZI + 堆栈总大小,不能超过芯片 SRAM 实际大小;裁剪固件或者更换 SRAM 更大型号 MCU。
  3. Keil 复位之后无法重新跑起来
    • 确认 run.ini 脚本已经正确配置,调试选项加载 ini 脚本;确认 Flash 下载算法全部移除。
  4. Flash 已经全部擦除,调试可以运行,断电复位不能运行
    • 现象属于预期行为:本方案是调试器动态加载 AXF 镜像到 SRAM;硬件上电复位 SRAM 内容丢失,不能作为上电自启动方案;上电自启动需要 Bootloader 把 bin 拷贝进 SRAM 再跳转。
  5. IAR 修改 icf 之后编译报段放置错误
    • 核对 icf 脚本 ROM 区域修改为 SRAM 起始地址,.intvec向量表段放置 SRAM 首地址。

5. 小结

  1. 将 STM32 全部代码运行于 SRAM,多用于 IAP 解密临时代码调试;该调试方案依靠调试器把镜像加载进 SRAM,芯片上电复位 SRAM 内容丢失,不能直接实现上电自动从 SRAM 启动;文档不介绍 System‑Bootloader 加载 bin 到 SRAM 业务流程。
  2. IAR 重点:修改 icf 链接脚本映射 ROM 到 SRAM,增加VECT_TAB_SRAM向量表宏。
  3. Keil MDK 重点:自定义 SRAM 分散加载 sct 脚本,配置 run.ini 调试初始化脚本,移除 Flash 下载算法,增加向量表切换宏。
  4. 必须重定向中断向量表 VTOR;不配置 VECT_TAB_SRAM,触发中断直接 HardFault。
  5. 验证标准:擦除 Flash,调试下代码可运行;汇编窗口确认 PC 指针在 SRAM 地址;硬件复位程序停止执行。

6. FAQ

Q:调试器可以把代码下载 SRAM 跑,那产品上电可以直接从 SRAM 运行吗?

A:不行。SRAM 是非易失存储器,复位掉电数据丢失。产品上电想要 SRAM 运行,需要 Bootloader/System‑Bootloader 把 bin 镜像拷贝到 SRAM,再跳转执行,本文只讲调试器调试场景。

Q:只需要部分函数跑在 SRAM,需要这套全部配置吗?

A:不需要。部分函数 SRAM 运行,只需要修改链接脚本把指定函数段放到 RAM,向量表依然保留 Flash,不需要 VECT_TAB_SRAM 宏。

Q:VECT_TAB_SRAM 宏的作用是什么?

A:在 SystemInit 内部配置内核 VTOR 寄存器,告诉内核中断向量表现在存放在 SRAM,中断响应才可以正常寻址向量表。

免责声明:本文全部基于 ST 官方 LAT1705 文档,不同 STM32 系列 SRAM 起始地址、大小存在差异,链接脚本务必匹配芯片参考手册内存映射。

相关推荐