Embasy-rp ws2812-pio does not work from a task
⚓ Rust 📅 2026-02-11 👤 surdeus 👁️ 1I'm trying to use the neopixel PIO program from embassy_rp, based on this example. That works, but if I try to move my use of the RGB led to a task, it does not. It's not panicing, but the led does not change. I can verify the task is running by blinking a plain led in the same loop.
My board is the waveshare rp2040-zero, which unfortunately does not expose debug pins.
Can anyone help me figure out what's going on?
Full code below:
//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules.
//! See (https://www.sparkfun.com/categories/tags/ws2812)
//! original example: https://raw.githubusercontent.com/embassy-rs/embassy/refs/tags/embassy-rp-v0.9.0/examples/rp/src/bin/pio_ws2812.rs
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::peripherals::PIO0;
use embassy_rp::pio::{InterruptHandler, Pio};
use embassy_rp::pio_programs::ws2812::{Grb, PioWs2812, PioWs2812Program};
use embassy_time::{Duration, Ticker};
use smart_leds::RGB8;
use panic_probe as _;
bind_interrupts!(struct Irqs {
PIO0_IRQ_0 => InterruptHandler<PIO0>;
});
/// Input a value 0 to 255 to get a color value
/// The colours are a transition r - g - b - back to r.
fn wheel(mut wheel_pos: u8) -> RGB8 {
wheel_pos = 255 - wheel_pos;
if wheel_pos < 85 {
return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
}
if wheel_pos < 170 {
wheel_pos -= 85;
return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
}
wheel_pos -= 170;
(wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
}
#[embassy_executor::main]
async fn main(#[allow(unused_variables)]spawner: Spawner) {
//info!("Start");
let p = embassy_rp::init(Default::default());
// normal led on breadboard at pin 29
let led = Output::new(p.PIN_29, Level::Low);
let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
// waveshare rp2040-zero neopixel on pin 16:
let program = PioWs2812Program::new(&mut common);
let ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program);
// Works:
// blink(led, ws2812).await;
// Doesn't work, RBG does not change:
spawner.spawn(blink_task(led, ws2812)).unwrap();
}
async fn blink(mut led: Output<'static>, mut ws2812: PioWs2812<'static, PIO0, 0, 1, Grb>) {
// Loop forever making RGB values and pushing them out to the WS2812.
const NUM_LEDS: usize = 1;
let mut data = [RGB8::default(); NUM_LEDS];
let mut ticker = Ticker::every(Duration::from_millis(100));
loop {
for j in 0..(256 * 5) {
// debug!("New Colors:");
for i in 0..NUM_LEDS {
data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
// debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
}
ws2812.write(&data).await;
led.toggle(); // blink normal led as proof of life
ticker.next().await;
}
}
}
#[embassy_executor::task]
async fn blink_task(led: Output<'static>, ws2812: PioWs2812<'static, PIO0, 0, 1, Grb>) {
blink(led, ws2812).await;
}
Thanks.
4 posts - 2 participants
🏷️ Rust_feed