Compare commits

...

4 Commits

Author SHA1 Message Date
football2801 fc1367fc55 chore(13e6): bump PANEL_FW_VERSION to v1.0.1
First post-v1.0 driver release. Power-monitor telemetry from d900083
has been reverted (28b6a35) — clean release with no debug headers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:28:58 -04:00
football2801 28b6a353aa Revert "chore(13e6): TEMP power-monitor telemetry headers"
This reverts commit d900083398.
2026-05-15 20:28:22 -04:00
football2801 d900083398 chore(13e6): TEMP power-monitor telemetry headers
To validate the PIN_PWR rail-cut change (e2c9d8f) without a bench
multimeter, have the device report its previous cycle's awake time
and panel-init time on each poll:

  X-Prev-Awake-Ms       — millis() at the moment esp_deep_sleep_start
                          armed, last cycle. Total awake duration
                          since reset, ~5–10 s steady-state.
  X-Prev-Panel-Init-Ms  — duration of epd_init() last cycle. Spikes
                          here would suggest the rail isn't coming
                          back up cleanly after the GPIO-hold release.

Headers are sent only when the cached NVS values are non-zero (skips
the first boot under this firmware). All call sites marked `// TEMP:
power-monitor` for clean removal once the change is validated. Two
new NVS keys (tm_awk, tm_pin) sit alongside the existing ones; mock
Preferences extended with getUInt/putUInt to match.

Server side logs the headers via `device.poll.power_telemetry`
(separate commit in pictureFrame-webApp).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 14:15:37 -04:00
football2801 e2c9d8f1e4 feat(13e6): cut panel power rail in deep sleep via PIN_PWR + GPIO hold
The Waveshare board exposes PIN_PWR (GPIO 1) specifically so battery
designs can gate the panel rail between refreshes. Before this commit
PIN_PWR was driven HIGH at boot and never released, so the panel's
boost converter kept its quiescent draw (50–500 µA) through every
deep sleep. The e-ink particles are bistable so the displayed image
persists without VDD; dropping the rail is a free win.

Three pieces:
  • epd_sleep() drives PIN_PWR LOW after issuing the panel-internal
    DEEP_SLEEP command, then gpio_hold_en() latches the level so it
    survives the chip's RTC transition.
  • normal_operation_impl() calls gpio_deep_sleep_hold_en() just
    before esp_deep_sleep_start() so the per-pin hold extends through
    the deep sleep period itself (without this the holds release on
    the transition and the rail comes back up).
  • epd_setup_pins() calls gpio_hold_dis() at the very top to free
    PIN_PWR on wake before re-driving it HIGH; no-op on cold boot.

Tests: 47/47 pass. Added test/mocks/driver/gpio.h with no-op stubs so
the native test build links cleanly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 14:05:24 -04:00
4 changed files with 37 additions and 1 deletions
+8
View File
@@ -9,9 +9,11 @@
// The test build adds test/mocks to the include path via -iquote. // The test build adds test/mocks to the include path via -iquote.
#include "epd_mock.h" #include "epd_mock.h"
#include "esp_sleep.h" #include "esp_sleep.h"
#include "driver/gpio.h"
#else #else
#include "epd.h" #include "epd.h"
#include <esp_sleep.h> #include <esp_sleep.h>
#include <driver/gpio.h>
#include <mbedtls/sha256.h> #include <mbedtls/sha256.h>
#endif #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 // false → normal_operation_impl runs → the next poll fetches a fresh
// image, which doubles as a "force refresh" gesture. // image, which doubles as a "force refresh" gesture.
esp_sleep_enable_ext0_wakeup((gpio_num_t)PIN_BTN_RESET, 0); 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(); esp_deep_sleep_start();
} }
@@ -24,6 +24,7 @@
#include <qrcode.h> #include <qrcode.h>
#include <esp_task_wdt.h> #include <esp_task_wdt.h>
#include <esp_heap_caps.h> #include <esp_heap_caps.h>
#include <driver/gpio.h>
static constexpr uint16_t W = 1200; static constexpr uint16_t W = 1200;
static constexpr uint16_t H = 1600; static constexpr uint16_t H = 1600;
@@ -103,6 +104,12 @@ static void panel_reset() {
} }
void epd_setup_pins() { 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_PWR, OUTPUT);
pinMode(PIN_RST, OUTPUT); pinMode(PIN_RST, OUTPUT);
pinMode(PIN_DC, OUTPUT); pinMode(PIN_DC, OUTPUT);
@@ -191,6 +198,16 @@ void epd_sleep() {
SPI.transfer(0xA5); // sentinel SPI.transfer(0xA5); // sentinel
cs_both(HIGH); cs_both(HIGH);
s_initialized = false; 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 (~50500 µ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 ─────────────────────────────────────────────────────────────── // ── Draw helpers ───────────────────────────────────────────────────────────────
+1 -1
View File
@@ -3,4 +3,4 @@
// Panel-specific firmware version for the Waveshare 13.3" Spectra-6 driver. // Panel-specific firmware version for the Waveshare 13.3" Spectra-6 driver.
// Bump on each driver change worth correlating with server-side reports. // Bump on each driver change worth correlating with server-side reports.
// Independent of the shared firmware version (HTTP / NVS / sleep / etc.). // Independent of the shared firmware version (HTTP / NVS / sleep / etc.).
#define PANEL_FW_VERSION "v1.0" #define PANEL_FW_VERSION "v1.0.1"
+11
View File
@@ -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() {}