diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 42c4fd13e..75d7492e0 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -1,82 +1,265 @@ +use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::{Context, Poll}; -use embassy_hal_common::impl_peripheral; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; +use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +use futures::Future; +use pac::dma::vals::DataSize; use crate::pac::dma::vals; -use crate::{pac, peripherals}; +use crate::{interrupt, pac, peripherals}; -pub struct Dma { - _inner: T, +#[interrupt] +unsafe fn DMA_IRQ_0() { + let ints0 = pac::DMA.ints0().read().ints0(); + for channel in 0..CHANNEL_COUNT { + let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); + if ctrl_trig.ahb_error() { + panic!("DMA: error on DMA_0 channel {}", channel); + } + + if ints0 & (1 << channel) == (1 << channel) { + CHANNEL_WAKERS[channel].wake(); + } + } + pac::DMA.ints0().write(|w| w.set_ints0(ints0)); } -impl Dma { - pub fn copy(inner: T, from: &[u32], to: &mut [u32]) { - assert!(from.len() == to.len()); +pub(crate) unsafe fn init() { + let irq = interrupt::DMA_IRQ_0::steal(); + irq.disable(); + irq.set_priority(interrupt::Priority::P3); + pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); + + irq.enable(); +} + +pub unsafe fn read<'a, C: Channel, W: Word>( + ch: impl Peripheral

+ 'a, + from: *const W, + to: &mut [W], + dreq: u8, +) -> Transfer<'a, C> { + let (to_ptr, len) = crate::dma::slice_ptr_parts_mut(to); + copy_inner( + ch, + from as *const u32, + to_ptr as *mut u32, + len, + W::size(), + false, + true, + dreq, + ) +} + +pub unsafe fn write<'a, C: Channel, W: Word>( + ch: impl Peripheral

+ 'a, + from: &[W], + to: *mut W, + dreq: u8, +) -> Transfer<'a, C> { + let (from_ptr, len) = crate::dma::slice_ptr_parts(from); + copy_inner( + ch, + from_ptr as *const u32, + to as *mut u32, + len, + W::size(), + true, + false, + dreq, + ) +} + +pub unsafe fn copy<'a, C: Channel, W: Word>( + ch: impl Peripheral

+ 'a, + from: &[W], + to: &mut [W], +) -> Transfer<'a, C> { + let (from_ptr, from_len) = crate::dma::slice_ptr_parts(from); + let (to_ptr, to_len) = crate::dma::slice_ptr_parts_mut(to); + assert_eq!(from_len, to_len); + copy_inner( + ch, + from_ptr as *const u32, + to_ptr as *mut u32, + from_len, + W::size(), + true, + true, + vals::TreqSel::PERMANENT.0, + ) +} + +fn copy_inner<'a, C: Channel>( + ch: impl Peripheral

+ 'a, + from: *const u32, + to: *mut u32, + len: usize, + data_size: DataSize, + incr_read: bool, + incr_write: bool, + dreq: u8, +) -> Transfer<'a, C> { + into_ref!(ch); + + unsafe { + let p = ch.regs(); + + p.read_addr().write_value(from as u32); + p.write_addr().write_value(to as u32); + p.trans_count().write_value(len as u32); + + compiler_fence(Ordering::SeqCst); + + p.ctrl_trig().write(|w| { + // TODO: Add all DREQ options to pac vals::TreqSel, and use + // `set_treq:sel` + w.0 = ((dreq as u32) & 0x3f) << 15usize; + w.set_data_size(data_size); + w.set_incr_read(incr_read); + w.set_incr_write(incr_write); + w.set_chain_to(ch.number()); + w.set_en(true); + }); + + compiler_fence(Ordering::SeqCst); + } + Transfer::new(ch) +} + +pub struct Transfer<'a, C: Channel> { + channel: PeripheralRef<'a, C>, +} + +impl<'a, C: Channel> Transfer<'a, C> { + pub(crate) fn new(channel: impl Peripheral

+ 'a) -> Self { + into_ref!(channel); + + Self { channel } + } +} + +impl<'a, C: Channel> Drop for Transfer<'a, C> { + fn drop(&mut self) { + let p = self.channel.regs(); unsafe { - let p = inner.regs(); - - p.read_addr().write_value(from.as_ptr() as u32); - p.write_addr().write_value(to.as_mut_ptr() as u32); - p.trans_count().write_value(from.len() as u32); - - compiler_fence(Ordering::SeqCst); - - p.ctrl_trig().write(|w| { - w.set_data_size(vals::DataSize::SIZE_WORD); - w.set_incr_read(true); - w.set_incr_write(true); - w.set_chain_to(inner.number()); - w.set_en(true); - }); - + pac::DMA + .chan_abort() + .modify(|m| m.set_chan_abort(1 << self.channel.number())); while p.ctrl_trig().read().busy() {} - - compiler_fence(Ordering::SeqCst); } } } -pub struct NoDma; +impl<'a, C: Channel> Unpin for Transfer<'a, C> {} +impl<'a, C: Channel> Future for Transfer<'a, C> { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // We need to register/re-register the waker for each poll because any + // calls to wake will deregister the waker. + CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); -impl_peripheral!(NoDma); + if unsafe { self.channel.regs().ctrl_trig().read().busy() } { + Poll::Pending + } else { + Poll::Ready(()) + } + } +} + +const CHANNEL_COUNT: usize = 12; +const NEW_AW: AtomicWaker = AtomicWaker::new(); +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; mod sealed { - use super::*; + pub trait Channel {} - pub trait Channel { - fn number(&self) -> u8; + pub trait Word {} +} - fn regs(&self) -> pac::dma::Channel { - pac::DMA.ch(self.number() as _) - } +pub trait Channel: Peripheral

+ sealed::Channel + Into + Sized + 'static { + fn number(&self) -> u8; + + fn regs(&self) -> pac::dma::Channel { + pac::DMA.ch(self.number() as _) + } + + fn degrade(self) -> AnyChannel { + AnyChannel { number: self.number() } } } -pub trait Channel: sealed::Channel {} +pub trait Word: sealed::Word { + fn size() -> vals::DataSize; +} + +impl sealed::Word for u8 {} +impl Word for u8 { + fn size() -> vals::DataSize { + vals::DataSize::SIZE_BYTE + } +} + +impl sealed::Word for u16 {} +impl Word for u16 { + fn size() -> vals::DataSize { + vals::DataSize::SIZE_HALFWORD + } +} + +impl sealed::Word for u32 {} +impl Word for u32 { + fn size() -> vals::DataSize { + vals::DataSize::SIZE_WORD + } +} pub struct AnyChannel { number: u8, } -impl Channel for AnyChannel {} -impl sealed::Channel for AnyChannel { +impl_peripheral!(AnyChannel); + +impl sealed::Channel for AnyChannel {} +impl Channel for AnyChannel { fn number(&self) -> u8 { self.number } } macro_rules! channel { - ($type:ident, $num:expr) => { - impl Channel for peripherals::$type {} - impl sealed::Channel for peripherals::$type { + ($name:ident, $num:expr) => { + impl sealed::Channel for peripherals::$name {} + impl Channel for peripherals::$name { fn number(&self) -> u8 { $num } } + + impl From for crate::dma::AnyChannel { + fn from(val: peripherals::$name) -> Self { + crate::dma::Channel::degrade(val) + } + } }; } +// TODO: replace transmutes with core::ptr::metadata once it's stable +#[allow(unused)] +pub(crate) fn slice_ptr_parts(slice: *const [T]) -> (usize, usize) { + unsafe { core::mem::transmute(slice) } +} + +#[allow(unused)] +pub(crate) fn slice_ptr_parts_mut(slice: *mut [T]) -> (usize, usize) { + unsafe { core::mem::transmute(slice) } +} + channel!(DMA_CH0, 0); channel!(DMA_CH1, 1); channel!(DMA_CH2, 2); diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 8c053a4f7..6db77b8cd 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -105,6 +105,7 @@ pub fn init(_config: config::Config) -> Peripherals { unsafe { clocks::init(); timer::init(); + dma::init(); } peripherals diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart.rs index 6c5ab3515..4a3c7a0ce 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart.rs @@ -2,6 +2,7 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; +use crate::dma::{AnyChannel, Channel}; use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; use crate::{pac, peripherals, Peripheral}; @@ -76,26 +77,27 @@ pub enum Error { Framing, } -pub struct Uart<'d, T: Instance> { - tx: UartTx<'d, T>, - rx: UartRx<'d, T>, +pub struct Uart<'d, T: Instance, M: Mode> { + tx: UartTx<'d, T, M>, + rx: UartRx<'d, T, M>, } -pub struct UartTx<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, +pub struct UartTx<'d, T: Instance, M: Mode> { + tx_dma: Option>, + phantom: PhantomData<(&'d mut T, M)>, } -pub struct UartRx<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, +pub struct UartRx<'d, T: Instance, M: Mode> { + rx_dma: Option>, + phantom: PhantomData<(&'d mut T, M)>, } -impl<'d, T: Instance> UartTx<'d, T> { - fn new() -> Self { - Self { phantom: PhantomData } - } - - pub async fn write(&mut self, _buffer: &[u8]) -> Result<(), Error> { - todo!() +impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { + fn new(tx_dma: Option>) -> Self { + Self { + tx_dma, + phantom: PhantomData, + } } pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { @@ -111,18 +113,33 @@ impl<'d, T: Instance> UartTx<'d, T> { pub fn blocking_flush(&mut self) -> Result<(), Error> { let r = T::regs(); - unsafe { while r.uartfr().read().txff() {} } + unsafe { while !r.uartfr().read().txfe() {} } Ok(()) } } -impl<'d, T: Instance> UartRx<'d, T> { - fn new() -> Self { - Self { phantom: PhantomData } +impl<'d, T: Instance> UartTx<'d, T, Async> { + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + let ch = self.tx_dma.as_mut().unwrap(); + let transfer = unsafe { + T::regs().uartdmacr().modify(|reg| { + reg.set_txdmae(true); + }); + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) + }; + transfer.await; + Ok(()) } +} - pub async fn read(&mut self, _buffer: &mut [u8]) -> Result<(), Error> { - todo!(); +impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { + fn new(rx_dma: Option>) -> Self { + Self { + rx_dma, + phantom: PhantomData, + } } pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { @@ -130,6 +147,10 @@ impl<'d, T: Instance> UartRx<'d, T> { unsafe { for b in buffer { *b = loop { + if r.uartfr().read().rxfe() { + continue; + } + let dr = r.uartdr().read(); if dr.oe() { @@ -140,7 +161,7 @@ impl<'d, T: Instance> UartRx<'d, T> { return Err(Error::Parity); } else if dr.fe() { return Err(Error::Framing); - } else if dr.fe() { + } else { break dr.data(); } }; @@ -150,25 +171,41 @@ impl<'d, T: Instance> UartRx<'d, T> { } } -impl<'d, T: Instance> Uart<'d, T> { +impl<'d, T: Instance> UartRx<'d, T, Async> { + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + let ch = self.rx_dma.as_mut().unwrap(); + let transfer = unsafe { + T::regs().uartdmacr().modify(|reg| { + reg.set_rxdmae(true); + }); + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) + }; + transfer.await; + Ok(()) + } +} + +impl<'d, T: Instance> Uart<'d, T, Blocking> { /// Create a new UART without hardware flow control - pub fn new( + pub fn new_blocking( uart: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, rx: impl Peripheral

> + 'd, config: Config, ) -> Self { into_ref!(tx, rx); - Self::new_inner(uart, rx.map_into(), tx.map_into(), None, None, config) + Self::new_inner(uart, rx.map_into(), tx.map_into(), None, None, None, None, config) } /// Create a new UART with hardware flow control (RTS/CTS) - pub fn new_with_rtscts( + pub fn new_with_rtscts_blocking( uart: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, rx: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, rts: impl Peripheral

> + 'd, + cts: impl Peripheral

> + 'd, config: Config, ) -> Self { into_ref!(tx, rx, cts, rts); @@ -176,18 +213,72 @@ impl<'d, T: Instance> Uart<'d, T> { uart, rx.map_into(), tx.map_into(), - Some(cts.map_into()), Some(rts.map_into()), + Some(cts.map_into()), + None, + None, + config, + ) + } +} + +impl<'d, T: Instance> Uart<'d, T, Async> { + /// Create a new DMA enabled UART without hardware flow control + pub fn new( + uart: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + rx: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

+ 'd, + rx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(tx, rx, tx_dma, rx_dma); + Self::new_inner( + uart, + rx.map_into(), + tx.map_into(), + None, + None, + Some(tx_dma.map_into()), + Some(rx_dma.map_into()), config, ) } + /// Create a new DMA enabled UART with hardware flow control (RTS/CTS) + pub fn new_with_rtscts( + uart: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + rx: impl Peripheral

> + 'd, + rts: impl Peripheral

> + 'd, + cts: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

+ 'd, + rx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(tx, rx, cts, rts, tx_dma, rx_dma); + Self::new_inner( + uart, + rx.map_into(), + tx.map_into(), + Some(rts.map_into()), + Some(cts.map_into()), + Some(tx_dma.map_into()), + Some(rx_dma.map_into()), + config, + ) + } +} + +impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { fn new_inner( _uart: impl Peripheral

+ 'd, tx: PeripheralRef<'d, AnyPin>, rx: PeripheralRef<'d, AnyPin>, - cts: Option>, rts: Option>, + cts: Option>, + tx_dma: Option>, + rx_dma: Option>, config: Config, ) -> Self { into_ref!(_uart); @@ -195,6 +286,30 @@ impl<'d, T: Instance> Uart<'d, T> { unsafe { let r = T::regs(); + tx.io().ctrl().write(|w| w.set_funcsel(2)); + rx.io().ctrl().write(|w| w.set_funcsel(2)); + + tx.pad_ctrl().write(|w| { + w.set_ie(true); + }); + + rx.pad_ctrl().write(|w| { + w.set_ie(true); + }); + + if let Some(pin) = &cts { + pin.io().ctrl().write(|w| w.set_funcsel(2)); + pin.pad_ctrl().write(|w| { + w.set_ie(true); + }); + } + if let Some(pin) = &rts { + pin.io().ctrl().write(|w| w.set_funcsel(2)); + pin.pad_ctrl().write(|w| { + w.set_ie(true); + }); + } + let clk_base = crate::clocks::clk_peri_freq(); let baud_rate_div = (8 * clk_base) / config.baudrate; @@ -215,10 +330,14 @@ impl<'d, T: Instance> Uart<'d, T> { let (pen, eps) = match config.parity { Parity::ParityNone => (false, false), - Parity::ParityEven => (true, true), Parity::ParityOdd => (true, false), + Parity::ParityEven => (true, true), }; + // PL011 needs a (dummy) line control register write to latch in the + // divisors. We don't want to actually change LCR contents here. + r.uartlcr_h().modify(|_| {}); + r.uartlcr_h().write(|w| { w.set_wlen(config.data_bits.bits()); w.set_stp2(config.stop_bits == StopBits::STOP2); @@ -234,27 +353,16 @@ impl<'d, T: Instance> Uart<'d, T> { w.set_ctsen(cts.is_some()); w.set_rtsen(rts.is_some()); }); - - tx.io().ctrl().write(|w| w.set_funcsel(2)); - rx.io().ctrl().write(|w| w.set_funcsel(2)); - if let Some(pin) = &cts { - pin.io().ctrl().write(|w| w.set_funcsel(2)); - } - if let Some(pin) = &rts { - pin.io().ctrl().write(|w| w.set_funcsel(2)); - } } Self { - tx: UartTx::new(), - rx: UartRx::new(), + tx: UartTx::new(tx_dma), + rx: UartRx::new(rx_dma), } } +} - pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { - self.tx.write(buffer).await - } - +impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.blocking_write(buffer) } @@ -263,30 +371,39 @@ impl<'d, T: Instance> Uart<'d, T> { self.tx.blocking_flush() } - pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - self.rx.read(buffer).await - } - pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.blocking_read(buffer) } - /// Split the Uart into a transmitter and receiver, which is - /// particuarly useful when having two tasks correlating to - /// transmitting and receiving. - pub fn split(self) -> (UartTx<'d, T>, UartRx<'d, T>) { + /// Split the Uart into a transmitter and receiver, which is particuarly + /// useful when having two tasks correlating to transmitting and receiving. + pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { (self.tx, self.rx) } } +impl<'d, T: Instance> Uart<'d, T, Async> { + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.tx.write(buffer).await + } + + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.rx.read(buffer).await + } +} + mod eh02 { use super::*; - impl<'d, T: Instance> embedded_hal_02::serial::Read for UartRx<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for UartRx<'d, T, M> { type Error = Error; fn read(&mut self) -> Result> { let r = T::regs(); unsafe { + if r.uartfr().read().rxfe() { + return Err(nb::Error::WouldBlock); + } + let dr = r.uartdr().read(); if dr.oe() { @@ -297,16 +414,14 @@ mod eh02 { Err(nb::Error::Other(Error::Parity)) } else if dr.fe() { Err(nb::Error::Other(Error::Framing)) - } else if dr.fe() { - Ok(dr.data()) } else { - Err(nb::Error::WouldBlock) + Ok(dr.data()) } } } } - impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for UartTx<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write for UartTx<'d, T, M> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { self.blocking_write(buffer) @@ -316,14 +431,14 @@ mod eh02 { } } - impl<'d, T: Instance> embedded_hal_02::serial::Read for Uart<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for Uart<'d, T, M> { type Error = Error; fn read(&mut self) -> Result> { embedded_hal_02::serial::Read::read(&mut self.rx) } } - impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for Uart<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write for Uart<'d, T, M> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { self.blocking_write(buffer) @@ -349,15 +464,15 @@ mod eh1 { } } - impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uart<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for Uart<'d, T, M> { type Error = Error; } - impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UartTx<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartTx<'d, T, M> { type Error = Error; } - impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UartRx<'d, T> { + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { type Error = Error; } } @@ -366,7 +481,7 @@ cfg_if::cfg_if! { if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] { use core::future::Future; - impl<'d, T: Instance> embedded_hal_async::serial::Write for UartTx<'d, T> + impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Write for UartTx<'d, T, M> { type WriteFuture<'a> = impl Future> + 'a where Self: 'a; @@ -381,7 +496,7 @@ cfg_if::cfg_if! { } } - impl<'d, T: Instance> embedded_hal_async::serial::Read for UartRx<'d, T> + impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Read for UartRx<'d, T, M> { type ReadFuture<'a> = impl Future> + 'a where Self: 'a; @@ -390,7 +505,7 @@ cfg_if::cfg_if! { } } - impl<'d, T: Instance> embedded_hal_async::serial::Write for Uart<'d, T> + impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Write for Uart<'d, T, M> { type WriteFuture<'a> = impl Future> + 'a where Self: 'a; @@ -405,7 +520,7 @@ cfg_if::cfg_if! { } } - impl<'d, T: Instance> embedded_hal_async::serial::Read for Uart<'d, T> + impl<'d, T: Instance, M: Mode> embedded_hal_async::serial::Read for Uart<'d, T, M> { type ReadFuture<'a> = impl Future> + 'a where Self: 'a; @@ -419,7 +534,12 @@ cfg_if::cfg_if! { mod sealed { use super::*; + pub trait Mode {} + pub trait Instance { + const TX_DREQ: u8; + const RX_DREQ: u8; + fn regs() -> pac::uart::Uart; } pub trait TxPin {} @@ -428,11 +548,29 @@ mod sealed { pub trait RtsPin {} } +pub trait Mode: sealed::Mode {} + +macro_rules! impl_mode { + ($name:ident) => { + impl sealed::Mode for $name {} + impl Mode for $name {} + }; +} + +pub struct Blocking; +pub struct Async; + +impl_mode!(Blocking); +impl_mode!(Async); + pub trait Instance: sealed::Instance {} macro_rules! impl_instance { - ($inst:ident, $irq:ident) => { + ($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; + fn regs() -> pac::uart::Uart { pac::$inst } @@ -441,8 +579,8 @@ macro_rules! impl_instance { }; } -impl_instance!(UART0, UART0); -impl_instance!(UART1, UART1); +impl_instance!(UART0, UART0, 20, 21); +impl_instance!(UART1, UART1, 22, 23); pub trait TxPin: sealed::TxPin + crate::gpio::Pin {} pub trait RxPin: sealed::RxPin + crate::gpio::Pin {} diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs index c63b31cae..05177a6b4 100644 --- a/examples/rp/src/bin/uart.rs +++ b/examples/rp/src/bin/uart.rs @@ -10,7 +10,7 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let config = uart::Config::default(); - let mut uart = uart::Uart::new_with_rtscts(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config); + let mut uart = uart::Uart::new_with_rtscts_blocking(p.UART0, p.PIN_0, p.PIN_1, p.PIN_3, p.PIN_2, config); uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap(); loop { diff --git a/tests/rp/src/bin/dma_copy_async.rs b/tests/rp/src/bin/dma_copy_async.rs new file mode 100644 index 000000000..c53f644bd --- /dev/null +++ b/tests/rp/src/bin/dma_copy_async.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_rp::dma::copy; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + // Check `u8` copy + { + let data: [u8; 2] = [0xC0, 0xDE]; + let mut buf = [0; 2]; + unsafe { copy(p.DMA_CH0, &data, &mut buf).await }; + assert_eq!(buf, data); + } + + // Check `u16` copy + { + let data: [u16; 2] = [0xC0BE, 0xDEAD]; + let mut buf = [0; 2]; + unsafe { copy(p.DMA_CH1, &data, &mut buf).await }; + assert_eq!(buf, data); + } + + // Check `u32` copy + { + let data: [u32; 2] = [0xC0BEDEAD, 0xDEADAAFF]; + let mut buf = [0; 2]; + unsafe { copy(p.DMA_CH2, &data, &mut buf).await }; + assert_eq!(buf, data); + } + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs new file mode 100644 index 000000000..92f61464e --- /dev/null +++ b/tests/rp/src/bin/uart.rs @@ -0,0 +1,32 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_rp::uart::{Config, Uart}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); + + let config = Config::default(); + let mut uart = Uart::new_blocking(uart, tx, rx, 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. + + let data = [0xC0, 0xDE]; + uart.blocking_write(&data).unwrap(); + + let mut buf = [0; 2]; + uart.blocking_read(&mut buf).unwrap(); + assert_eq!(buf, data); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs new file mode 100644 index 000000000..963c22707 --- /dev/null +++ b/tests/rp/src/bin/uart_dma.rs @@ -0,0 +1,32 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_rp::uart::{Config, Uart}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); + + let config = Config::default(); + let mut uart = Uart::new(uart, tx, rx, p.DMA_CH0, p.DMA_CH1, 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. + + let data = [0xC0, 0xDE]; + uart.write(&data).await.unwrap(); + + let mut buf = [0; 2]; + uart.read(&mut buf).await.unwrap(); + assert_eq!(buf, data); + + info!("Test OK"); + cortex_m::asm::bkpt(); +}