diff options
| author | Caleb Jamison <[email protected]> | 2023-05-19 16:48:47 -0400 |
|---|---|---|
| committer | Caleb Jamison <[email protected]> | 2023-05-19 16:48:47 -0400 |
| commit | 1ebb742fbf9839ab393c038f320003a9346d37ff (patch) | |
| tree | 39c10160c5e0e182d2e217db05a1738aac314229 | |
| parent | 1be6e533165cb773979739c203b745df24ff1ecf (diff) | |
Switch to DMA, use new clocks, don't take ownership of pio common
| -rw-r--r-- | examples/rp/src/bin/pio_ws2812.rs | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index 4915c7e92..26422421f 100644 --- a/examples/rp/src/bin/pio_ws2812.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 |
| @@ -56,7 +68,7 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { | |||
| 56 | 68 | ||
| 57 | // Clock config, measured in kHz to avoid overflows | 69 | // Clock config, measured in kHz to avoid overflows |
| 58 | // TODO CLOCK_FREQ should come from embassy_rp | 70 | // TODO CLOCK_FREQ should come from embassy_rp |
| 59 | let clock_freq = fixed!(125_000: U24F8); | 71 | let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); |
| 60 | let ws2812_freq = fixed!(800: U24F8); | 72 | let ws2812_freq = fixed!(800: U24F8); |
| 61 | let bit_freq = ws2812_freq * CYCLES_PER_BIT; | 73 | let bit_freq = ws2812_freq * CYCLES_PER_BIT; |
| 62 | cfg.clock_divider = clock_freq / bit_freq; | 74 | cfg.clock_divider = clock_freq / bit_freq; |
| @@ -72,16 +84,22 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { | |||
| 72 | sm.set_config(&cfg); | 84 | sm.set_config(&cfg); |
| 73 | sm.set_enable(true); | 85 | sm.set_enable(true); |
| 74 | 86 | ||
| 75 | Self { sm } | 87 | Self { |
| 88 | dma: dma.map_into(), | ||
| 89 | sm, | ||
| 90 | } | ||
| 76 | } | 91 | } |
| 77 | 92 | ||
| 78 | pub async fn write(&mut self, colors: &[RGB8]) { | 93 | pub async fn write(&mut self, colors: &[RGB8; N]) { |
| 79 | for color in colors { | 94 | // Precompute the word bytes from the colors |
| 80 | let word = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); | 95 | let mut words = [0u32; N]; |
| 81 | if !self.sm.tx().try_push(word) { | 96 | for i in 0..N { |
| 82 | self.sm.tx().wait_push(word).await; | 97 | let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); |
| 83 | } | 98 | words[i] = word; |
| 84 | } | 99 | } |
| 100 | |||
| 101 | // DMA transfer | ||
| 102 | self.sm.tx().dma_push(self.dma.reborrow(), &words).await; | ||
| 85 | } | 103 | } |
| 86 | } | 104 | } |
| 87 | 105 | ||
| @@ -105,7 +123,7 @@ async fn main(_spawner: Spawner) { | |||
| 105 | info!("Start"); | 123 | info!("Start"); |
| 106 | let p = embassy_rp::init(Default::default()); | 124 | let p = embassy_rp::init(Default::default()); |
| 107 | 125 | ||
| 108 | let Pio { common, sm0, .. } = Pio::new(p.PIO0); | 126 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0); |
| 109 | 127 | ||
| 110 | // 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 |
| 111 | // feather boards for the 2040 both have one built in. | 129 | // feather boards for the 2040 both have one built in. |
| @@ -114,7 +132,7 @@ async fn main(_spawner: Spawner) { | |||
| 114 | 132 | ||
| 115 | // For the thing plus, use pin 8 | 133 | // For the thing plus, use pin 8 |
| 116 | // For the feather, use pin 16 | 134 | // For the feather, use pin 16 |
| 117 | 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); |
| 118 | 136 | ||
| 119 | // 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. |
| 120 | loop { | 138 | loop { |
