How to use a Global Struct Array in psram esp32-wrover

I’m not sure if this is possible to do, but someone may know a solution.

I have a structured array:

struct Plot
  {
    float lng, lat;
  };
struct Plot roundplot[50000];

But this is too big for the internal memory.
So I was hoping to put this array in the PSRAM.

But this needs to be global so I can call a function and others that can access it like this for example:

void my_function()
{
  roundplot[roundplotIndex] = {longitude, latitude};
  roundplotIndex++;
}

I have seen this;

But I can’t get it working.

I’m using v1.0.6 and my “platformio.ini” is…

[env:esp-wrover-kit]
platform = espressif32@3.4.0
board = esp-wrover-kit
framework = arduino
build_flags = 
	-D_BSD_SOURCE
	-DBOARD_HAS_PSRAM
	-mfix-esp32-psram-cache-issue
upload_speed = 1500000
monitor_speed = 921600
lib_deps = 
	vshymanskyy/TinyGSM@^0.11.5
	knolleary/PubSubClient@^2.8
	bblanchon/ArduinoJson@^6.19.4
	adafruit/Adafruit GFX Library@^1.11.3
	adafruit/Adafruit SSD1306@^2.5.6

I assume I have to change some settings in a config file somewhere?

Any help would be appreciated.

1 Like

Well first of all, is PSRAM generally detected initialized correctly? Run a simple

#include <Arduino.h>

void setup() {
  log_d("Total heap: %d", ESP.getHeapSize());
  log_d("Free heap: %d", ESP.getFreeHeap());
  log_d("Total PSRAM: %d", ESP.getPsramSize());
  log_d("Free PSRAM: %d", ESP.getFreePsram());
}

void loop() {}

what does it output?

1 Like

Yes, I have this (I’m using flash FFS too):

FFS available memory:        1378241 bytes
FFS memory used:                9789 bytes
PSRAM size:                  4194252 bytes
PSRAM available memory:      4194252 bytes

I get this if I do this in setup():

Plot *roundplot = (Plot *)ps_malloc(128000 * sizeof(Plot));
Serial.printf("PSRAM available memory:     %8d bytes\n", ESP.getFreePsram());

PSRAM available memory:      3170236 bytes

So it looks like it’s allocating the psram memory usage.

Great, just change your global variable to be

struct Plot* roundplot;

in which you allocated then and it should be fine.

1 Like

Many thanks @maxgerhardt

I’ve stitched in the code as below to my project and is looking good, it compiles no errors or warnings and runs, the psram memory allocation looks correct too.

#include <Arduino.h>

struct Plot
{
  float lng, lat;
};
struct Plot* roundplot;

void setup() 
{
Serial.printf("PSRAM size:                 %8d bytes\n", ESP.getPsramSize());
Serial.printf("PSRAM available memory:     %8d bytes\n", ESP.getFreePsram());

roundplot = (Plot *)ps_malloc(128000 * sizeof(Plot));

Serial.printf("PSRAM available memory:     %8d bytes\n", ESP.getFreePsram());
}

void loop(){};
1 Like

Attribute to force static allocation in PSRAM is:

EXT_RAM_BSS_ATTR uint8_t Buffer[30000];

In IDF you have to enable a few SDK settings to get this to work. In Arduino the pre-compiled SDK does not have this enabled, you you have to use this:

__ attribute __((section(“.ext_ram.bss”))) uint8_t Buffer[30000]; // remove spaces around underline

Dynamic allocation in PSRAM is achieved by:

uint8_t *Buffer = nullptr;
Buffer = (uint8_t *) heap_caps_malloc(30000, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);

Alternatively, you can use:

ps_malloc // same as above, just cleaner + checks for PSRAM presence
ps_calloc // same as all above + initializes memory to zero

Verify where it is actually located:

printf(“Address: %p\n”, (void *)Buffer);

Can you name the settings please?
I would like to try this with pioarduino’s hybrid compile feature.

In Espressif32 Arduino a simple malloc > 4096 bytes will allocate from PSRAM automatically if PSRAM is available.

The threshold of 4096 bytes can be changed by calling heap_caps_malloc_extmem_enable(size_t limit);

1 Like

SDK setting is: CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY

You are correct that malloc will automatically decide on the memory location, however sometimes user should be able to decide what to do. In my case I have a static 3kB array that is rarely used and in a non time critical code. I wanted to place it in PSRAM exclusively, so there is more space for fast operations in an integrated RAM.

Thank you for the reply!

I’m utlizing pioarduino’s hybrid compile feature which allows to change SDK config via the platformio.ini. But just changing CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y leads to a crash on my ESP32-S3 DevKit C1 N16R8:

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x400570e8
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x1188
load:0x403c8700,len:0x4
load:0x403c8704,len:0xbf0
load:0x403cb700,len:0x30e4
entry 0x403c88ac
Guru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
Memory dump at 0x42006e0c: 08e0e666 03eb8000 89048d80
Core  1 register dump:
PC      : 0x42006e11  PS      : 0x00060034  A0      : 0x803768b4  A1      : 0x3fcec9e0  
A2      : 0x3fceca50  A3      : 0x00000000  A4      : 0x00000004  A5      : 0x3fc96eb0  
A6      : 0x00000001  A7      : 0x3fcec9ec  A8      : 0x00600000  A9      : 0x3fcec9c0  
A10     : 0x00000000  A11     : 0x3fc93cc0  A12     : 0x60020000  A13     : 0x00000002  
A14     : 0x7fffffff  A15     : 0x00000000  SAR     : 0x00000006  EXCCAUSE: 0x00000000  
EXCVADDR: 0x00000000  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0xffffffff  


Backtrace: 0x42006e0e:0x3fcec9e0 0x403768b1:0x3fceca30 0x40378034:0x3fceca50 0x42006d7d:0x3fcecb10 0x403768b1:0x3fcecb60 0x40378034:0x3fcecb80 0x3ffffffd:0x3fcecc40 |<-CORRUPTED
[env:esp32s3]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip
board = esp32-s3-devkitc-1
framework = arduino

board_build.arduino.memory_type = qio_opi
board_build.flash_mode = qio
board_build.psram_type = opi
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.extra_flags = 
  -DBOARD_HAS_PSRAM

custom_sdkconfig = 
  CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y

custom_component_remove =
    espressif/esp_hosted
    espressif/esp_wifi_remote
    espressif/esp-dsp
    espressif/esp32-camera
    espressif/libsodium
    espressif/esp-modbus
    espressif/qrcode
    espressif/esp_insights
    espressif/esp_diag_data_store
    espressif/esp_diagnostics
    espressif/esp_rainmaker
    espressif/rmaker_common

monitor_speed = 115200
#include <Arduino.h>

EXT_RAM_BSS_ATTR uint8_t buffer[4*1024*1024];

void setup() {
    Serial.begin(115200);
    Serial.printf("Free PSRAM: %d\r\n", ESP.getFreePsram());
    memset(buffer, 0, 4*1024*1024);
}

void loop() {}

Interesting. There must be something else behind, that causes crash.
I am using those lines of code without any issues on ESP32-S3:

__ attribute__((section(“.ext_ram.bss”))) uint8_t gBuffer[3000];
__ attribute__((section(“.ext_ram.bss”))) uint8_t GIFimage[100000]; // 100 kB, typ image is 50 kB

I’ll crosscheck this against an Arduino as ESP-IDF component project.

I don’t know why, but now it works :slight_smile:

Maybe I have forgotten a full clean in between my tests.

Using pioarduino’s platform-espressif32 with the settings shown in the platformio.ini above and
EXT_RAM_BSS_ATTR uint8_t buffer[4 * 1024 * 1024]; will reduce my available PSRAM by 4 MB as expected.

Nice to know - thanks again @aly-fly!

1 Like