Files
portal/firmware/panel/README.md
Jimmy d5cab2efdf Add multi-panel Pico UDP firmware and Python LED control.
Pico panels get static IPs on 10.1.1.10–14 with per-panel LED counts, Makefile deploy targets, and Python examples for animations, sync tests, and direct Pi SPI control.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-28 22:46:08 +12:00

126 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Portal panel firmware (Pico SDK)
C firmware for a **Pico + W5500 + WS2812** panel adapter. Replaces the slow CircuitPython `adapter/code.py` path with native UDP receive and PIO WS2812 output.
## Hardware
Matches `adapter/code.py`:
| Signal | GPIO |
|--------|------|
| W5500 CS | GP9 |
| SPI1 SCK | GP10 |
| SPI1 MOSI | GP11 |
| SPI1 MISO | GP12 |
| W5500 RST | GP13 |
| Status LED | GP25 |
| WS2812 data | GP27 |
Default: **405 LEDs** (45×9 matrix chain), one data pin per panel.
WS2812 output uses [ForsakenNGS/Pico_WS2812](https://github.com/ForsakenNGS/Pico_WS2812) (FORMAT_GRB on GP27).
## Build
Requires [pico-sdk](https://github.com/raspberrypi/pico-sdk) and the ARM GCC toolchain (`arm-none-eabi-gcc`).
```bash
# From repo root
make deploy # build + flash over USB
make build # build only
# Or from this directory
make deploy
```
Manual cmake (one-time pico-sdk setup):
```bash
git clone https://github.com/raspberrypi/pico-sdk.git ~/pico/pico-sdk
cd ~/pico/pico-sdk && git submodule update --init
export PICO_SDK_PATH=~/pico/pico-sdk
mkdir -p build && cd build
cmake ..
make -j$(nproc)
```
UF2 output: `build/panel.uf2` — hold BOOTSEL and copy to the Pico.
### Options
```bash
# Panel 0 of 5 → 10.1.1.10, unique MAC, UDP panel_id filter
make deploy PANEL_ID=0 # 10.1.1.10
make deploy PANEL_ID=1 # 10.1.1.11
# DHCP instead of static 10.1.1.1014
make deploy PANEL_ID=0 NO_DHCP=0
# Fewer LEDs for bench test
make deploy NUM_LEDS=2
```
Static IP and MAC are derived from `PANEL_ID`:
| Panel | IP | MAC |
|-------|-----|-----|
| 0 | 10.1.1.10 | 02:50:52:54:4C:00 |
| 1 | 10.1.1.11 | 02:50:52:54:4C:01 |
| … | … | … |
| 4 | 10.1.1.14 | 02:50:52:54:4C:04 |
| 255 (bench) | 10.1.1.19 | 02:50:52:54:4C:FF |
Edit `board_config.h` for gateway, subnet, and pin changes.
## UDP protocol (port 50007)
| Payload | Action |
|---------|--------|
| **1215 bytes** | Raw RGB (`405 × 3`), show immediately |
| **1216 bytes** | `panel_id` (byte 0) + RGB; `255` = accept on any panel |
| **4 bytes `SHOW`** | Push buffered pixels to the strip (sync helper) |
Pi sends **RGB** order; firmware converts to WS2812 **GRB**.
Target throughput: ~3050 fps per panel (vs ~1020 fps on CircuitPython).
## Pi test sender
```bash
pipenv run python examples/panel_udp_send.py --host 192.168.2.111 --animation rainbow
```
## Flashing
Requires [picotool](https://github.com/raspberrypi/picotool) with libusb support:
```bash
make deploy
```
Or `./scripts/panel_deploy.sh` (same thing).
Or manually:
```bash
picotool load -x -f build/panel.uf2
```
`-f` forces a USB reboot into BOOTSEL when the panel is already running.
Legacy UF2 drag-and-drop also works: hold BOOTSEL, plug USB, copy `panel.uf2` to `RPI-RP2`.
Serial debug:
```bash
make monitor
# or: picocom /dev/ttyACM0
```
Ctrl+A then Ctrl+X to exit picocom.
## Multi-panel (5 Picos)
Flash each Pico with `PANEL_ID` 04 (`make deploy PANEL_ID=N`). Each gets `10.1.1.1N` (1014), a unique MAC, and UDP filtering. Send frames from the Pi to each panels IP, or use a leading `panel_id` byte with `255` broadcast filtering.