Arduinojson: Custom allocator (e.g., ESP32 WROVER External RAM)

Created on 26 Dec 2018  路  7Comments  路  Source: bblanchon/ArduinoJson

First of all, this library is awesome! I am developing an Arduino ESP32 project using the WROVER module. The WROVER chip (https://www.adafruit.com/product/3384) supports external RAM (up to 4MB), and I'd like to use DynamicJsonBuffer to allocate memory to the external RAM module. I'm making calls to a JSON backend that returns large(ish) JSON responses, and ideally, I would like to reserve internal RAM for ESP32 core functions.

You can specify the memory strategy on the ESP32 for malloc calls to potentially use external RAM; however, the compiled ESP32 arduino core requires explicit allocation to external memory. I've created a custom allocator that uses the heap_caps_malloc(..., MALLOC_CAP_SPIRAM) call; however, I don't think I can specify how to allocate the DynamicJsonBuffer internal allocations.

I know it's very platform specific, but 1) Is there a way to configure ArduinoJson to support ESP32 external allocation? 2) If not, it'd be great to have a way to do that :)

enhancement

Most helpful comment

Got it!
I'll leave this issue opened as a reminder.

All 7 comments

Hi @czuvich,

Yes, in ArduinoJson v5, you can replace the allocator of DynamicJsonBuffer.

Here is the definition of DynamicJsonBuffer:

typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator> DynamicJsonBuffer;

As you can see, it's a typedef of a template class named DynamicJsonBufferBase that take an allocator class as a parameter. Here is the definition of DefaultAllocator:

class DefaultAllocator {
 public:
  void* allocate(size_t size) {
    return malloc(size);
  }
  void deallocate(void* pointer) {
    free(pointer);
  }
};

To use the external memory, we need to substitute this class with one that uses the right functions. If I understand correctly, it should be something like that:

class SpiRamAllocator {
 public:
  void* allocate(size_t size) {
    return heap_caps_malloc(size, MALLOC_CAP_SPIRAM);
  }
  void deallocate(void* pointer) {
    heap_caps_free(pointer);
  }
};

typedef ArduinoJson::Internals::DynamicJsonBufferBase<SpiRamAllocator> SpiRamJsonBuffer;

I'd be very interested in knowing if it works, so please keep me informed.

It's currently not possible to do something like that with ArduinoJson version 6. However, if you confirm that it's useful, I can add something similar.

Thank you very much for this excellent question.

Regards,
Benoit

@bblanchon The solution worked flawlessly! Thank you for the detailed response! I have some fallback code in the allocator just in case SPI ram allocation failed (in case you're interested), and you can just call free(p) instead of the explicit heap_caps_free(p) in IDF.

void* ret = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM);
  if (ret)
    return ret;
  else
    return malloc(sz);

It would be great to see this capability in ArduinoJson v6.

One of the biggest complaints with the ESP32 SDK is running the BLE and WiFi stacks are very heap intense. As you probably know, serialization and deserialization are intense operations. If we have the capability to leverage external memory on the ESP32 with ArduinoJson, I think that would be a huge help.

Hi @czuvich,

Thank you very much for the feedback.
I'll add something similar in version 6.

If we have the capability to leverage external memory on the ESP32 with ArduinoJson, I think that would be a huge help.

I'm puzzled by this sentence. Do you expect more from me than adding the customizable allocator in v6?

Regards,
Benoit

The customizable allocator is perfect.

Got it!
I'll leave this issue opened as a reminder.

oh my... i searched for custom allocator and didn't find it. oops...

I just added BasicJsonDocument in the 6.x branch.
You can use it like that:

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

using SpiRamJsonDocument = BasicJsonDocument<SpiRamAllocator>;

It will be available in 6.10.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zixzixzix picture zixzixzix  路  5Comments

HilalAH picture HilalAH  路  3Comments

ghost picture ghost  路  7Comments

ligantx picture ligantx  路  4Comments

nickels picture nickels  路  4Comments