ESP32 解决ESP32内部RAM内存不足的问题 开启外部SPI RAM

一,为什么需要外部RAM

ESP32有520kB的内部RAM空间可以使用,这对于一般的情况是够用的,但是如果设备需要涉及音频或者显示图像等处理时,需要更大的内存空间来处理这些数据。ESP32支持扩展外部RAM,其实乐鑫已经在其ESP32 WROVER系列模组中集成了一个4M大小的外部PSRAM。乐鑫官网文档对外部RAM作了详解:片外RAM

乐鑫对于ESP32 WROVER的介绍也是:

ESP32-WROVER 系列模组基于 ESP32-D0WD 双核芯片设计,其强大的双核性能适用于对内存需求大的应用场景,例如多样的 AIoT 应用和网关应用。

如果你的设备需要使用大内存,例如wifi与ble并存,音频处理和图像显示功能,推荐使用这个模组。

二 快速上手外部RAM

2.1 使能外部RAM

首先必须确保你的芯片是有外部RAM的。例如ESP32 WROVER模组。
进入idf.py menuconfig->component config->ESP32-specific
在下图的Support for external,SPI-connected RAM选项中按y选中,这样就使能了外部RAM。

在这里插入图片描述

2.2 配置外部RAM

进入下一行的SPI RAM config进行配置更多的细节。这里讲一下比较重要的配置选项。

在这里插入图片描述

2.2.1 第二项配置系统的动态内存分配功能

有三个选项,当选择Make RAM allocatable using heap_caps_malloc(..., M时,需要在代码中使用heap_caps_malloc()函数才能在外部RAM中分配内存。

当选择Make RAM allocatable using malloc() as well时,代码中malloc()函数会自动从外部RAM中分配内存。
当使能这个选项时,还能配置第九行Maximum malloc() size, in bytes, to always put in internal memory,该配置设置了一个阈值,这里我设置的是1024bytes,当使用malloc()分配内存时,如果分配的内存小于1024字节,就会从内部RAM中分配,否则从外部RAM中分配。

2.2.2 将BSS段添加到外部RAM

第13行中选择Allow .bss segment placed in external memory,可以将BSS段的lwip、net80211、libpp 和 bluedroid ESP-IDF 库中零初始化的数据存入外部RAM。此外全局变量,静态变量也可以放到外部RAM中,只需要在变量声明的地方加上宏EXT_RAM_ATTR,并将变量初始化为0。

EXT_RAM_ATTR static int num[1024]={
    
    0};
 

2.2.3 其他可放入外部RAM的数据

第十行Try to allocate memories of WiFi and LWIP in SPIRAM firstly. If failed, allocate inter会尝试优先使用外部RAM给wifi与lwip协议栈分配内存,如果失败则会使用内部RAM分配。

2.2.4 创建静态任务

xTaskCreate()会使用内部RAM给任务分配任务堆栈。而使用xTaskCreateStatic()系统会检查传入的buff数组是否是属于内部RAM的。

但对于不以任何方式直接或间接调用 ROM 中代码的任务,选项 Allow external memory as an argument to xTaskCreateStatic 将解除 xTaskCreateStatic 中的检查,从而允许任务堆栈存储在外部 RAM 中。但是,不建议使用此方法。

实际使用过程中我也发现使用该函数创建任务会出现assert error的错误,不知道具体的原因是什么,希望了解的大佬解答一下。

2.2.5 修改分区表

由于使用了外部RAM会使partitionstable.bin增加,0x8000的偏移地址会出现覆盖,所以需要修改分区表和partitionstable.bin的偏移地址:
idf.py menuconfig->Partition Table修改成0x10000
如果使用本地的分区表,还需要将分区表修改如下

这是由于partitionstable.bin默认是起始地址0x8000修改成0x10000后,由于其占用0xc00大小的空间,而nvs要实现内存对齐,至少要在0x11000处开始.

# Espressif ESP32 Partition Table
# Name,   Type, SubType, Offset,  Size
nvs,      data, nvs,     0x11000,  0x4000,
phy_init, data, phy,     0x15000,  0x1000,
factory,  app,  factory, 0x20000, 0x300000,
flash_tone,data, 0x04,   0x320000,  50k,

在这里插入图片描述

三 使用效果

使用外部RAM前,可用的内存只有几十K,开启外部RAM后,可用的内存增加了几十倍,我使用内存获取函数,打印出内存的使用情况:

下图表示SPI RAM初始化成功。
在这里插入图片描述

下图信息说明,外部RAM可用的内存为4049k bytes,当freertos开始运行,进入main函数后,esp_get_free_heap_size()获取到的可用内存为4253k bytes,这是由内部RAM和外部RAM的所有可用的内存的总和,大概可知道可用的内部RAM只有约200k bytes。可见外部RAM极大的扩展了可用内存。

在这里插入图片描述

四 深度解放内部RAM

IRAM是内部RAM,当我使用wifi+ble+ASR组成的一个工程时,编译后出现Section .iram0.text will not fit in region iram0_0_seg的错误,原因是IRAM的内存空间仍然不够,这是因为任务堆栈等数据是不能存放在外部RAM中的,所以IRAM中的内存依然紧张。

解决办法是参考 https://github.com/espressif/esp-idf/issues/2566

原理就是关闭一些网络功能的优化来减少IRAM的使用
按照这位老哥的说法,将wifi,lwip的优化功能关闭,以减少IRAM的占用,这样下来能省出大约37KB的内存。这样就能正常的编译运行了。
在这里插入图片描述
具体步骤如下
idf.py menuconfig->component config->Wi-Fi,将箭头所指的两项按n取消选择
在这里插入图片描述
lwip部分同理:进入idf.py menuconfig->component config->LWIP,取消箭头所指。

在这里插入图片描述

五,小结

由于外部RAM足足有4M 大小,使得esp32在应对语音,图像时依然能应对,对于一个使用了wifi,ble,lwip或者语音识别的程序来说,这4M的内存是必须的。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44821644/article/details/109207305