Public Access
Move the Nano link to Serial2, update READMEs
- ESP32 talks to the Nano on UART2 (GPIO 17 TX / GPIO 16 RX); Serial (USB) is now free for debug output and boot messages no longer reach the Nano - README: wiring table, actual schedule (clock from 08:00), TODO section for the rewiring Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c67a90ba09
commit
75f677a2eb
6 files changed
+58
-29
No files matched your search
@@ -23,17 +23,17 @@ See README.md for the overview.
|
|||||||
- **Nano RAM is tight** (ATmega328P, 2 KB). The frame buffers are allocated with
|
- **Nano RAM is tight** (ATmega328P, 2 KB). The frame buffers are allocated with
|
||||||
`calloc`. Avoid `String`, large stack buffers and new globals in Nano code. Put constant
|
`calloc`. Avoid `String`, large stack buffers and new globals in Nano code. Put constant
|
||||||
data in `PROGMEM`.
|
data in `PROGMEM`.
|
||||||
- The Nano and the ESP32 share one UART. On the ESP32, `Serial` is the display link, so
|
- The ESP32 talks to the Nano on `Serial2` (`nanoSerial` in `libs.h`, GPIO 17 TX / GPIO 16
|
||||||
**don't print debug output on the ESP32's `Serial`**: the Nano would read it as
|
RX). `Serial` (UART0/USB) is free for debug output. Never write debug text to
|
||||||
commands. The Nano ignores unknown command bytes, but text that starts with
|
`nanoSerial`: the Nano runs lines that start with s/S/F/D/P/B/R/T as commands.
|
||||||
s/S/F/D/P/B/R/T will be run as a command.
|
- Open hardware TODOs are listed in the README `TODO` section. Update it when one is done.
|
||||||
- `src/esp32/secrets.h` holds the real credentials and is gitignored. Never commit it.
|
- `src/esp32/secrets.h` holds the real credentials and is gitignored. Never commit it.
|
||||||
Add new secrets to `secrets.example.h` as placeholders.
|
Add new secrets to `secrets.example.h` as placeholders.
|
||||||
- The relay (ESP32 GPIO 13, `LOW` = on) powers both the panels and the Nano. Each time it
|
- 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 sends `READY`. The ESP's `relayOn()` waits for
|
switches on, the Nano cold-boots and then sends `READY`. The ESP's `relayOn()` waits for
|
||||||
that message, at most `NANO_BOOT_TIMEOUT`. The timeout also covers the case where the
|
that message, at most `NANO_BOOT_TIMEOUT`. The timeout also covers the case where the
|
||||||
Nano's TX isn't wired to the ESP's RX.
|
Nano's TX isn't wired to the ESP's RX.
|
||||||
- `relayOff()` ends `Serial` and sets the TX pin to input. Otherwise the idle-high TX line
|
- `relayOff()` ends `nanoSerial` and sets its TX pin to input. Otherwise the idle-high TX line
|
||||||
powers the Nano through its RX pin. Never send display commands while `relay_on` is
|
powers the Nano through its RX pin. Never send display commands while `relay_on` is
|
||||||
false.
|
false.
|
||||||
- The Nano keeps no state over a power cycle except the flip time in EEPROM. The driver
|
- The Nano keeps no state over a power cycle except the flip time in EEPROM. The driver
|
||||||
|
|||||||
@@ -68,21 +68,34 @@ pio device monitor -e nano # serial monitor
|
|||||||
|
|
||||||
In VS Code you can also pick the environment in the PlatformIO status bar.
|
In VS Code you can also pick the environment in the PlatformIO status bar.
|
||||||
|
|
||||||
> **Tip:** The Nano and the ESP32 share a serial line. Disconnect the ESP32 TX → Nano RX
|
> **Tip:** The ESP32 → Nano wire goes to the Nano's RX pin, which the Nano's USB chip
|
||||||
> wire before you flash the Nano over USB, or the upload may fail.
|
> also uses. Disconnect that wire before you flash the Nano over USB, or the upload may
|
||||||
|
> fail.
|
||||||
|
|
||||||
|
## Wiring between ESP32 and Nano
|
||||||
|
|
||||||
|
The ESP32 talks to the Nano on **UART2** (`Serial2`, 115200 baud). The ESP32's own
|
||||||
|
`Serial` (UART0, USB) is free for debug output.
|
||||||
|
|
||||||
|
| 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. |
|
||||||
|
| GND | GND | Common ground |
|
||||||
|
| GPIO 13 | Relay input | Relay powers the panels and the Nano (`LOW` = on) |
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
1. **ESP32 boot.** The ESP32 connects to WiFi and starts ArduinoOTA. After a crash or
|
1. **ESP32 boot.** The ESP32 connects to WiFi and starts ArduinoOTA. After a crash or
|
||||||
unexpected reset it stays in an *OTA panic window* for 15 seconds, so you can flash a
|
unexpected reset it stays in an *OTA panic window* for 15 seconds, so you can flash a
|
||||||
fix before the main code runs again. It then switches the display relay on, starts NTP
|
fix before the main code runs again. It then switches the display relay on, waits for
|
||||||
and connects to MQTT.
|
the Nano's `READY` message (at most 3 s), starts NTP and connects to MQTT.
|
||||||
2. **Clock loop (every second).**
|
2. **Clock loop (every second).**
|
||||||
- **07:00–22:00:** Pikachu with a thought bubble showing `HH:MM`. A yawning Pikachu is
|
- **08:00–22:00:** Pikachu with a thought bubble showing `HH:MM`. A yawning Pikachu is
|
||||||
shown from 17:00.
|
shown from 17:00.
|
||||||
- **22:00–23:30:** the clock is only drawn on the quarter hour. In between, the relay
|
- **22:00–23:30:** the clock is only shown during the minutes :00, :15, :30 and :45.
|
||||||
turns the display off.
|
30 seconds after each of those minutes, the relay turns the display off.
|
||||||
- **Night:** the screen is cleared and power is cut after 30 seconds.
|
- **23:31–08:00:** the screen is cleared and power is cut after 30 seconds.
|
||||||
3. **Home Assistant switches** (MQTT discovery):
|
3. **Home Assistant switches** (MQTT discovery):
|
||||||
- `FlipDot Display Clock`: off shows a Nintendo logo instead of the clock.
|
- `FlipDot Display Clock`: off shows a Nintendo logo instead of the clock.
|
||||||
- `FlipDot Display Power`: off clears the display and cuts power through the relay.
|
- `FlipDot Display Power`: off clears the display and cuts power through the relay.
|
||||||
@@ -91,3 +104,15 @@ In VS Code you can also pick the environment in the PlatformIO status bar.
|
|||||||
to fix dots that did not flip.
|
to fix dots that did not flip.
|
||||||
|
|
||||||
The serial protocol is described in [src/nano/README.md](src/nano/README.md).
|
The serial protocol is described in [src/nano/README.md](src/nano/README.md).
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [ ] **Rewire the Nano link to UART2.** The firmware now uses `Serial2` (GPIO 16/17)
|
||||||
|
instead of `Serial` (GPIO 1/3). Move the ESP32 TX wire from GPIO 1 to **GPIO 17** before
|
||||||
|
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.
|
||||||
|
- [ ] **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.
|
||||||
+6
-5
@@ -3,8 +3,9 @@
|
|||||||
PlatformIO environments: `esp32` (OTA) and `esp32_usb` (USB)
|
PlatformIO environments: `esp32` (OTA) and `esp32_usb` (USB)
|
||||||
|
|
||||||
The ESP32 decides what is shown on the display. It never touches the panel itself. The
|
The ESP32 decides what is shown on the display. It never touches the panel itself. The
|
||||||
BROSE9323 driver is built with `-D ESPSERIAL`, so every GFX call is sent over `Serial`
|
BROSE9323 driver is built with `-D ESPSERIAL`, so every GFX call is sent to the Nano over
|
||||||
(115200 baud) to the Nano.
|
`Serial2` (UART2, GPIO 17 TX / GPIO 16 RX, 115200 baud). `Serial` (USB) is only used for
|
||||||
|
debug output. Wiring is described in the [main README](../../README.md#wiring-between-esp32-and-nano).
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
@@ -40,10 +41,10 @@ BROSE9323 driver is built with `-D ESPSERIAL`, so every GFX call is sent over `S
|
|||||||
|
|
||||||
| Time | Display |
|
| Time | Display |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| 07:00 – 17:00 | Pikachu and the clock, updated every minute |
|
| 08:00 – 17:00 | Pikachu and the clock, updated every minute |
|
||||||
| 17:00 – 22:00 | Yawning Pikachu and the clock |
|
| 17:00 – 22:00 | Yawning Pikachu and the clock |
|
||||||
| 22:00 – 23:30 | Clock drawn only on the quarter hour; power is off in between |
|
| 22:00 – 23:30 | Clock shown only during the minutes :00, :15, :30 and :45; power is off in between |
|
||||||
| night | Screen cleared, power off |
|
| 23:31 – 08:00 | Screen cleared, power off |
|
||||||
|
|
||||||
## Adding bitmaps
|
## Adding bitmaps
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -45,7 +45,10 @@ bool power = true;
|
|||||||
|
|
||||||
const int led1 = BUILTIN_LED; // Pin of the LED
|
const int led1 = BUILTIN_LED; // Pin of the LED
|
||||||
const int relay = 13; // Pin of the relay, powers the panels and the Nano (LOW = on)
|
const int relay = 13; // Pin of the relay, powers the panels and the Nano (LOW = on)
|
||||||
const int nano_tx = 1; // UART0 TX, wired to the Nano RX
|
// Link to the Nano on UART2. Serial (UART0) stays free for USB / debug output.
|
||||||
|
HardwareSerial &nanoSerial = Serial2;
|
||||||
|
const int nano_rx = 16; // UART2 RX, wired to the Nano TX (through a 5V -> 3.3V divider)
|
||||||
|
const int nano_tx = 17; // UART2 TX, wired to the Nano RX
|
||||||
bool relay_on = false;
|
bool relay_on = false;
|
||||||
// Max wait for the Nano's READY after power on (also the wait when Nano TX is not wired to our RX)
|
// Max wait for the Nano's READY after power on (also the wait when Nano TX is not wired to our RX)
|
||||||
const uint32_t NANO_BOOT_TIMEOUT = 3000;
|
const uint32_t NANO_BOOT_TIMEOUT = 3000;
|
||||||
|
|||||||
+8
-8
@@ -14,9 +14,9 @@ void waitForNano()
|
|||||||
uint32_t start = millis();
|
uint32_t start = millis();
|
||||||
while (millis() - start < NANO_BOOT_TIMEOUT)
|
while (millis() - start < NANO_BOOT_TIMEOUT)
|
||||||
{
|
{
|
||||||
while (Serial.available())
|
while (nanoSerial.available())
|
||||||
{
|
{
|
||||||
char c = Serial.read();
|
char c = nanoSerial.read();
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
line[len] = '\0';
|
line[len] = '\0';
|
||||||
@@ -39,10 +39,10 @@ void relayOn()
|
|||||||
if (relay_on)
|
if (relay_on)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Serial.begin(115200);
|
nanoSerial.begin(115200, SERIAL_8N1, nano_rx, nano_tx);
|
||||||
// drop old data (e.g. ERR replies) so only a new READY counts
|
// drop old data (e.g. ERR replies) so only a new READY counts
|
||||||
while (Serial.available())
|
while (nanoSerial.available())
|
||||||
Serial.read();
|
nanoSerial.read();
|
||||||
|
|
||||||
digitalWrite(relay, LOW);
|
digitalWrite(relay, LOW);
|
||||||
waitForNano();
|
waitForNano();
|
||||||
@@ -55,8 +55,8 @@ void relayOff()
|
|||||||
relay_on = false;
|
relay_on = false;
|
||||||
|
|
||||||
// An idle UART TX line is high and would power the Nano through its RX pin
|
// An idle UART TX line is high and would power the Nano through its RX pin
|
||||||
Serial.flush();
|
nanoSerial.flush();
|
||||||
Serial.end();
|
nanoSerial.end();
|
||||||
pinMode(nano_tx, INPUT);
|
pinMode(nano_tx, INPUT);
|
||||||
}
|
}
|
||||||
void turnPowerOff(uint32_t delay = 30000, bool _turn_hassio_power_off = false)
|
void turnPowerOff(uint32_t delay = 30000, bool _turn_hassio_power_off = false)
|
||||||
@@ -289,7 +289,7 @@ void setup()
|
|||||||
pinMode(relay, OUTPUT);
|
pinMode(relay, OUTPUT);
|
||||||
relayOn();
|
relayOn();
|
||||||
|
|
||||||
display.begin(&Serial);
|
display.begin(&nanoSerial);
|
||||||
// display.setTiming(200);
|
// display.setTiming(200);
|
||||||
// display.setTiming(180);
|
// display.setTiming(180);
|
||||||
// display.setTiming(220); // works best so far
|
// display.setTiming(220); // works best so far
|
||||||
|
|||||||
+2
-2
@@ -77,5 +77,5 @@ pinout.
|
|||||||
| ROW_0 … ROW_4 | A3, A4, A2, A0, A1 |
|
| ROW_0 … ROW_4 | A3, A4, A2, A0, A1 |
|
||||||
| ROW_RESET | D13 |
|
| ROW_RESET | D13 |
|
||||||
| ROW_SET | A5 |
|
| ROW_SET | A5 |
|
||||||
| Serial RX | D0 (from ESP32 TX) |
|
| Serial RX | D0 (from ESP32 GPIO 17, TX2) |
|
||||||
| Serial TX | D1 (to ESP32 RX, through a 5 V → 3.3 V voltage divider). Optional: needed for `READY`. Without it, the ESP waits the full 3 s timeout. |
|
| 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. |
|
||||||
Reference in new issue
Block a user