-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove buffering when writing data to neopixels
Co-authored-by: pnwkw <pnwkw@users.noreply.github.com>
- Loading branch information
Showing
2 changed files
with
109 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use embassy_rp::dma::{AnyChannel, Channel}; | ||
use embassy_rp::pio::{Common, FifoJoin, Instance, PioPin, ShiftConfig, ShiftDirection, StateMachine}; | ||
use embassy_rp::{clocks, into_ref, Peripheral, PeripheralRef}; | ||
use fixed::types::U24F8; | ||
use fixed_macro::fixed; | ||
pub struct Ws2812<'d, P: Instance, const S: usize> { | ||
#[allow(dead_code)] // leaving dma for future experiments | ||
dma: PeripheralRef<'d, AnyChannel>, | ||
sm: StateMachine<'d, P, S>, | ||
} | ||
|
||
impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { | ||
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 | ||
|
||
// prepare the PIO program | ||
let side_set = pio::SideSet::new(false, 1, false); | ||
let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); | ||
|
||
const T1: u8 = 2; // start bit | ||
const T2: u8 = 5; // data bit | ||
const T3: u8 = 3; // stop bit | ||
const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; | ||
|
||
let mut wrap_target = a.label(); | ||
let mut wrap_source = a.label(); | ||
let mut do_zero = a.label(); | ||
a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); | ||
a.bind(&mut wrap_target); | ||
// Do stop bit | ||
a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); | ||
// Do start bit | ||
a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); | ||
// Do data bit = 1 | ||
a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); | ||
a.bind(&mut do_zero); | ||
// Do data bit = 0 | ||
a.nop_with_delay_and_side_set(T2 - 1, 0); | ||
a.bind(&mut wrap_source); | ||
|
||
let prg = a.assemble_with_wrap(wrap_source, wrap_target); | ||
let mut cfg = embassy_rp::pio::Config::default(); | ||
|
||
// Pin config | ||
let out_pin = pio.make_pio_pin(pin); | ||
cfg.set_out_pins(&[&out_pin]); | ||
cfg.set_set_pins(&[&out_pin]); | ||
|
||
cfg.use_program(&pio.load_program(&prg), &[&out_pin]); | ||
|
||
// Clock config, measured in kHz to avoid overflows | ||
// TODO CLOCK_FREQ should come from embassy_rp | ||
let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); | ||
let ws2812_freq = fixed!(800: U24F8); | ||
let bit_freq = ws2812_freq * CYCLES_PER_BIT; | ||
cfg.clock_divider = clock_freq / bit_freq; | ||
|
||
// FIFO config | ||
cfg.fifo_join = FifoJoin::TxOnly; | ||
cfg.shift_out = ShiftConfig { | ||
auto_fill: true, | ||
threshold: 24, | ||
direction: ShiftDirection::Left, | ||
}; | ||
|
||
sm.set_config(&cfg); | ||
sm.set_enable(true); | ||
|
||
Self { | ||
dma: dma.map_into(), | ||
sm, | ||
} | ||
} | ||
|
||
// left here for future experiments | ||
pub async fn _write_dma(&mut self, data: &[u32]) { | ||
self.sm.tx().dma_push(self.dma.reborrow(), data).await; | ||
} | ||
|
||
pub fn write(&mut self, r: u8, g: u8, b: u8) { | ||
let word = u32::from_be_bytes([g, r, b, 0]); | ||
// we need to watch out not to overflow the FIFO, see: | ||
// https://github.com/rp-rs/ws2812-pio-rs/blob/944494ca9dad73933f700408c3054c8f14c78998/src/lib.rs#L177-L179 | ||
while !self.sm.tx().try_push(word) { | ||
cortex_m::asm::nop(); | ||
} | ||
} | ||
} |