aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-19 20:53:26 +0000
committerGitHub <[email protected]>2023-05-19 20:53:26 +0000
commitd55b9bc6e2de528e1351b992bb30f54ec6f76b6d (patch)
tree39c10160c5e0e182d2e217db05a1738aac314229
parentd737e3dcbb67af114490834c617de9100b65d5fb (diff)
parent1ebb742fbf9839ab393c038f320003a9346d37ff (diff)
Merge #1440
1440: rp: Pin fix, improve fifo handling r=Dirbaio a=CBJamo Went to actually use this code and found two issues: * The config for the pins got dropped in the shuffle. * I found that when using more than one ws2812, only the first would get data. I'm pretty sure the data was shifted out before the task got back to push the next word. So now the fifo gets filled, then we wait. Co-authored-by: Caleb Jamison <[email protected]> Co-authored-by: Caleb Jamison <[email protected]>
-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
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::dma::{AnyChannel, Channel};
7use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; 8use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
8use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
10use embassy_rp::{clocks, into_ref, Peripheral, PeripheralRef};
9use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
12use fixed::types::U24F8;
10use fixed_macro::fixed; 13use fixed_macro::fixed;
11use smart_leds::RGB8; 14use smart_leds::RGB8;
12use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
13pub struct Ws2812<'d, P: Instance, const S: usize> { 16
17pub 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
17impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { 22impl<'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 {