Public Access
- Uploader sends 'FLASH <baud>' first; the ESP32 restarts the Nano and bridges at that baud rate, then answers OK - --baud=auto (default) tries 57600 (old ATmegaBOOT) then 115200 (Optiboot) - Optional nano_reset GPIO (NPN to Nano RESET) pulses reset after power on, needed for Optiboot which skips the bootloader after a power cycle - Clear errors for outdated ESP32 firmware and missing wires - README: bootloader table, reset wire, troubleshooting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.0 KiB
5.0 KiB
Flipdot display: notes for Claude
A PlatformIO project with two firmware targets for an 84×19 Brose flipdot clock. See README.md for the overview.
Layout and build
platformio.inihas the environmentsnano,esp32(OTA to 10.1.1.198) andesp32_usb(COM11). The sources are split withbuild_src_filter(src/nano/,src/esp32/).lib/BROSE9323/is the shared driver. Its behaviour depends on build flags set inplatformio.ini, not in the header:ESPSERIAL(ESP32): draw calls become serial commands.FLIPDOT_PLCC_ADAPTER(Nano, optional): alternative pinout.
- PlatformIO CLI is not on PATH. Run
~/.platformio/penv/Scripts/pio.exe run(Git Bash) or$env:USERPROFILE\.platformio\penv\Scripts\pio.exe run(PowerShell). - If an ESP32 build fails with
No module named 'intelhex', run~/.platformio/penv/Scripts/python.exe -m pip install intelhex. nano_otaflashes the Nano over WiFi:tools/nano_net_upload.py(STK500v1 over TCP) talks toNanoFlashBridgeon the ESP32 (port 2323). The uploader first sendsFLASH <baud>\n. The ESP power cycles the Nano (plus an optional reset pulse onnano_reset), answersOK\n, then passes the bytes through at that baud rate.--baud=autotries 57600 (old ATmegaBOOT, which also starts after a power cycle), then 115200 (Optiboot, which only starts after a reset-pin reset, so it needsnano_reset). avrdude 6.3'snet:port is broken on Windows (ser_drain()fails), which is why the uploader is a Python script. The uploader only uses the Python standard library. Test it against a simulated bootloader before changing it.src/esp32/libs.hdefines globals in the header, so it can only be included frommain.cpp. New ESP32 modules must be self-contained (seenano_flash_bridge.*).- After any change, build both targets (
pio run). After Nano changes, also runpio test -e native.
Constraints
- Nano RAM is tight (ATmega328P, 2 KB). The frame buffers are allocated with
calloc. AvoidString, large stack buffers and new globals in Nano code. Put constant data inPROGMEM. - The ESP32 talks to the Nano on
Serial2(nanoSerialinlibs.h, GPIO 17 TX / GPIO 16 RX).Serial(UART0/USB) is free for debug output. Never write debug text tonanoSerial: the Nano runs lines that start with s/S/F/D/P/B/R/T as commands. - Open hardware TODOs are listed in the README
TODOsection. Update it when one is done. src/esp32/secrets.hholds the real credentials and is gitignored. Never commit it. Add new secrets tosecrets.example.has placeholders.- The relay (ESP32 GPIO 13,
LOW= on) powers both the panels and the Nano. Each time it switches on, the Nano cold-boots and then sendsREADY. The ESP'srelayOn()waits for that message, at mostNANO_BOOT_TIMEOUT. The timeout also covers the case where the Nano's TX isn't wired to the ESP's RX. relayOff()endsnanoSerialand sets its TX pin to input. Otherwise the idle-high TX line powers the Nano through its RX pin. Never send display commands whilerelay_onis false.- The Nano keeps no state over a power cycle except the flip time in EEPROM. The driver
forces a full redraw on the first
display()after boot (_force_next). - Hardware is not available here. Builds can be checked, but runtime behaviour can't.
Nano serial parser (src/nano/main.cpp)
- Files:
main.cpp(setup/loop, refresh),config.h(all constants and debug defines),command_parser.*(protocol, one method per command),settings.*(EEPROM). - Line based and non-blocking: bytes are collected into a 64-character buffer and a
command runs when
\narrives. Bitmap (B) pixel data is the exception. It is drawn while it arrives, so it can be longer than the buffer. Keeploop()free of busy-waits. - A full redraw (
display(true)) blocks for about 0.5 s, which overflows the 64-byte serial receive buffer. Only run it when no data is expected: right after aD, or after 2 s with no serial data. The ESP sends one frame per second, ending withD. - Flip time is stored in EEPROM as a magic word at address 0 and a
uint16_tat address 2. Values outside 50–2000 µs are rejected. - The Nano only replies
READY(at boot) andERR: .... There is no per-frame acknowledgement. Whether the Nano's TX is wired to the ESP's RX is unconfirmed, so every wait for a reply needs a timeout. - Unit tests:
pio test -e nativerunstest/test_nano/on the PC with the fakes intest/mocks/(Arduino, EEPROM, and aBROSE9323that records calls). It needs gcc on PATH (Strawberry Perl provides it atC:\Strawberry\c\bin). Add a test for every protocol change. The mocks only implement what the Nano code uses, so extend them when new Arduino or driver functions are called. - The board environments have
test_ignore = *, so test firmware is never uploaded. Plainpio testruns nothing; always pass-e native.
Git
- Remote: https://mangavalk.com/mangavalk/Flipdot-display.git, branch
main.