summaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorMathias <mk@blackbird.online>2022-08-18 19:39:13 +0200
committerMathias <mk@blackbird.online>2022-08-18 19:39:13 +0200
commitd35a1c9790e32477aac2fd6abe38a8c76263fcc8 (patch)
tree8889211d1d33bf75083e7863fc48b4d7bd1b6982 /embassy-rp
parent0f74f870b00942a3020a32d44470edf80870676c (diff)
downloadembassy-d35a1c9790e32477aac2fd6abe38a8c76263fcc8.zip
Preliminary DMA support for RP2040
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/dma.rs139
-rw-r--r--embassy-rp/src/uart.rs195
2 files changed, 257 insertions, 77 deletions
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 42c4fd13..dfa047a2 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<T: Channel> {
- _inner: T,
-}
+pub fn copy<'a, C: Channel, W: Word>(ch: impl Peripheral<P = C> + 'a, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
+ assert!(from.len() == to.len());
-impl<T: Channel> Dma<T> {
- pub fn copy(inner: T, from: &[u32], to: &mut [u32]) {
- assert!(from.len() == to.len());
+ into_ref!(ch);
- unsafe {
- let p = inner.regs();
+ 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);
+ 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);
+ 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);
- });
+ 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);
+ });
- while p.ctrl_trig().read().busy() {}
+ // FIXME:
+ while p.ctrl_trig().read().busy() {}
- compiler_fence(Ordering::SeqCst);
- }
+ compiler_fence(Ordering::SeqCst);
+ }
+ Transfer::new(ch)
+}
+
+pub(crate) struct Transfer<'a, C: Channel> {
+ channel: PeripheralRef<'a, C>,
+}
+
+impl<'a, C: Channel> Transfer<'a, C> {
+ pub(crate) fn new(channel: impl Peripheral<P = C> + 'a) -> Self {
+ into_ref!(channel);
+ Self { channel }
+ }
+}
+
+impl<'a, C: Channel> Drop for Transfer<'a, C> {
+ fn drop(&mut self) {
+ // self.channel.request_stop();
+ // while self.channel.is_running() {}
+ }
+}
+
+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::Output> {
+ // 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 Word {}
+}
- pub trait Channel {
- fn number(&self) -> u8;
+pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static {
+ fn number(&self) -> u8;
- fn regs(&self) -> pac::dma::Channel {
- pac::DMA.ch(self.number() as _)
+ 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<peripherals::$name> 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 6c5ab351..c1596960 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<PeripheralRef<'d, AnyChannel>>,
+ 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<PeripheralRef<'d, AnyChannel>>,
+ 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<PeripheralRef<'d, AnyChannel>>) -> 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<PeripheralRef<'d, AnyChannel>>) -> 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<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + '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<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
- cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
+ cts: impl Peripheral<P = impl CtsPin<T>> + '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(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<P = T> + 'd,
+ tx: impl Peripheral<P = impl TxPin<T>> + 'd,
+ rx: impl Peripheral<P = impl RxPin<T>> + 'd,
+ tx_dma: impl Peripheral<P = impl Channel> + 'd,
+ rx_dma: impl Peripheral<P = impl Channel> + '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<P = T> + 'd,
+ tx: impl Peripheral<P = impl TxPin<T>> + 'd,
+ rx: impl Peripheral<P = impl RxPin<T>> + 'd,
+ rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
+ cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
+ tx_dma: impl Peripheral<P = impl Channel> + 'd,
+ rx_dma: impl Peripheral<P = impl Channel> + '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<P = T> + 'd,
tx: PeripheralRef<'d, AnyPin>,
rx: PeripheralRef<'d, AnyPin>,
- cts: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
+ cts: Option<PeripheralRef<'d, AnyPin>>,
+ tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
+ rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
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<u8> for UartRx<'d, T> {
+ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs();
@@ -306,7 +398,7 @@ mod eh02 {
}
}
- impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T> {
+ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> 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<u8> for Uart<'d, T> {
+ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
embedded_hal_02::serial::Read::read(&mut self.rx)
}
}
- impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T> {
+ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> 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<T: Instance> {}
}
+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 {