psram-aware malloc functions (backport of upstream #4895) (#342)

Introduces new memory allocation functions, based on wled#4895 by @DedeHai

* keep a minimum of 15KB RAM available to UI - improves stability
* S3/S2/C3 automatically use "fast RTC Ram" for small data (reduces fragmentation)
* auto-detects PSRAM (or no PSRAM) when firmware was built with -D BOARD_HAS_PSRAM
* d_malloc() and d_calloc() prefer DRAM if possible (faster), but fall back to PSRAM when free RAM gets low.
This commit is contained in:
Frank Möhle
2026-02-18 17:57:47 +01:00
committed by GitHub
parent 50bb4d2910
commit cce3c0b5d3
19 changed files with 696 additions and 191 deletions

View File

@@ -57,6 +57,8 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte
#define DEBUGOUT Serial
#endif
#include "util.h"
#ifdef WLED_DEBUG
#ifndef ESP8266
#include <rom/rtc.h>
@@ -502,7 +504,7 @@ BusNetwork::BusNetwork(BusConfig &bc, const ColorOrderMap &com) : Bus(bc.type, b
}
_UDPchannels = _rgbw ? 4 : 3;
#ifdef ESP32
_data = (byte*) heap_caps_calloc_prefer((bc.count * _UDPchannels)+15, sizeof(byte), 3, MALLOC_CAP_DEFAULT, MALLOC_CAP_SPIRAM);
_data = (byte*) heap_caps_calloc_prefer((bc.count * _UDPchannels)+15, sizeof(byte), 3, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT, MALLOC_CAP_DEFAULT|MALLOC_CAP_8BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#else
_data = (byte*) calloc((bc.count * _UDPchannels)+15, sizeof(byte));
#endif
@@ -592,7 +594,11 @@ uint8_t BusNetwork::getPins(uint8_t* pinArray) const {
void BusNetwork::cleanup() {
_type = I_NONE;
_valid = false;
if (_data != nullptr) free(_data);
#ifdef ESP32
if (_data != nullptr) heap_caps_free(_data);
#else
if (_data != nullptr) free(_data);
#endif
_data = nullptr;
_len = 0;
}
@@ -935,7 +941,8 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
USER_PRINTF("\tLAT = %2d, OE = %2d, CLK = %2d\n\n", mxconfig.gpio.lat, mxconfig.gpio.oe, mxconfig.gpio.clk);
USER_FLUSH();
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); lastHeap = ESP.getFreeHeap();
lastHeap = ESP.getFreeHeap();
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(lastHeap);
// check if we can re-use the existing display driver
if (activeDisplay) {
@@ -1030,20 +1037,16 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
display->clearScreen(); // initially clear the screen buffer
USER_PRINTLN("MatrixPanel_I2S_DMA clear ok");
if (_ledBuffer) free(_ledBuffer); // should not happen
if (_ledsDirty) free(_ledsDirty); // should not happen
if (_ledBuffer) p_free(_ledBuffer); // should not happen
if (_ledsDirty) d_free(_ledsDirty); // should not happen
_ledsDirty = (byte*) malloc(getBitArrayBytes(_len)); // create LEDs dirty bits
_ledsDirty = (byte*) d_malloc(getBitArrayBytes(_len)); // create LEDs dirty bits
if (_ledsDirty) setBitArray(_ledsDirty, _len, false); // reset dirty bits
#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_SPIRAM_MODE_OCT && defined(BOARD_HAS_PSRAM) && (defined(WLED_USE_PSRAM) || defined(WLED_USE_PSRAM_JSON))
if (psramFound()) {
_ledBuffer = (CRGB*) ps_calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
} else {
_ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
}
#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_SPIRAM_MODE_OCT && defined(BOARD_HAS_PSRAM)
_ledBuffer = (CRGB*) p_calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
#else
_ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
_ledBuffer = (CRGB*) d_calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
#endif
}
@@ -1227,8 +1230,8 @@ void BusHub75Matrix::cleanup() {
#endif
if (instanceCount > 0) instanceCount--;
if (_ledBuffer != nullptr) free(_ledBuffer); _ledBuffer = nullptr;
if (_ledsDirty != nullptr) free(_ledsDirty); _ledsDirty = nullptr;
if (_ledBuffer != nullptr) p_free(_ledBuffer); _ledBuffer = nullptr;
if (_ledsDirty != nullptr) d_free(_ledsDirty); _ledsDirty = nullptr;
}
void BusHub75Matrix::deallocatePins() {