(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);
}

我的设置:

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中。如果不是,它会把东西放入内部内存,但如果内部内存不足以分配,它会尝试从外部内存分配。