2026-10-12 23:55:15 +02:00
# Arduino Nano: flipdot driver
PlatformIO environment: `nano`
The Nano is connected directly to the Brose panel electronics. It keeps an 84 × 19 frame
buffer and takes drawing commands over serial (115200 baud). It has no clock or network
logic.
2026-10-13 00:19:15 +02:00
## Files
| File | Contents |
|------|----------|
| `main.cpp` | `setup()` / `loop()` , feeds serial bytes to the parser, periodic full redraw |
| `config.h` | All settings: debug options, display size, flip time limits, timings |
| `command_parser.h/.cpp` | `CommandParser` : the serial protocol, one method per command |
| `settings.h/.cpp` | Flip time stored in EEPROM |
The display driver itself is in [lib/BROSE9323 ](../../lib/BROSE9323/README.md ).
2026-10-13 00:23:07 +02:00
## Tests
2026-10-13 00:56:32 +02:00
`pio test -e test_nano` runs the unit tests in [test/test_nano ](../../test/test_nano/test_main.cpp )
2026-10-13 00:23:07 +02:00
on the PC. They feed serial data to the firmware and check what it asks the display to do:
every command, bitmaps, bad input, flip time storage and the full-redraw timing. The
Arduino core, EEPROM and the display driver are replaced by fakes in
[test/mocks ](../../test/mocks ).
2026-10-12 23:55:15 +02:00
## Behaviour
2026-10-13 00:12:28 +02:00
- **Boot:** the Nano loads the flip time from EEPROM, sets up the pins and sends `READY` .
It doesn't flip any dots at boot. The relay powers the Nano, so it boots every time the
display is switched on.
- **First `display()` after boot** redraws every dot, because the Nano doesn't know which
state the dots were left in.
2026-10-12 23:55:15 +02:00
- **`display()` :** compares the new buffer with the last one that was shown and strobes
only the dots that changed.
2026-10-13 00:06:49 +02:00
- **Every 2 minutes** (`REFRESH_TIME` ) it does a full redraw to fix dots that got stuck.
A full redraw blocks for about half a second, which is long enough to overflow the
64-byte serial buffer. So it only runs right after a `D` (the end of a frame, when the
ESP is quiet) or when no serial data has arrived for 2 seconds.
- **Flip pulse length** (µs, 50– 2000) is set with the `T` command and stored in EEPROM,
so it is kept after a reboot. The default is 200 µs.
### Debug options
2026-10-13 00:19:15 +02:00
Uncomment these in `config.h` :
2026-10-13 00:06:49 +02:00
| Define | Effect |
|--------|--------|
| `DEBUG` | Print unknown command bytes on the serial port |
| `MEASURE_REFRESH` | At boot, time a full redraw and print the duration in ms |
2026-10-12 23:55:15 +02:00
## Serial protocol
2026-10-13 00:06:49 +02:00
Each command is one ASCII line that **ends with `\n`** (`\r` is ignored). The Nano
collects a whole line before it runs the command. If a line is broken or unknown, it is
skipped and the next line starts clean. Coordinates are 2-digit **hex** . Color is `0`
(black) or `1` (yellow). The ESP32 driver (`ESPSERIAL` ) only uses `s` , `S` , `F` , `D` and
`T` .
2026-10-12 23:55:15 +02:00
| Cmd | Format | Meaning |
|-----|--------|---------|
| `s` | `sXXYYc` | Set pixel in the buffer |
| `S` | `SXXYYc` | Set pixel and flip it right away (direct mode) |
| `F` | `Fc` | Fill the whole buffer |
| `D` | `D` | Push the buffer to the display (changed dots only) |
2026-10-13 00:06:49 +02:00
| `P` | `PXXYYcsTEXT` | Print text at (XX,YY), color `c` , size `s` . A literal `\n` (backslash, n) in TEXT starts a new line. The whole line can be at most 64 characters. |
| `B` | `BXXYYWWHHcHEX...` | Draw a bitmap. WW must be a multiple of 4. Pixel data is one hex digit per 4 pixels, row by row. The data is drawn while it arrives, so it is not limited to 64 characters. |
2026-10-12 23:55:15 +02:00
| `R` | `R` | Print the buffer as ASCII art on the serial port |
2026-10-13 00:06:49 +02:00
| `T` | `Tnnn` | Set the flip pulse length in µs (decimal, 50– 2000), stored in EEPROM |
2026-10-13 00:12:28 +02:00
Replies on the Nano's TX pin:
- `READY` after booting. The ESP waits for it before sending the first frame.
- `ERR: ...` for invalid commands.
2026-10-12 23:55:15 +02:00
Example (what the ESP32 sends for one pixel and a refresh):
```
s0a051
D
```
## Wiring (default pinout)
The pins are defined in [lib/BROSE9323/BROSE9323.h ](../../lib/BROSE9323/BROSE9323.h ).
If you use the PLCC adapter board, build with `-D FLIPDOT_PLCC_ADAPTER` to switch to its
pinout.
| Signal | Nano pin |
|--------|----------|
| ENABLE | D7 |
| ADDR_0 / 1 / 2 (panel select) | D3 / D5 / D6 |
| COL_DATA | D4 |
| COL_0 … COL_4 | D8, D10, D9, D11, D12 |
| ROW_0 … ROW_4 | A3, A4, A2, A0, A1 |
| ROW_RESET | D13 |
| ROW_SET | A5 |
2026-10-13 00:16:24 +02:00
| Serial RX | D0 (from ESP32 GPIO 17, TX2) |
| Serial TX | D1 (to ESP32 GPIO 16, RX2, through a 5 V → 3.3 V voltage divider). Optional: needed for `READY` . Without it, the ESP waits the full 3 s timeout. |