fix(t5s3-epaper): 40MHz octal PSRAM; guard EInk init; esp32s3 sw-atomic shim (#11062)
- t5s3-epaper: the board's 3.3V octal (AP_3v3) PSRAM is unreliable at the qio_opi
default of 80MHz (Total PSRAM reads 0, display dead / boot-loop); clock it at 40MHz.
- EInkParallelDisplay: skip EInk init and no-op display ops when the PSRAM framebuffer
is unavailable, so the node boots headless instead of hard-faulting on a NULL buffer.
- src/platform/esp32: weak software __atomic_*_{1,2,4} so esp32s3 links on toolchains
(e.g. macOS) that lack the sized libcalls GCC emits under -mdisable-hardware-atomics.
This commit is contained in:
@@ -77,12 +77,13 @@ EInkParallelDisplay::~EInkParallelDisplay()
|
||||
bool EInkParallelDisplay::connect()
|
||||
{
|
||||
LOG_INFO("Do EPD init");
|
||||
int initRc = BBEP_SUCCESS;
|
||||
if (!epaper) {
|
||||
epaper = new FASTEPD;
|
||||
#if defined(T5_S3_EPAPER_PRO_V1)
|
||||
epaper->initPanel(BB_PANEL_LILYGO_T5PRO, 28000000);
|
||||
initRc = epaper->initPanel(BB_PANEL_LILYGO_T5PRO, 28000000);
|
||||
#elif defined(T5_S3_EPAPER_PRO_V2)
|
||||
epaper->initPanel(BB_PANEL_LILYGO_T5PRO_V2, 28000000);
|
||||
initRc = epaper->initPanel(BB_PANEL_LILYGO_T5PRO_V2, 28000000);
|
||||
// initialize all port 0 pins (0-7) as outputs / HIGH
|
||||
for (int i = 0; i < 8; i++) {
|
||||
epaper->ioPinMode(i, OUTPUT);
|
||||
@@ -93,6 +94,16 @@ bool EInkParallelDisplay::connect()
|
||||
#endif
|
||||
}
|
||||
|
||||
// FastEPD allocates its framebuffer only from PSRAM; if PSRAM init failed the alloc returns
|
||||
// NULL and initPanel() returns an error, so clearWhite() below would memset(NULL). Skip EInk
|
||||
// bring-up but return true so OLEDDisplay still allocates its base buffer (base draw ops stay
|
||||
// safe); displayReady stays false so the FastEPD push paths no-op -> node runs headless.
|
||||
if (initRc != BBEP_SUCCESS || epaper->currentBuffer() == nullptr) {
|
||||
LOG_ERROR("EPD framebuffer unavailable (initPanel rc=%d, PSRAM=%u); running headless", initRc,
|
||||
(unsigned)ESP.getPsramSize());
|
||||
return true;
|
||||
}
|
||||
|
||||
// epaper->setRotation(rotation); // does not work, messes up width/height
|
||||
epaper->setMode(BB_MODE_1BPP);
|
||||
epaper->clearWhite();
|
||||
@@ -103,6 +114,7 @@ bool EInkParallelDisplay::connect()
|
||||
resetGhostPixelTracking();
|
||||
#endif
|
||||
|
||||
displayReady = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -187,6 +199,9 @@ void EInkParallelDisplay::asyncFullUpdateTask(void *pvParameters)
|
||||
*/
|
||||
void EInkParallelDisplay::display(void)
|
||||
{
|
||||
if (!displayReady) // no framebuffer (PSRAM absent / init failed) -> nothing to push
|
||||
return;
|
||||
|
||||
const uint16_t w = this->displayWidth;
|
||||
const uint16_t h = this->displayHeight;
|
||||
|
||||
@@ -400,6 +415,9 @@ void EInkParallelDisplay::resetGhostPixelTracking()
|
||||
*/
|
||||
bool EInkParallelDisplay::forceDisplay(uint32_t msecLimit)
|
||||
{
|
||||
if (!displayReady)
|
||||
return false;
|
||||
|
||||
uint32_t now = millis();
|
||||
if (lastDrawMsec == 0 || (now - lastDrawMsec) > msecLimit) {
|
||||
display();
|
||||
@@ -410,6 +428,8 @@ bool EInkParallelDisplay::forceDisplay(uint32_t msecLimit)
|
||||
|
||||
void EInkParallelDisplay::endUpdate()
|
||||
{
|
||||
if (!displayReady)
|
||||
return;
|
||||
{
|
||||
// ensure any async full update is started/completed
|
||||
if (asyncFullRunning.load()) {
|
||||
|
||||
@@ -40,6 +40,9 @@ class EInkParallelDisplay : public OLEDDisplay
|
||||
uint32_t lastDrawMsec = 0;
|
||||
FASTEPD *epaper;
|
||||
|
||||
// Set only when connect() fully succeeds; framebuffer-touching methods no-op while false.
|
||||
bool displayReady = false;
|
||||
|
||||
private:
|
||||
// Async full-refresh support
|
||||
std::atomic<bool> asyncFullRunning{false};
|
||||
|
||||
Reference in New Issue
Block a user