diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 42c4fd13e..dfa047a2f 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -1,39 +1,71 @@ +use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::{Context, Poll}; -use embassy_hal_common::impl_peripheral; +use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; +use futures::Future; use crate::pac::dma::vals; use crate::{pac, peripherals}; -pub struct Dma { - _inner: T, +pub fn copy<'a, C: Channel, W: Word>(ch: impl Peripheral

+ 'a, from: &[W], to: &mut [W]) -> Transfer<'a, C> { + assert!(from.len() == to.len()); + + into_ref!(ch); + + unsafe { + let p = ch.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(W::size()); + w.set_incr_read(true); + w.set_incr_write(true); + w.set_chain_to(ch.number()); + w.set_en(true); + }); + + // FIXME: + while p.ctrl_trig().read().busy() {} + + compiler_fence(Ordering::SeqCst); + } + Transfer::new(ch) } -impl Dma { - pub fn copy(inner: T, from: &[u32], to: &mut [u32]) { - assert!(from.len() == to.len()); +pub(crate) struct Transfer<'a, C: Channel> { + channel: PeripheralRef<'a, C>, +} - unsafe { - let p = inner.regs(); +impl<'a, C: Channel> Transfer<'a, C> { + pub(crate) fn new(channel: impl Peripheral

+ 'a) -> Self { + into_ref!(channel); + Self { channel } + } +} - 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); +impl<'a, C: Channel> Drop for Transfer<'a, C> { + fn drop(&mut self) { + // self.channel.request_stop(); + // while self.channel.is_running() {} + } +} - 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); - }); - - while p.ctrl_trig().read().busy() {} - - compiler_fence(Ordering::SeqCst); - } +impl<'a, C: Channel> Unpin for Transfer<'a, C> {} +impl<'a, C: Channel> Future for Transfer<'a, C> { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // self.channel.set_waker(cx.waker()); + // if self.channel.is_running() { + // Poll::Pending + // } else { + Poll::Ready(()) + // } } } @@ -42,38 +74,77 @@ pub struct NoDma; impl_peripheral!(NoDma); 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) + } + } }; } diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart.rs index 6c5ab3515..c1596960f 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> { @@ -116,13 +118,29 @@ impl<'d, T: Instance> UartTx<'d, T> { } } -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> { + if let Some(ch) = &mut self.tx_dma { + 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. + let transfer = crate::dma::copy(ch, buffer, unsafe { T::regs().uartdr().ptr() }); + 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> { @@ -150,25 +168,42 @@ 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> { + if let Some(ch) = &mut self.rx_dma { + 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. + let transfer = crate::dma::copy(ch, unsafe { T::regs().uartdr().ptr() }, buffer); + 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 +211,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); @@ -246,15 +335,13 @@ impl<'d, T: Instance> Uart<'d, T> { } 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,26 +350,31 @@ 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(); @@ -306,7 +398,7 @@ mod eh02 { } } - 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 +408,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) @@ -419,6 +511,8 @@ cfg_if::cfg_if! { mod sealed { use super::*; + pub trait Mode {} + pub trait Instance { fn regs() -> pac::uart::Uart; } @@ -428,6 +522,21 @@ 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 {