I am trying to create a vector in PSRAM on an ESP32-S3 with PSRAM enabled. Here is my test code (using std=gnu++14).
I can: allocate some PSRAM memory, create a vector in the PSRAM, create a test record and add it to the vector and confirm the size goes up, delete records from the start of the vector and confirm the size goes down
But I can't work out how to read the vector data, see block in the middle commented out.
struct EventRecord_t { // owned by MESH_ROOT
uint8_t node = 0;
uint8_t errorCount;
};
void eventsStart(){
void* eventsRam;
eventsRam = heap_caps_malloc(1000000, MALLOC_CAP_SPIRAM); // get memory from PSRAM
std::vector<EventRecord_t>* eventStack; // declare pointer to vector of struct
eventStack = (std::vector<EventRecord_t>*) eventsRam; // create vector in PSRAM
EventRecord_t eventRecord; // create record entry and populate it
eventRecord.node = 1;
eventRecord.errorCount = 34;
eventStack->push_back(eventRecord); // add record to eventstack
std::cout << "Size: " << eventStack->size() << std::endl; // confirm size is increasing
eventRecord.node = 2;
eventStack->push_back(eventRecord);
std::cout << "Size: " << eventStack->size() << std::endl;
eventRecord.node = 3;
eventStack->push_back(eventRecord);
std::cout << "Size: " << eventStack->size() << std::endl;
// how to access eventStack data here;
// eventRecord = eventStack[0];
// uint8_t inode = eventStack[0]->node;
eventStack->erase(eventStack->begin()); // delete first record from eventStack
std::cout << "Size: " << eventStack->size() << std::endl; // confirm size is increasing
eventStack->erase(eventStack->begin());
std::cout << "Size: " << eventStack->size() << std::endl;
eventStack->erase(eventStack->begin());
std::cout << "Size: " << eventStack->size() << std::endl;
free(eventsRam);
}
Output:
Size: 1
Size: 2
Size: 3
Size: 2
Size: 1
Size: 0
You need to write your own allocator
template <typename T>
class SPIRamAllocator {
public:
using value_type = T;
SPIRamAllocator() = default;
template <typename U>
constexpr SPIRamAllocator(const SPIRamAllocator<U>&) noexcept {}
[[nodiscard]] T* allocate(std::size_t n) {
// Allocate memory using heap_caps_malloc with MALLOC_CAP_SPIRAM
T* ptr = static_cast<T*>(heap_caps_malloc(n * sizeof(T), MALLOC_CAP_SPIRAM));
if (!ptr) {
/* do something */
}
return ptr;
}
void deallocate(T* ptr, std::size_t) noexcept {
// Free the allocated memory
heap_caps_free(ptr);
}
};
template <typename T, typename U>
bool operator==(const SPIRamAllocator<T>&, const SPIRamAllocator<U>&) {
return true;
}
template <typename T, typename U>
bool operator!=(const SPIRamAllocator<T>&, const SPIRamAllocator<U>&) {
return false;
}
and then you can use it:
std::vector<int, SpirAMAllocator<int>> vec;
std::vector<EventRecord_t, SpirAMAllocator<EventRecord_t>> vec;
This allocator is not too good, but it is just to show how to write them. You may want to provide max size for the vector, allocate in larger chunks or combine any other methods.