zl程序教程

您现在的位置是:首页 >  其它

当前栏目

ESP32系列--存储器类型和XIP特性

-- 系列 类型 特性 存储器 ESP32
2023-09-11 14:21:44 时间

一、目的

        当我们通过ESP-IDF开发ESP32时,可能会遇到类似这样的场景需要对某个函数的执行速度进行优化例如中断执行函数需要快入快出,那么应该怎么做呢,ESP-IDF里面有没有提供这样的方法或者机制呢?

        按照常识我们总认为内部SRAM的读写速度一般是最快的(有些芯片内部还有TCM--紧凑内存,可以认为是和CPU同频的内存),那么我们将代码放置到内部SRAM中就可以加快函数的执行。

       鉴于此我们需要对ESP32的存储器类型做个全面介绍,。以帮助大家对代码段、数据段、BSS的地址分配有个系统了解。

二、介绍

        参考资料

Memory Types - ESP32-S3 - — ESP-IDF Programming Guide latest documentationhttps://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/memory-types.html

        在讲解内部映射之前,我们需要知道下面几个基本概念:

  • code 代码段
  • rw data 读写段
  • ro data  只读数据段
  • bss 未初始化的或者数值为0的全局变量                

        在我们最终的image中,占用的Flash大小为code + rw data,占用的ram大小为rw data + bss段。

        下面我们介绍一些ESP-IDF中的内存映射以及各个段的特征  

        IRAM

        可以用于执行代码的RAM区域,ESP-IDF编译链接时默认代码的存放和执行都是在IROM(即Flash);通过MMU和指令Cache进行映射和执行加速。

        因为Flash的读取相比IRAM的读写较慢,当需要优化代码执行速度时,可以考虑将代码放置到IRAM中;在ESP-IDF的驱动代码中,如果指定中断Flags设置为ESP_INTR_FLAG_IRAM时,中断函数就必须放置到IRAM中。

        通过IRAM_ATTR宏定义来指定代码段的位置

#include "esp_attr.h"

void IRAM_ATTR gpio_isr_handler(void* arg)
{
        // ...
}

        IROM

        用于存放代码或者执行代码的区域,即Flash地址空间;一般情况下代码和只读数据都是存放在Flash中,程序运行时XIP;由于SRAM有限,大部分情况下我们自己的代码尽量都放置在此区域


        DROM

        用于存放只读数据(即只读数据也放置在Flash中)


        DRAM

        用于存放初始化的全局变量(RW段)和未初始化的全局变量(BSS段);链接器会将此区域定向到芯片内部的SRAM,其剩余空间用于Heap分配;

        RW、BSS段一般都是存放在内部SRAM,但是BSS也可以放置在外部SRAM中。

        这边有个概念RW段执行的时候在SRAM,但是RW的数据是要先保存在Flash中(加载视图与执行视图的区别)

        通过EXT_RAM_BSS_ATTR宏定义可以将BSS段放置在外置在外部SRAM,需要在menuconfig中配置如下选项(高亮处)

        

         注意此选项也会将一些组件的bss段放置在外部SRAM中

        DRAM的空间大小受限于IRAM的使用,IRAM使用越多,DRAM就越少,Heap的大小也就更少。

        只读数据也通过DRAM_ATTR宏将数据放置到DRAM中(不建议,但是有些场景必须要这样做)

        指令Memory是可以执行的,且只能4字节对齐读写;数据Memory不可执行,可以单字节读写


        低功耗模式下使用的代码段和数据段

        Fast RTC

        用于低功耗代码的执行

        Slow RTC RAM

        放置在此区域的全局变量和静态变量可以被Fast RTC中的代码访问,通过RTC_NOINIT_ATTR宏定义来实现。

        DMA

        必须放置在内部SRAM中

void app_main()
{
    uint8_t stuff;
    WORD_ALIGNED_ATTR uint8_t buffer[] = "I want to send something";   //or the buffer will be placed right after stuff.
    // initialization code...
    spi_transaction_t temp = {
        .tx_buffer = buffer,
        .length = 8 * sizeof(buffer),
    };
    spi_device_transmit(spi, &temp);
    // other stuff
}