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::SIO;
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
||||
|
||||
const PIN_COUNT: usize = 30;
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
@ -136,16 +136,11 @@ pub enum InterruptTrigger {
|
||||
AnyEdge,
|
||||
}
|
||||
|
||||
impl InterruptTrigger {
|
||||
fn from_u32(value: u32) -> Option<InterruptTrigger> {
|
||||
match value {
|
||||
1 => Some(InterruptTrigger::LevelLow),
|
||||
2 => Some(InterruptTrigger::LevelHigh),
|
||||
3 => Some(InterruptTrigger::EdgeLow),
|
||||
4 => Some(InterruptTrigger::EdgeHigh),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub(crate) unsafe fn init() {
|
||||
let irq = interrupt::IO_IRQ_BANK0::steal();
|
||||
irq.disable();
|
||||
irq.set_priority(interrupt::Priority::P3);
|
||||
irq.enable();
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
@ -166,27 +161,15 @@ unsafe fn IO_IRQ_BANK0() {
|
||||
let pin_group = (pin % 8) as usize;
|
||||
let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32;
|
||||
|
||||
if let Some(trigger) = InterruptTrigger::from_u32(event) {
|
||||
critical_section::with(|_| {
|
||||
proc_intx.inte(pin / 8).modify(|w| match trigger {
|
||||
InterruptTrigger::AnyEdge => {
|
||||
w.set_edge_high(pin_group, false);
|
||||
w.set_edge_low(pin_group, false);
|
||||
}
|
||||
InterruptTrigger::LevelHigh => {
|
||||
trace!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin);
|
||||
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);
|
||||
}
|
||||
});
|
||||
// no more than one event can be awaited per pin at any given time, so
|
||||
// we can just clear all interrupt enables for that pin without having
|
||||
// to check which event was signalled.
|
||||
if event != 0 {
|
||||
proc_intx.inte(pin / 8).write_clear(|w| {
|
||||
w.set_edge_high(pin_group, true);
|
||||
w.set_edge_low(pin_group, true);
|
||||
w.set_level_high(pin_group, true);
|
||||
w.set_level_low(pin_group, true);
|
||||
});
|
||||
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 {
|
||||
into_ref!(pin);
|
||||
unsafe {
|
||||
let irq = interrupt::IO_IRQ_BANK0::steal();
|
||||
irq.disable();
|
||||
irq.set_priority(interrupt::Priority::P3);
|
||||
let pin_group = (pin.pin() % 8) as usize;
|
||||
// first, clear the INTR register bits. without this INTR will still
|
||||
// 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
|
||||
// pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
|
||||
// and EGDE_HIGH.
|
||||
let pin_group = (pin.pin() % 8) as usize;
|
||||
critical_section::with(|_| {
|
||||
pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
|
||||
pin.int_proc()
|
||||
.inte((pin.pin() / 8) as usize)
|
||||
.write_set(|w| match level {
|
||||
InterruptTrigger::LevelHigh => {
|
||||
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
|
||||
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);
|
||||
}
|
||||
InterruptTrigger::AnyEdge => {
|
||||
// noop
|
||||
w.set_edge_high(pin_group, true);
|
||||
w.set_edge_low(pin_group, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
irq.enable();
|
||||
}
|
||||
|
||||
Self { pin, level }
|
||||
@ -257,47 +248,21 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
|
||||
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
|
||||
let pin_group = (self.pin.pin() % 8) as usize;
|
||||
|
||||
// This should check the the level of the interrupt trigger level of
|
||||
// the pin and if it has been disabled that means it was done by the
|
||||
// interrupt service routine, so we then know that the event/trigger
|
||||
// happened and Poll::Ready will be returned.
|
||||
trace!("{:?} for pin {}", self.level, self.pin.pin());
|
||||
match self.level {
|
||||
InterruptTrigger::AnyEdge => {
|
||||
if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
|
||||
#[rustfmt::skip]
|
||||
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
|
||||
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(());
|
||||
}
|
||||
}
|
||||
// since the interrupt handler clears all INTE flags we'll check that
|
||||
// all have been cleared and unconditionally return Ready(()) if so.
|
||||
// we don't need further handshaking since only a single event wait
|
||||
// is possible for any given pin at any given time.
|
||||
if !inte.edge_high(pin_group)
|
||||
&& !inte.edge_low(pin_group)
|
||||
&& !inte.level_high(pin_group)
|
||||
&& !inte.level_low(pin_group)
|
||||
{
|
||||
trace!(
|
||||
"{:?} for pin {} was cleared, return Poll::Ready",
|
||||
self.level,
|
||||
self.pin.pin()
|
||||
);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
trace!("InputFuture::poll return Poll::Pending");
|
||||
Poll::Pending
|
||||
@ -644,23 +609,17 @@ impl<'d, T: Pin> Flex<'d, T> {
|
||||
|
||||
#[inline]
|
||||
pub async fn wait_for_rising_edge(&mut self) {
|
||||
self.wait_for_low().await;
|
||||
self.wait_for_high().await;
|
||||
InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn wait_for_falling_edge(&mut self) {
|
||||
self.wait_for_high().await;
|
||||
self.wait_for_low().await;
|
||||
InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn wait_for_any_edge(&mut self) {
|
||||
if self.is_high() {
|
||||
self.wait_for_low().await;
|
||||
} else {
|
||||
self.wait_for_high().await;
|
||||
}
|
||||
InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,7 @@ pub fn init(_config: config::Config) -> Peripherals {
|
||||
timer::init();
|
||||
dma::init();
|
||||
pio::init();
|
||||
gpio::init();
|
||||
}
|
||||
|
||||
peripherals
|
||||
|
@ -33,7 +33,7 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::peripherals::CORE1;
|
||||
use crate::{interrupt, pac};
|
||||
use crate::{gpio, interrupt, pac};
|
||||
|
||||
const PAUSE_TOKEN: u32 = 0xDEADBEEF;
|
||||
const RESUME_TOKEN: u32 = !0xDEADBEEF;
|
||||
@ -68,6 +68,9 @@ fn install_stack_guard(stack_bottom: *mut usize) {
|
||||
#[inline(always)]
|
||||
fn core1_setup(stack_bottom: *mut usize) {
|
||||
install_stack_guard(stack_bottom);
|
||||
unsafe {
|
||||
gpio::init();
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy_hal_common::PeripheralRef;
|
||||
use embassy_hal_common::{Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::dma::{Channel, Transfer};
|
||||
use crate::dma::{Channel, Transfer, Word};
|
||||
use crate::gpio::sealed::Pin as SealedPin;
|
||||
use crate::gpio::{Drive, Pin, Pull, SlewRate};
|
||||
use crate::pac::dma::vals::{DataSize, TreqSel};
|
||||
use crate::pio::sealed::{PioInstance as _, SmInstance as _};
|
||||
use crate::pac::dma::vals::TreqSel;
|
||||
use crate::pio::sealed::PioInstance as _;
|
||||
use crate::{interrupt, pac, peripherals, RegExt};
|
||||
|
||||
struct Wakers([AtomicWaker; 12]);
|
||||
@ -119,10 +119,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture
|
||||
if self.get_mut().sm.try_push_tx(value) {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker());
|
||||
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::SM as usize].register(cx.waker());
|
||||
unsafe {
|
||||
PIO::PIO.irqs(0).inte().write_set(|m| {
|
||||
m.0 = TXNFULL_MASK << SM::Sm::SM_NO;
|
||||
m.0 = TXNFULL_MASK << SM::SM;
|
||||
});
|
||||
}
|
||||
// debug!("Pending");
|
||||
@ -135,7 +135,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
||||
m.0 = TXNFULL_MASK << SM::Sm::SM_NO;
|
||||
m.0 = TXNFULL_MASK << SM::SM;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -164,10 +164,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO,
|
||||
if let Some(v) = self.sm.try_pull_rx() {
|
||||
Poll::Ready(v)
|
||||
} else {
|
||||
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker());
|
||||
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::SM].register(cx.waker());
|
||||
unsafe {
|
||||
PIO::PIO.irqs(0).inte().write_set(|m| {
|
||||
m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO;
|
||||
m.0 = RXNEMPTY_MASK << SM::SM;
|
||||
});
|
||||
}
|
||||
//debug!("Pending");
|
||||
@ -180,7 +180,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
||||
m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO;
|
||||
m.0 = RXNEMPTY_MASK << SM::SM;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -277,15 +277,14 @@ impl<PIO: PioInstance> PioPin<PIO> {
|
||||
#[inline]
|
||||
pub fn set_pull(&mut self, pull: Pull) {
|
||||
unsafe {
|
||||
self.pad_ctrl().modify(|w| match pull {
|
||||
Pull::Up => w.set_pue(true),
|
||||
Pull::Down => w.set_pde(true),
|
||||
Pull::None => {}
|
||||
self.pad_ctrl().modify(|w| {
|
||||
w.set_pue(pull == Pull::Up);
|
||||
w.set_pde(pull == Pull::Down);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the pin's pull.
|
||||
/// Set the pin's schmitt trigger.
|
||||
#[inline]
|
||||
pub fn set_schmitt(&mut self, enable: bool) {
|
||||
unsafe {
|
||||
@ -298,9 +297,11 @@ impl<PIO: PioInstance> PioPin<PIO> {
|
||||
pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
|
||||
let mask = 1 << self.pin();
|
||||
unsafe {
|
||||
PIO::PIO
|
||||
.input_sync_bypass()
|
||||
.modify(|w| *w = if bypass { *w & !mask } else { *w | mask });
|
||||
if bypass {
|
||||
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
|
||||
} else {
|
||||
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,16 +316,15 @@ impl<PIO: PioInstance> SealedPin for PioPin<PIO> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PioStateMachineInstance<PIO: PioInstance, SM: SmInstance> {
|
||||
pio: PhantomData<PIO>,
|
||||
sm: PhantomData<SM>,
|
||||
pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> {
|
||||
pio: PhantomData<&'d PIO>,
|
||||
}
|
||||
|
||||
impl<PIO: PioInstance, SM: SmInstance> sealed::PioStateMachine for PioStateMachineInstance<PIO, SM> {
|
||||
impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {
|
||||
type Pio = PIO;
|
||||
type Sm = SM;
|
||||
const SM: usize = SM;
|
||||
}
|
||||
impl<PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<PIO, SM> {}
|
||||
impl<'d, PIO: PioInstance, const SM: usize> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {}
|
||||
|
||||
pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn pio_no(&self) -> u8 {
|
||||
@ -332,60 +332,61 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
}
|
||||
|
||||
fn sm_no(&self) -> u8 {
|
||||
Self::Sm::SM_NO
|
||||
Self::SM as u8
|
||||
}
|
||||
|
||||
fn restart(&mut self) {
|
||||
let mask = 1u8 << Self::SM;
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.ctrl()
|
||||
.modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO));
|
||||
Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
|
||||
}
|
||||
}
|
||||
fn set_enable(&mut self, enable: bool) {
|
||||
let mask = 1u8 << Self::Sm::SM_NO;
|
||||
let mask = 1u8 << Self::SM;
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.ctrl()
|
||||
.modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 })));
|
||||
if enable {
|
||||
Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
|
||||
} else {
|
||||
Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_enabled(&self) -> bool {
|
||||
unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 }
|
||||
unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::SM) != 0 }
|
||||
}
|
||||
|
||||
fn is_tx_empty(&self) -> bool {
|
||||
unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 }
|
||||
unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::SM) != 0 }
|
||||
}
|
||||
fn is_tx_full(&self) -> bool {
|
||||
unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 }
|
||||
unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::SM) != 0 }
|
||||
}
|
||||
|
||||
fn is_rx_empty(&self) -> bool {
|
||||
unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 }
|
||||
unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::SM) != 0 }
|
||||
}
|
||||
fn is_rx_full(&self) -> bool {
|
||||
unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 }
|
||||
unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::SM) != 0 }
|
||||
}
|
||||
|
||||
fn tx_level(&self) -> u8 {
|
||||
unsafe {
|
||||
let flevel = Self::Pio::PIO.flevel().read().0;
|
||||
(flevel >> (Self::Sm::SM_NO * 8)) as u8 & 0x0f
|
||||
(flevel >> (Self::SM * 8)) as u8 & 0x0f
|
||||
}
|
||||
}
|
||||
|
||||
fn rx_level(&self) -> u8 {
|
||||
unsafe {
|
||||
let flevel = Self::Pio::PIO.flevel().read().0;
|
||||
(flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f
|
||||
(flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f
|
||||
}
|
||||
}
|
||||
|
||||
fn push_tx(&mut self, v: u32) {
|
||||
unsafe {
|
||||
Self::Pio::PIO.txf(Self::Sm::SM_NO as usize).write_value(v);
|
||||
Self::Pio::PIO.txf(Self::SM).write_value(v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,7 +399,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
}
|
||||
|
||||
fn pull_rx(&mut self) -> u32 {
|
||||
unsafe { Self::Pio::PIO.rxf(Self::Sm::SM_NO as usize).read() }
|
||||
unsafe { Self::Pio::PIO.rxf(Self::SM).read() }
|
||||
}
|
||||
|
||||
fn try_pull_rx(&mut self) -> Option<u32> {
|
||||
@ -410,73 +411,54 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
|
||||
fn set_clkdiv(&mut self, div_x_256: u32) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.clkdiv()
|
||||
.write(|w| w.0 = div_x_256 << 8);
|
||||
Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_clkdiv(&self) -> u32 {
|
||||
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).clkdiv().read().0 >> 8 }
|
||||
unsafe { Self::this_sm().clkdiv().read().0 >> 8 }
|
||||
}
|
||||
|
||||
fn clkdiv_restart(&mut self) {
|
||||
let mask = 1u8 << Self::SM;
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.ctrl()
|
||||
.modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO));
|
||||
Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
|
||||
}
|
||||
}
|
||||
|
||||
fn set_side_enable(&self, enable: bool) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.execctrl()
|
||||
.modify(|w| w.set_side_en(enable));
|
||||
Self::this_sm().execctrl().modify(|w| w.set_side_en(enable));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_side_enabled(&self) -> bool {
|
||||
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().side_en() }
|
||||
unsafe { Self::this_sm().execctrl().read().side_en() }
|
||||
}
|
||||
|
||||
fn set_side_pindir(&mut self, pindir: bool) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.execctrl()
|
||||
.modify(|w| w.set_side_pindir(pindir));
|
||||
Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_side_pindir(&self) -> bool {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.execctrl()
|
||||
.read()
|
||||
.side_pindir()
|
||||
}
|
||||
unsafe { Self::this_sm().execctrl().read().side_pindir() }
|
||||
}
|
||||
|
||||
fn set_jmp_pin(&mut self, pin: u8) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.execctrl()
|
||||
.modify(|w| w.set_jmp_pin(pin));
|
||||
Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_jmp_pin(&mut self) -> u8 {
|
||||
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().jmp_pin() }
|
||||
unsafe { Self::this_sm().execctrl().read().jmp_pin() }
|
||||
}
|
||||
|
||||
fn set_wrap(&self, source: u8, target: u8) {
|
||||
unsafe {
|
||||
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().modify(|w| {
|
||||
Self::this_sm().execctrl().modify(|w| {
|
||||
w.set_wrap_top(source);
|
||||
w.set_wrap_bottom(target)
|
||||
});
|
||||
@ -486,7 +468,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
/// Get wrapping addresses. Returns (source, target).
|
||||
fn get_wrap(&self) -> (u8, u8) {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read();
|
||||
let r = Self::this_sm().execctrl().read();
|
||||
(r.wrap_top(), r.wrap_bottom())
|
||||
}
|
||||
}
|
||||
@ -498,7 +480,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
FifoJoin::TxOnly => (false, true),
|
||||
};
|
||||
unsafe {
|
||||
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().modify(|w| {
|
||||
Self::this_sm().shiftctrl().modify(|w| {
|
||||
w.set_fjoin_rx(rx);
|
||||
w.set_fjoin_tx(tx)
|
||||
});
|
||||
@ -506,7 +488,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
}
|
||||
fn get_fifo_join(&self) -> FifoJoin {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
|
||||
let r = Self::this_sm().shiftctrl().read();
|
||||
// Ignores the invalid state when both bits are set
|
||||
if r.fjoin_rx() {
|
||||
FifoJoin::RxOnly
|
||||
@ -521,7 +503,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn clear_fifos(&mut self) {
|
||||
// Toggle FJOIN_RX to flush FIFOs
|
||||
unsafe {
|
||||
let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl();
|
||||
let shiftctrl = Self::this_sm().shiftctrl();
|
||||
shiftctrl.modify(|w| {
|
||||
w.set_fjoin_rx(!w.fjoin_rx());
|
||||
});
|
||||
@ -533,51 +515,33 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
|
||||
fn set_pull_threshold(&mut self, threshold: u8) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.modify(|w| w.set_pull_thresh(threshold));
|
||||
Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pull_threshold(&self) -> u8 {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
|
||||
r.pull_thresh()
|
||||
}
|
||||
unsafe { Self::this_sm().shiftctrl().read().pull_thresh() }
|
||||
}
|
||||
fn set_push_threshold(&mut self, threshold: u8) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.modify(|w| w.set_push_thresh(threshold));
|
||||
Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_push_threshold(&self) -> u8 {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
|
||||
r.push_thresh()
|
||||
}
|
||||
unsafe { Self::this_sm().shiftctrl().read().push_thresh() }
|
||||
}
|
||||
|
||||
fn set_out_shift_dir(&mut self, dir: ShiftDirection) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
Self::this_sm()
|
||||
.shiftctrl()
|
||||
.modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right));
|
||||
}
|
||||
}
|
||||
fn get_out_shiftdir(&self) -> ShiftDirection {
|
||||
unsafe {
|
||||
if Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.read()
|
||||
.out_shiftdir()
|
||||
{
|
||||
if Self::this_sm().shiftctrl().read().out_shiftdir() {
|
||||
ShiftDirection::Right
|
||||
} else {
|
||||
ShiftDirection::Left
|
||||
@ -587,20 +551,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
|
||||
fn set_in_shift_dir(&mut self, dir: ShiftDirection) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
Self::this_sm()
|
||||
.shiftctrl()
|
||||
.modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right));
|
||||
}
|
||||
}
|
||||
fn get_in_shiftdir(&self) -> ShiftDirection {
|
||||
unsafe {
|
||||
if Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.read()
|
||||
.in_shiftdir()
|
||||
{
|
||||
if Self::this_sm().shiftctrl().read().in_shiftdir() {
|
||||
ShiftDirection::Right
|
||||
} else {
|
||||
ShiftDirection::Left
|
||||
@ -610,76 +568,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
|
||||
fn set_autopull(&mut self, auto: bool) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.modify(|w| w.set_autopull(auto));
|
||||
Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_autopull(&self) -> bool {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.read()
|
||||
.autopull()
|
||||
}
|
||||
unsafe { Self::this_sm().shiftctrl().read().autopull() }
|
||||
}
|
||||
|
||||
fn set_autopush(&mut self, auto: bool) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.modify(|w| w.set_autopush(auto));
|
||||
Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_autopush(&self) -> bool {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.shiftctrl()
|
||||
.read()
|
||||
.autopush()
|
||||
}
|
||||
unsafe { Self::this_sm().shiftctrl().read().autopush() }
|
||||
}
|
||||
|
||||
fn get_addr(&self) -> u8 {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read();
|
||||
r.addr()
|
||||
}
|
||||
unsafe { Self::this_sm().addr().read().addr() }
|
||||
}
|
||||
fn set_sideset_count(&mut self, count: u8) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.pinctrl()
|
||||
.modify(|w| w.set_sideset_count(count));
|
||||
Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sideset_count(&self) -> u8 {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
|
||||
r.sideset_count()
|
||||
}
|
||||
unsafe { Self::this_sm().pinctrl().read().sideset_count() }
|
||||
}
|
||||
|
||||
fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.pinctrl()
|
||||
.modify(|w| w.set_sideset_base(base_pin.pin()));
|
||||
Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin()));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sideset_base(&self) -> u8 {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
|
||||
let r = Self::this_sm().pinctrl().read();
|
||||
r.sideset_base()
|
||||
}
|
||||
}
|
||||
@ -688,7 +616,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn set_set_range(&mut self, base: u8, count: u8) {
|
||||
assert!(base + count < 32);
|
||||
unsafe {
|
||||
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| {
|
||||
Self::this_sm().pinctrl().modify(|w| {
|
||||
w.set_set_base(base);
|
||||
w.set_set_count(count)
|
||||
});
|
||||
@ -698,23 +626,20 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
/// Get the range of out pins affected by a set instruction. Returns (base, count).
|
||||
fn get_set_range(&self) -> (u8, u8) {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
|
||||
let r = Self::this_sm().pinctrl().read();
|
||||
(r.set_base(), r.set_count())
|
||||
}
|
||||
}
|
||||
|
||||
fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.pinctrl()
|
||||
.modify(|w| w.set_in_base(base.pin()));
|
||||
Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin()));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_in_base(&self) -> u8 {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
|
||||
let r = Self::this_sm().pinctrl().read();
|
||||
r.in_base()
|
||||
}
|
||||
}
|
||||
@ -722,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn set_out_range(&mut self, base: u8, count: u8) {
|
||||
assert!(base + count < 32);
|
||||
unsafe {
|
||||
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| {
|
||||
Self::this_sm().pinctrl().modify(|w| {
|
||||
w.set_out_base(base);
|
||||
w.set_out_count(count)
|
||||
});
|
||||
@ -732,7 +657,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
/// Get the range of out pins affected by a set instruction. Returns (base, count).
|
||||
fn get_out_range(&self) -> (u8, u8) {
|
||||
unsafe {
|
||||
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
|
||||
let r = Self::this_sm().pinctrl().read();
|
||||
(r.out_base(), r.out_count())
|
||||
}
|
||||
}
|
||||
@ -760,15 +685,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
}
|
||||
|
||||
fn get_current_instr() -> u32 {
|
||||
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).instr().read().0 }
|
||||
unsafe { Self::this_sm().instr().read().0 }
|
||||
}
|
||||
|
||||
fn exec_instr(&mut self, instr: u16) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.sm(Self::Sm::SM_NO as usize)
|
||||
.instr()
|
||||
.write(|w| w.set_instr(instr));
|
||||
Self::this_sm().instr().write(|w| w.set_instr(instr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -787,8 +709,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn has_tx_stalled(&self) -> bool {
|
||||
unsafe {
|
||||
let fdebug = Self::Pio::PIO.fdebug();
|
||||
let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0;
|
||||
fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO));
|
||||
let ret = fdebug.read().txstall() & (1 << Self::SM) != 0;
|
||||
fdebug.write(|w| w.set_txstall(1 << Self::SM));
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -796,8 +718,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn has_tx_overflowed(&self) -> bool {
|
||||
unsafe {
|
||||
let fdebug = Self::Pio::PIO.fdebug();
|
||||
let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0;
|
||||
fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO));
|
||||
let ret = fdebug.read().txover() & (1 << Self::SM) != 0;
|
||||
fdebug.write(|w| w.set_txover(1 << Self::SM));
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -805,8 +727,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn has_rx_stalled(&self) -> bool {
|
||||
unsafe {
|
||||
let fdebug = Self::Pio::PIO.fdebug();
|
||||
let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0;
|
||||
fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO));
|
||||
let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0;
|
||||
fdebug.write(|w| w.set_rxstall(1 << Self::SM));
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -814,25 +736,25 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
fn has_rx_underflowed(&self) -> bool {
|
||||
unsafe {
|
||||
let fdebug = Self::Pio::PIO.fdebug();
|
||||
let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0;
|
||||
fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO));
|
||||
let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0;
|
||||
fdebug.write(|w| w.set_rxunder(1 << Self::SM));
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> {
|
||||
fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
|
||||
unsafe {
|
||||
let pio_no = Self::Pio::PIO_NO;
|
||||
let sm_no = Self::Sm::SM_NO;
|
||||
let sm_no = Self::SM;
|
||||
let p = ch.regs();
|
||||
p.read_addr().write_value(data.as_ptr() as u32);
|
||||
p.write_addr()
|
||||
.write_value(Self::Pio::PIO.txf(sm_no as usize).ptr() as u32);
|
||||
p.write_addr().write_value(Self::Pio::PIO.txf(sm_no).ptr() as u32);
|
||||
p.trans_count().write_value(data.len() as u32);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
p.ctrl_trig().write(|w| {
|
||||
// Set TX DREQ for this statemachine
|
||||
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no));
|
||||
w.set_data_size(DataSize::SIZE_WORD);
|
||||
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8));
|
||||
w.set_data_size(W::size());
|
||||
w.set_chain_to(ch.number());
|
||||
w.set_incr_read(true);
|
||||
w.set_incr_write(false);
|
||||
@ -843,19 +765,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
Transfer::new(ch)
|
||||
}
|
||||
|
||||
fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> {
|
||||
fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> {
|
||||
unsafe {
|
||||
let pio_no = Self::Pio::PIO_NO;
|
||||
let sm_no = Self::Sm::SM_NO;
|
||||
let sm_no = Self::SM;
|
||||
let p = ch.regs();
|
||||
p.write_addr().write_value(data.as_ptr() as u32);
|
||||
p.read_addr()
|
||||
.write_value(Self::Pio::PIO.rxf(sm_no as usize).ptr() as u32);
|
||||
p.read_addr().write_value(Self::Pio::PIO.rxf(sm_no).ptr() as u32);
|
||||
p.trans_count().write_value(data.len() as u32);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
p.ctrl_trig().write(|w| {
|
||||
// Set TX DREQ for this statemachine
|
||||
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4));
|
||||
w.set_data_size(DataSize::SIZE_WORD);
|
||||
// Set RX DREQ for this statemachine
|
||||
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8 + 4));
|
||||
w.set_data_size(W::size());
|
||||
w.set_chain_to(ch.number());
|
||||
w.set_incr_read(false);
|
||||
w.set_incr_write(true);
|
||||
@ -867,21 +789,18 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PioCommonInstance<PIO: PioInstance> {
|
||||
pub struct PioCommon<'d, PIO: PioInstance> {
|
||||
instructions_used: u32,
|
||||
pio: PhantomData<PIO>,
|
||||
pio: PhantomData<&'d PIO>,
|
||||
}
|
||||
|
||||
pub struct PioInstanceMemory<PIO: PioInstance> {
|
||||
pub struct PioInstanceMemory<'d, PIO: PioInstance> {
|
||||
used_mask: u32,
|
||||
pio: PhantomData<PIO>,
|
||||
pio: PhantomData<&'d PIO>,
|
||||
}
|
||||
|
||||
impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> {
|
||||
type Pio = PIO;
|
||||
}
|
||||
impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
|
||||
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
|
||||
impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
|
||||
pub fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO>
|
||||
where
|
||||
I: Iterator<Item = u16>,
|
||||
{
|
||||
@ -908,66 +827,50 @@ impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
|
||||
}
|
||||
}
|
||||
|
||||
fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>) {
|
||||
// TODO make instruction memory that is currently in use unfreeable
|
||||
pub fn free_instr(&mut self, instrs: PioInstanceMemory<PIO>) {
|
||||
self.instructions_used &= !instrs.used_mask;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PioCommon: sealed::PioCommon + Sized {
|
||||
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
|
||||
where
|
||||
I: Iterator<Item = u16>;
|
||||
|
||||
// TODO make instruction memory that is currently in use unfreeable
|
||||
fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>);
|
||||
|
||||
fn is_irq_set(&self, irq_no: u8) -> bool {
|
||||
pub fn is_irq_set(&self, irq_no: u8) -> bool {
|
||||
assert!(irq_no < 8);
|
||||
unsafe {
|
||||
let irq_flags = Self::Pio::PIO.irq();
|
||||
let irq_flags = PIO::PIO.irq();
|
||||
irq_flags.read().0 & (1 << irq_no) != 0
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_irq(&mut self, irq_no: usize) {
|
||||
pub fn clear_irq(&mut self, irq_no: usize) {
|
||||
assert!(irq_no < 8);
|
||||
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) }
|
||||
unsafe { PIO::PIO.irq().write(|w| w.set_irq(1 << irq_no)) }
|
||||
}
|
||||
|
||||
fn clear_irqs(&mut self, mask: u8) {
|
||||
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) }
|
||||
pub fn clear_irqs(&mut self, mask: u8) {
|
||||
unsafe { PIO::PIO.irq().write(|w| w.set_irq(mask)) }
|
||||
}
|
||||
|
||||
fn force_irq(&mut self, irq_no: usize) {
|
||||
pub fn force_irq(&mut self, irq_no: usize) {
|
||||
assert!(irq_no < 8);
|
||||
unsafe { Self::Pio::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) }
|
||||
unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) }
|
||||
}
|
||||
|
||||
fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
|
||||
pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
|
||||
unsafe {
|
||||
Self::Pio::PIO
|
||||
.input_sync_bypass()
|
||||
.modify(|w| *w = (*w & !mask) | (bypass & mask));
|
||||
// this can interfere with per-pin bypass functions. splitting the
|
||||
// modification is going to be fine since nothing that relies on
|
||||
// it can reasonably run before we finish.
|
||||
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
|
||||
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_input_sync_bypass(&self) -> u32 {
|
||||
unsafe { Self::Pio::PIO.input_sync_bypass().read() }
|
||||
pub fn get_input_sync_bypass(&self) -> u32 {
|
||||
unsafe { PIO::PIO.input_sync_bypass().read() }
|
||||
}
|
||||
|
||||
fn make_pio_pin(&self, pin: impl Pin) -> PioPin<Self::Pio> {
|
||||
pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin<PIO> {
|
||||
unsafe {
|
||||
pin.io().ctrl().write(|w| {
|
||||
w.set_funcsel(
|
||||
if Self::Pio::PIO_NO == 1 {
|
||||
pac::io::vals::Gpio0ctrlFuncsel::PIO1_0
|
||||
} else {
|
||||
// PIO == 0
|
||||
pac::io::vals::Gpio0ctrlFuncsel::PIO0_0
|
||||
}
|
||||
.0,
|
||||
);
|
||||
});
|
||||
pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
|
||||
}
|
||||
PioPin {
|
||||
pin_bank: pin.pin_bank(),
|
||||
@ -976,112 +879,63 @@ pub trait PioCommon: sealed::PioCommon + Sized {
|
||||
}
|
||||
}
|
||||
|
||||
// Identifies a specific state machine inside a PIO device
|
||||
pub struct SmInstanceBase<const SM_NO: u8> {}
|
||||
|
||||
pub trait SmInstance: sealed::SmInstance + Unpin {}
|
||||
|
||||
impl<const SM_NO: u8> sealed::SmInstance for SmInstanceBase<SM_NO> {
|
||||
const SM_NO: u8 = SM_NO;
|
||||
pub struct Pio<'d, PIO: PioInstance> {
|
||||
pub common: PioCommon<'d, PIO>,
|
||||
pub sm0: PioStateMachineInstance<'d, PIO, 0>,
|
||||
pub sm1: PioStateMachineInstance<'d, PIO, 1>,
|
||||
pub sm2: PioStateMachineInstance<'d, PIO, 2>,
|
||||
pub sm3: PioStateMachineInstance<'d, PIO, 3>,
|
||||
}
|
||||
impl<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {}
|
||||
|
||||
pub trait PioPeripheral: sealed::PioPeripheral + Sized {
|
||||
fn pio(&self) -> u8 {
|
||||
Self::Pio::PIO_NO
|
||||
}
|
||||
|
||||
fn split(
|
||||
self,
|
||||
) -> (
|
||||
PioCommonInstance<Self::Pio>,
|
||||
PioStateMachineInstance<Self::Pio, SmInstanceBase<0>>,
|
||||
PioStateMachineInstance<Self::Pio, SmInstanceBase<1>>,
|
||||
PioStateMachineInstance<Self::Pio, SmInstanceBase<2>>,
|
||||
PioStateMachineInstance<Self::Pio, SmInstanceBase<3>>,
|
||||
) {
|
||||
(
|
||||
PioCommonInstance {
|
||||
impl<'d, PIO: PioInstance> Pio<'d, PIO> {
|
||||
pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
|
||||
Self {
|
||||
common: PioCommon {
|
||||
instructions_used: 0,
|
||||
pio: PhantomData::default(),
|
||||
pio: PhantomData,
|
||||
},
|
||||
PioStateMachineInstance {
|
||||
sm: PhantomData::default(),
|
||||
pio: PhantomData::default(),
|
||||
},
|
||||
PioStateMachineInstance {
|
||||
sm: PhantomData::default(),
|
||||
pio: PhantomData::default(),
|
||||
},
|
||||
PioStateMachineInstance {
|
||||
sm: PhantomData::default(),
|
||||
pio: PhantomData::default(),
|
||||
},
|
||||
PioStateMachineInstance {
|
||||
sm: PhantomData::default(),
|
||||
pio: PhantomData::default(),
|
||||
},
|
||||
)
|
||||
sm0: PioStateMachineInstance { pio: PhantomData },
|
||||
sm1: PioStateMachineInstance { pio: PhantomData },
|
||||
sm2: PioStateMachineInstance { pio: PhantomData },
|
||||
sm3: PioStateMachineInstance { pio: PhantomData },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PioInstance: sealed::PioInstance + Sized + Unpin {
|
||||
fn pio(&self) -> u8 {
|
||||
Self::PIO_NO
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait PioStateMachine {
|
||||
type Pio: super::PioInstance;
|
||||
const SM: usize;
|
||||
|
||||
#[inline(always)]
|
||||
fn this_sm() -> crate::pac::pio::StateMachine {
|
||||
Self::Pio::PIO.sm(Self::SM as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PioInstance {
|
||||
const PIO_NO: u8;
|
||||
const PIO: &'static crate::pac::pio::Pio;
|
||||
}
|
||||
|
||||
pub trait PioCommon {
|
||||
type Pio: super::PioInstance;
|
||||
}
|
||||
|
||||
pub trait PioStateMachine {
|
||||
type Pio: super::PioInstance;
|
||||
type Sm: super::SmInstance;
|
||||
}
|
||||
|
||||
pub trait SmInstance {
|
||||
const SM_NO: u8;
|
||||
}
|
||||
|
||||
pub trait PioPeripheral {
|
||||
type Pio: super::PioInstance;
|
||||
const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
|
||||
}
|
||||
}
|
||||
|
||||
// Identifies a specific PIO device
|
||||
pub struct PioInstanceBase<const PIO_NO: u8> {}
|
||||
|
||||
pub trait PioInstance: sealed::PioInstance + Unpin {}
|
||||
|
||||
impl sealed::PioInstance for PioInstanceBase<0> {
|
||||
const PIO_NO: u8 = 0;
|
||||
const PIO: &'static pac::pio::Pio = &pac::PIO0;
|
||||
}
|
||||
impl PioInstance for PioInstanceBase<0> {}
|
||||
|
||||
impl sealed::PioInstance for PioInstanceBase<1> {
|
||||
const PIO_NO: u8 = 1;
|
||||
const PIO: &'static pac::pio::Pio = &pac::PIO1;
|
||||
}
|
||||
impl PioInstance for PioInstanceBase<1> {}
|
||||
|
||||
pub type Pio0 = PioInstanceBase<0>;
|
||||
pub type Pio1 = PioInstanceBase<1>;
|
||||
|
||||
pub type Sm0 = SmInstanceBase<0>;
|
||||
pub type Sm1 = SmInstanceBase<1>;
|
||||
pub type Sm2 = SmInstanceBase<2>;
|
||||
pub type Sm3 = SmInstanceBase<3>;
|
||||
|
||||
macro_rules! impl_pio_sm {
|
||||
($name:ident, $pio:expr) => {
|
||||
impl sealed::PioPeripheral for peripherals::$name {
|
||||
type Pio = PioInstanceBase<$pio>;
|
||||
macro_rules! impl_pio {
|
||||
($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => {
|
||||
impl sealed::PioInstance for peripherals::$name {
|
||||
const PIO_NO: u8 = $pio;
|
||||
const PIO: &'static pac::pio::Pio = &pac::$pac;
|
||||
const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
|
||||
}
|
||||
impl PioPeripheral for peripherals::$name {}
|
||||
impl PioInstance for peripherals::$name {}
|
||||
};
|
||||
}
|
||||
|
||||
impl_pio_sm!(PIO0, 0);
|
||||
impl_pio_sm!(PIO1, 1);
|
||||
impl_pio!(PIO0, 0, PIO0, PIO0_0);
|
||||
impl_pio!(PIO1, 1, PIO1, PIO1_0);
|
||||
|
@ -874,7 +874,6 @@ mod sealed {
|
||||
pub trait Instance {
|
||||
const TX_DREQ: u8;
|
||||
const RX_DREQ: u8;
|
||||
const ID: usize;
|
||||
|
||||
type Interrupt: crate::interrupt::Interrupt;
|
||||
|
||||
@ -909,11 +908,10 @@ impl_mode!(Async);
|
||||
pub trait Instance: sealed::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 {
|
||||
const TX_DREQ: u8 = $tx_dreq;
|
||||
const RX_DREQ: u8 = $rx_dreq;
|
||||
const ID: usize = $id;
|
||||
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
|
||||
@ -939,8 +937,8 @@ macro_rules! impl_instance {
|
||||
};
|
||||
}
|
||||
|
||||
impl_instance!(UART0, UART0_IRQ, 0, 20, 21);
|
||||
impl_instance!(UART1, UART1_IRQ, 1, 22, 23);
|
||||
impl_instance!(UART0, UART0_IRQ, 20, 21);
|
||||
impl_instance!(UART1, UART1_IRQ, 22, 23);
|
||||
|
||||
pub trait TxPin<T: Instance>: sealed::TxPin<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 }
|
||||
critical-section = "1.1"
|
||||
atomic-polyfill = "1.0.1"
|
||||
stm32-metapac = "6"
|
||||
stm32-metapac = "7"
|
||||
vcell = "0.1.3"
|
||||
bxcan = "0.7.0"
|
||||
nb = "1.0.0"
|
||||
@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||
[build-dependencies]
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
stm32-metapac = { version = "6", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { version = "7", default-features = false, features = ["metadata"]}
|
||||
|
||||
[features]
|
||||
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)
|
||||
}
|
||||
|
||||
#[cfg(not(usart_v1))]
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
pub fn new_with_de(
|
||||
peri: impl Peripheral<P = T> + '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);
|
||||
}
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
|
||||
configure(r, &config, T::frequency(), T::KIND, true, true);
|
||||
|
||||
unsafe {
|
||||
r.cr1().modify(|w| {
|
||||
|
@ -12,10 +12,11 @@ use futures::future::{select, Either};
|
||||
|
||||
use crate::dma::{NoDma, Transfer};
|
||||
use crate::gpio::sealed::AFType;
|
||||
#[cfg(any(lpuart_v1, lpuart_v2))]
|
||||
use crate::pac::lpuart::{regs, vals, Lpuart as Regs};
|
||||
#[cfg(not(any(lpuart_v1, lpuart_v2)))]
|
||||
use crate::pac::usart::{regs, vals, Usart as Regs};
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
use crate::pac::usart::Lpuart as Regs;
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
use crate::pac::usart::Usart as Regs;
|
||||
use crate::pac::usart::{regs, vals};
|
||||
use crate::time::Hertz;
|
||||
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);
|
||||
}
|
||||
|
||||
configure(r, &config, T::frequency(), T::MULTIPLIER, false, true);
|
||||
configure(r, &config, T::frequency(), T::KIND, false, true);
|
||||
|
||||
// create state once!
|
||||
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);
|
||||
}
|
||||
|
||||
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.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)
|
||||
}
|
||||
|
||||
#[cfg(not(usart_v1))]
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
pub fn new_with_de(
|
||||
peri: impl Peripheral<P = 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);
|
||||
}
|
||||
|
||||
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.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 {
|
||||
panic!("USART: At least one of RX or TX should be enabled");
|
||||
}
|
||||
|
||||
// TODO: better calculation, including error checking and OVER8 if possible.
|
||||
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
|
||||
#[cfg(not(usart_v4))]
|
||||
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 {
|
||||
r.brr().write_value(regs::Brr(div));
|
||||
r.cr2().write(|w| {
|
||||
w.set_stop(match config.stop_bits {
|
||||
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,
|
||||
_ => vals::Ps::EVEN,
|
||||
});
|
||||
#[cfg(not(usart_v1))]
|
||||
w.set_over8(vals::Over8(over8 as _));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -986,43 +1047,45 @@ mod rx_ringbuffered;
|
||||
#[cfg(not(gpdma))]
|
||||
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 {
|
||||
r.dr().ptr() as _
|
||||
}
|
||||
|
||||
#[cfg(usart_v1)]
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||
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> {
|
||||
r.sr()
|
||||
}
|
||||
|
||||
#[cfg(usart_v1)]
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
#[allow(unused)]
|
||||
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
||||
// 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 {
|
||||
r.tdr().ptr() as _
|
||||
}
|
||||
|
||||
#[cfg(usart_v2)]
|
||||
#[cfg(any(usart_v3, usart_v4))]
|
||||
fn rdr(r: Regs) -> *mut u8 {
|
||||
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> {
|
||||
r.isr()
|
||||
}
|
||||
|
||||
#[cfg(usart_v2)]
|
||||
#[cfg(any(usart_v3, usart_v4))]
|
||||
#[allow(unused)]
|
||||
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
||||
r.icr().write(|w| *w = regs::Icr(sr.0));
|
||||
@ -1033,6 +1096,13 @@ pub(crate) mod sealed {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Kind {
|
||||
Uart,
|
||||
#[cfg(any(usart_v3, usart_v4))]
|
||||
Lpuart,
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub rx_waker: AtomicWaker,
|
||||
pub tx_waker: AtomicWaker,
|
||||
@ -1048,7 +1118,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
|
||||
pub trait BasicInstance: crate::rcc::RccPeripheral {
|
||||
const MULTIPLIER: u32;
|
||||
const KIND: Kind;
|
||||
type Interrupt: crate::interrupt::Interrupt;
|
||||
|
||||
fn regs() -> Regs;
|
||||
@ -1077,10 +1147,10 @@ pin_trait!(DePin, BasicInstance);
|
||||
dma_trait!(TxDma, BasicInstance);
|
||||
dma_trait!(RxDma, BasicInstance);
|
||||
|
||||
macro_rules! impl_lpuart {
|
||||
($inst:ident, $irq:ident, $mul:expr) => {
|
||||
macro_rules! impl_usart {
|
||||
($inst:ident, $irq:ident, $kind:expr) => {
|
||||
impl sealed::BasicInstance for crate::peripherals::$inst {
|
||||
const MULTIPLIER: u32 = $mul;
|
||||
const KIND: Kind = $kind;
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
|
||||
fn regs() -> Regs {
|
||||
@ -1104,21 +1174,19 @@ macro_rules! impl_lpuart {
|
||||
}
|
||||
|
||||
foreach_interrupt!(
|
||||
($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
impl_lpuart!($inst, $irq, 256);
|
||||
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
|
||||
impl_usart!($inst, $irq, Kind::Lpuart);
|
||||
};
|
||||
|
||||
($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 {
|
||||
|
||||
fn regs_uart() -> crate::pac::usart::Usart {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
impl FullInstance for peripherals::$inst {
|
||||
}
|
||||
impl FullInstance for peripherals::$inst {}
|
||||
};
|
||||
);
|
||||
|
@ -4,15 +4,13 @@
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{AnyPin, Pin};
|
||||
use embassy_rp::pio::{
|
||||
Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0,
|
||||
Sm1, Sm2,
|
||||
};
|
||||
use embassy_rp::peripherals::PIO0;
|
||||
use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection};
|
||||
use embassy_rp::pio_instr_util;
|
||||
use embassy_rp::relocate::RelocatedProgram;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
|
||||
fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 0>, pin: AnyPin) {
|
||||
// Setup sm0
|
||||
|
||||
// Send data serially to pin
|
||||
@ -40,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) {
|
||||
async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) {
|
||||
sm.set_enable(true);
|
||||
|
||||
let mut v = 0x0f0caffa;
|
||||
@ -51,7 +49,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm1>) {
|
||||
fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 1>) {
|
||||
// Setupm sm1
|
||||
|
||||
// Read 0b10101 repeatedly until ISR is full
|
||||
@ -70,7 +68,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
|
||||
async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) {
|
||||
sm.set_enable(true);
|
||||
loop {
|
||||
let rx = sm.wait_pull().await;
|
||||
@ -78,7 +76,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm2>) {
|
||||
fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 2>) {
|
||||
// Setup sm2
|
||||
|
||||
// Repeatedly trigger IRQ 3
|
||||
@ -102,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
|
||||
async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) {
|
||||
sm.set_enable(true);
|
||||
loop {
|
||||
sm.wait_irq(3).await;
|
||||
@ -115,11 +113,17 @@ async fn main(spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let pio = p.PIO0;
|
||||
|
||||
let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split();
|
||||
let Pio {
|
||||
mut common,
|
||||
mut sm0,
|
||||
mut sm1,
|
||||
mut sm2,
|
||||
..
|
||||
} = Pio::new(pio);
|
||||
|
||||
setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade());
|
||||
setup_pio_task_sm1(&mut pio0, &mut sm1);
|
||||
setup_pio_task_sm2(&mut pio0, &mut sm2);
|
||||
setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade());
|
||||
setup_pio_task_sm1(&mut common, &mut sm1);
|
||||
setup_pio_task_sm2(&mut common, &mut sm2);
|
||||
spawner.spawn(pio_task_sm0(sm0)).unwrap();
|
||||
spawner.spawn(pio_task_sm1(sm1)).unwrap();
|
||||
spawner.spawn(pio_task_sm2(sm2)).unwrap();
|
||||
|
@ -4,7 +4,7 @@
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_rp::pio::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection};
|
||||
use embassy_rp::pio::{Pio, PioStateMachine, ShiftDirection};
|
||||
use embassy_rp::relocate::RelocatedProgram;
|
||||
use embassy_rp::{pio_instr_util, Peripheral};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
@ -19,7 +19,11 @@ fn swap_nibbles(v: u32) -> u32 {
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let pio = p.PIO0;
|
||||
let (mut pio0, mut sm, ..) = pio.split();
|
||||
let Pio {
|
||||
mut common,
|
||||
sm0: mut sm,
|
||||
..
|
||||
} = Pio::new(pio);
|
||||
|
||||
let prg = pio_proc::pio_asm!(
|
||||
".origin 0",
|
||||
@ -34,7 +38,7 @@ async fn main(_spawner: Spawner) {
|
||||
);
|
||||
|
||||
let relocated = RelocatedProgram::new(&prg.program);
|
||||
pio0.write_instr(relocated.origin() as usize, relocated.code());
|
||||
common.write_instr(relocated.origin() as usize, relocated.code());
|
||||
pio_instr_util::exec_jmp(&mut sm, relocated.origin());
|
||||
sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
|
||||
let pio::Wrap { source, target } = relocated.wrap();
|
||||
|
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_rp::gpio::{self, Pin};
|
||||
use embassy_rp::pio::{
|
||||
FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance,
|
||||
ShiftDirection, SmInstance,
|
||||
FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection,
|
||||
};
|
||||
use embassy_rp::pio_instr_util;
|
||||
use embassy_rp::relocate::RelocatedProgram;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use smart_leds::RGB8;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
pub struct Ws2812<P: PioInstance, S: SmInstance> {
|
||||
sm: PioStateMachineInstance<P, S>,
|
||||
pub struct Ws2812<'d, P: PioInstance, const S: usize> {
|
||||
sm: PioStateMachineInstance<'d, P, S>,
|
||||
}
|
||||
|
||||
impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
|
||||
pub fn new(mut pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self {
|
||||
impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
|
||||
pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self {
|
||||
// Setup sm0
|
||||
|
||||
// prepare the PIO program
|
||||
@ -116,7 +115,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Start");
|
||||
let p = embassy_rp::init(Default::default());
|
||||
|
||||
let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split();
|
||||
let Pio { common, sm0, .. } = Pio::new(p.PIO0);
|
||||
|
||||
// This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
|
||||
// feather boards for the 2040 both have one built in.
|
||||
@ -125,7 +124,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
// For the thing plus, use pin 8
|
||||
// For the feather, use pin 16
|
||||
let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade());
|
||||
let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade());
|
||||
|
||||
// Loop forever making RGB values and pushing them out to the WS2812.
|
||||
loop {
|
||||
|
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 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.
|
||||
// This is because we aren't sending+receiving at the same time.
|
||||
{
|
||||
|
@ -3,6 +3,7 @@ edition = "2021"
|
||||
name = "embassy-stm32-tests"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
autobins = false
|
||||
|
||||
[features]
|
||||
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());
|
||||
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
println!("cargo:rerun-if-changed=link_ram.x");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
|
||||
// too little RAM to run from RAM.
|
||||
#[cfg(any(feature = "stm32c031c6"))]
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
#[cfg(not(any(feature = "stm32c031c6")))]
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
|
||||
if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rerun-if-changed=link.x");
|
||||
} else {
|
||||
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");
|
||||
|
||||
|
@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) {
|
||||
#[cfg(feature = "stm32c031c6")]
|
||||
let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
|
||||
|
||||
info!("asdfa;");
|
||||
let mut spi = Spi::new(
|
||||
spi,
|
||||
sck, // Arduino D13
|
||||
|
@ -9,6 +9,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::interrupt;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_time::{Duration, Instant};
|
||||
use example_common::*;
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -19,36 +20,76 @@ async fn main(_spawner: Spawner) {
|
||||
// Arduino pins D0 and D1
|
||||
// They're connected together with a 1K resistor.
|
||||
#[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")]
|
||||
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")]
|
||||
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")]
|
||||
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")]
|
||||
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")]
|
||||
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")]
|
||||
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")]
|
||||
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")]
|
||||
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 mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config);
|
||||
{
|
||||
let config = Config::default();
|
||||
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.
|
||||
// This is because we aren't sending+receiving at the same time.
|
||||
// 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.
|
||||
|
||||
let data = [0xC0, 0xDE];
|
||||
usart.blocking_write(&data).unwrap();
|
||||
let data = [0xC0, 0xDE];
|
||||
usart.blocking_write(&data).unwrap();
|
||||
|
||||
let mut buf = [0; 2];
|
||||
usart.blocking_read(&mut buf).unwrap();
|
||||
assert_eq!(buf, data);
|
||||
let mut buf = [0; 2];
|
||||
usart.blocking_read(&mut buf).unwrap();
|
||||
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");
|
||||
cortex_m::asm::bkpt();
|
||||
|
@ -94,6 +94,9 @@ async fn main(_spawner: Spawner) {
|
||||
let rx_fut = async {
|
||||
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;
|
||||
|
||||
assert_eq!(tx_buf, rx_buf);
|
||||
|
@ -145,13 +145,16 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
#[embassy_executor::task]
|
||||
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);
|
||||
|
||||
info!("Starting random transmissions into void...");
|
||||
|
||||
let mut i: u8 = 0;
|
||||
loop {
|
||||
let mut buf = [0; 32];
|
||||
let mut buf = [0; 256];
|
||||
let len = 1 + (rng.next_u32() as usize % buf.len());
|
||||
for b in &mut buf[..len] {
|
||||
*b = i;
|
||||
@ -172,7 +175,7 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
|
||||
let mut i = 0;
|
||||
let mut expected = 0;
|
||||
loop {
|
||||
let mut buf = [0; 100];
|
||||
let mut buf = [0; 256];
|
||||
let max_len = 1 + (rng.next_u32() as usize % buf.len());
|
||||
let received = match rx.read(&mut buf[..max_len]).await {
|
||||
Ok(r) => r,
|
||||
|
@ -16,5 +16,10 @@ pub fn config() -> Config {
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user