From edc877ac0a1a6f8dcbeb25d5b55c858fdc35d49e Mon Sep 17 00:00:00 2001 From: Riker Date: Wed, 29 Apr 2026 16:16:28 +0800 Subject: [PATCH 1/2] Restore global font namespace access The previous change to namespace alias broke direct font calls in user scripts. Reverting to ensure users don't need to manually update their font references. --- src/lgfx/v1/lgfx_fonts.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lgfx/v1/lgfx_fonts.hpp b/src/lgfx/v1/lgfx_fonts.hpp index dbd2075..8d80552 100644 --- a/src/lgfx/v1/lgfx_fonts.hpp +++ b/src/lgfx/v1/lgfx_fonts.hpp @@ -613,7 +613,11 @@ namespace lgfx } } -namespace fonts = lgfx::v1::fonts; +namespace fonts +{ + using namespace lgfx::v1::fonts; +} +using namespace fonts; #ifndef _GFXFONT_H_ #define _GFXFONT_H_ From c71573a789a42fcfd30e63efdfcebc0dcf24cee4 Mon Sep 17 00:00:00 2001 From: Zac Anderson Date: Mon, 6 Jul 2026 11:55:13 +0100 Subject: [PATCH 2/2] fix(amoled): guard null DMA buffer in framebuffer flush Panel_AMOLED_Framebuffer::display() guards a null _frame_buffer but not the per-line DMA buffers from getDMABuffer(), which return nullptr when the DMA-capable internal heap is transiently exhausted. The subsequent memcpy into a null pointer faults (StoreProhibited). Skip the flush and leave the dirty range intact so the next display() retries once memory frees. A new per-instance _dma_oom flag edge-logs the condition (ESP_LOGW) and its recovery (ESP_LOGI) without per-frame spam. Reproduced and fixed on an M5Stack StopWatch (466x466 CO5300): under memory pressure the small per-line alloc fails while a full-screen buffer is cached, and any transient (e.g. a TLS reconnect) tips it over. Co-Authored-By: Claude Opus 4.8 --- src/lgfx/v1/panel/Panel_AMOLED.cpp | 25 +++++++++++++++++++++++++ src/lgfx/v1/panel/Panel_AMOLED.hpp | 1 + 2 files changed, 26 insertions(+) diff --git a/src/lgfx/v1/panel/Panel_AMOLED.cpp b/src/lgfx/v1/panel/Panel_AMOLED.cpp index 7aed8b9..3d402b1 100644 --- a/src/lgfx/v1/panel/Panel_AMOLED.cpp +++ b/src/lgfx/v1/panel/Panel_AMOLED.cpp @@ -685,6 +685,31 @@ namespace lgfx buf[0] = bus->getDMABuffer(wb); buf[1] = bus->getDMABuffer(wb); + // getDMABuffer() returns nullptr when the DMA-capable internal heap + // cannot satisfy the per-line buffer (transient starvation under + // memory pressure). Skip this flush rather than memcpy into a null + // pointer; _range_mod stays dirty so the next display() retries once + // memory frees. Without this a null buffer faults (StoreProhibited). + // Log only the OOM edge and the recovery edge, not every frame. + if (!buf[0] || !buf[1]) + { + if (!_dma_oom) + { + _dma_oom = true; +#if defined ( ESP_LOGW ) + ESP_LOGW("Panel_AMOLED", "DMA buffer alloc failed (%u bytes/line); deferring flush", (unsigned)wb); +#endif + } + return; + } + if (_dma_oom) + { + _dma_oom = false; +#if defined ( ESP_LOGI ) + ESP_LOGI("Panel_AMOLED", "DMA buffer available; resuming flush"); +#endif + } + _panel->start_qspi(); int fbpos = ys * stride + (xs * bpp); diff --git a/src/lgfx/v1/panel/Panel_AMOLED.hpp b/src/lgfx/v1/panel/Panel_AMOLED.hpp index 807fe08..8ebe56b 100644 --- a/src/lgfx/v1/panel/Panel_AMOLED.hpp +++ b/src/lgfx/v1/panel/Panel_AMOLED.hpp @@ -55,6 +55,7 @@ namespace lgfx protected: uint8_t* _frame_buffer = nullptr; Panel_AMOLED* _panel = nullptr; + bool _dma_oom = false; // edge state: DMA line-buffer alloc failing };