STM32性能飞跃:函数内存RAM执行提速秘籍!
2025-09-23 来源:cnblogs
在嵌入式开发中,优化系统的执行效率是每个工程师都需要关注的核心问题。STM32等基于ARM Cortex-M的微控制器通常将程序代码存储在闪存(Flash)中,从闪存中读取并执行。虽然这种方式在大多数情况下已经足够,但在一些关键应用场景中,程序执行的速度和响应时间可能成为瓶颈。如何突破这个瓶颈,提高系统性能?今天,我们将揭开一个STM32优化性能的秘密武器——将函数放入RAM中执行!
为什么将函数放入RAM中执行?
STM32的闪存读取速度虽不慢,但与RAM相比,速度差距明显。RAM的访问速度要比闪存快得多,尤其是在频繁读取或者执行大量数据时,RAM能够提供更高的带宽和更低的延迟。因此,将一些关键函数或者中断处理函数放入RAM中执行,能够显著提高系统的响应速度和执行效率。
适用场景
高频中断处理:中断服务程序(ISR)通常对执行时间有着极高的要求。将ISR放入RAM中,可以减少执行延迟,提高系统的实时性。
实时性要求高的算法:对于需要大量计算或者频繁操作的数据,放入RAM中可以显著提高算法的处理速度,适合处理图像、声音等实时数据。
安全性和灵活性需求:通过将代码动态加载到RAM中执行,可以实现某些代码的更新或者保护,防止闪存中的程序被篡改。
如何将STM32函数放入RAM中执行?
1. 修改链接脚本 (Linker Script)
将函数放入RAM的第一步是修改链接脚本。链接脚本定义了各个段如何映射到内存中。通过在链接脚本中指定RAM区域,我们可以将特定的函数或数据放入RAM中。


步骤:
定义RAM区域:在链接脚本中定义一个RAM区域,指定起始地址和大小。
/* 修改链接脚本 */
LR_IROM1 0x08000000 0x00100000 {
; 注释说明:这是一个加载区域,包含程序代码等信息
ER_IROM1 0x08000000 0x00100000 {
; 注释说明:加载地址即为执行地址
; *.o 对象文件中的 RESET 段和 +First 段会被加载到这个区域
*.o (RESET, +First)
; 将 InRoot$$Sections 段加载到此区域
*(InRoot$$Sections)
; 将所有只读段 (RO) 放入此区域
.ANY (+RO)
; 将所有外部符号段 (XO) 放入此区域
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x0001C000 {
; 注释说明:这是一个用于存储读写数据的RAM区域
.ANY (+RW +ZI) ; 将所有读写数据 (RW) 和未初始化数据 (ZI) 放入此区域
}
RW_IRAM2 0x2001C000 0x00004000 {
.ANY (+RW +ZI) ; 将所有读写数据 (RW) 和未初始化数据 (ZI) 放入此区域
}
}
解释:
LR_IROM1:定义了一个加载区域,起始地址为 0x08000000,大小为 1MB,用于存储程序代码和只读数据。
ER_IROM1:执行区域的定义,加载地址即为执行地址,指明将程序的代码从闪存加载到该区域并执行。
*.o (RESET, +First):将目标文件中的
RESET 和
+First 段加载到此区域。
*(InRoot$$Sections):将指定的
InRoot$$Sections 段加载到执行区域。
.ANY (+RO):将所有只读段(如代码段)放入此区域。
.ANY (+XO):将外部符号段加载到此区域。
RW_IRAM1:定义了一个读写数据区域,起始地址为 0x20000000,大小为 112KB,用于存储可读写数据和未初始化数据。
.ANY (+RW +ZI):将所有读写数据(RW)和未初始化数据(ZI)放入该区域。
RW_IRAM2:另一个读写数据区域,起始地址为 0x2001C000,大小为 16KB,同样用于存储读写数据和未初始化数据。
2. 使用GCC属性将函数放入RAM
GCC提供了 __attribute__((section('.RAM_FUNCTIONS'))) 属性,可以将特定的函数放入RAM中的特定段。
示例代码:
void MyFunction(void) __attribute__((section('.RAM_FUNCTIONS'))); // 指定放入 RAM 区域
void MyFunction(void)
{
// 函数体
}
解释:
通过
__attribute__((section('.RAM_FUNCTIONS'))),我们将
MyFunction 函数放入
.RAM_FUNCTIONS 区域,确保它存储在RAM中。
3. 启动时拷贝代码到RAM并执行
有时候,我们可能需要在程序启动时将代码从闪存拷贝到RAM,并执行。通常,这种方法用于Bootloader或者自定义固件更新方案。
示例代码:
#define CODE_IN_FLASH ((uint32_t)0x08008000) // 假设代码存储在闪存的 0x08008000 地址处
#define CODE_IN_RAM ((uint32_t)0x20000000) // 假设 RAM 的起始地址是 0x20000000
void (*ram_function)(void);
void CopyToRAM(void)
{
uint32_t i;
uint32_t *flash_ptr = (uint32_t *)CODE_IN_FLASH;
uint32_t *ram_ptr = (uint32_t *)CODE_IN_RAM;
// 假设代码的长度是 1KB
for (i = 0; i < 256; i++) {
ram_ptr[i] = flash_ptr[i];
}
// 设置函数指针指向 RAM 中的函数
ram_function = (void (*)(void)) CODE_IN_RAM;
// 跳转到 RAM 中执行函数
ram_function();
}
解释:
该代码演示了如何将存储在闪存中的代码拷贝到RAM中,并通过函数指针跳转到RAM中执行。这样可以动态加载并执行RAM中的代码。
4. 在中断服务程序中使用RAM执行
对于中断服务函数(ISR),通常对响应速度有严格的要求。将ISR存储在RAM中,能够减少访问延迟,提高响应速度。
示例代码:
void MyIRQHandler(void) __attribute__((section('.IRQ_FUNCTIONS')));
void MyIRQHandler(void)
{
// 中断服务处理代码
}
通过 __attribute__((section('.IRQ_FUNCTIONS'))),将 MyIRQHandler 函数放入特定的RAM区域中执行,从而提高中断响应速度。
将函数放入RAM中的优势
提高执行速度:将函数放入RAM中执行,减少了闪存读取的延迟,尤其是在数据处理频繁的情况下,RAM的访问速度能够显著提升系统的响应时间。
增强实时性:对于需要高实时响应的应用,比如中断处理、实时信号处理等,放入RAM中的函数能够提供更快速的执行路径。
灵活的代码更新:将代码放入RAM中执行,能够更方便地进行固件更新和动态加载,实现代码的灵活性和可更新性。
节省闪存空间:通过将不常用的代码存放在闪存中,只在需要时加载到RAM中,可以有效节省闪存空间。
- 意法半导体中国本地造STM32微控制器启动规模量产
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 基于机智云与STM32的智能拐杖安全监测系统在养老物联网中的应用
- 内置全栈安全,一站式满足CRA法案与IEC 62443标准——米尔STM32MP257核心板
- 如何用 STM32 FLASH 实现等效 100 万次擦写的 EEPROM 功能?
- 实战解析:通过一个小项目掌握STM32所有外设
- STM32学了两年半,却还是不会做项目
- 意法半导体推出最新STM32MP21微处理器,兼具高性价比、低功耗、高灵活性
- 基于STM32的矿井作业环境监测系统设计与实现
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析
- 蓝牙信道探测技术原理与开发套件实践
- 意法半导体中国本地造STM32微控制器启动规模量产




