Merge #1425
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:
commit
2afa08c923
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
243
examples/rp/src/bin/pio_hd44780.rs
Normal file
243
examples/rp/src/bin/pio_hd44780.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user