Flash the Nano over WiFi through the ESP32

- ESP32: NanoFlashBridge on TCP port 2323. A connection power cycles the
  Nano into its bootloader and bridges TCP <-> Serial2 at 57600 baud; the
  clock pauses during the session, 10 s idle timeout
- tools/nano_net_upload.py: STK500v1 uploader over TCP (standard library
  only), with sync retries, write and read-back verification. avrdude 6.3
  net: ports are broken on Windows, so avrdude is not used
- New nano_ota environment: pio run -e nano_ota -t upload
- README: usage, requirements, troubleshooting; TODO for hardware test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-13 00:35:28 +02:00
1 parent 8415dee347
commit bea5b9daa1
10 files changed
+438 -7

No files matched your search

+64 -4
View File
@@ -40,6 +40,7 @@ src/esp32/ ESP32 firmware
secrets.example.h template for WiFi / MQTT credentials
test/test_nano/ unit tests for the Nano firmware (run on the PC)
test/mocks/ fake Arduino, EEPROM and display driver for the tests
tools/nano_net_upload.py uploader for flashing the Nano over WiFi
archive/ old, unused sketches kept for reference
CLAUDE.md project notes for Claude Code
```
@@ -57,12 +58,14 @@ this folder.
| Environment | Board | Upload method |
|-------------|-------|---------------|
| `nano` | Arduino Nano (ATmega328P) | USB (`COM10`) |
| `nano_ota` | Arduino Nano (ATmega328P) | Over WiFi through the ESP32 (`10.1.1.198`). See [Flashing the Nano over WiFi](#flashing-the-nano-over-wifi). |
| `esp32` | ESP32 DevKit v1 | OTA over WiFi (`10.1.1.198`) |
| `esp32_usb` | ESP32 DevKit v1 | USB (`COM11`). Use it for the first flash or for recovery. |
```sh
pio run # build nano + esp32
pio run -e nano -t upload # flash the Nano
pio run -e nano -t upload # flash the Nano over USB
pio run -e nano_ota -t upload # flash the Nano over WiFi, through the ESP32
pio run -e esp32 -t upload # flash the ESP32 over the air
pio run -e esp32_usb -t upload # flash the ESP32 over USB
pio device monitor -e nano # serial monitor
@@ -76,7 +79,60 @@ In VS Code you can also pick the environment in the PlatformIO status bar.
> **Tip:** The ESP32 → Nano wire goes to the Nano's RX pin, which the Nano's USB chip
> also uses. Disconnect that wire before you flash the Nano over USB, or the upload may
> fail.
> fail. Flashing over WiFi (`nano_ota`) doesn't have this problem.
## Flashing the Nano over WiFi
The ESP32 can flash the Nano for you, so you don't need a USB cable at the display:
```sh
pio run -e nano_ota -t upload
```
What happens:
1. The uploader ([tools/nano_net_upload.py](tools/nano_net_upload.py)) connects to the
ESP32 on TCP port **2323**.
2. The ESP32 pauses the clock and switches the relay off for 1 second, then on again. This
restarts the Nano, and its bootloader starts.
3. The ESP32 switches its link to the bootloader's 57600 baud and passes bytes between
WiFi and the Nano.
4. The uploader writes the new firmware and reads it back to verify it.
5. When the uploader disconnects, the ESP32 switches the relay off. The clock powers the
Nano on again with the new firmware and continues.
The display goes dark for the duration of the upload, which takes a few seconds.
**Requirements**
- The reply wire must be connected: Nano D1 (TX) → voltage divider → ESP32 GPIO 16. The
uploader needs the bootloader's answers.
- The ESP32 must be running firmware with the flash bridge (this version or newer).
- The Nano must have the **old bootloader** (the `nanoatmega328` board, 57600 baud), which
also runs at power-on. The newer Optiboot bootloader only runs after a reset-pin reset,
so the relay power cycle would not start it.
**Settings**
- ESP32 IP address: `upload_port` in the `nano_ota` environment in `platformio.ini`. You
can add a port number: `10.1.1.198:2323`. For a one-time different address, use
`pio run -e nano_ota -t upload --upload-port 10.1.1.50`.
- Port, baud rate and power-off time: `NANO_FLASH_PORT`, `NANO_BOOTLOADER_BAUD` and
`NANO_POWER_OFF_TIME` in `src/esp32/libs.h`.
**If it fails**
| Message | Cause |
|---------|-------|
| `can't connect to ...` | Wrong IP address, or the ESP32 is offline or running older firmware |
| `no answer from the Nano bootloader` | Reply wire missing, or the Nano has Optiboot |
| `bad reply to command ...` / `verify failed` | Connection problem. Try again. A failed upload can leave the Nano without working firmware, but the bootloader itself is never overwritten, so flashing again (over WiFi or USB) always fixes it. |
The ESP32 ends the session after 10 seconds without data, so the clock always resumes,
even if the uploader is interrupted.
> **Security:** anyone on your network can connect to port 2323 and flash the Nano, just
> like the ESP32's own OTA has no password. Keep the display on a trusted network.
## Wiring between ESP32 and Nano
@@ -86,7 +142,7 @@ The ESP32 talks to the Nano on **UART2** (`Serial2`, 115200 baud). The ESP32's o
| ESP32 | Nano | Notes |
|-------|------|-------|
| GPIO 17 (TX2) | D0 (RX) | Display commands |
| GPIO 16 (RX2) | D1 (TX) | `READY` and `ERR` replies. Use a 5 V → 3.3 V voltage divider (e.g. 1 kΩ / 2 kΩ), because the ESP32 is not 5 V tolerant. Optional: without it, the ESP waits a fixed 3 s after power-on. |
| GPIO 16 (RX2) | D1 (TX) | `READY` and `ERR` replies, and bootloader answers when flashing over WiFi. Use a 5 V → 3.3 V voltage divider (e.g. 1 kΩ / 2 kΩ), because the ESP32 is not 5 V tolerant. Without it, the ESP waits a fixed 3 s after power-on, and `nano_ota` doesn't work. |
| GND | GND | Common ground |
| GPIO 13 | Relay input | Relay powers the panels and the Nano (`LOW` = on) |
@@ -118,7 +174,11 @@ The serial protocol is described in [src/nano/README.md](src/nano/README.md).
you flash this firmware, or the display gets no data. See
[Wiring between ESP32 and Nano](#wiring-between-esp32-and-nano).
- [ ] **Add the reply wire:** Nano D1 (TX) → voltage divider → ESP32 GPIO 16 (RX2). With it,
the ESP sends the first frame as soon as the Nano is ready, instead of after 3 s.
the ESP sends the first frame as soon as the Nano is ready, instead of after 3 s, and
the Nano can be flashed over WiFi (`nano_ota`).
- [ ] **Test flashing over WiFi on the real hardware.** The uploader is tested against a
simulated bootloader, not yet against the real Nano. Check especially that the old
bootloader starts after the relay power cycle.
- [ ] **Check the boot timing.** Build the Nano with `MEASURE_REFRESH` to see how long a
full redraw takes. If the reply wire isn't fitted, check that 3 s
(`NANO_BOOT_TIMEOUT`) is enough for the Nano to boot.