Merge branch 'embassy-rs:master' into master
This commit is contained in:
commit
91d1fff4ed
@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
|||||||
|
|
||||||
use crate::pac::common::{Reg, RW};
|
use crate::pac::common::{Reg, RW};
|
||||||
use crate::pac::SIO;
|
use crate::pac::SIO;
|
||||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
||||||
|
|
||||||
const PIN_COUNT: usize = 30;
|
const PIN_COUNT: usize = 30;
|
||||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||||
@ -136,16 +136,11 @@ pub enum InterruptTrigger {
|
|||||||
AnyEdge,
|
AnyEdge,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptTrigger {
|
pub(crate) unsafe fn init() {
|
||||||
fn from_u32(value: u32) -> Option<InterruptTrigger> {
|
let irq = interrupt::IO_IRQ_BANK0::steal();
|
||||||
match value {
|
irq.disable();
|
||||||
1 => Some(InterruptTrigger::LevelLow),
|
irq.set_priority(interrupt::Priority::P3);
|
||||||
2 => Some(InterruptTrigger::LevelHigh),
|
irq.enable();
|
||||||
3 => Some(InterruptTrigger::EdgeLow),
|
|
||||||
4 => Some(InterruptTrigger::EdgeHigh),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
@ -166,27 +161,15 @@ unsafe fn IO_IRQ_BANK0() {
|
|||||||
let pin_group = (pin % 8) as usize;
|
let pin_group = (pin % 8) as usize;
|
||||||
let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32;
|
let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32;
|
||||||
|
|
||||||
if let Some(trigger) = InterruptTrigger::from_u32(event) {
|
// no more than one event can be awaited per pin at any given time, so
|
||||||
critical_section::with(|_| {
|
// we can just clear all interrupt enables for that pin without having
|
||||||
proc_intx.inte(pin / 8).modify(|w| match trigger {
|
// to check which event was signalled.
|
||||||
InterruptTrigger::AnyEdge => {
|
if event != 0 {
|
||||||
w.set_edge_high(pin_group, false);
|
proc_intx.inte(pin / 8).write_clear(|w| {
|
||||||
w.set_edge_low(pin_group, false);
|
w.set_edge_high(pin_group, true);
|
||||||
}
|
w.set_edge_low(pin_group, true);
|
||||||
InterruptTrigger::LevelHigh => {
|
w.set_level_high(pin_group, true);
|
||||||
trace!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin);
|
w.set_level_low(pin_group, true);
|
||||||
w.set_level_high(pin_group, false);
|
|
||||||
}
|
|
||||||
InterruptTrigger::LevelLow => {
|
|
||||||
w.set_level_low(pin_group, false);
|
|
||||||
}
|
|
||||||
InterruptTrigger::EdgeHigh => {
|
|
||||||
w.set_edge_high(pin_group, false);
|
|
||||||
}
|
|
||||||
InterruptTrigger::EdgeLow => {
|
|
||||||
w.set_edge_low(pin_group, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
INTERRUPT_WAKERS[pin as usize].wake();
|
INTERRUPT_WAKERS[pin as usize].wake();
|
||||||
}
|
}
|
||||||
@ -203,16 +186,26 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
|||||||
pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
|
pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
unsafe {
|
unsafe {
|
||||||
let irq = interrupt::IO_IRQ_BANK0::steal();
|
let pin_group = (pin.pin() % 8) as usize;
|
||||||
irq.disable();
|
// first, clear the INTR register bits. without this INTR will still
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
// contain reports of previous edges, causing the IRQ to fire early
|
||||||
|
// on stale state. clearing these means that we can only detect edges
|
||||||
|
// that occur *after* the clear happened, but since both this and the
|
||||||
|
// alternative are fundamentally racy it's probably fine.
|
||||||
|
// (the alternative being checking the current level and waiting for
|
||||||
|
// its inverse, but that requires reading the current level and thus
|
||||||
|
// missing anything that happened before the level was read.)
|
||||||
|
pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
|
||||||
|
w.set_edge_high(pin_group, true);
|
||||||
|
w.set_edge_low(pin_group, true);
|
||||||
|
});
|
||||||
|
|
||||||
// Each INTR register is divided into 8 groups, one group for each
|
// Each INTR register is divided into 8 groups, one group for each
|
||||||
// pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
|
// pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
|
||||||
// and EGDE_HIGH.
|
// and EGDE_HIGH.
|
||||||
let pin_group = (pin.pin() % 8) as usize;
|
pin.int_proc()
|
||||||
critical_section::with(|_| {
|
.inte((pin.pin() / 8) as usize)
|
||||||
pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
|
.write_set(|w| match level {
|
||||||
InterruptTrigger::LevelHigh => {
|
InterruptTrigger::LevelHigh => {
|
||||||
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
|
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
|
||||||
w.set_level_high(pin_group, true);
|
w.set_level_high(pin_group, true);
|
||||||
@ -227,12 +220,10 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
|||||||
w.set_edge_low(pin_group, true);
|
w.set_edge_low(pin_group, true);
|
||||||
}
|
}
|
||||||
InterruptTrigger::AnyEdge => {
|
InterruptTrigger::AnyEdge => {
|
||||||
// noop
|
w.set_edge_high(pin_group, true);
|
||||||
|
w.set_edge_low(pin_group, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
irq.enable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { pin, level }
|
Self { pin, level }
|
||||||
@ -257,48 +248,22 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
|
|||||||
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
|
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
|
||||||
let pin_group = (self.pin.pin() % 8) as usize;
|
let pin_group = (self.pin.pin() % 8) as usize;
|
||||||
|
|
||||||
// This should check the the level of the interrupt trigger level of
|
// since the interrupt handler clears all INTE flags we'll check that
|
||||||
// the pin and if it has been disabled that means it was done by the
|
// all have been cleared and unconditionally return Ready(()) if so.
|
||||||
// interrupt service routine, so we then know that the event/trigger
|
// we don't need further handshaking since only a single event wait
|
||||||
// happened and Poll::Ready will be returned.
|
// is possible for any given pin at any given time.
|
||||||
trace!("{:?} for pin {}", self.level, self.pin.pin());
|
if !inte.edge_high(pin_group)
|
||||||
match self.level {
|
&& !inte.edge_low(pin_group)
|
||||||
InterruptTrigger::AnyEdge => {
|
&& !inte.level_high(pin_group)
|
||||||
if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
|
&& !inte.level_low(pin_group)
|
||||||
#[rustfmt::skip]
|
{
|
||||||
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
|
trace!(
|
||||||
|
"{:?} for pin {} was cleared, return Poll::Ready",
|
||||||
|
self.level,
|
||||||
|
self.pin.pin()
|
||||||
|
);
|
||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
InterruptTrigger::LevelHigh => {
|
|
||||||
if !inte.level_high(pin_group) {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InterruptTrigger::LevelLow => {
|
|
||||||
if !inte.level_low(pin_group) {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InterruptTrigger::EdgeHigh => {
|
|
||||||
if !inte.edge_high(pin_group) {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InterruptTrigger::EdgeLow => {
|
|
||||||
if !inte.edge_low(pin_group) {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace!("InputFuture::poll return Poll::Pending");
|
trace!("InputFuture::poll return Poll::Pending");
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
@ -644,23 +609,17 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn wait_for_rising_edge(&mut self) {
|
pub async fn wait_for_rising_edge(&mut self) {
|
||||||
self.wait_for_low().await;
|
InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await;
|
||||||
self.wait_for_high().await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn wait_for_falling_edge(&mut self) {
|
pub async fn wait_for_falling_edge(&mut self) {
|
||||||
self.wait_for_high().await;
|
InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await;
|
||||||
self.wait_for_low().await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn wait_for_any_edge(&mut self) {
|
pub async fn wait_for_any_edge(&mut self) {
|
||||||
if self.is_high() {
|
InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await;
|
||||||
self.wait_for_low().await;
|
|
||||||
} else {
|
|
||||||
self.wait_for_high().await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +157,7 @@ pub fn init(_config: config::Config) -> Peripherals {
|
|||||||
timer::init();
|
timer::init();
|
||||||
dma::init();
|
dma::init();
|
||||||
pio::init();
|
pio::init();
|
||||||
|
gpio::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
peripherals
|
peripherals
|
||||||
|
@ -33,7 +33,7 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
|
|||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{Interrupt, InterruptExt};
|
||||||
use crate::peripherals::CORE1;
|
use crate::peripherals::CORE1;
|
||||||
use crate::{interrupt, pac};
|
use crate::{gpio, interrupt, pac};
|
||||||
|
|
||||||
const PAUSE_TOKEN: u32 = 0xDEADBEEF;
|
const PAUSE_TOKEN: u32 = 0xDEADBEEF;
|
||||||
const RESUME_TOKEN: u32 = !0xDEADBEEF;
|
const RESUME_TOKEN: u32 = !0xDEADBEEF;
|
||||||
@ -68,6 +68,9 @@ fn install_stack_guard(stack_bottom: *mut usize) {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn core1_setup(stack_bottom: *mut usize) {
|
fn core1_setup(stack_bottom: *mut usize) {
|
||||||
install_stack_guard(stack_bottom);
|
install_stack_guard(stack_bottom);
|
||||||
|
unsafe {
|
||||||
|
gpio::init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data type for a properly aligned stack of N bytes
|
/// Data type for a properly aligned stack of N bytes
|
||||||
|
@ -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 {
|
|
||||||
fn pio(&self) -> u8 {
|
|
||||||
Self::Pio::PIO_NO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split(
|
impl<'d, PIO: PioInstance> Pio<'d, PIO> {
|
||||||
self,
|
pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
|
||||||
) -> (
|
Self {
|
||||||
PioCommonInstance<Self::Pio>,
|
common: PioCommon {
|
||||||
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 PioInstance for peripherals::$name {}
|
||||||
|
|
||||||
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_pio_sm!(PIO0, 0);
|
impl_pio!(PIO0, 0, PIO0, PIO0_0);
|
||||||
impl_pio_sm!(PIO1, 1);
|
impl_pio!(PIO1, 1, PIO1, PIO1_0);
|
||||||
|
@ -874,7 +874,6 @@ mod sealed {
|
|||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
const TX_DREQ: u8;
|
const TX_DREQ: u8;
|
||||||
const RX_DREQ: u8;
|
const RX_DREQ: u8;
|
||||||
const ID: usize;
|
|
||||||
|
|
||||||
type Interrupt: crate::interrupt::Interrupt;
|
type Interrupt: crate::interrupt::Interrupt;
|
||||||
|
|
||||||
@ -909,11 +908,10 @@ impl_mode!(Async);
|
|||||||
pub trait Instance: sealed::Instance {}
|
pub trait Instance: sealed::Instance {}
|
||||||
|
|
||||||
macro_rules! impl_instance {
|
macro_rules! impl_instance {
|
||||||
($inst:ident, $irq:ident, $id:expr, $tx_dreq:expr, $rx_dreq:expr) => {
|
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||||
impl sealed::Instance for peripherals::$inst {
|
impl sealed::Instance for peripherals::$inst {
|
||||||
const TX_DREQ: u8 = $tx_dreq;
|
const TX_DREQ: u8 = $tx_dreq;
|
||||||
const RX_DREQ: u8 = $rx_dreq;
|
const RX_DREQ: u8 = $rx_dreq;
|
||||||
const ID: usize = $id;
|
|
||||||
|
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::$irq;
|
||||||
|
|
||||||
@ -939,8 +937,8 @@ macro_rules! impl_instance {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_instance!(UART0, UART0_IRQ, 0, 20, 21);
|
impl_instance!(UART0, UART0_IRQ, 20, 21);
|
||||||
impl_instance!(UART1, UART1_IRQ, 1, 22, 23);
|
impl_instance!(UART1, UART1_IRQ, 22, 23);
|
||||||
|
|
||||||
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
|
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
|
||||||
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
|
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
|
||||||
|
@ -58,7 +58,7 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = "6"
|
stm32-metapac = "7"
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { version = "6", default-features = false, features = ["metadata"]}
|
stm32-metapac = { version = "7", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["stm32-metapac/rt"]
|
default = ["stm32-metapac/rt"]
|
||||||
|
@ -84,7 +84,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
|
Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(usart_v1))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
pub fn new_with_de(
|
pub fn new_with_de(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||||
@ -133,7 +133,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
|
configure(r, &config, T::frequency(), T::KIND, true, true);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
|
@ -12,10 +12,11 @@ use futures::future::{select, Either};
|
|||||||
|
|
||||||
use crate::dma::{NoDma, Transfer};
|
use crate::dma::{NoDma, Transfer};
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
#[cfg(any(lpuart_v1, lpuart_v2))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
use crate::pac::lpuart::{regs, vals, Lpuart as Regs};
|
use crate::pac::usart::Lpuart as Regs;
|
||||||
#[cfg(not(any(lpuart_v1, lpuart_v2)))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
use crate::pac::usart::{regs, vals, Usart as Regs};
|
use crate::pac::usart::Usart as Regs;
|
||||||
|
use crate::pac::usart::{regs, vals};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::{peripherals, Peripheral};
|
use crate::{peripherals, Peripheral};
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
|||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::MULTIPLIER, false, true);
|
configure(r, &config, T::frequency(), T::KIND, false, true);
|
||||||
|
|
||||||
// create state once!
|
// create state once!
|
||||||
let _s = T::state();
|
let _s = T::state();
|
||||||
@ -261,7 +262,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, false);
|
configure(r, &config, T::frequency(), T::KIND, true, false);
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
irq.set_handler(Self::on_interrupt);
|
||||||
irq.unpend();
|
irq.unpend();
|
||||||
@ -653,7 +654,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||||||
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(usart_v1))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
pub fn new_with_de(
|
pub fn new_with_de(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
@ -696,7 +697,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
|
configure(r, &config, T::frequency(), T::KIND, true, true);
|
||||||
|
|
||||||
irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
|
irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
|
||||||
irq.unpend();
|
irq.unpend();
|
||||||
@ -763,16 +764,74 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) {
|
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) {
|
||||||
if !enable_rx && !enable_tx {
|
if !enable_rx && !enable_tx {
|
||||||
panic!("USART: At least one of RX or TX should be enabled");
|
panic!("USART: At least one of RX or TX should be enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better calculation, including error checking and OVER8 if possible.
|
#[cfg(not(usart_v4))]
|
||||||
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
|
static DIVS: [(u16, ()); 1] = [(1, ())];
|
||||||
|
|
||||||
|
#[cfg(usart_v4)]
|
||||||
|
static DIVS: [(u16, vals::Presc); 12] = [
|
||||||
|
(1, vals::Presc::DIV1),
|
||||||
|
(2, vals::Presc::DIV2),
|
||||||
|
(4, vals::Presc::DIV4),
|
||||||
|
(6, vals::Presc::DIV6),
|
||||||
|
(8, vals::Presc::DIV8),
|
||||||
|
(10, vals::Presc::DIV10),
|
||||||
|
(12, vals::Presc::DIV12),
|
||||||
|
(16, vals::Presc::DIV16),
|
||||||
|
(32, vals::Presc::DIV32),
|
||||||
|
(64, vals::Presc::DIV64),
|
||||||
|
(128, vals::Presc::DIV128),
|
||||||
|
(256, vals::Presc::DIV256),
|
||||||
|
];
|
||||||
|
|
||||||
|
let (mul, brr_min, brr_max) = match kind {
|
||||||
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
|
Kind::Lpuart => (256, 0x300, 0x10_0000),
|
||||||
|
Kind::Uart => (1, 0x10, 0x1_0000),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(usart_v1))]
|
||||||
|
let mut over8 = false;
|
||||||
|
let mut found = false;
|
||||||
|
for &(presc, _presc_val) in &DIVS {
|
||||||
|
let denom = (config.baudrate * presc as u32) as u64;
|
||||||
|
let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom;
|
||||||
|
trace!("USART: presc={} div={:08x}", presc, div);
|
||||||
|
|
||||||
|
if div < brr_min {
|
||||||
|
#[cfg(not(usart_v1))]
|
||||||
|
if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
|
||||||
|
over8 = true;
|
||||||
|
let div = div as u32;
|
||||||
|
unsafe {
|
||||||
|
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
|
||||||
|
#[cfg(usart_v4)]
|
||||||
|
r.presc().write(|w| w.set_prescaler(_presc_val));
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
panic!("USART: baudrate too high");
|
||||||
|
}
|
||||||
|
|
||||||
|
if div < brr_max {
|
||||||
|
unsafe {
|
||||||
|
r.brr().write_value(regs::Brr(div as u32));
|
||||||
|
#[cfg(usart_v4)]
|
||||||
|
r.presc().write(|w| w.set_prescaler(_presc_val));
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(found, "USART: baudrate too low");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
r.brr().write_value(regs::Brr(div));
|
|
||||||
r.cr2().write(|w| {
|
r.cr2().write(|w| {
|
||||||
w.set_stop(match config.stop_bits {
|
w.set_stop(match config.stop_bits {
|
||||||
StopBits::STOP0P5 => vals::Stop::STOP0P5,
|
StopBits::STOP0P5 => vals::Stop::STOP0P5,
|
||||||
@ -801,6 +860,8 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable
|
|||||||
Parity::ParityEven => vals::Ps::EVEN,
|
Parity::ParityEven => vals::Ps::EVEN,
|
||||||
_ => vals::Ps::EVEN,
|
_ => vals::Ps::EVEN,
|
||||||
});
|
});
|
||||||
|
#[cfg(not(usart_v1))]
|
||||||
|
w.set_over8(vals::Over8(over8 as _));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -986,43 +1047,45 @@ mod rx_ringbuffered;
|
|||||||
#[cfg(not(gpdma))]
|
#[cfg(not(gpdma))]
|
||||||
pub use rx_ringbuffered::RingBufferedUartRx;
|
pub use rx_ringbuffered::RingBufferedUartRx;
|
||||||
|
|
||||||
#[cfg(usart_v1)]
|
use self::sealed::Kind;
|
||||||
|
|
||||||
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||||
r.dr().ptr() as _
|
r.dr().ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v1)]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||||
r.dr().ptr() as _
|
r.dr().ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v1)]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
|
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
|
||||||
r.sr()
|
r.sr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v1)]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
||||||
// On v1 the flags are cleared implicitly by reads and writes to DR.
|
// On v1 the flags are cleared implicitly by reads and writes to DR.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v2)]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn tdr(r: Regs) -> *mut u8 {
|
fn tdr(r: Regs) -> *mut u8 {
|
||||||
r.tdr().ptr() as _
|
r.tdr().ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v2)]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn rdr(r: Regs) -> *mut u8 {
|
fn rdr(r: Regs) -> *mut u8 {
|
||||||
r.rdr().ptr() as _
|
r.rdr().ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v2)]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
|
fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
|
||||||
r.isr()
|
r.isr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v2)]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
||||||
r.icr().write(|w| *w = regs::Icr(sr.0));
|
r.icr().write(|w| *w = regs::Icr(sr.0));
|
||||||
@ -1033,6 +1096,13 @@ pub(crate) mod sealed {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Kind {
|
||||||
|
Uart,
|
||||||
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
|
Lpuart,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub rx_waker: AtomicWaker,
|
pub rx_waker: AtomicWaker,
|
||||||
pub tx_waker: AtomicWaker,
|
pub tx_waker: AtomicWaker,
|
||||||
@ -1048,7 +1118,7 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait BasicInstance: crate::rcc::RccPeripheral {
|
pub trait BasicInstance: crate::rcc::RccPeripheral {
|
||||||
const MULTIPLIER: u32;
|
const KIND: Kind;
|
||||||
type Interrupt: crate::interrupt::Interrupt;
|
type Interrupt: crate::interrupt::Interrupt;
|
||||||
|
|
||||||
fn regs() -> Regs;
|
fn regs() -> Regs;
|
||||||
@ -1077,10 +1147,10 @@ pin_trait!(DePin, BasicInstance);
|
|||||||
dma_trait!(TxDma, BasicInstance);
|
dma_trait!(TxDma, BasicInstance);
|
||||||
dma_trait!(RxDma, BasicInstance);
|
dma_trait!(RxDma, BasicInstance);
|
||||||
|
|
||||||
macro_rules! impl_lpuart {
|
macro_rules! impl_usart {
|
||||||
($inst:ident, $irq:ident, $mul:expr) => {
|
($inst:ident, $irq:ident, $kind:expr) => {
|
||||||
impl sealed::BasicInstance for crate::peripherals::$inst {
|
impl sealed::BasicInstance for crate::peripherals::$inst {
|
||||||
const MULTIPLIER: u32 = $mul;
|
const KIND: Kind = $kind;
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::$irq;
|
||||||
|
|
||||||
fn regs() -> Regs {
|
fn regs() -> Regs {
|
||||||
@ -1104,21 +1174,19 @@ macro_rules! impl_lpuart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach_interrupt!(
|
foreach_interrupt!(
|
||||||
($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => {
|
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
|
||||||
impl_lpuart!($inst, $irq, 256);
|
impl_usart!($inst, $irq, Kind::Lpuart);
|
||||||
};
|
};
|
||||||
|
|
||||||
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
|
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||||
impl_lpuart!($inst, $irq, 1);
|
impl_usart!($inst, $irq, Kind::Uart);
|
||||||
|
|
||||||
impl sealed::FullInstance for peripherals::$inst {
|
impl sealed::FullInstance for peripherals::$inst {
|
||||||
|
|
||||||
fn regs_uart() -> crate::pac::usart::Usart {
|
fn regs_uart() -> crate::pac::usart::Usart {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FullInstance for peripherals::$inst {
|
impl FullInstance for peripherals::$inst {}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
@ -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 {
|
||||||
|
63
tests/rp/src/bin/gpio_multicore.rs
Normal file
63
tests/rp/src/bin/gpio_multicore.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::{info, unwrap};
|
||||||
|
use embassy_executor::Executor;
|
||||||
|
use embassy_executor::_export::StaticCell;
|
||||||
|
use embassy_rp::gpio::{Input, Level, Output, Pull};
|
||||||
|
use embassy_rp::multicore::{spawn_core1, Stack};
|
||||||
|
use embassy_rp::peripherals::{PIN_0, PIN_1};
|
||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
|
use embassy_sync::channel::Channel;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
static mut CORE1_STACK: Stack<1024> = Stack::new();
|
||||||
|
static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
|
||||||
|
static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
|
||||||
|
static CHANNEL0: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
|
||||||
|
static CHANNEL1: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
|
||||||
|
|
||||||
|
#[cortex_m_rt::entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
|
||||||
|
let executor1 = EXECUTOR1.init(Executor::new());
|
||||||
|
executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1))));
|
||||||
|
});
|
||||||
|
let executor0 = EXECUTOR0.init(Executor::new());
|
||||||
|
executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn core0_task(p: PIN_0) {
|
||||||
|
info!("CORE0 is running");
|
||||||
|
|
||||||
|
let mut pin = Output::new(p, Level::Low);
|
||||||
|
|
||||||
|
CHANNEL0.send(()).await;
|
||||||
|
CHANNEL1.recv().await;
|
||||||
|
|
||||||
|
pin.set_high();
|
||||||
|
|
||||||
|
CHANNEL1.recv().await;
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn core1_task(p: PIN_1) {
|
||||||
|
info!("CORE1 is running");
|
||||||
|
|
||||||
|
CHANNEL0.recv().await;
|
||||||
|
|
||||||
|
let mut pin = Input::new(p, Pull::Down);
|
||||||
|
let wait = pin.wait_for_rising_edge();
|
||||||
|
|
||||||
|
CHANNEL1.send(()).await;
|
||||||
|
|
||||||
|
wait.await;
|
||||||
|
|
||||||
|
CHANNEL1.send(()).await;
|
||||||
|
}
|
@ -53,10 +53,6 @@ async fn main(_spawner: Spawner) {
|
|||||||
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
|
||||||
let mut irq = interrupt::take!(UART0_IRQ);
|
let mut irq = interrupt::take!(UART0_IRQ);
|
||||||
|
|
||||||
// TODO
|
|
||||||
// nuclear error reporting. just abort the entire transfer and invalidate the
|
|
||||||
// dma buffer, buffered buffer, fifo etc.
|
|
||||||
|
|
||||||
// We can't send too many bytes, they have to fit in the FIFO.
|
// We can't send too many bytes, they have to fit in the FIFO.
|
||||||
// This is because we aren't sending+receiving at the same time.
|
// This is because we aren't sending+receiving at the same time.
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@ edition = "2021"
|
|||||||
name = "embassy-stm32-tests"
|
name = "embassy-stm32-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
autobins = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
|
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
|
||||||
|
@ -6,15 +6,16 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
|
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
|
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
|
||||||
println!("cargo:rustc-link-search={}", out.display());
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
println!("cargo:rerun-if-changed=link_ram.x");
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||||
|
|
||||||
// too little RAM to run from RAM.
|
// too little RAM to run from RAM.
|
||||||
#[cfg(any(feature = "stm32c031c6"))]
|
if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||||
#[cfg(not(any(feature = "stm32c031c6")))]
|
println!("cargo:rerun-if-changed=link.x");
|
||||||
|
} else {
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
|
||||||
|
println!("cargo:rerun-if-changed=link_ram.x");
|
||||||
|
}
|
||||||
|
|
||||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) {
|
|||||||
#[cfg(feature = "stm32c031c6")]
|
#[cfg(feature = "stm32c031c6")]
|
||||||
let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
|
let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
|
||||||
|
|
||||||
info!("asdfa;");
|
|
||||||
let mut spi = Spi::new(
|
let mut spi = Spi::new(
|
||||||
spi,
|
spi,
|
||||||
sck, // Arduino D13
|
sck, // Arduino D13
|
||||||
|
@ -9,6 +9,7 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_stm32::dma::NoDma;
|
use embassy_stm32::dma::NoDma;
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::usart::{Config, Uart};
|
use embassy_stm32::usart::{Config, Uart};
|
||||||
|
use embassy_time::{Duration, Instant};
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -19,26 +20,27 @@ async fn main(_spawner: Spawner) {
|
|||||||
// Arduino pins D0 and D1
|
// Arduino pins D0 and D1
|
||||||
// They're connected together with a 1K resistor.
|
// They're connected together with a 1K resistor.
|
||||||
#[cfg(feature = "stm32f103c8")]
|
#[cfg(feature = "stm32f103c8")]
|
||||||
let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1));
|
||||||
#[cfg(feature = "stm32g491re")]
|
#[cfg(feature = "stm32g491re")]
|
||||||
let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
|
||||||
#[cfg(feature = "stm32g071rb")]
|
#[cfg(feature = "stm32g071rb")]
|
||||||
let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
|
||||||
#[cfg(feature = "stm32f429zi")]
|
#[cfg(feature = "stm32f429zi")]
|
||||||
let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6));
|
||||||
#[cfg(feature = "stm32wb55rg")]
|
#[cfg(feature = "stm32wb55rg")]
|
||||||
let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1));
|
||||||
#[cfg(feature = "stm32h755zi")]
|
#[cfg(feature = "stm32h755zi")]
|
||||||
let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
|
||||||
#[cfg(feature = "stm32u585ai")]
|
#[cfg(feature = "stm32u585ai")]
|
||||||
let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
|
||||||
#[cfg(feature = "stm32h563zi")]
|
#[cfg(feature = "stm32h563zi")]
|
||||||
let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1));
|
||||||
#[cfg(feature = "stm32c031c6")]
|
#[cfg(feature = "stm32c031c6")]
|
||||||
let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
|
let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
|
||||||
|
|
||||||
|
{
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config);
|
let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config);
|
||||||
|
|
||||||
// We can't send too many bytes, they have to fit in the FIFO.
|
// We can't send too many bytes, they have to fit in the FIFO.
|
||||||
// This is because we aren't sending+receiving at the same time.
|
// This is because we aren't sending+receiving at the same time.
|
||||||
@ -49,6 +51,45 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
usart.blocking_read(&mut buf).unwrap();
|
usart.blocking_read(&mut buf).unwrap();
|
||||||
assert_eq!(buf, data);
|
assert_eq!(buf, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that baudrate divider is calculated correctly.
|
||||||
|
// Do it by comparing the time it takes to send a known number of bytes.
|
||||||
|
for baudrate in [
|
||||||
|
300,
|
||||||
|
9600,
|
||||||
|
115200,
|
||||||
|
250_000,
|
||||||
|
337_934,
|
||||||
|
#[cfg(not(feature = "stm32f103c8"))]
|
||||||
|
1_000_000,
|
||||||
|
#[cfg(not(feature = "stm32f103c8"))]
|
||||||
|
2_000_000,
|
||||||
|
] {
|
||||||
|
info!("testing baudrate {}", baudrate);
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
config.baudrate = baudrate;
|
||||||
|
let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config);
|
||||||
|
|
||||||
|
let n = (baudrate as usize / 100).max(64);
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
for _ in 0..n {
|
||||||
|
usart.blocking_write(&[0x00]).unwrap();
|
||||||
|
}
|
||||||
|
let dur = Instant::now() - start;
|
||||||
|
let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64));
|
||||||
|
let fuzz = want_dur / 5;
|
||||||
|
if dur < want_dur - fuzz || dur > want_dur + fuzz {
|
||||||
|
defmt::panic!(
|
||||||
|
"bad duration for baudrate {}: got {:?} want {:?}",
|
||||||
|
baudrate,
|
||||||
|
dur,
|
||||||
|
want_dur
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
info!("Test OK");
|
info!("Test OK");
|
||||||
cortex_m::asm::bkpt();
|
cortex_m::asm::bkpt();
|
||||||
|
@ -94,6 +94,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
let rx_fut = async {
|
let rx_fut = async {
|
||||||
rx.read(&mut rx_buf).await.unwrap();
|
rx.read(&mut rx_buf).await.unwrap();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// note: rx needs to be polled first, to workaround this bug:
|
||||||
|
// https://github.com/embassy-rs/embassy/issues/1426
|
||||||
join(rx_fut, tx_fut).await;
|
join(rx_fut, tx_fut).await;
|
||||||
|
|
||||||
assert_eq!(tx_buf, rx_buf);
|
assert_eq!(tx_buf, rx_buf);
|
||||||
|
@ -145,13 +145,16 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
|
async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
|
||||||
|
// workaround https://github.com/embassy-rs/embassy/issues/1426
|
||||||
|
Timer::after(Duration::from_millis(100) as _).await;
|
||||||
|
|
||||||
let mut rng = ChaCha8Rng::seed_from_u64(1337);
|
let mut rng = ChaCha8Rng::seed_from_u64(1337);
|
||||||
|
|
||||||
info!("Starting random transmissions into void...");
|
info!("Starting random transmissions into void...");
|
||||||
|
|
||||||
let mut i: u8 = 0;
|
let mut i: u8 = 0;
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0; 32];
|
let mut buf = [0; 256];
|
||||||
let len = 1 + (rng.next_u32() as usize % buf.len());
|
let len = 1 + (rng.next_u32() as usize % buf.len());
|
||||||
for b in &mut buf[..len] {
|
for b in &mut buf[..len] {
|
||||||
*b = i;
|
*b = i;
|
||||||
@ -172,7 +175,7 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut expected = 0;
|
let mut expected = 0;
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0; 100];
|
let mut buf = [0; 256];
|
||||||
let max_len = 1 + (rng.next_u32() as usize % buf.len());
|
let max_len = 1 + (rng.next_u32() as usize % buf.len());
|
||||||
let received = match rx.read(&mut buf[..max_len]).await {
|
let received = match rx.read(&mut buf[..max_len]).await {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
|
@ -16,5 +16,10 @@ pub fn config() -> Config {
|
|||||||
config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
|
config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stm32u585ai")]
|
||||||
|
{
|
||||||
|
config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz);
|
||||||
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user