Build and push server image / build-and-push (push) Successful in 36s
- version.txt + esp_app_desc_t version reporting (X-Frame-Version header); new ota_update.c checks the server's advertised version against the running one and streams+applies an update via esp_https_ota, gated by bootloader rollback (marks the image valid only after a full successful cycle, so a bad update can't brick a wall-mounted frame). - Dual-OTA partition tables: partitions.csv (8MB dev board, 2MB slots) and new partitions_xiao.csv (4MB XIAO, 1.875MB slots -- the dev board's table doesn't fit the XIAO's flash). New build_for_board.sh gives each board its own build dir + generated sdkconfig via SDKCONFIG_DEFAULTS layering, so switching boards never clobbers the other's config. - fetch_photo_info()/fetch_face_labels() were using the short reachability-check timeout even though the manage-menu path can be the first (cold, TLS-handshake-paying) request of a wake cycle -- switched to the longer fetch timeout to stop spurious ESP_ERR_HTTP_CONNECT failures. - XIAO: the RF switch that selects onboard vs. external antenna (GPIO3/14) isn't initialized by plain ESP-IDF the way Seeed's Arduino package does it, leaving WiFi unable to reliably reach the antenna at all -- new board_antenna.c powers the switch and selects the onboard antenna, gated behind FRAME_XIAO_ANTENNA_INIT (on by default in sdkconfig.xiao). Also remaps the EPD DC/RST/BUSY pins, since the dev board's defaults (GPIO9/10/11) aren't physically exposed on the XIAO.
143 lines
7.1 KiB
Markdown
143 lines
7.1 KiB
Markdown
# Hardware
|
|
|
|
## Parts
|
|
|
|
- An ESP32-C6 dev board (e.g. ESP32-C6-DevKitC-1). Needs 8MB flash --
|
|
see [`firmware/sdkconfig.defaults`](../firmware/sdkconfig.defaults) and
|
|
[`firmware/partitions.csv`](../firmware/partitions.csv) if yours differs.
|
|
- [Waveshare 7.3" E Ink Spectra 6 (E6) panel](https://www.waveshare.com/7.3inch-e-paper-hat-e.htm) --
|
|
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`](../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`](../firmware/README.md#skipping-to-the-next-photo).
|
|
- **Back photo (GPIO0)**: a normal press returns to the previously-shown
|
|
photo; see
|
|
[`firmware/README.md`](../firmware/README.md#going-back-to-the-previous-photo).
|
|
- **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`](../firmware/README.md#managing-the-queue-soft-resetting-and-factory-resetting).
|
|
|
|
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.
|
|
|
|
### Wiring on the Seeed XIAO ESP32-C6
|
|
|
|
The XIAO only breaks out 11 GPIOs (0, 1, 2, 16, 17, 18, 19, 20, 21, 22,
|
|
23), so the dev-board defaults above don't fit -- DC/RST/BUSY (GPIO 9,
|
|
10, 11) aren't exposed on this board at all. Built with
|
|
[`build_for_board.sh xiao`](../firmware/README.md#building-for-the-seeed-xiao-esp32-c6-production-board),
|
|
which layers [`firmware/sdkconfig.xiao`](../firmware/sdkconfig.xiao) on
|
|
top of the dev-board defaults, remapping DC/RST/BUSY onto three of the
|
|
remaining free pins:
|
|
|
|
| Panel pin | XIAO GPIO | XIAO silkscreen label | Kconfig option |
|
|
| --------- | --------- | ---------------------- | --------------- |
|
|
| CLK | 20 | D9 | `EPD_PIN_CLK` (unchanged) |
|
|
| DIN | 19 | D8 | `EPD_PIN_MOSI` (unchanged) |
|
|
| CS | 18 | D10 | `EPD_PIN_CS` (unchanged) |
|
|
| DC | 16 | D6 | `EPD_PIN_DC` |
|
|
| RST | 17 | D7 | `EPD_PIN_RST` |
|
|
| BUSY | 21 | D3 | `EPD_PIN_BUSY` |
|
|
| VCC | 3.3V | 3V3 | -- |
|
|
| GND | GND | GND | -- |
|
|
|
|
The XIAO's silkscreen labels its pins D0-D10, not raw GPIO numbers --
|
|
the table above gives both.
|
|
|
|
Buttons (unchanged from the table above -- the XIAO's only three
|
|
ADC/deep-sleep-capable pins, GPIO 0/1/2, are exactly the ones already
|
|
used): next=GPIO2/**D2**, back=GPIO0/**D0**, menu/reset=GPIO1/**D1**.
|
|
That leaves GPIO22/**D4** and GPIO23/**D5** free, e.g. for the optional
|
|
VBUS mains-sense divider described under
|
|
[Battery](#battery-optional-xiao-esp32-c6) below.
|
|
|
|
`sdkconfig.xiao` also sets `FRAME_XIAO_ANTENNA_INIT=y`, which powers
|
|
the XIAO's onboard RF switch and selects its ceramic antenna at boot
|
|
(GPIO3/14, internal to the board -- not part of the wiring above).
|
|
Without it, WiFi doesn't reliably work on this board at all: the radio
|
|
comes up and logs look normal (e.g. the softAP starts and prints its
|
|
SSID/password) but the switch's control pins are left floating, so
|
|
nothing actually reaches the antenna -- the AP never becomes visible to
|
|
a scan, and a station connection would fail to associate the same way.
|
|
Seeed's own Arduino board package does this automatically; plain
|
|
ESP-IDF (what this firmware uses) doesn't, hence the explicit init.
|
|
|
|
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.
|
|
|
|
## Battery (optional, XIAO ESP32-C6)
|
|
|
|
For a battery-powered build on the Seeed XIAO ESP32-C6 (which has
|
|
BAT+/BAT- charge pads on its underside and charges over USB-C):
|
|
|
|
- A 1S 3.7V LiPo **with an integrated protection circuit** (the board
|
|
does no low-voltage cutoff of its own), soldered or JST-PH-pigtailed
|
|
to the BAT pads. JST-PH polarity is not standardized -- verify with a
|
|
multimeter before connecting.
|
|
- Battery level sense: 2x200k divider from BAT+ to GND, midpoint to
|
|
GPIO0/A0 (shared with the back button -- deliberate, see
|
|
[`firmware/README.md`](../firmware/README.md#battery-xiao-esp32-c6)).
|
|
- Optional mains detection: 2x100k divider from the 5V pin to GND,
|
|
midpoint to a spare GPIO (e.g. 22).
|
|
|
|
Both features are off by default in firmware
|
|
(`FRAME_BATTERY_ADC_GPIO`/`FRAME_VBUS_SENSE_GPIO` = -1).
|
|
|
|
## 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.
|