(ESP32 Arduino Wrover-E) 如何使以下代码片段仅在外部 RAM 中分配资源?
(ESP32 Arduino Wrover-E) How to make the following snippet allocate resources only in External RAM?
目标是在ESP32的External Ram中分配一个类的数组。
他们说编译器会在外部内存中自动分配space的大块,但事实并非如此。通过此代码段,我的堆变小了,但 ext ram 大小保持不变。
#define TEST_CLASS_ARR_SIZE 100
class testClass {
long testVar;
public:
testClass() {
//Serial.println("testClass constructor");
}
~testClass() {
//Serial.println("testClass destructor");
}
void sayHello(){
Serial.println("Hello!");
}
};
testClass* testClassesArray[TEST_CLASS_ARR_SIZE];
void testExtRamAllocation(){
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
// allocate testClasses in external ram with extRam allocator and put them in testClassesArray
for(int i = 0; i < TEST_CLASS_ARR_SIZE; i++){
testClassesArray[i] = new testClass();
}
// I can use any of the calsses like this: testClassesArray[15]->sayHello();
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
// delete testClasses in external ram
for(int i = 0; i < TEST_CLASS_ARR_SIZE; i++){
delete testClassesArray[i];
}
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
}
void setup(){
Serial.begin(115200);
testExtRamAllocation();
}
void loop(){
vTaskDelete(NULL);
}
我的设置:
- ESP32-Wrover-E(16mb 闪存,8mb psRAM)
- IDE:VsCode - 平台 IO
PIO配置:
[env:esp-wrover-kit]
platform = espressif32
board = esp-wrover-kit
framework = arduino
board_build.filesystem = littlefs
board_build.f_cpu = 240000000L
upload_port = COM8
upload_speed = 921600
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
board_upload.flash_size = 16MB
board_build.flash_mode = qio
board_build.partitions = large_spiffs_16MB.csv
board_build.f_flash = 80000000L
build_flags = -DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-mfix-esp32-psram-cache-strategy=memw
-DCORE_DEBUG_LEVEL=0
我试过的:
有一个自定义向量 ps_ram 分配器可用,如下所示:
#include <Arduino.h>
#include <vector>
template <class T>
struct PSallocator {
typedef T value_type;
PSallocator() = default;
template <class U> constexpr PSallocator(const PSallocator<U>&) noexcept {}
[[nodiscard]] T* allocate(std::size_t n) {
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
if(auto p = static_cast<T*>(ps_malloc(n*sizeof(T)))) return p;
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t) noexcept { std::free(p); }
};
template <class T, class U>
bool operator==(const PSallocator<T>&, const PSallocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const PSallocator<T>&, const PSallocator<U>&) { return false; }
std::vector<int, PSallocator<int> > extRam;
有了这个,我尝试了以下但没有成功:
void testCustomAllocator(){
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
extRam.reserve( TEST_CLASS_ARR_SIZE * sizeof(testClass) );
for (size_t x=0; x<TEST_CLASS_ARR_SIZE; x++) {
testClass* p = new testClass();
extRam.push_back( p );
}
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
extRam.clear();
extRam.shrink_to_fit();
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
}
我遇到编译器错误:
src/main.cpp: In function 'void testCustomAllocator()':
src/main.cpp:117:29: error: no matching function for call to 'push_back(testClass*&)'
extRam.push_back( p );
^
In file included from c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\vector:64,
from src/main.cpp:2:
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1074:7: note: candidate: 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = int; _Alloc = PSallocator<int>; std::vector<_Tp, _Alloc>::value_type = int]'
<near match>
push_back(const value_type& __x)
^~~~~~~~~
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1074:7: note: conversion of argument 1 would be ill-formed:
src/main.cpp:117:27: error: invalid conversion from 'testClass*' to 'std::vector<int, PSallocator<int> >::value_type' {aka 'int'} [-fpermissive]
extRam.push_back( p );
^
In file included from c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\vector:64,
from src/main.cpp:2:
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1090:7: note: candidate: 'void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = int; _Alloc = PSallocator<int>; std::vector<_Tp, _Alloc>::value_type = int]' <near match>
push_back(value_type&& __x)
^~~~~~~~~
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1090:7: note: conversion of argument 1 would be ill-formed:
src/main.cpp:117:27: error: invalid conversion from 'testClass*' to 'std::vector<int, PSallocator<int> >::value_type' {aka 'int'} [-fpermissive]
extRam.push_back( p );
^
*** [.pio\build\esp-wrover-kit\src\main.cpp.o] Error 1
我会回答我自己的问题。
如果可分配内存超过4k,新的arduino框架会将东西放在外部ram中。如果不是,它会把东西放入内部内存,但如果内部内存不足以分配,它会尝试从外部内存分配。
目标是在ESP32的External Ram中分配一个类的数组。
他们说编译器会在外部内存中自动分配space的大块,但事实并非如此。通过此代码段,我的堆变小了,但 ext ram 大小保持不变。
#define TEST_CLASS_ARR_SIZE 100
class testClass {
long testVar;
public:
testClass() {
//Serial.println("testClass constructor");
}
~testClass() {
//Serial.println("testClass destructor");
}
void sayHello(){
Serial.println("Hello!");
}
};
testClass* testClassesArray[TEST_CLASS_ARR_SIZE];
void testExtRamAllocation(){
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
// allocate testClasses in external ram with extRam allocator and put them in testClassesArray
for(int i = 0; i < TEST_CLASS_ARR_SIZE; i++){
testClassesArray[i] = new testClass();
}
// I can use any of the calsses like this: testClassesArray[15]->sayHello();
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
// delete testClasses in external ram
for(int i = 0; i < TEST_CLASS_ARR_SIZE; i++){
delete testClassesArray[i];
}
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
}
void setup(){
Serial.begin(115200);
testExtRamAllocation();
}
void loop(){
vTaskDelete(NULL);
}
我的设置:
- ESP32-Wrover-E(16mb 闪存,8mb psRAM)
- IDE:VsCode - 平台 IO
PIO配置:
[env:esp-wrover-kit]
platform = espressif32
board = esp-wrover-kit
framework = arduino
board_build.filesystem = littlefs
board_build.f_cpu = 240000000L
upload_port = COM8
upload_speed = 921600
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
board_upload.flash_size = 16MB
board_build.flash_mode = qio
board_build.partitions = large_spiffs_16MB.csv
board_build.f_flash = 80000000L
build_flags = -DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-mfix-esp32-psram-cache-strategy=memw
-DCORE_DEBUG_LEVEL=0
我试过的:
有一个自定义向量 ps_ram 分配器可用,如下所示:
#include <Arduino.h>
#include <vector>
template <class T>
struct PSallocator {
typedef T value_type;
PSallocator() = default;
template <class U> constexpr PSallocator(const PSallocator<U>&) noexcept {}
[[nodiscard]] T* allocate(std::size_t n) {
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
if(auto p = static_cast<T*>(ps_malloc(n*sizeof(T)))) return p;
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t) noexcept { std::free(p); }
};
template <class T, class U>
bool operator==(const PSallocator<T>&, const PSallocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const PSallocator<T>&, const PSallocator<U>&) { return false; }
std::vector<int, PSallocator<int> > extRam;
有了这个,我尝试了以下但没有成功:
void testCustomAllocator(){
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
extRam.reserve( TEST_CLASS_ARR_SIZE * sizeof(testClass) );
for (size_t x=0; x<TEST_CLASS_ARR_SIZE; x++) {
testClass* p = new testClass();
extRam.push_back( p );
}
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
extRam.clear();
extRam.shrink_to_fit();
// print available external and internal ram size
Serial.printf("Free Heap Size: %d\n", ESP.getFreeHeap());
Serial.printf("Free ExtRam Size: %d\n", ESP.getFreePsram());
}
我遇到编译器错误:
src/main.cpp: In function 'void testCustomAllocator()':
src/main.cpp:117:29: error: no matching function for call to 'push_back(testClass*&)'
extRam.push_back( p );
^
In file included from c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\vector:64,
from src/main.cpp:2:
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1074:7: note: candidate: 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = int; _Alloc = PSallocator<int>; std::vector<_Tp, _Alloc>::value_type = int]'
<near match>
push_back(const value_type& __x)
^~~~~~~~~
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1074:7: note: conversion of argument 1 would be ill-formed:
src/main.cpp:117:27: error: invalid conversion from 'testClass*' to 'std::vector<int, PSallocator<int> >::value_type' {aka 'int'} [-fpermissive]
extRam.push_back( p );
^
In file included from c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\vector:64,
from src/main.cpp:2:
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1090:7: note: candidate: 'void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = int; _Alloc = PSallocator<int>; std::vector<_Tp, _Alloc>::value_type = int]' <near match>
push_back(value_type&& __x)
^~~~~~~~~
c:\users\pc\.platformio\packages\toolchain-xtensa-esp32\xtensa-esp32-elf\include\c++.4.0\bits\stl_vector.h:1090:7: note: conversion of argument 1 would be ill-formed:
src/main.cpp:117:27: error: invalid conversion from 'testClass*' to 'std::vector<int, PSallocator<int> >::value_type' {aka 'int'} [-fpermissive]
extRam.push_back( p );
^
*** [.pio\build\esp-wrover-kit\src\main.cpp.o] Error 1
我会回答我自己的问题。
如果可分配内存超过4k,新的arduino框架会将东西放在外部ram中。如果不是,它会把东西放入内部内存,但如果内部内存不足以分配,它会尝试从外部内存分配。