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 core::task::{Context, Poll};
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::PeripheralRef; use embassy_hal_common::{Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; 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::sealed::Pin as SealedPin;
use crate::gpio::{Drive, Pin, Pull, SlewRate}; use crate::gpio::{Drive, Pin, Pull, SlewRate};
use crate::pac::dma::vals::{DataSize, TreqSel}; use crate::pac::dma::vals::TreqSel;
use crate::pio::sealed::{PioInstance as _, SmInstance as _}; use crate::pio::sealed::PioInstance as _;
use crate::{interrupt, pac, peripherals, RegExt}; use crate::{interrupt, pac, peripherals, RegExt};
struct Wakers([AtomicWaker; 12]); 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) { if self.get_mut().sm.try_push_tx(value) {
Poll::Ready(()) Poll::Ready(())
} else { } 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 { unsafe {
PIO::PIO.irqs(0).inte().write_set(|m| { PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = TXNFULL_MASK << SM::Sm::SM_NO; m.0 = TXNFULL_MASK << SM::SM;
}); });
} }
// debug!("Pending"); // debug!("Pending");
@ -135,7 +135,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
PIO::PIO.irqs(0).inte().write_clear(|m| { 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() { if let Some(v) = self.sm.try_pull_rx() {
Poll::Ready(v) Poll::Ready(v)
} else { } 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 { unsafe {
PIO::PIO.irqs(0).inte().write_set(|m| { PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; m.0 = RXNEMPTY_MASK << SM::SM;
}); });
} }
//debug!("Pending"); //debug!("Pending");
@ -180,7 +180,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
PIO::PIO.irqs(0).inte().write_clear(|m| { 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] #[inline]
pub fn set_pull(&mut self, pull: Pull) { pub fn set_pull(&mut self, pull: Pull) {
unsafe { unsafe {
self.pad_ctrl().modify(|w| match pull { self.pad_ctrl().modify(|w| {
Pull::Up => w.set_pue(true), w.set_pue(pull == Pull::Up);
Pull::Down => w.set_pde(true), w.set_pde(pull == Pull::Down);
Pull::None => {}
}); });
} }
} }
/// Set the pin's pull. /// Set the pin's schmitt trigger.
#[inline] #[inline]
pub fn set_schmitt(&mut self, enable: bool) { pub fn set_schmitt(&mut self, enable: bool) {
unsafe { unsafe {
@ -298,9 +297,11 @@ impl<PIO: PioInstance> PioPin<PIO> {
pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
let mask = 1 << self.pin(); let mask = 1 << self.pin();
unsafe { unsafe {
PIO::PIO if bypass {
.input_sync_bypass() PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
.modify(|w| *w = if bypass { *w & !mask } else { *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> { pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> {
pio: PhantomData<PIO>, pio: PhantomData<&'d PIO>,
sm: PhantomData<SM>,
} }
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 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 { pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn pio_no(&self) -> u8 { fn pio_no(&self) -> u8 {
@ -332,60 +332,61 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn sm_no(&self) -> u8 { fn sm_no(&self) -> u8 {
Self::Sm::SM_NO Self::SM as u8
} }
fn restart(&mut self) { fn restart(&mut self) {
let mask = 1u8 << Self::SM;
unsafe { unsafe {
Self::Pio::PIO Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
.ctrl()
.modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO));
} }
} }
fn set_enable(&mut self, enable: bool) { fn set_enable(&mut self, enable: bool) {
let mask = 1u8 << Self::Sm::SM_NO; let mask = 1u8 << Self::SM;
unsafe { unsafe {
Self::Pio::PIO if enable {
.ctrl() Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
.modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); } else {
Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
}
} }
} }
fn is_enabled(&self) -> bool { 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 { 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 { 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 { 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 { 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 { fn tx_level(&self) -> u8 {
unsafe { unsafe {
let flevel = Self::Pio::PIO.flevel().read().0; 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 { fn rx_level(&self) -> u8 {
unsafe { unsafe {
let flevel = Self::Pio::PIO.flevel().read().0; 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) { fn push_tx(&mut self, v: u32) {
unsafe { 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 { 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> { 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) { fn set_clkdiv(&mut self, div_x_256: u32) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8);
.sm(Self::Sm::SM_NO as usize)
.clkdiv()
.write(|w| w.0 = div_x_256 << 8);
} }
} }
fn get_clkdiv(&self) -> u32 { 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) { fn clkdiv_restart(&mut self) {
let mask = 1u8 << Self::SM;
unsafe { unsafe {
Self::Pio::PIO Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
.ctrl()
.modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO));
} }
} }
fn set_side_enable(&self, enable: bool) { fn set_side_enable(&self, enable: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().execctrl().modify(|w| w.set_side_en(enable));
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.modify(|w| w.set_side_en(enable));
} }
} }
fn is_side_enabled(&self) -> bool { 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) { fn set_side_pindir(&mut self, pindir: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir));
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.modify(|w| w.set_side_pindir(pindir));
} }
} }
fn is_side_pindir(&self) -> bool { fn is_side_pindir(&self) -> bool {
unsafe { unsafe { Self::this_sm().execctrl().read().side_pindir() }
Self::Pio::PIO
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.read()
.side_pindir()
}
} }
fn set_jmp_pin(&mut self, pin: u8) { fn set_jmp_pin(&mut self, pin: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin));
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.modify(|w| w.set_jmp_pin(pin));
} }
} }
fn get_jmp_pin(&mut self) -> u8 { 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) { fn set_wrap(&self, source: u8, target: u8) {
unsafe { 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_top(source);
w.set_wrap_bottom(target) w.set_wrap_bottom(target)
}); });
@ -486,7 +468,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
/// Get wrapping addresses. Returns (source, target). /// Get wrapping addresses. Returns (source, target).
fn get_wrap(&self) -> (u8, u8) { fn get_wrap(&self) -> (u8, u8) {
unsafe { 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()) (r.wrap_top(), r.wrap_bottom())
} }
} }
@ -498,7 +480,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
FifoJoin::TxOnly => (false, true), FifoJoin::TxOnly => (false, true),
}; };
unsafe { 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_rx(rx);
w.set_fjoin_tx(tx) w.set_fjoin_tx(tx)
}); });
@ -506,7 +488,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn get_fifo_join(&self) -> FifoJoin { fn get_fifo_join(&self) -> FifoJoin {
unsafe { 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 // Ignores the invalid state when both bits are set
if r.fjoin_rx() { if r.fjoin_rx() {
FifoJoin::RxOnly FifoJoin::RxOnly
@ -521,7 +503,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn clear_fifos(&mut self) { fn clear_fifos(&mut self) {
// Toggle FJOIN_RX to flush FIFOs // Toggle FJOIN_RX to flush FIFOs
unsafe { unsafe {
let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl(); let shiftctrl = Self::this_sm().shiftctrl();
shiftctrl.modify(|w| { shiftctrl.modify(|w| {
w.set_fjoin_rx(!w.fjoin_rx()); 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) { fn set_pull_threshold(&mut self, threshold: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_pull_thresh(threshold));
} }
} }
fn get_pull_threshold(&self) -> u8 { fn get_pull_threshold(&self) -> u8 {
unsafe { unsafe { Self::this_sm().shiftctrl().read().pull_thresh() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
r.pull_thresh()
}
} }
fn set_push_threshold(&mut self, threshold: u8) { fn set_push_threshold(&mut self, threshold: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_push_thresh(threshold));
} }
} }
fn get_push_threshold(&self) -> u8 { fn get_push_threshold(&self) -> u8 {
unsafe { unsafe { Self::this_sm().shiftctrl().read().push_thresh() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
r.push_thresh()
}
} }
fn set_out_shift_dir(&mut self, dir: ShiftDirection) { fn set_out_shift_dir(&mut self, dir: ShiftDirection) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm()
.sm(Self::Sm::SM_NO as usize)
.shiftctrl() .shiftctrl()
.modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right));
} }
} }
fn get_out_shiftdir(&self) -> ShiftDirection { fn get_out_shiftdir(&self) -> ShiftDirection {
unsafe { unsafe {
if Self::Pio::PIO if Self::this_sm().shiftctrl().read().out_shiftdir() {
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.out_shiftdir()
{
ShiftDirection::Right ShiftDirection::Right
} else { } else {
ShiftDirection::Left ShiftDirection::Left
@ -587,20 +551,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_in_shift_dir(&mut self, dir: ShiftDirection) { fn set_in_shift_dir(&mut self, dir: ShiftDirection) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm()
.sm(Self::Sm::SM_NO as usize)
.shiftctrl() .shiftctrl()
.modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right));
} }
} }
fn get_in_shiftdir(&self) -> ShiftDirection { fn get_in_shiftdir(&self) -> ShiftDirection {
unsafe { unsafe {
if Self::Pio::PIO if Self::this_sm().shiftctrl().read().in_shiftdir() {
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.in_shiftdir()
{
ShiftDirection::Right ShiftDirection::Right
} else { } else {
ShiftDirection::Left ShiftDirection::Left
@ -610,76 +568,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_autopull(&mut self, auto: bool) { fn set_autopull(&mut self, auto: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_autopull(auto));
} }
} }
fn is_autopull(&self) -> bool { fn is_autopull(&self) -> bool {
unsafe { unsafe { Self::this_sm().shiftctrl().read().autopull() }
Self::Pio::PIO
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.autopull()
}
} }
fn set_autopush(&mut self, auto: bool) { fn set_autopush(&mut self, auto: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_autopush(auto));
} }
} }
fn is_autopush(&self) -> bool { fn is_autopush(&self) -> bool {
unsafe { unsafe { Self::this_sm().shiftctrl().read().autopush() }
Self::Pio::PIO
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.autopush()
}
} }
fn get_addr(&self) -> u8 { fn get_addr(&self) -> u8 {
unsafe { unsafe { Self::this_sm().addr().read().addr() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read();
r.addr()
}
} }
fn set_sideset_count(&mut self, count: u8) { fn set_sideset_count(&mut self, count: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count));
.sm(Self::Sm::SM_NO as usize)
.pinctrl()
.modify(|w| w.set_sideset_count(count));
} }
} }
fn get_sideset_count(&self) -> u8 { fn get_sideset_count(&self) -> u8 {
unsafe { unsafe { Self::this_sm().pinctrl().read().sideset_count() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
r.sideset_count()
}
} }
fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) { fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin()));
.sm(Self::Sm::SM_NO as usize)
.pinctrl()
.modify(|w| w.set_sideset_base(base_pin.pin()));
} }
} }
fn get_sideset_base(&self) -> u8 { fn get_sideset_base(&self) -> u8 {
unsafe { 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() r.sideset_base()
} }
} }
@ -688,7 +616,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_set_range(&mut self, base: u8, count: u8) { fn set_set_range(&mut self, base: u8, count: u8) {
assert!(base + count < 32); assert!(base + count < 32);
unsafe { 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_base(base);
w.set_set_count(count) 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). /// Get the range of out pins affected by a set instruction. Returns (base, count).
fn get_set_range(&self) -> (u8, u8) { fn get_set_range(&self) -> (u8, u8) {
unsafe { 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()) (r.set_base(), r.set_count())
} }
} }
fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) { fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin()));
.sm(Self::Sm::SM_NO as usize)
.pinctrl()
.modify(|w| w.set_in_base(base.pin()));
} }
} }
fn get_in_base(&self) -> u8 { fn get_in_base(&self) -> u8 {
unsafe { 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() r.in_base()
} }
} }
@ -722,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_out_range(&mut self, base: u8, count: u8) { fn set_out_range(&mut self, base: u8, count: u8) {
assert!(base + count < 32); assert!(base + count < 32);
unsafe { 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_base(base);
w.set_out_count(count) 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). /// Get the range of out pins affected by a set instruction. Returns (base, count).
fn get_out_range(&self) -> (u8, u8) { fn get_out_range(&self) -> (u8, u8) {
unsafe { 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()) (r.out_base(), r.out_count())
} }
} }
@ -760,15 +685,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn get_current_instr() -> u32 { 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) { fn exec_instr(&mut self, instr: u16) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().instr().write(|w| w.set_instr(instr));
.sm(Self::Sm::SM_NO as usize)
.instr()
.write(|w| w.set_instr(instr));
} }
} }
@ -787,8 +709,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_tx_stalled(&self) -> bool { fn has_tx_stalled(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().txstall() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_txstall(1 << Self::SM));
ret ret
} }
} }
@ -796,8 +718,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_tx_overflowed(&self) -> bool { fn has_tx_overflowed(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().txover() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_txover(1 << Self::SM));
ret ret
} }
} }
@ -805,8 +727,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_rx_stalled(&self) -> bool { fn has_rx_stalled(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_rxstall(1 << Self::SM));
ret ret
} }
} }
@ -814,25 +736,25 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_rx_underflowed(&self) -> bool { fn has_rx_underflowed(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_rxunder(1 << Self::SM));
ret 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 { unsafe {
let pio_no = Self::Pio::PIO_NO; let pio_no = Self::Pio::PIO_NO;
let sm_no = Self::Sm::SM_NO; let sm_no = Self::SM;
let p = ch.regs(); let p = ch.regs();
p.read_addr().write_value(data.as_ptr() as u32); p.read_addr().write_value(data.as_ptr() as u32);
p.write_addr() p.write_addr().write_value(Self::Pio::PIO.txf(sm_no).ptr() as u32);
.write_value(Self::Pio::PIO.txf(sm_no as usize).ptr() as u32);
p.trans_count().write_value(data.len() as u32); p.trans_count().write_value(data.len() as u32);
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| { p.ctrl_trig().write(|w| {
// Set TX DREQ for this statemachine // Set TX DREQ for this statemachine
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no)); w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8));
w.set_data_size(DataSize::SIZE_WORD); w.set_data_size(W::size());
w.set_chain_to(ch.number()); w.set_chain_to(ch.number());
w.set_incr_read(true); w.set_incr_read(true);
w.set_incr_write(false); w.set_incr_write(false);
@ -843,19 +765,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
Transfer::new(ch) 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 { unsafe {
let pio_no = Self::Pio::PIO_NO; let pio_no = Self::Pio::PIO_NO;
let sm_no = Self::Sm::SM_NO; let sm_no = Self::SM;
let p = ch.regs(); let p = ch.regs();
p.write_addr().write_value(data.as_ptr() as u32); p.write_addr().write_value(data.as_ptr() as u32);
p.read_addr() p.read_addr().write_value(Self::Pio::PIO.rxf(sm_no).ptr() as u32);
.write_value(Self::Pio::PIO.rxf(sm_no as usize).ptr() as u32);
p.trans_count().write_value(data.len() as u32); p.trans_count().write_value(data.len() as u32);
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| { p.ctrl_trig().write(|w| {
// Set TX DREQ for this statemachine // Set RX DREQ for this statemachine
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4)); w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8 + 4));
w.set_data_size(DataSize::SIZE_WORD); w.set_data_size(W::size());
w.set_chain_to(ch.number()); w.set_chain_to(ch.number());
w.set_incr_read(false); w.set_incr_read(false);
w.set_incr_write(true); 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, instructions_used: u32,
pio: PhantomData<PIO>, pio: PhantomData<&'d PIO>,
} }
pub struct PioInstanceMemory<PIO: PioInstance> { pub struct PioInstanceMemory<'d, PIO: PioInstance> {
used_mask: u32, used_mask: u32,
pio: PhantomData<PIO>, pio: PhantomData<&'d PIO>,
} }
impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> { impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
type Pio = PIO; pub fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO>
}
impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
where where
I: Iterator<Item = u16>, 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; self.instructions_used &= !instrs.used_mask;
} }
}
pub trait PioCommon: sealed::PioCommon + Sized { pub fn is_irq_set(&self, irq_no: u8) -> bool {
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 {
assert!(irq_no < 8); assert!(irq_no < 8);
unsafe { unsafe {
let irq_flags = Self::Pio::PIO.irq(); let irq_flags = PIO::PIO.irq();
irq_flags.read().0 & (1 << irq_no) != 0 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); 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) { pub fn clear_irqs(&mut self, mask: u8) {
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) } 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); 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 { unsafe {
Self::Pio::PIO // this can interfere with per-pin bypass functions. splitting the
.input_sync_bypass() // modification is going to be fine since nothing that relies on
.modify(|w| *w = (*w & !mask) | (bypass & mask)); // 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 { pub fn get_input_sync_bypass(&self) -> u32 {
unsafe { Self::Pio::PIO.input_sync_bypass().read() } 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 { unsafe {
pin.io().ctrl().write(|w| { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
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,
);
});
} }
PioPin { PioPin {
pin_bank: pin.pin_bank(), 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 Pio<'d, PIO: PioInstance> {
pub struct SmInstanceBase<const SM_NO: u8> {} pub common: PioCommon<'d, PIO>,
pub sm0: PioStateMachineInstance<'d, PIO, 0>,
pub trait SmInstance: sealed::SmInstance + Unpin {} pub sm1: PioStateMachineInstance<'d, PIO, 1>,
pub sm2: PioStateMachineInstance<'d, PIO, 2>,
impl<const SM_NO: u8> sealed::SmInstance for SmInstanceBase<SM_NO> { pub sm3: PioStateMachineInstance<'d, PIO, 3>,
const SM_NO: u8 = SM_NO;
} }
impl<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {}
pub trait PioPeripheral: sealed::PioPeripheral + Sized { impl<'d, PIO: PioInstance> Pio<'d, PIO> {
fn pio(&self) -> u8 { pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
Self::Pio::PIO_NO Self {
} common: PioCommon {
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 {
instructions_used: 0, instructions_used: 0,
pio: PhantomData::default(), pio: PhantomData,
}, },
PioStateMachineInstance { sm0: PioStateMachineInstance { pio: PhantomData },
sm: PhantomData::default(), sm1: PioStateMachineInstance { pio: PhantomData },
pio: PhantomData::default(), sm2: PioStateMachineInstance { pio: PhantomData },
}, sm3: PioStateMachineInstance { pio: PhantomData },
PioStateMachineInstance { }
sm: PhantomData::default(), }
pio: PhantomData::default(), }
},
PioStateMachineInstance { pub trait PioInstance: sealed::PioInstance + Sized + Unpin {
sm: PhantomData::default(), fn pio(&self) -> u8 {
pio: PhantomData::default(), Self::PIO_NO
},
PioStateMachineInstance {
sm: PhantomData::default(),
pio: PhantomData::default(),
},
)
} }
} }
mod sealed { 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 { pub trait PioInstance {
const PIO_NO: u8; const PIO_NO: u8;
const PIO: &'static crate::pac::pio::Pio; const PIO: &'static crate::pac::pio::Pio;
} const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
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;
} }
} }
// Identifies a specific PIO device macro_rules! impl_pio {
pub struct PioInstanceBase<const PIO_NO: u8> {} ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => {
impl sealed::PioInstance for peripherals::$name {
pub trait PioInstance: sealed::PioInstance + Unpin {} const PIO_NO: u8 = $pio;
const PIO: &'static pac::pio::Pio = &pac::$pac;
impl sealed::PioInstance for PioInstanceBase<0> { const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
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>;
} }
impl PioPeripheral for peripherals::$name {} impl PioInstance for peripherals::$name {}
}; };
} }
impl_pio_sm!(PIO0, 0); impl_pio!(PIO0, 0, PIO0, PIO0_0);
impl_pio_sm!(PIO1, 1); impl_pio!(PIO1, 1, PIO1, PIO1_0);

View File

@ -4,15 +4,13 @@
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio::{AnyPin, Pin}; use embassy_rp::gpio::{AnyPin, Pin};
use embassy_rp::pio::{ use embassy_rp::peripherals::PIO0;
Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection};
Sm1, Sm2,
};
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use {defmt_rtt as _, panic_probe as _}; 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 // Setup sm0
// Send data serially to pin // Send data serially to pin
@ -40,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
} }
#[embassy_executor::task] #[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); sm.set_enable(true);
let mut v = 0x0f0caffa; 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 // Setupm sm1
// Read 0b10101 repeatedly until ISR is full // 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] #[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); sm.set_enable(true);
loop { loop {
let rx = sm.wait_pull().await; 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 // Setup sm2
// Repeatedly trigger IRQ 3 // Repeatedly trigger IRQ 3
@ -102,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
} }
#[embassy_executor::task] #[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); sm.set_enable(true);
loop { loop {
sm.wait_irq(3).await; sm.wait_irq(3).await;
@ -115,11 +113,17 @@ async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let pio = p.PIO0; 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_sm0(&mut common, &mut sm0, p.PIN_0.degrade());
setup_pio_task_sm1(&mut pio0, &mut sm1); setup_pio_task_sm1(&mut common, &mut sm1);
setup_pio_task_sm2(&mut pio0, &mut sm2); setup_pio_task_sm2(&mut common, &mut sm2);
spawner.spawn(pio_task_sm0(sm0)).unwrap(); spawner.spawn(pio_task_sm0(sm0)).unwrap();
spawner.spawn(pio_task_sm1(sm1)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap();
spawner.spawn(pio_task_sm2(sm2)).unwrap(); spawner.spawn(pio_task_sm2(sm2)).unwrap();

View File

@ -4,7 +4,7 @@
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::join::join; 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::relocate::RelocatedProgram;
use embassy_rp::{pio_instr_util, Peripheral}; use embassy_rp::{pio_instr_util, Peripheral};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -19,7 +19,11 @@ fn swap_nibbles(v: u32) -> u32 {
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let pio = p.PIO0; 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!( let prg = pio_proc::pio_asm!(
".origin 0", ".origin 0",
@ -34,7 +38,7 @@ async fn main(_spawner: Spawner) {
); );
let relocated = RelocatedProgram::new(&prg.program); 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()); pio_instr_util::exec_jmp(&mut sm, relocated.origin());
sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
let pio::Wrap { source, target } = relocated.wrap(); 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_executor::Spawner;
use embassy_rp::gpio::{self, Pin}; use embassy_rp::gpio::{self, Pin};
use embassy_rp::pio::{ use embassy_rp::pio::{
FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection,
ShiftDirection, SmInstance,
}; };
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
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<P: PioInstance, S: SmInstance> { pub struct Ws2812<'d, P: PioInstance, const S: usize> {
sm: PioStateMachineInstance<P, S>, sm: PioStateMachineInstance<'d, P, S>,
} }
impl<P: PioInstance, S: SmInstance> Ws2812<P, S> { impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
pub fn new(mut pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self { pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self {
// Setup sm0 // Setup sm0
// prepare the PIO program // prepare the PIO program
@ -116,7 +115,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 (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 // 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.
@ -125,7 +124,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(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 forever making RGB values and pushing them out to the WS2812.
loop { loop {