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>
126 lines
3.1 KiB
Markdown
126 lines
3.1 KiB
Markdown
# 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.10–14
|
||
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: ~30–50 fps per panel (vs ~10–20 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` 0–4 (`make deploy PANEL_ID=N`). Each gets `10.1.1.1N` (10–14), a unique MAC, and UDP filtering. Send frames from the Pi to each panel’s IP, or use a leading `panel_id` byte with `255` broadcast filtering.
|