diff --git a/src/operation.h b/src/operation.h index 7104bf4..e193760 100644 --- a/src/operation.h +++ b/src/operation.h @@ -9,9 +9,11 @@ // The test build adds test/mocks to the include path via -iquote. #include "epd_mock.h" #include "esp_sleep.h" +#include "driver/gpio.h" #else #include "epd.h" #include +#include #include #endif @@ -354,6 +356,12 @@ void normal_operation_impl(const String& mac, HTTP& http, const String& url, Pre // false → normal_operation_impl runs → the next poll fetches a fresh // image, which doubles as a "force refresh" gesture. esp_sleep_enable_ext0_wakeup((gpio_num_t)PIN_BTN_RESET, 0); + // Latch any gpio_hold_en pins through the deep sleep period. + // epd_sleep() cuts PIN_PWR LOW + holds it; without this call the + // hold releases on the RTC transition and the panel rail comes back + // up, losing the saving. Released per-pin in epd_setup_pins() on + // wake via gpio_hold_dis(). + gpio_deep_sleep_hold_en(); esp_deep_sleep_start(); } diff --git a/src/panels/waveshare13e6/v1/epd_driver.cpp b/src/panels/waveshare13e6/v1/epd_driver.cpp index 0e203e8..1a1af16 100644 --- a/src/panels/waveshare13e6/v1/epd_driver.cpp +++ b/src/panels/waveshare13e6/v1/epd_driver.cpp @@ -24,6 +24,7 @@ #include #include #include +#include static constexpr uint16_t W = 1200; static constexpr uint16_t H = 1600; @@ -103,6 +104,12 @@ static void panel_reset() { } void epd_setup_pins() { + // Release the PIN_PWR hold latched from the previous deep sleep so we + // can drive it again. No-op on cold boot (nothing was held). Paired + // with gpio_hold_en() in epd_sleep() and gpio_deep_sleep_hold_en() in + // operation.h. + gpio_hold_dis((gpio_num_t)PIN_PWR); + pinMode(PIN_PWR, OUTPUT); pinMode(PIN_RST, OUTPUT); pinMode(PIN_DC, OUTPUT); @@ -191,6 +198,16 @@ void epd_sleep() { SPI.transfer(0xA5); // sentinel cs_both(HIGH); s_initialized = false; + + // Cut the panel power rail. The Waveshare board exposes PIN_PWR + // specifically for battery operation — the e-ink image persists + // without VDD (particles are bistable), and dropping the rail kills + // the boost converter's quiescent draw (~50–500 µA depending on the + // load on the rail). Latch LOW so it survives deep sleep; paired with + // gpio_deep_sleep_hold_en() in operation.h just before the chip + // enters sleep. + digitalWrite(PIN_PWR, LOW); + gpio_hold_en((gpio_num_t)PIN_PWR); } // ── Draw helpers ─────────────────────────────────────────────────────────────── diff --git a/test/mocks/driver/gpio.h b/test/mocks/driver/gpio.h new file mode 100644 index 0000000..363d368 --- /dev/null +++ b/test/mocks/driver/gpio.h @@ -0,0 +1,11 @@ +#pragma once +// Native-test stubs for gpio_hold_* — operation.h calls +// gpio_deep_sleep_hold_en() before esp_deep_sleep_start() to latch +// PIN_PWR LOW through deep sleep. epd_driver.cpp (not built natively) +// also uses gpio_hold_en / gpio_hold_dis. Stubs let tests link. +#include "esp_sleep.h" // for gpio_num_t + +inline void gpio_hold_en(gpio_num_t) {} +inline void gpio_hold_dis(gpio_num_t) {} +inline void gpio_deep_sleep_hold_en() {} +inline void gpio_deep_sleep_hold_dis() {}