单片机
返回首页

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中,可以有效节省闪存空间。


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 设计汽车集群电源

  • 6晶体管H桥

  • USB自供电声卡

  • AVR LCD温度计—LM35

  • AVR PC步进电机驱动器

  • AVR温度计TCN75

    相关电子头条文章