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:
@@ -39,7 +39,7 @@ performs no I/O and touches no peripherals; everything hardware-shaped lives in
|
||||
| 2 | SIO output | transceiver `DE` **and** `/RE`, tied together |
|
||||
| 14 | I2C1 SDA | SHT31 `SDA` |
|
||||
| 15 | I2C1 SCL | SHT31 `SCL` |
|
||||
| 25 | SIO output | status LED, active high |
|
||||
| 16 | PIO0 | WS2812B status indicator, data in |
|
||||
| — | SWD | `SWCLK`/`SWDIO` on the dedicated pads, for the probe |
|
||||
|
||||
Why this arrangement:
|
||||
@@ -54,8 +54,10 @@ Why this arrangement:
|
||||
- **I2C1 on GPIO 14/15, physically far from the RS485 block.** The sensor is the
|
||||
noise-sensitive part and the differential driver is the noisy part. Using I2C1
|
||||
also leaves I2C0 free.
|
||||
- **GPIO 25 for the LED** matches the Raspberry Pi Pico, so this image blinks on
|
||||
a bare Pico as well — handy for bring-up before the real board exists.
|
||||
- **GPIO 16 for the WS2812B**, because that is where the addressable LED sits on
|
||||
the boards this targets. Any GPIO would do, since PIO can drive the waveform
|
||||
from any pin, but it is kept clear of the RS485 block so the LED's switching
|
||||
current does not share a return path with the differential pair.
|
||||
|
||||
### Hardware notes the firmware cannot enforce
|
||||
|
||||
@@ -70,6 +72,33 @@ Why this arrangement:
|
||||
reset command.
|
||||
- `.boot2` is built for a **W25Q080-class** QSPI flash. Change
|
||||
`BOOT2_FIRMWARE` in `firmware/src/main.rs` if the board carries something else.
|
||||
- The **WS2812B** wants 100 nF of local decoupling and draws tens of mA at full
|
||||
brightness. The firmware keeps it deliberately dim, which is both easier to
|
||||
read on a bench and easier on that current.
|
||||
|
||||
## Status indicator
|
||||
|
||||
The WS2812B on GPIO16 reports health at a glance, with no serial port attached:
|
||||
|
||||
| Colour | Meaning | Condition |
|
||||
|---|---|---|
|
||||
| Green, dim | running | default |
|
||||
| Blue | measurement taken | within 120 ms of a successful reading |
|
||||
| Red | sensor error | any failed poll, or `SENSOR_OK` clear |
|
||||
|
||||
The most urgent condition wins: red over blue, blue over green. So a healthy node
|
||||
reads as dim green with a distinct blue pip once a second, and a stalled or
|
||||
failing one is obvious immediately.
|
||||
|
||||
Driven from PIO (`firmware/src/status_led.rs`) rather than via `ws2812-pio`, whose
|
||||
current release pins `rp2040-hal` 0.11 against this project's 0.12 — see that
|
||||
module's header. Generating the waveform in the state machine also means the bus
|
||||
tasks can preempt the LED task freely without glitching it.
|
||||
|
||||
Note that **many parts sold as WS2812B expect red-first rather than green-first
|
||||
byte order**, including the boards this targets. That is one constant,
|
||||
`CHANNEL_ORDER`; if red and green come out swapped while blue is correct, it is
|
||||
the only thing to change.
|
||||
|
||||
## Protocol
|
||||
|
||||
@@ -403,7 +432,7 @@ drives it from registers thereafter.
|
||||
| 1 | `sensor_task` | async | Poll the SHT31 once a second |
|
||||
| 1 | `usb_irq` | hardware | Service the USB CDC diagnostic port |
|
||||
| 1 | `usb_report` | async | Emit a diagnostic line once a second |
|
||||
| 1 | `heartbeat` | async | Blink the status LED |
|
||||
| 1 | `status_led` | async | Repaint the WS2812B indicator |
|
||||
|
||||
The central decision is that **requests are answered entirely from a cached
|
||||
reading**. An SHT31 high-repeatability conversion takes up to 15 ms — far longer
|
||||
|
||||
Reference in New Issue
Block a user