Back button (new GPIO0, POST /frame/back): the server now tracks a bounded history of previously-current photos (photo_queue.py), pushed to on every advance (auto or forced) and popped by back_forced() -- symmetric with advance, so pressing next afterwards returns to right where you were. frame_client.c's force_advance bool becomes a 3-way fetch_action_t (NORMAL/ADVANCE/BACK) threaded through the whole fetch path. Also folds the separate reset and manage buttons onto one pin (combo_button.c, replacing reset_button.c/manage_button.c entirely), disambiguated by hold duration: quick press shows the management menu (unchanged), ~3s hold-then-release soft-resets (esp_restart(), config kept -- new), ~15s hold factory-resets (today's old reset behavior, extended from 10s for clearer tier separation). Driven by a production board (Seeed XIAO ESP32-C6) exposing only 3 of the ESP32-C6's 8 deep-sleep-wakeup-capable GPIOs -- next/back keep their own dedicated pins where instant response matters most, everything else shares the third pin via timing instead of needing its own. Same three-pin layout now works on both the dev board and the production board. Fixed a fast-tap bug in combo_button_check() before shipping: it only did a live gpio_get_level() read to decide whether the button was pressed at all, so a press fast enough to already be released by the time boot reached that check was missed entirely (treated as "never pressed" rather than "quick press"). Added the same latched esp_sleep_get_gpio_wakeup_status() check the other buttons already use for exactly this reason.
4.0 KiB
Hardware
Parts
- An ESP32-C6 dev board (e.g. ESP32-C6-DevKitC-1). Needs 8MB flash --
see
firmware/sdkconfig.defaultsandfirmware/partitions.csvif yours differs. - Waveshare 7.3" E Ink Spectra 6 (E6) panel -- 800x480, 6-color, SPI.
- A USB cable for flashing/power.
Wiring
The panel connects over SPI plus three control lines (data/command, reset,
busy). Defaults below match the reference build and are set in
firmware/components/epd7in3e/Kconfig --
override via idf.py menuconfig under E-Paper Display (epd7in3e)
Configuration if your wiring differs.
| Panel pin | ESP32-C6 GPIO | Kconfig option |
|---|---|---|
| CLK | 20 | EPD_PIN_CLK |
| DIN | 19 | EPD_PIN_MOSI |
| CS | 18 | EPD_PIN_CS |
| DC | 9 | EPD_PIN_DC |
| RST | 10 | EPD_PIN_RST |
| BUSY | 11 | EPD_PIN_BUSY |
| VCC | 3.3V | -- |
| GND | GND | -- |
Optionally, three buttons, all wired the same way -- momentary push button between the GPIO and GND, no external resistor needed (the firmware enables each pin's internal pull-up, so it idles high and reads low when pressed):
- Next photo (GPIO2): a normal press skips immediately to the next
photo; see
firmware/README.md. - Back photo (GPIO0): a normal press returns to the previously-shown
photo; see
firmware/README.md. - Menu / reset (GPIO1): one button, three actions by hold duration --
a quick press overlays a "scan to manage" QR code on the current photo
for 30 seconds; holding ~3s then releasing soft-resets the device
(config kept); holding ~15s factory-resets it (clears WiFi/server
config, reprovisions); see
firmware/README.md.
All three pins were picked because they're within GPIO 0-7 -- the only
pins the ESP32-C6 can wake from deep sleep on -- aren't strapping pins,
and aren't already used by the panel wiring above. Also, not
incidentally, GPIO 0-7 is all the deep-sleep-wakeup-capable pins this
chip has (SOC_RTCIO_PIN_COUNT is 8) -- worth knowing if you're
targeting a compact board like the Seeed XIAO ESP32-C6, which only
breaks out 3 of them (GPIO0/1/2). These three buttons were deliberately
designed to fit exactly that budget: two dedicated pins for the
actions where instant, unambiguous response matters most (next, back),
and everything else folded onto the third pin via hold duration instead
of needing its own pin.
A couple of things worth knowing if you pick different pins:
- Avoid the ESP32-C6's strapping pins (GPIO 4, 5, 8, 9, 15) and the USB-JTAG pins (12, 13) where possible -- strapping pins are sampled at reset to select boot mode. The reference wiring above already uses GPIO9 for DC, which is a strapping pin; it's only sampled during power-on/reset, so it's safe once the app is running, but if flashing/boot ever misbehaves on your board, check whether the panel is pulling that line low during reset.
- The panel's SPI interface is rated well above the firmware's default
4MHz clock (
EPD_SPI_CLOCK_HZ), but breadboard/dupont-wire connections are often unreliable much past a few MHz. Raise it once your physical wiring is confirmed solid.
Power
The device spends nearly all its time in deep sleep, waking briefly once an hour (configurable, see the server's web UI) to fetch and display a photo. A full-color refresh on this panel takes 15-30+ seconds and draws more current than deep sleep by a wide margin -- expect battery life (if not running from USB power) to be dominated by refresh frequency, not sleep current.