1425: rp pio, round 2 r=Dirbaio a=pennae

another round of bugfixes for pio, and some refactoring. in the end we'd like to make pio look like all the other modules and not expose traits that provide all the methods of a type, but put them onto the type itself. traits only make much sense, even if we added an AnyPio and merged the types for the member state machines (at the cost of at least a u8 per member of Pio).

Co-authored-by: pennae <github@quasiparticle.net>
This commit is contained in:
bors[bot] 2023-05-02 18:03:00 +00:00 committed by GitHub
commit 2afa08c923
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 446 additions and 342 deletions

View file

@ -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<PIO: PioInstance> PioPin<PIO> {
#[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<PIO: PioInstance> PioPin<PIO> {
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<PIO: PioInstance> SealedPin for PioPin<PIO> {
}
}
pub struct PioStateMachineInstance<PIO: PioInstance, SM: SmInstance> {
pio: PhantomData<PIO>,
sm: PhantomData<SM>,
pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> {
pio: PhantomData<&'d PIO>,
}
impl<PIO: PioInstance, SM: SmInstance> sealed::PioStateMachine for PioStateMachineInstance<PIO, SM> {
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<PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<PIO, SM> {}
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<u32> {
@ -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<Self::Pio>) {
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<Self::Pio>) {
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<PIO: PioInstance> {
pub struct PioCommon<'d, PIO: PioInstance> {
instructions_used: u32,
pio: PhantomData<PIO>,
pio: PhantomData<&'d PIO>,
}
pub struct PioInstanceMemory<PIO: PioInstance> {
pub struct PioInstanceMemory<'d, PIO: PioInstance> {
used_mask: u32,
pio: PhantomData<PIO>,
pio: PhantomData<&'d PIO>,
}
impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> {
type Pio = PIO;
}
impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
pub fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO>
where
I: Iterator<Item = u16>,
{
@ -908,66 +827,50 @@ impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
}
}
fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>) {
// TODO make instruction memory that is currently in use unfreeable
pub fn free_instr(&mut self, instrs: PioInstanceMemory<PIO>) {
self.instructions_used &= !instrs.used_mask;
}
}
pub trait PioCommon: sealed::PioCommon + Sized {
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
where
I: Iterator<Item = u16>;
// TODO make instruction memory that is currently in use unfreeable
fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>);
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<Self::Pio> {
pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin<PIO> {
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<const SM_NO: u8> {}
pub trait SmInstance: sealed::SmInstance + Unpin {}
impl<const SM_NO: u8> sealed::SmInstance for SmInstanceBase<SM_NO> {
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<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {}
pub trait PioPeripheral: sealed::PioPeripheral + Sized {
fn pio(&self) -> u8 {
Self::Pio::PIO_NO
}
fn split(
self,
) -> (
PioCommonInstance<Self::Pio>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<0>>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<1>>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<2>>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<3>>,
) {
(
PioCommonInstance {
impl<'d, PIO: PioInstance> Pio<'d, PIO> {
pub fn new(_pio: impl Peripheral<P = PIO> + '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<const PIO_NO: u8> {}
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);

View file

@ -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<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 0>, pin: AnyPin) {
// Setup sm0
// Send data serially to pin
@ -40,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
}
#[embassy_executor::task]
async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) {
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<Pio0, Sm0>) {
}
}
fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm1>) {
fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 1>) {
// Setupm sm1
// Read 0b10101 repeatedly until ISR is full
@ -70,7 +68,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
}
#[embassy_executor::task]
async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
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<Pio0, Sm1>) {
}
}
fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm2>) {
fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 2>) {
// Setup sm2
// Repeatedly trigger IRQ 3
@ -102,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
}
#[embassy_executor::task]
async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
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();

View file

@ -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();

View file

@ -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<const N: usize>([u8; N], usize);
impl<const N: usize> Write for Buf<N> {
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<P = PIO0> + 'l,
dma: impl Peripheral<P = impl Channel> + '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 (<wait:24> <command:4> <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 (<rs:1> <count:7>, 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;
}
}

View file

@ -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<P: PioInstance, S: SmInstance> {
sm: PioStateMachineInstance<P, S>,
pub struct Ws2812<'d, P: PioInstance, const S: usize> {
sm: PioStateMachineInstance<'d, P, S>,
}
impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
pub fn new(mut pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, 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 {