Switch to DMA, use new clocks, don't take ownership of pio common
This commit is contained in:
parent
1be6e53316
commit
1ebb742fbf
@ -4,18 +4,30 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::dma::{AnyChannel, Channel};
|
||||||
use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
|
use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
|
||||||
use embassy_rp::relocate::RelocatedProgram;
|
use embassy_rp::relocate::RelocatedProgram;
|
||||||
|
use embassy_rp::{clocks, into_ref, Peripheral, PeripheralRef};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use fixed::types::U24F8;
|
||||||
use fixed_macro::fixed;
|
use fixed_macro::fixed;
|
||||||
use smart_leds::RGB8;
|
use smart_leds::RGB8;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
pub struct Ws2812<'d, P: Instance, const S: usize> {
|
|
||||||
|
pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
|
||||||
|
dma: PeripheralRef<'d, AnyChannel>,
|
||||||
sm: StateMachine<'d, P, S>,
|
sm: StateMachine<'d, P, S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
|
impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
|
||||||
pub fn new(mut pio: Common<'d, P>, mut sm: StateMachine<'d, P, S>, pin: impl PioPin) -> Self {
|
pub fn new(
|
||||||
|
pio: &mut Common<'d, P>,
|
||||||
|
mut sm: StateMachine<'d, P, S>,
|
||||||
|
dma: impl Peripheral<P = impl Channel> + 'd,
|
||||||
|
pin: impl PioPin,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(dma);
|
||||||
|
|
||||||
// Setup sm0
|
// Setup sm0
|
||||||
|
|
||||||
// prepare the PIO program
|
// prepare the PIO program
|
||||||
@ -56,7 +68,7 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
|
|||||||
|
|
||||||
// Clock config, measured in kHz to avoid overflows
|
// Clock config, measured in kHz to avoid overflows
|
||||||
// TODO CLOCK_FREQ should come from embassy_rp
|
// TODO CLOCK_FREQ should come from embassy_rp
|
||||||
let clock_freq = fixed!(125_000: U24F8);
|
let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000);
|
||||||
let ws2812_freq = fixed!(800: U24F8);
|
let ws2812_freq = fixed!(800: U24F8);
|
||||||
let bit_freq = ws2812_freq * CYCLES_PER_BIT;
|
let bit_freq = ws2812_freq * CYCLES_PER_BIT;
|
||||||
cfg.clock_divider = clock_freq / bit_freq;
|
cfg.clock_divider = clock_freq / bit_freq;
|
||||||
@ -72,16 +84,22 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
|
|||||||
sm.set_config(&cfg);
|
sm.set_config(&cfg);
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
|
|
||||||
Self { sm }
|
Self {
|
||||||
|
dma: dma.map_into(),
|
||||||
|
sm,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn write(&mut self, colors: &[RGB8]) {
|
pub async fn write(&mut self, colors: &[RGB8; N]) {
|
||||||
for color in colors {
|
// Precompute the word bytes from the colors
|
||||||
let word = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8);
|
let mut words = [0u32; N];
|
||||||
if !self.sm.tx().try_push(word) {
|
for i in 0..N {
|
||||||
self.sm.tx().wait_push(word).await;
|
let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8);
|
||||||
}
|
words[i] = word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA transfer
|
||||||
|
self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +123,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
info!("Start");
|
info!("Start");
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
let Pio { common, sm0, .. } = Pio::new(p.PIO0);
|
let Pio { mut common, sm0, .. } = Pio::new(p.PIO0);
|
||||||
|
|
||||||
// This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
|
// This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
|
||||||
// feather boards for the 2040 both have one built in.
|
// feather boards for the 2040 both have one built in.
|
||||||
@ -114,7 +132,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
// For the thing plus, use pin 8
|
// For the thing plus, use pin 8
|
||||||
// For the feather, use pin 16
|
// For the feather, use pin 16
|
||||||
let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8);
|
let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
|
||||||
|
|
||||||
// Loop forever making RGB values and pushing them out to the WS2812.
|
// Loop forever making RGB values and pushing them out to the WS2812.
|
||||||
loop {
|
loop {
|
||||||
|
Loading…
Reference in New Issue
Block a user