diff options
| -rw-r--r-- | examples/rp/src/bin/pio_ws2812.rs (renamed from examples/rp/src/bin/ws2812-pio.rs) | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/pio_ws2812.rs index f4c2d6313..26422421f 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/pio_ws2812.rs | |||
| @@ -4,18 +4,30 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_rp::dma::{AnyChannel, Channel}; | ||
| 7 | use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; | 8 | use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; |
| 8 | use embassy_rp::relocate::RelocatedProgram; | 9 | use embassy_rp::relocate::RelocatedProgram; |
| 10 | use embassy_rp::{clocks, into_ref, Peripheral, PeripheralRef}; | ||
| 9 | use embassy_time::{Duration, Timer}; | 11 | use embassy_time::{Duration, Timer}; |
| 12 | use fixed::types::U24F8; | ||
| 10 | use fixed_macro::fixed; | 13 | use fixed_macro::fixed; |
| 11 | use smart_leds::RGB8; | 14 | use smart_leds::RGB8; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | pub struct Ws2812<'d, P: Instance, const S: usize> { | 16 | |
| 17 | pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { | ||
| 18 | dma: PeripheralRef<'d, AnyChannel>, | ||
| 14 | sm: StateMachine<'d, P, S>, | 19 | sm: StateMachine<'d, P, S>, |
| 15 | } | 20 | } |
| 16 | 21 | ||
| 17 | impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { | 22 | impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { |
| 18 | pub fn new(mut pio: Common<'d, P>, mut sm: StateMachine<'d, P, S>, pin: impl PioPin) -> Self { | 23 | pub fn new( |
| 24 | pio: &mut Common<'d, P>, | ||
| 25 | mut sm: StateMachine<'d, P, S>, | ||
| 26 | dma: impl Peripheral<P = impl Channel> + 'd, | ||
| 27 | pin: impl PioPin, | ||
| 28 | ) -> Self { | ||
| 29 | into_ref!(dma); | ||
| 30 | |||
| 19 | // Setup sm0 | 31 | // Setup sm0 |
| 20 | 32 | ||
| 21 | // prepare the PIO program | 33 | // prepare the PIO program |
| @@ -48,13 +60,15 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { | |||
| 48 | 60 | ||
| 49 | // Pin config | 61 | // Pin config |
| 50 | let out_pin = pio.make_pio_pin(pin); | 62 | let out_pin = pio.make_pio_pin(pin); |
| 63 | cfg.set_out_pins(&[&out_pin]); | ||
| 64 | cfg.set_set_pins(&[&out_pin]); | ||
| 51 | 65 | ||
| 52 | let relocated = RelocatedProgram::new(&prg); | 66 | let relocated = RelocatedProgram::new(&prg); |
| 53 | cfg.use_program(&pio.load_program(&relocated), &[&out_pin]); | 67 | cfg.use_program(&pio.load_program(&relocated), &[&out_pin]); |
| 54 | 68 | ||
| 55 | // Clock config, measured in kHz to avoid overflows | 69 | // Clock config, measured in kHz to avoid overflows |
| 56 | // TODO CLOCK_FREQ should come from embassy_rp | 70 | // TODO CLOCK_FREQ should come from embassy_rp |
| 57 | let clock_freq = fixed!(125_000: U24F8); | 71 | let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); |
| 58 | let ws2812_freq = fixed!(800: U24F8); | 72 | let ws2812_freq = fixed!(800: U24F8); |
| 59 | let bit_freq = ws2812_freq * CYCLES_PER_BIT; | 73 | let bit_freq = ws2812_freq * CYCLES_PER_BIT; |
| 60 | cfg.clock_divider = clock_freq / bit_freq; | 74 | cfg.clock_divider = clock_freq / bit_freq; |
| @@ -70,14 +84,22 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { | |||
| 70 | sm.set_config(&cfg); | 84 | sm.set_config(&cfg); |
| 71 | sm.set_enable(true); | 85 | sm.set_enable(true); |
| 72 | 86 | ||
| 73 | Self { sm } | 87 | Self { |
| 88 | dma: dma.map_into(), | ||
| 89 | sm, | ||
| 90 | } | ||
| 74 | } | 91 | } |
| 75 | 92 | ||
| 76 | pub async fn write(&mut self, colors: &[RGB8]) { | 93 | pub async fn write(&mut self, colors: &[RGB8; N]) { |
| 77 | for color in colors { | 94 | // Precompute the word bytes from the colors |
| 78 | let word = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); | 95 | let mut words = [0u32; N]; |
| 79 | self.sm.tx().wait_push(word).await; | 96 | for i in 0..N { |
| 97 | let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); | ||
| 98 | words[i] = word; | ||
| 80 | } | 99 | } |
| 100 | |||
| 101 | // DMA transfer | ||
| 102 | self.sm.tx().dma_push(self.dma.reborrow(), &words).await; | ||
| 81 | } | 103 | } |
| 82 | } | 104 | } |
| 83 | 105 | ||
| @@ -101,7 +123,7 @@ async fn main(_spawner: Spawner) { | |||
| 101 | info!("Start"); | 123 | info!("Start"); |
| 102 | let p = embassy_rp::init(Default::default()); | 124 | let p = embassy_rp::init(Default::default()); |
| 103 | 125 | ||
| 104 | let Pio { common, sm0, .. } = Pio::new(p.PIO0); | 126 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0); |
| 105 | 127 | ||
| 106 | // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit | 128 | // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit |
| 107 | // feather boards for the 2040 both have one built in. | 129 | // feather boards for the 2040 both have one built in. |
| @@ -110,7 +132,7 @@ async fn main(_spawner: Spawner) { | |||
| 110 | 132 | ||
| 111 | // For the thing plus, use pin 8 | 133 | // For the thing plus, use pin 8 |
| 112 | // For the feather, use pin 16 | 134 | // For the feather, use pin 16 |
| 113 | let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8); | 135 | let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); |
| 114 | 136 | ||
| 115 | // Loop forever making RGB values and pushing them out to the WS2812. | 137 | // Loop forever making RGB values and pushing them out to the WS2812. |
| 116 | loop { | 138 | loop { |
