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

@@ -151,9 +151,9 @@ private:
unsigned char Enc_A_prev = 0;
bool currentEffectAndPaletteInitialized = false;
uint8_t effectCurrentIndex = 0;
uint16_t effectCurrentIndex = 0;
uint8_t effectPaletteIndex = 0;
uint8_t knownMode = 0;
uint16_t knownMode = 0;
uint8_t knownPalette = 0;
uint8_t currentCCT = 128;
@@ -339,9 +339,11 @@ void RotaryEncoderUIUsermod::sortModesAndPalettes() {
//modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
modes_qstrings = strip.getModeDataSrc();
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
if (!modes_alpha_indexes) return; // avoid nullptr crash when allocation has failed (OOM)
re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT);
palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount());
if (!palettes_qstrings) return; // avoid nullptr crash when allocation has failed (OOM)
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()); // only use internal palettes
// How many palette names start with '*' and should not be sorted?
@@ -352,9 +354,10 @@ void RotaryEncoderUIUsermod::sortModesAndPalettes() {
}
byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) {
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
for (byte i = 0; i < numModes; i++) {
indexes[i] = i;
byte* indexes = (byte *)p_calloc(numModes, sizeof(byte));
if (!indexes) return nullptr; // avoid OOM crash
for (uint16_t i = 0; i < numModes; i++) {
indexes[i] = min(i, uint16_t(255));
}
return indexes;
}
@@ -364,8 +367,10 @@ byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) {
* They don't end in '\0', they end in '"'.
*/
const char **RotaryEncoderUIUsermod::re_findModeStrings(const char json[], int numModes) {
const char **modeStrings = (const char **)malloc(sizeof(const char *) * numModes);
uint8_t modeIndex = 0;
const char** modeStrings = (const char **)p_calloc(numModes, sizeof(const char *));
if (!modeStrings) return nullptr; // avoid OOM crash
uint16_t modeIndex = 0;
bool insideQuotes = false;
// advance past the mark for markLineNum that may exist.
char singleJsonSymbol;
@@ -380,7 +385,7 @@ const char **RotaryEncoderUIUsermod::re_findModeStrings(const char json[], int n
insideQuotes = !insideQuotes;
if (insideQuotes) {
// We have a new mode or palette
modeStrings[modeIndex] = (char *)(json + i + 1);
if (modeIndex < numModes) modeStrings[modeIndex] = (char *)(json + i + 1); //WLEDMM prevent array bounds violation
}
break;
case '[':
@@ -630,7 +635,7 @@ void RotaryEncoderUIUsermod::displayNetworkInfo() {
void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() {
if (modes_alpha_indexes == nullptr) return; // WLEDMM bugfix
currentEffectAndPaletteInitialized = true;
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
for (uint16_t i = 0; i < strip.getModeCount(); i++) {
if (modes_alpha_indexes[i] == effectCurrent) {
effectCurrentIndex = i;
break;