diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 7faec10b..5433d3f2 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -5,14 +5,14 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; -use embassy_hal_common::PeripheralRef; +use embassy_hal_common::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::{Channel, Transfer}; +use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{Drive, Pin, Pull, SlewRate}; -use crate::pac::dma::vals::{DataSize, TreqSel}; -use crate::pio::sealed::{PioInstance as _, SmInstance as _}; +use crate::pac::dma::vals::TreqSel; +use crate::pio::sealed::PioInstance as _; use crate::{interrupt, pac, peripherals, RegExt}; struct Wakers([AtomicWaker; 12]); @@ -119,10 +119,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture if self.get_mut().sm.try_push_tx(value) { Poll::Ready(()) } else { - WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::SM as usize].register(cx.waker()); unsafe { PIO::PIO.irqs(0).inte().write_set(|m| { - m.0 = TXNFULL_MASK << SM::Sm::SM_NO; + m.0 = TXNFULL_MASK << SM::SM; }); } // debug!("Pending"); @@ -135,7 +135,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<' fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { - m.0 = TXNFULL_MASK << SM::Sm::SM_NO; + m.0 = TXNFULL_MASK << SM::SM; }); } } @@ -164,10 +164,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, if let Some(v) = self.sm.try_pull_rx() { Poll::Ready(v) } else { - WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::SM].register(cx.waker()); unsafe { PIO::PIO.irqs(0).inte().write_set(|m| { - m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; + m.0 = RXNEMPTY_MASK << SM::SM; }); } //debug!("Pending"); @@ -180,7 +180,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { - m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; + m.0 = RXNEMPTY_MASK << SM::SM; }); } } @@ -277,15 +277,14 @@ impl PioPin { #[inline] pub fn set_pull(&mut self, pull: Pull) { unsafe { - self.pad_ctrl().modify(|w| match pull { - Pull::Up => w.set_pue(true), - Pull::Down => w.set_pde(true), - Pull::None => {} + self.pad_ctrl().modify(|w| { + w.set_pue(pull == Pull::Up); + w.set_pde(pull == Pull::Down); }); } } - /// Set the pin's pull. + /// Set the pin's schmitt trigger. #[inline] pub fn set_schmitt(&mut self, enable: bool) { unsafe { @@ -298,9 +297,11 @@ impl PioPin { pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { let mask = 1 << self.pin(); unsafe { - PIO::PIO - .input_sync_bypass() - .modify(|w| *w = if bypass { *w & !mask } else { *w | mask }); + if bypass { + PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); + } else { + PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); + } } } @@ -315,16 +316,15 @@ impl SealedPin for PioPin { } } -pub struct PioStateMachineInstance { - pio: PhantomData, - sm: PhantomData, +pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> { + pio: PhantomData<&'d PIO>, } -impl sealed::PioStateMachine for PioStateMachineInstance { +impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { type Pio = PIO; - type Sm = SM; + const SM: usize = SM; } -impl PioStateMachine for PioStateMachineInstance {} +impl<'d, PIO: PioInstance, const SM: usize> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {} pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn pio_no(&self) -> u8 { @@ -332,60 +332,61 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn sm_no(&self) -> u8 { - Self::Sm::SM_NO + Self::SM as u8 } fn restart(&mut self) { + let mask = 1u8 << Self::SM; unsafe { - Self::Pio::PIO - .ctrl() - .modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO)); + Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); } } fn set_enable(&mut self, enable: bool) { - let mask = 1u8 << Self::Sm::SM_NO; + let mask = 1u8 << Self::SM; unsafe { - Self::Pio::PIO - .ctrl() - .modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); + if enable { + Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); + } else { + Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); + } } } fn is_enabled(&self) -> bool { - unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::SM) != 0 } } fn is_tx_empty(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::SM) != 0 } } fn is_tx_full(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::SM) != 0 } } fn is_rx_empty(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::SM) != 0 } } fn is_rx_full(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::SM) != 0 } } fn tx_level(&self) -> u8 { unsafe { let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::Sm::SM_NO * 8)) as u8 & 0x0f + (flevel >> (Self::SM * 8)) as u8 & 0x0f } } fn rx_level(&self) -> u8 { unsafe { let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f + (flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f } } fn push_tx(&mut self, v: u32) { unsafe { - Self::Pio::PIO.txf(Self::Sm::SM_NO as usize).write_value(v); + Self::Pio::PIO.txf(Self::SM).write_value(v); } } @@ -398,7 +399,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn pull_rx(&mut self) -> u32 { - unsafe { Self::Pio::PIO.rxf(Self::Sm::SM_NO as usize).read() } + unsafe { Self::Pio::PIO.rxf(Self::SM).read() } } fn try_pull_rx(&mut self) -> Option { @@ -410,73 +411,54 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_clkdiv(&mut self, div_x_256: u32) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .clkdiv() - .write(|w| w.0 = div_x_256 << 8); + Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); } } fn get_clkdiv(&self) -> u32 { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).clkdiv().read().0 >> 8 } + unsafe { Self::this_sm().clkdiv().read().0 >> 8 } } fn clkdiv_restart(&mut self) { + let mask = 1u8 << Self::SM; unsafe { - Self::Pio::PIO - .ctrl() - .modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO)); + Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); } } fn set_side_enable(&self, enable: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| w.set_side_en(enable)); + Self::this_sm().execctrl().modify(|w| w.set_side_en(enable)); } } fn is_side_enabled(&self) -> bool { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().side_en() } + unsafe { Self::this_sm().execctrl().read().side_en() } } fn set_side_pindir(&mut self, pindir: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| w.set_side_pindir(pindir)); + Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir)); } } fn is_side_pindir(&self) -> bool { - unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .read() - .side_pindir() - } + unsafe { Self::this_sm().execctrl().read().side_pindir() } } fn set_jmp_pin(&mut self, pin: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| w.set_jmp_pin(pin)); + Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); } } fn get_jmp_pin(&mut self) -> u8 { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().jmp_pin() } + unsafe { Self::this_sm().execctrl().read().jmp_pin() } } fn set_wrap(&self, source: u8, target: u8) { unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().modify(|w| { + Self::this_sm().execctrl().modify(|w| { w.set_wrap_top(source); w.set_wrap_bottom(target) }); @@ -486,7 +468,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { /// Get wrapping addresses. Returns (source, target). fn get_wrap(&self) -> (u8, u8) { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read(); + let r = Self::this_sm().execctrl().read(); (r.wrap_top(), r.wrap_bottom()) } } @@ -498,7 +480,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { FifoJoin::TxOnly => (false, true), }; unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().modify(|w| { + Self::this_sm().shiftctrl().modify(|w| { w.set_fjoin_rx(rx); w.set_fjoin_tx(tx) }); @@ -506,7 +488,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_fifo_join(&self) -> FifoJoin { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); + let r = Self::this_sm().shiftctrl().read(); // Ignores the invalid state when both bits are set if r.fjoin_rx() { FifoJoin::RxOnly @@ -521,7 +503,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs unsafe { - let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl(); + let shiftctrl = Self::this_sm().shiftctrl(); shiftctrl.modify(|w| { w.set_fjoin_rx(!w.fjoin_rx()); }); @@ -533,51 +515,33 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_pull_threshold(&mut self, threshold: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_pull_thresh(threshold)); + Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold)); } } fn get_pull_threshold(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); - r.pull_thresh() - } + unsafe { Self::this_sm().shiftctrl().read().pull_thresh() } } fn set_push_threshold(&mut self, threshold: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_push_thresh(threshold)); + Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold)); } } fn get_push_threshold(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); - r.push_thresh() - } + unsafe { Self::this_sm().shiftctrl().read().push_thresh() } } fn set_out_shift_dir(&mut self, dir: ShiftDirection) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) + Self::this_sm() .shiftctrl() .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); } } fn get_out_shiftdir(&self) -> ShiftDirection { unsafe { - if Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .out_shiftdir() - { + if Self::this_sm().shiftctrl().read().out_shiftdir() { ShiftDirection::Right } else { ShiftDirection::Left @@ -587,20 +551,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_in_shift_dir(&mut self, dir: ShiftDirection) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) + Self::this_sm() .shiftctrl() .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); } } fn get_in_shiftdir(&self) -> ShiftDirection { unsafe { - if Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .in_shiftdir() - { + if Self::this_sm().shiftctrl().read().in_shiftdir() { ShiftDirection::Right } else { ShiftDirection::Left @@ -610,76 +568,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_autopull(&mut self, auto: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_autopull(auto)); + Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto)); } } fn is_autopull(&self) -> bool { - unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .autopull() - } + unsafe { Self::this_sm().shiftctrl().read().autopull() } } fn set_autopush(&mut self, auto: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_autopush(auto)); + Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto)); } } fn is_autopush(&self) -> bool { - unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .autopush() - } + unsafe { Self::this_sm().shiftctrl().read().autopush() } } fn get_addr(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read(); - r.addr() - } + unsafe { Self::this_sm().addr().read().addr() } } fn set_sideset_count(&mut self, count: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| w.set_sideset_count(count)); + Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count)); } } fn get_sideset_count(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); - r.sideset_count() - } + unsafe { Self::this_sm().pinctrl().read().sideset_count() } } fn set_sideset_base_pin(&mut self, base_pin: &PioPin) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| w.set_sideset_base(base_pin.pin())); + Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin())); } } fn get_sideset_base(&self) -> u8 { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); r.sideset_base() } } @@ -688,7 +616,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_set_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { + Self::this_sm().pinctrl().modify(|w| { w.set_set_base(base); w.set_set_count(count) }); @@ -698,23 +626,20 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { /// Get the range of out pins affected by a set instruction. Returns (base, count). fn get_set_range(&self) -> (u8, u8) { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); (r.set_base(), r.set_count()) } } fn set_in_base_pin(&mut self, base: &PioPin) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| w.set_in_base(base.pin())); + Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin())); } } fn get_in_base(&self) -> u8 { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); r.in_base() } } @@ -722,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_out_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { + Self::this_sm().pinctrl().modify(|w| { w.set_out_base(base); w.set_out_count(count) }); @@ -732,7 +657,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { /// Get the range of out pins affected by a set instruction. Returns (base, count). fn get_out_range(&self) -> (u8, u8) { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); (r.out_base(), r.out_count()) } } @@ -760,15 +685,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_current_instr() -> u32 { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).instr().read().0 } + unsafe { Self::this_sm().instr().read().0 } } fn exec_instr(&mut self, instr: u16) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .instr() - .write(|w| w.set_instr(instr)); + Self::this_sm().instr().write(|w| w.set_instr(instr)); } } @@ -787,8 +709,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_tx_stalled(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().txstall() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_txstall(1 << Self::SM)); ret } } @@ -796,8 +718,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_tx_overflowed(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().txover() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_txover(1 << Self::SM)); ret } } @@ -805,8 +727,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_rx_stalled(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_rxstall(1 << Self::SM)); ret } } @@ -814,25 +736,25 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_rx_underflowed(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_rxunder(1 << Self::SM)); ret } } - fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> { + fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { unsafe { let pio_no = Self::Pio::PIO_NO; - let sm_no = Self::Sm::SM_NO; + let sm_no = Self::SM; let p = ch.regs(); p.read_addr().write_value(data.as_ptr() as u32); - p.write_addr() - .write_value(Self::Pio::PIO.txf(sm_no as usize).ptr() as u32); + p.write_addr().write_value(Self::Pio::PIO.txf(sm_no).ptr() as u32); p.trans_count().write_value(data.len() as u32); + compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { // Set TX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + sm_no)); - w.set_data_size(DataSize::SIZE_WORD); + w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8)); + w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(true); w.set_incr_write(false); @@ -843,19 +765,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { Transfer::new(ch) } - fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> { + fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> { unsafe { let pio_no = Self::Pio::PIO_NO; - let sm_no = Self::Sm::SM_NO; + let sm_no = Self::SM; let p = ch.regs(); p.write_addr().write_value(data.as_ptr() as u32); - p.read_addr() - .write_value(Self::Pio::PIO.rxf(sm_no as usize).ptr() as u32); + p.read_addr().write_value(Self::Pio::PIO.rxf(sm_no).ptr() as u32); p.trans_count().write_value(data.len() as u32); + compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { - // Set TX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4)); - w.set_data_size(DataSize::SIZE_WORD); + // Set RX DREQ for this statemachine + w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8 + 4)); + w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(false); w.set_incr_write(true); @@ -867,21 +789,18 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } -pub struct PioCommonInstance { +pub struct PioCommon<'d, PIO: PioInstance> { instructions_used: u32, - pio: PhantomData, + pio: PhantomData<&'d PIO>, } -pub struct PioInstanceMemory { +pub struct PioInstanceMemory<'d, PIO: PioInstance> { used_mask: u32, - pio: PhantomData, + pio: PhantomData<&'d PIO>, } -impl sealed::PioCommon for PioCommonInstance { - type Pio = PIO; -} -impl PioCommon for PioCommonInstance { - fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory +impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { + pub fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO> where I: Iterator, { @@ -908,66 +827,50 @@ impl PioCommon for PioCommonInstance { } } - fn free_instr(&mut self, instrs: PioInstanceMemory) { + // TODO make instruction memory that is currently in use unfreeable + pub fn free_instr(&mut self, instrs: PioInstanceMemory) { self.instructions_used &= !instrs.used_mask; } -} -pub trait PioCommon: sealed::PioCommon + Sized { - fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory - where - I: Iterator; - - // TODO make instruction memory that is currently in use unfreeable - fn free_instr(&mut self, instrs: PioInstanceMemory); - - fn is_irq_set(&self, irq_no: u8) -> bool { + pub fn is_irq_set(&self, irq_no: u8) -> bool { assert!(irq_no < 8); unsafe { - let irq_flags = Self::Pio::PIO.irq(); + let irq_flags = PIO::PIO.irq(); irq_flags.read().0 & (1 << irq_no) != 0 } } - fn clear_irq(&mut self, irq_no: usize) { + pub fn clear_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } + unsafe { PIO::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } } - fn clear_irqs(&mut self, mask: u8) { - unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) } + pub fn clear_irqs(&mut self, mask: u8) { + unsafe { PIO::PIO.irq().write(|w| w.set_irq(mask)) } } - fn force_irq(&mut self, irq_no: usize) { + pub fn force_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { Self::Pio::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } + unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } } - fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { + pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { unsafe { - Self::Pio::PIO - .input_sync_bypass() - .modify(|w| *w = (*w & !mask) | (bypass & mask)); + // this can interfere with per-pin bypass functions. splitting the + // modification is going to be fine since nothing that relies on + // it can reasonably run before we finish. + PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); + PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); } } - fn get_input_sync_bypass(&self) -> u32 { - unsafe { Self::Pio::PIO.input_sync_bypass().read() } + pub fn get_input_sync_bypass(&self) -> u32 { + unsafe { PIO::PIO.input_sync_bypass().read() } } - fn make_pio_pin(&self, pin: impl Pin) -> PioPin { + pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin { unsafe { - pin.io().ctrl().write(|w| { - w.set_funcsel( - if Self::Pio::PIO_NO == 1 { - pac::io::vals::Gpio0ctrlFuncsel::PIO1_0 - } else { - // PIO == 0 - pac::io::vals::Gpio0ctrlFuncsel::PIO0_0 - } - .0, - ); - }); + pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); } PioPin { pin_bank: pin.pin_bank(), @@ -976,112 +879,63 @@ pub trait PioCommon: sealed::PioCommon + Sized { } } -// Identifies a specific state machine inside a PIO device -pub struct SmInstanceBase {} - -pub trait SmInstance: sealed::SmInstance + Unpin {} - -impl sealed::SmInstance for SmInstanceBase { - const SM_NO: u8 = SM_NO; +pub struct Pio<'d, PIO: PioInstance> { + pub common: PioCommon<'d, PIO>, + pub sm0: PioStateMachineInstance<'d, PIO, 0>, + pub sm1: PioStateMachineInstance<'d, PIO, 1>, + pub sm2: PioStateMachineInstance<'d, PIO, 2>, + pub sm3: PioStateMachineInstance<'d, PIO, 3>, } -impl SmInstance for SmInstanceBase {} -pub trait PioPeripheral: sealed::PioPeripheral + Sized { - fn pio(&self) -> u8 { - Self::Pio::PIO_NO - } - - fn split( - self, - ) -> ( - PioCommonInstance, - PioStateMachineInstance>, - PioStateMachineInstance>, - PioStateMachineInstance>, - PioStateMachineInstance>, - ) { - ( - PioCommonInstance { +impl<'d, PIO: PioInstance> Pio<'d, PIO> { + pub fn new(_pio: impl Peripheral

+ 'd) -> Self { + Self { + common: PioCommon { instructions_used: 0, - pio: PhantomData::default(), + pio: PhantomData, }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - ) + sm0: PioStateMachineInstance { pio: PhantomData }, + sm1: PioStateMachineInstance { pio: PhantomData }, + sm2: PioStateMachineInstance { pio: PhantomData }, + sm3: PioStateMachineInstance { pio: PhantomData }, + } + } +} + +pub trait PioInstance: sealed::PioInstance + Sized + Unpin { + fn pio(&self) -> u8 { + Self::PIO_NO } } mod sealed { + pub trait PioStateMachine { + type Pio: super::PioInstance; + const SM: usize; + + #[inline(always)] + fn this_sm() -> crate::pac::pio::StateMachine { + Self::Pio::PIO.sm(Self::SM as usize) + } + } + pub trait PioInstance { const PIO_NO: u8; const PIO: &'static crate::pac::pio::Pio; - } - - pub trait PioCommon { - type Pio: super::PioInstance; - } - - pub trait PioStateMachine { - type Pio: super::PioInstance; - type Sm: super::SmInstance; - } - - pub trait SmInstance { - const SM_NO: u8; - } - - pub trait PioPeripheral { - type Pio: super::PioInstance; + const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; } } -// Identifies a specific PIO device -pub struct PioInstanceBase {} - -pub trait PioInstance: sealed::PioInstance + Unpin {} - -impl sealed::PioInstance for PioInstanceBase<0> { - const PIO_NO: u8 = 0; - const PIO: &'static pac::pio::Pio = &pac::PIO0; -} -impl PioInstance for PioInstanceBase<0> {} - -impl sealed::PioInstance for PioInstanceBase<1> { - const PIO_NO: u8 = 1; - const PIO: &'static pac::pio::Pio = &pac::PIO1; -} -impl PioInstance for PioInstanceBase<1> {} - -pub type Pio0 = PioInstanceBase<0>; -pub type Pio1 = PioInstanceBase<1>; - -pub type Sm0 = SmInstanceBase<0>; -pub type Sm1 = SmInstanceBase<1>; -pub type Sm2 = SmInstanceBase<2>; -pub type Sm3 = SmInstanceBase<3>; - -macro_rules! impl_pio_sm { - ($name:ident, $pio:expr) => { - impl sealed::PioPeripheral for peripherals::$name { - type Pio = PioInstanceBase<$pio>; +macro_rules! impl_pio { + ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { + impl sealed::PioInstance for peripherals::$name { + const PIO_NO: u8 = $pio; + const PIO: &'static pac::pio::Pio = &pac::$pac; + const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel; } - impl PioPeripheral for peripherals::$name {} + impl PioInstance for peripherals::$name {} }; } -impl_pio_sm!(PIO0, 0); -impl_pio_sm!(PIO1, 1); +impl_pio!(PIO0, 0, PIO0, PIO0_0); +impl_pio!(PIO1, 1, PIO1, PIO1_0); diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 1b075b8f..5fea7034 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,15 +4,13 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{AnyPin, Pin}; -use embassy_rp::pio::{ - Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, - Sm1, Sm2, -}; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection}; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use {defmt_rtt as _, panic_probe as _}; -fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance, pin: AnyPin) { +fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstance, pin: AnyPin) { // Setup sm0 // Send data serially to pin @@ -40,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm0(mut sm: PioStateMachineInstance) { +async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) { sm.set_enable(true); let mut v = 0x0f0caffa; @@ -51,7 +49,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance) { } } -fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -70,7 +68,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm1(mut sm: PioStateMachineInstance) { +async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) { sm.set_enable(true); loop { let rx = sm.wait_pull().await; @@ -78,7 +76,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance) { } } -fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { // Setup sm2 // Repeatedly trigger IRQ 3 @@ -102,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm2(mut sm: PioStateMachineInstance) { +async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) { sm.set_enable(true); loop { sm.wait_irq(3).await; @@ -115,11 +113,17 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split(); + let Pio { + mut common, + mut sm0, + mut sm1, + mut sm2, + .. + } = Pio::new(pio); - setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); - setup_pio_task_sm1(&mut pio0, &mut sm1); - setup_pio_task_sm2(&mut pio0, &mut sm2); + setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade()); + setup_pio_task_sm1(&mut common, &mut sm1); + setup_pio_task_sm2(&mut common, &mut sm2); spawner.spawn(pio_task_sm0(sm0)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap(); spawner.spawn(pio_task_sm2(sm2)).unwrap(); diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 7d4919f7..0f1f6df1 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_rp::pio::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{Pio, PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +19,11 @@ fn swap_nibbles(v: u32) -> u32 { async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (mut pio0, mut sm, ..) = pio.split(); + let Pio { + mut common, + sm0: mut sm, + .. + } = Pio::new(pio); let prg = pio_proc::pio_asm!( ".origin 0", @@ -34,7 +38,7 @@ async fn main(_spawner: Spawner) { ); let relocated = RelocatedProgram::new(&prg.program); - pio0.write_instr(relocated.origin() as usize, relocated.code()); + common.write_instr(relocated.origin() as usize, relocated.code()); pio_instr_util::exec_jmp(&mut sm, relocated.origin()); sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); let pio::Wrap { source, target } = relocated.wrap(); diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs new file mode 100644 index 00000000..59b4c1f5 --- /dev/null +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -0,0 +1,243 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::fmt::Write; + +use embassy_executor::Spawner; +use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::gpio::Pin; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{FifoJoin, Pio, PioStateMachine, PioStateMachineInstance, ShiftDirection}; +use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::relocate::RelocatedProgram; +use embassy_rp::{into_ref, Peripheral, PeripheralRef}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // this test assumes a 2x16 HD44780 display attached as follow: + // rs = PIN0 + // rw = PIN1 + // e = PIN2 + // db4 = PIN3 + // db5 = PIN4 + // db6 = PIN5 + // db7 = PIN6 + // additionally a pwm signal for a bias voltage charge pump is provided on pin 15, + // allowing direct connection of the display to the RP2040 without level shifters. + let p = embassy_rp::init(Default::default()); + + let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { + let mut c = Config::default(); + c.divider = 125.into(); + c.top = 100; + c.compare_b = 50; + c + }); + + let mut hd = HD44780::new( + p.PIO0, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + ) + .await; + + loop { + struct Buf([u8; N], usize); + impl Write for Buf { + fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { + for b in s.as_bytes() { + if self.1 >= N { + return Err(core::fmt::Error); + } + self.0[self.1] = *b; + self.1 += 1; + } + Ok(()) + } + } + let mut buf = Buf([0; 16], 0); + write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap(); + hd.add_line(&buf.0[0..buf.1]).await; + Timer::after(Duration::from_secs(1)).await; + } +} + +pub struct HD44780<'l> { + dma: PeripheralRef<'l, AnyChannel>, + sm: PioStateMachineInstance<'l, PIO0, 0>, + + buf: [u8; 40], +} + +impl<'l> HD44780<'l> { + pub async fn new( + pio: impl Peripheral

+ 'l, + dma: impl Peripheral

+ 'l, + rs: impl Pin, + rw: impl Pin, + e: impl Pin, + db4: impl Pin, + db5: impl Pin, + db6: impl Pin, + db7: impl Pin, + ) -> HD44780<'l> { + into_ref!(dma); + + let db7pin = db7.pin(); + let Pio { + mut common, mut sm0, .. + } = Pio::new(pio); + + // takes command words ( <0:4>) + let prg = pio_proc::pio_asm!( + r#" + .side_set 1 opt + + loop: + out x, 24 + delay: + jmp x--, delay + out pins, 4 side 1 + out null, 4 side 0 + jmp !osre, loop + irq 0 + "#, + ); + + let rs = common.make_pio_pin(rs); + let rw = common.make_pio_pin(rw); + let e = common.make_pio_pin(e); + let db4 = common.make_pio_pin(db4); + let db5 = common.make_pio_pin(db5); + let db6 = common.make_pio_pin(db6); + let db7 = common.make_pio_pin(db7); + + sm0.set_set_pins(&[&rs, &rw]); + embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11); + sm0.set_set_pins(&[&e]); + embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1); + sm0.set_set_pins(&[&db4, &db5, &db6, &db7]); + embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111); + + let relocated = RelocatedProgram::new(&prg.program); + common.write_instr(relocated.origin() as usize, relocated.code()); + embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); + sm0.set_clkdiv(125 * 256); + let pio::Wrap { source, target } = relocated.wrap(); + sm0.set_wrap(source, target); + sm0.set_side_enable(true); + sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); + sm0.set_sideset_base_pin(&e); + sm0.set_sideset_count(2); + sm0.set_out_shift_dir(ShiftDirection::Left); + sm0.set_fifo_join(FifoJoin::TxOnly); + sm0.set_autopull(true); + sm0.set_pull_threshold(32); + + sm0.set_enable(true); + // init to 8 bit thrice + sm0.push_tx((50000 << 8) | 0x30); + sm0.push_tx((5000 << 8) | 0x30); + sm0.push_tx((200 << 8) | 0x30); + // init 4 bit + sm0.push_tx((200 << 8) | 0x20); + // set font and lines + sm0.push_tx((50 << 8) | 0x20); + sm0.push_tx(0b1100_0000); + + sm0.wait_irq(0).await; + sm0.set_enable(false); + + // takes command sequences ( , data...) + // many side sets are only there to free up a delay bit! + let prg = pio_proc::pio_asm!( + r#" + .origin 7 + .side_set 1 + + .wrap_target + pull side 0 + out x 1 side 0 ; !rs + out y 7 side 0 ; #data - 1 + + ; rs/rw to e: >= 60ns + ; e high time: >= 500ns + ; e low time: >= 500ns + ; read data valid after e falling: ~5ns + ; write data hold after e falling: ~10ns + + loop: + pull side 0 + jmp !x data side 0 + command: + set pins 0b00 side 0 + jmp shift side 0 + data: + set pins 0b01 side 0 + shift: + out pins 4 side 1 [9] + nop side 0 [9] + out pins 4 side 1 [9] + mov osr null side 0 [7] + out pindirs 4 side 0 + set pins 0b10 side 0 + busy: + nop side 1 [9] + jmp pin more side 0 [9] + mov osr ~osr side 1 [9] + nop side 0 [4] + out pindirs 4 side 0 + jmp y-- loop side 0 + .wrap + more: + nop side 1 [9] + jmp busy side 0 [9] + "# + ); + + let relocated = RelocatedProgram::new(&prg.program); + common.write_instr(relocated.origin() as usize, relocated.code()); + embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); + let pio::Wrap { source, target } = relocated.wrap(); + sm0.set_clkdiv(8 * 256); // ~64ns/insn + sm0.set_side_enable(false); + sm0.set_jmp_pin(db7pin); + sm0.set_wrap(source, target); + sm0.set_set_pins(&[&rs, &rw]); + sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); + sm0.set_sideset_base_pin(&e); + sm0.set_sideset_count(1); + sm0.set_out_shift_dir(ShiftDirection::Left); + sm0.set_fifo_join(FifoJoin::TxOnly); + + sm0.set_enable(true); + + // display on and cursor on and blinking, reset display + sm0.dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; + + Self { + dma: dma.map_into(), + sm: sm0, + buf: [0x20; 40], + } + } + + pub async fn add_line(&mut self, s: &[u8]) { + // move cursor to 0:0, prepare 16 characters + self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); + // move line 2 up + self.buf.copy_within(22..38, 3); + // move cursor to 1:0, prepare 16 characters + self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); + // file line 2 with spaces + self.buf[22..38].fill(0x20); + // copy input line + let len = s.len().min(16); + self.buf[22..22 + len].copy_from_slice(&s[0..len]); + // set cursor to 1:15 + self.buf[38..].copy_from_slice(&[0x80, 0xcf]); + + self.sm.dma_push(self.dma.reborrow(), &self.buf).await; + } +} diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 041e8ae1..0975559d 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -6,20 +6,19 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, - ShiftDirection, SmInstance, + FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, }; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use embassy_time::{Duration, Timer}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; -pub struct Ws2812 { - sm: PioStateMachineInstance, +pub struct Ws2812<'d, P: PioInstance, const S: usize> { + sm: PioStateMachineInstance<'d, P, S>, } -impl Ws2812 { - pub fn new(mut pio: PioCommonInstance

, mut sm: PioStateMachineInstance, pin: gpio::AnyPin) -> Self { +impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> { + pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self { // Setup sm0 // prepare the PIO program @@ -116,7 +115,7 @@ async fn main(_spawner: Spawner) { info!("Start"); let p = embassy_rp::init(Default::default()); - let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); + let Pio { common, sm0, .. } = Pio::new(p.PIO0); // 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. @@ -125,7 +124,7 @@ async fn main(_spawner: Spawner) { // For the thing plus, use pin 8 // For the feather, use pin 16 - let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade()); + let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade()); // Loop forever making RGB values and pushing them out to the WS2812. loop {