Replace the plain status LED with a WS2812B on PIO

The boards this targets carry an addressable LED on GPIO16 rather than a
plain LED, so the GPIO25 heartbeat had nothing to drive. Green means
running, blue flashes on each measurement, red means the sensor is
failing, with the most urgent condition winning. A healthy node reads as
dim green with a blue pip once a second, so a stalled or failing one is
obvious with no serial port attached.

Driven from PIO directly rather than via ws2812-pio, whose current
release pins rp2040-hal 0.11 against this project's 0.12. Those are
semver incompatible: cargo would build both HALs and the driver would not
accept our PIO, state machine or pin types. The alternative was pinning
the whole project back a HAL version, for four instructions of PIO.

Generating the waveform in the state machine matters beyond convenience.
The bus tasks preempt the LED task freely, and a CPU-timed WS2812 would
glitch the moment a frame arrived mid-update. The >50 us latch gap needs
no explicit delay either, since repaints are 25 ms apart.

Byte order is a named constant rather than two transposed shifts, because
it is a property of the part fitted and not of the protocol: many parts
sold as WS2812B, along with the WS2811 and SK6812 families, want red
first. These do. The unused ChannelOrder variant stays so the choice, and
the fix if a board differs, is legible.

The task derives everything from existing shared state — the reading's
own timestamp already says when the last measurement landed — so nothing
is published purely to drive an LED.

Colours confirmed on hardware after correcting the channel order; bus
suite still 15/15 and sensor counters clean, so PIO0 disturbs nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Oliver Walter
2026-07-28 21:26:14 +02:00
parent 46c26796cc
commit f2d06278af
6 changed files with 302 additions and 24 deletions
+5
View File
@@ -32,6 +32,11 @@ portable-atomic = { version = "1", features = ["critical-section"] }
embedded-hal = "1.0"
fugit = "0.3"
# WS2812 status indicator. Version must track rp2040-hal's own `pio` dependency
# so the assembled program type matches what its PIO driver accepts. The
# assembler proc macro comes along with it, so pio-proc needs no direct entry.
pio = "0.3"
defmt = { workspace = true }
defmt-rtt = "1.0"
panic-probe = { version = "1.0", features = ["print-defmt"] }