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>
This commit is contained in:
2026-06-28 22:46:08 +12:00
parent d8323bb9a3
commit d5cab2efdf
52 changed files with 4677 additions and 1 deletions

113
firmware/panel/Makefile Normal file
View File

@@ -0,0 +1,113 @@
# Portal panel firmware — build and USB deploy
#
# Usage:
# make # build only
# make deploy # build + flash over USB (picotool)
# make clean
#
# Options (passed to cmake on configure/reconfigure):
# make deploy PANEL_ID=0
# make deploy NO_DHCP=1
# make deploy WS2812_PIN=28 # if data wire is on GP28 not GP27
#
# Environment:
# PICO_SDK_PATH default: ~/pico/pico-sdk
# SERIAL_PORT default: first /dev/ttyACM* or /dev/ttyACM0
PICO_SDK_PATH ?= $(HOME)/pico/pico-sdk
BUILD_DIR := build
UF2 := $(BUILD_DIR)/panel.uf2
CMAKE_STAMP := $(BUILD_DIR)/.cmake_stamp
JOBS ?= $(shell nproc 2>/dev/null || echo 4)
SERIAL_PORT ?= $(shell ls /dev/ttyACM* 2>/dev/null | head -1)
ifeq ($(SERIAL_PORT),)
SERIAL_PORT := /dev/ttyACM0
endif
SERIAL_BAUD ?= 115200
CMAKE_ARGS :=
ifdef PANEL_ID
CMAKE_ARGS += -DPANEL_ID_BUILD=$(PANEL_ID)
# Panels 0 and 4 are 9×39 (351); others are 9×45 (405). Always pass NUM_LEDS so
# cmake cache cannot keep a stale count from a previous PANEL_ID flash.
ifeq ($(PANEL_ID),0)
NUM_LEDS ?= 351
else ifeq ($(PANEL_ID),4)
NUM_LEDS ?= 351
else
NUM_LEDS ?= 405
endif
CMAKE_ARGS += -DNUM_LEDS_BUILD=$(NUM_LEDS)
else
ifdef NUM_LEDS
CMAKE_ARGS += -DNUM_LEDS_BUILD=$(NUM_LEDS)
endif
endif
ifdef WS2812_PIN
CMAKE_ARGS += -DWS2812_PIN_BUILD=$(WS2812_PIN)
endif
ifeq ($(NO_DHCP),0)
CMAKE_ARGS += -DPORTAL_USE_DHCP=ON
else
CMAKE_ARGS += -DPORTAL_USE_DHCP=OFF
endif
CMAKE_STAMP_BODY := $(strip $(CMAKE_ARGS))
SOURCES := $(wildcard *.c *.cpp *.h) WS2812.pio CMakeLists.txt pico_sdk_import.cmake
.PHONY: all build configure reconfigure deploy flash upload monitor clean help
all: build
help:
@echo "Targets:"
@echo " make build Build panel.uf2"
@echo " make deploy Build and flash over USB"
@echo " make flash Alias for deploy"
@echo " make monitor USB serial console (picocom, Ctrl+A Ctrl+X to quit)"
@echo " make clean Remove build directory"
@echo " make reconfigure Re-run cmake (e.g. after changing PANEL_ID)"
build: configure
@echo "==> Building panel firmware"
PICO_SDK_PATH="$(PICO_SDK_PATH)" cmake --build $(BUILD_DIR) -j$(JOBS)
@test -f "$(UF2)" || (echo "Error: build did not produce panel.uf2" && exit 1)
@echo "==> Build OK: $(UF2)"
configure:
@test -d "$(PICO_SDK_PATH)" || (echo "Error: pico-sdk not found at $(PICO_SDK_PATH) (set PICO_SDK_PATH)" && exit 1)
@command -v cmake >/dev/null || (echo "Error: cmake is required" && exit 1)
@mkdir -p $(BUILD_DIR)
@STAMP='$(CMAKE_STAMP_BODY)'; \
if [ ! -f "$(BUILD_DIR)/CMakeCache.txt" ] || [ ! -f "$(CMAKE_STAMP)" ] || [ "$$(cat $(CMAKE_STAMP))" != "$$STAMP" ]; then \
echo "==> Configuring cmake in $(BUILD_DIR) $(CMAKE_ARGS)"; \
PICO_SDK_PATH="$(PICO_SDK_PATH)" cmake -S . -B $(BUILD_DIR) $(CMAKE_ARGS); \
echo "$$STAMP" > "$(CMAKE_STAMP)"; \
fi
reconfigure:
@test -d "$(PICO_SDK_PATH)" || (echo "Error: pico-sdk not found at $(PICO_SDK_PATH) (set PICO_SDK_PATH)" && exit 1)
@mkdir -p $(BUILD_DIR)
@echo "==> Reconfiguring cmake in $(BUILD_DIR) $(CMAKE_ARGS)"
PICO_SDK_PATH="$(PICO_SDK_PATH)" cmake -S . -B $(BUILD_DIR) $(CMAKE_ARGS)
@echo '$(CMAKE_STAMP_BODY)' > $(CMAKE_STAMP)
deploy: build
@command -v picotool >/dev/null || (echo "Error: picotool not found (https://github.com/raspberrypi/picotool)" && exit 1)
@picotool version 2>&1 | grep -q 'without USB support' && \
(echo "Error: picotool was built without USB support" && exit 1) || true
@echo "==> Uploading $(UF2) over USB"
@picotool load -x -f "$(UF2)"
flash: deploy
upload: deploy
monitor:
@command -v picocom >/dev/null || (echo "Error: picocom not found (sudo apt install picocom)" && exit 1)
@test -e "$(SERIAL_PORT)" || (echo "Error: $(SERIAL_PORT) not found (plug in Pico USB, or set SERIAL_PORT=...)" && exit 1)
@echo "==> Serial monitor on $(SERIAL_PORT) ($(SERIAL_BAUD) baud, Ctrl+A Ctrl+X to quit)"
picocom --baud $(SERIAL_BAUD) --flow n --echo $(SERIAL_PORT)
clean:
rm -rf $(BUILD_DIR)