一,为什么需要外部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
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前,可用的内存只有几十K,开启外部RAM后,可用的内存增加了几十倍,我使用内存获取函数,打印出内存的使用情况:
下图表示SPI RAM初始化成功。
下图信息说明,外部RAM可用的内存为4049k bytes,当freertos开始运行,进入main函数后,esp_get_free_heap_size()获取到的可用内存为4253k bytes,这是由内部RAM和外部RAM的所有可用的内存的总和,大概可知道可用的内部RAM只有约200k bytes。可见外部RAM极大的扩展了可用内存。
五,小结
由于外部RAM足足有4M 大小,使得esp32在应对语音,图像时依然能应对,对于一个使用了wifi,ble,lwip或者语音识别的程序来说,这4M的内存是必须的。
————————————————
版权声明:本文为CSDN博主「killer-p」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44821644/article/details/109207305