简体   繁体   中英

ESP32 Arduino allocate and use array of structs in PSRAM

I have a struct like this:

typedef struct {
    boolean isExists = false;

    uint16_t readBuffer[32]     = {0};
    uint16_t writeBuffer[13]    = {0};
    uint16_t ledBrgBuff[9]      = {0};

    uint16_t address    = 0x0000;
    uint16_t id         = 0x0000;
    uint16_t serial     = 0x0000;
    String   kind       = "RESERVED";
    String   name       = "RESERVED";

    uint16_t readNum        = 21;
    uint16_t writeNum       = 2;

    byte read_failCounter   = 0;
    byte write_failCounter  = 0;
    byte allowedFails       = 10;

    long lastWriteFailMSG   = 0;
    long lastReadFailMSG    = 0;
    boolean isTesting       = false;
    boolean criticalOff     = false;
    boolean onFault         = false;
    uint8_t data[RESPONSE_COUNT];
} expStruct;

I was using a dynamically allocated array of struct from ram before like this:

expStruct * expanders[MAX_EXPANDER] EXT_RAM_ATTR; // Globally
    
void fillStructsTest(){
    // Fill all the array of structs with data from a json string from the filesystem
    JsonArray hwConf = doc.as<JsonArray>();

    memset(expanders, 0, sizeof(expanders)); // here I null all the struct in the array

    for(byte i = 0; i < hwConf.size(); i ++){
      JsonObject module = hwConf[i];
      expanders[expCounter]            = new expStruct;
      expanders[expCounter]->address   = module["address"].as<uint16_t>();
      expanders[expCounter]->id        = module["moduleid"].as<uint16_t>();
      expanders[expCounter]->serial    = module["serialnr"].as<uint16_t>();
      expanders[expCounter]->kind      = module["kind"].as<String>();
      expanders[expCounter]->name      = module["name"].as<String>();
      expCounter++;
    }
}

That worked pretty well. I could use my array of structs like this:

void useStructTest(){
  if( expanders[0] != 0 ){
    expanders[0]->name = "Test";
    // I can reach every variable inside any of the structs in the array if the value on the index 
    // is not 0
  }
}

Now I want to place this array of structs into PSRAM on my esp32. I approached it like this:

typedef struct {
    boolean isExists = false;

    uint16_t readBuffer[32]     = {0};
    uint16_t writeBuffer[13]    = {0};
    uint16_t ledBrgBuff[9]      = {0};

    uint16_t address    = 0x0000;
    uint16_t id         = 0x0000;
    uint16_t serial     = 0x0000;
    String   kind       = "RESERVED";
    String   name       = "RESERVED";

    uint16_t readNum        = 21;
    uint16_t writeNum       = 2;

    byte read_failCounter   = 0;
    byte write_failCounter  = 0;
    byte allowedFails       = 10;

    long lastWriteFailMSG   = 0;
    long lastReadFailMSG    = 0;
    boolean isTesting       = false;
    boolean criticalOff     = false;
    boolean onFault         = false;
    uint8_t data[RESPONSE_COUNT];
} expStruct;
expStruct *expanders = (expStruct *) ps_malloc(MAX_EXPANDER * sizeof(expStruct));


void fill_PSRAM_StructsTest(){
        // Fill all the array of structs with data from a json string from the filesystem
        JsonArray hwConf = doc.as<JsonArray>();
    
        // memset(expanders, 0, sizeof(expanders)); // I can't do this now
    
        for(byte i = 0; i < hwConf.size(); i ++){
          JsonObject module = hwConf[i];
          // expanders[expCounter]            = new expStruct; // I can't do this now either.
          // also I must replace the -> with . because the compiler erroring me
          expanders[expCounter].address   = module["address"].as<uint16_t>();
          expanders[expCounter].id        = module["moduleid"].as<uint16_t>();
          expanders[expCounter].serial    = module["serialnr"].as<uint16_t>();
          expanders[expCounter].kind      = module["kind"].as<String>();
          expanders[expCounter].name      = module["name"].as<String>();
          expCounter++;
        }
}

Somewhere here my ESP crashing without a meaningful serial output, which is this:

Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x400ec9a7  PS      : 0x00060630  A0      : 0x80090915  A1      : 0x3ffdaee0
A2      : 0x00000000  A3      : 0x3f80afdc  A4      : 0x00000000  A5      : 0x3ffc25fc
A6      : 0x00000000  A7      : 0x3ffdaf64  A8      : 0x800ec9a2  A9      : 0x3ffdaeb0
A10     : 0x00000001  A11     : 0x3f40203a  A12     : 0x3ffdafd0  A13     : 0xf655c6f4
A14     : 0x3ffdadc0  A15     : 0x00000005  SAR     : 0x00000010  EXCCAUSE: 0x0000001d
EXCVADDR: 0x0000006e  LBEG    : 0x4008d6b1  LEND    : 0x4008d6c1  LCOUNT  : 0xfffffff7

ELF file SHA256: 0000000000000000

Backtrace: 0x400ec9a7:0x3ffdaee0 0x40090912:0x3ffdb000
  #0  0x400ec9a7:0x3ffdaee0 in mbusTask(void*) at lib/modbus-esp8266-3.0.6/src/Modbus.h:238
      (inlined by) mbusTask(void*) at src/Own_Headers/busCommunication.h:559
  #1  0x40090912:0x3ffdb000 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)

Rebooting...
ets Jul 29 2019 12:21:46

Should I allocate every index again in a function or what should I do to use it normally like before?

sorry for my english, you can't use String in PSRAM (dynamic)

you use: char name[100]; no String !!!

and... copy from JSON to stuct:-)

strcpy(expanders[expCounter].name, module["name"].as < string > ().c_str());

To move a ArduinoJsonDocument into PSRAM one needs to do it like so:

struct SpiRamAllocator {
  void* allocate(size_t size) {
    return heap_caps_malloc(size, MALLOC_CAP_SPIRAM);
  }

  void deallocate(void* pointer) {
    heap_caps_free(pointer);
  }

  void* reallocate(void* ptr, size_t new_size) {
    return heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM);
  }
};

using SpiRamJsonDocument = BasicJsonDocument<SpiRamAllocator>;

see here for a more detailed info.


To move any variable into PSRAM memory space one needs to declare it as below for the case of a uint16_t :

uint16_t* p_buffer_a = (uint16_t*) heap_caps_malloc(307200, MALLOC_CAP_SPIRAM );

where 307200 is the uint16_t byte size memory allocation to that specific variable p_buffer_a . The maximum element size for this array can be determined like this:

sizeof(p_buffer_a)/sizeof(uint16_t)

Mind you if one needs / wants to use Strings, it needs to rebuild the String class to accommodate PSRAM memory allocation.


Another way to move variable data into PSRAM is by wrapping it in a typedef struct .To allocate a buffer dynamically at runtime like the one below, one can declare it as follows:

typedef struct{
  int len;
  uint8_t buff[INTERRUPT_BUFFER_SIZE];
} Buffer;

this particular one stores a variable array named buff with element size of INTERRUPT_BUFFER_SIZE . Next is needs to declare a variable name that is stored directly into PSRAM:

Buffer *bufferA = (*Buffer)  heap_caps_malloc( sizeof(Buffer), MALLOC_CAP_SPIRAM );

Followed by its initialization in the setup function

//setup() initialization
void setup(){
bufferA = new Buffer();
...
}

Its usage through the code is made this way " bufferA->field " instead of the regular traditional way " bufferA.field ".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM