Merge #913
913: (embassy-rp): Add DMA implementation r=Dirbaio a=MathiasKoch This PR adds everything necessary to do peripheral to memory DMA & memory to memory DMA operations. It also adds async UART read & write, powered by DMA Co-authored-by: Mathias <mk@blackbird.online>
This commit is contained in:
commit
24ab21a7dd
7 changed files with 536 additions and 109 deletions
|
@ -1,82 +1,265 @@
|
||||||
|
use core::pin::Pin;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
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::dma::vals;
|
||||||
use crate::{pac, peripherals};
|
use crate::{interrupt, pac, peripherals};
|
||||||
|
|
||||||
pub struct Dma<T: Channel> {
|
#[interrupt]
|
||||||
_inner: T,
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Channel> Dma<T> {
|
if ints0 & (1 << channel) == (1 << channel) {
|
||||||
pub fn copy(inner: T, from: &[u32], to: &mut [u32]) {
|
CHANNEL_WAKERS[channel].wake();
|
||||||
assert!(from.len() == to.len());
|
}
|
||||||
|
}
|
||||||
|
pac::DMA.ints0().write(|w| w.set_ints0(ints0));
|
||||||
|
}
|
||||||
|
|
||||||
|
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<P = C> + '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<P = C> + '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<P = C> + '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<P = C> + '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 {
|
unsafe {
|
||||||
let p = inner.regs();
|
let p = ch.regs();
|
||||||
|
|
||||||
p.read_addr().write_value(from.as_ptr() as u32);
|
p.read_addr().write_value(from as u32);
|
||||||
p.write_addr().write_value(to.as_mut_ptr() as u32);
|
p.write_addr().write_value(to as u32);
|
||||||
p.trans_count().write_value(from.len() as u32);
|
p.trans_count().write_value(len as u32);
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
p.ctrl_trig().write(|w| {
|
p.ctrl_trig().write(|w| {
|
||||||
w.set_data_size(vals::DataSize::SIZE_WORD);
|
// TODO: Add all DREQ options to pac vals::TreqSel, and use
|
||||||
w.set_incr_read(true);
|
// `set_treq:sel`
|
||||||
w.set_incr_write(true);
|
w.0 = ((dreq as u32) & 0x3f) << 15usize;
|
||||||
w.set_chain_to(inner.number());
|
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);
|
w.set_en(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
while p.ctrl_trig().read().busy() {}
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
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<P = C> + 'a) -> Self {
|
||||||
|
into_ref!(channel);
|
||||||
|
|
||||||
|
Self { channel }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NoDma;
|
impl<'a, C: Channel> Drop for Transfer<'a, C> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let p = self.channel.regs();
|
||||||
|
unsafe {
|
||||||
|
pac::DMA
|
||||||
|
.chan_abort()
|
||||||
|
.modify(|m| m.set_chan_abort(1 << self.channel.number()));
|
||||||
|
while p.ctrl_trig().read().busy() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_peripheral!(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<Self::Output> {
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
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 {
|
mod sealed {
|
||||||
use super::*;
|
pub trait Channel {}
|
||||||
|
|
||||||
pub trait Channel {
|
pub trait Word {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static {
|
||||||
fn number(&self) -> u8;
|
fn number(&self) -> u8;
|
||||||
|
|
||||||
fn regs(&self) -> pac::dma::Channel {
|
fn regs(&self) -> pac::dma::Channel {
|
||||||
pac::DMA.ch(self.number() as _)
|
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 {
|
pub struct AnyChannel {
|
||||||
number: u8,
|
number: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for AnyChannel {}
|
impl_peripheral!(AnyChannel);
|
||||||
impl sealed::Channel for AnyChannel {
|
|
||||||
|
impl sealed::Channel for AnyChannel {}
|
||||||
|
impl Channel for AnyChannel {
|
||||||
fn number(&self) -> u8 {
|
fn number(&self) -> u8 {
|
||||||
self.number
|
self.number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! channel {
|
macro_rules! channel {
|
||||||
($type:ident, $num:expr) => {
|
($name:ident, $num:expr) => {
|
||||||
impl Channel for peripherals::$type {}
|
impl sealed::Channel for peripherals::$name {}
|
||||||
impl sealed::Channel for peripherals::$type {
|
impl Channel for peripherals::$name {
|
||||||
fn number(&self) -> u8 {
|
fn number(&self) -> u8 {
|
||||||
$num
|
$num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<peripherals::$name> 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<T>(slice: *const [T]) -> (usize, usize) {
|
||||||
|
unsafe { core::mem::transmute(slice) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
|
||||||
|
unsafe { core::mem::transmute(slice) }
|
||||||
|
}
|
||||||
|
|
||||||
channel!(DMA_CH0, 0);
|
channel!(DMA_CH0, 0);
|
||||||
channel!(DMA_CH1, 1);
|
channel!(DMA_CH1, 1);
|
||||||
channel!(DMA_CH2, 2);
|
channel!(DMA_CH2, 2);
|
||||||
|
|
|
@ -105,6 +105,7 @@ pub fn init(_config: config::Config) -> Peripherals {
|
||||||
unsafe {
|
unsafe {
|
||||||
clocks::init();
|
clocks::init();
|
||||||
timer::init();
|
timer::init();
|
||||||
|
dma::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
peripherals
|
peripherals
|
||||||
|
|
|
@ -2,6 +2,7 @@ use core::marker::PhantomData;
|
||||||
|
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
|
use crate::dma::{AnyChannel, Channel};
|
||||||
use crate::gpio::sealed::Pin;
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::gpio::AnyPin;
|
use crate::gpio::AnyPin;
|
||||||
use crate::{pac, peripherals, Peripheral};
|
use crate::{pac, peripherals, Peripheral};
|
||||||
|
@ -76,26 +77,27 @@ pub enum Error {
|
||||||
Framing,
|
Framing,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Uart<'d, T: Instance> {
|
pub struct Uart<'d, T: Instance, M: Mode> {
|
||||||
tx: UartTx<'d, T>,
|
tx: UartTx<'d, T, M>,
|
||||||
rx: UartRx<'d, T>,
|
rx: UartRx<'d, T, M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UartTx<'d, T: Instance> {
|
pub struct UartTx<'d, T: Instance, M: Mode> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||||
|
phantom: PhantomData<(&'d mut T, M)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UartRx<'d, T: Instance> {
|
pub struct UartRx<'d, T: Instance, M: Mode> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||||
|
phantom: PhantomData<(&'d mut T, M)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UartTx<'d, T> {
|
impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||||
fn new() -> Self {
|
fn new(tx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
||||||
Self { phantom: PhantomData }
|
Self {
|
||||||
|
tx_dma,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn write(&mut self, _buffer: &[u8]) -> Result<(), Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
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> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe { while r.uartfr().read().txff() {} }
|
unsafe { while !r.uartfr().read().txfe() {} }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UartRx<'d, T> {
|
impl<'d, T: Instance> UartTx<'d, T, Async> {
|
||||||
fn new() -> Self {
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
Self { phantom: PhantomData }
|
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> {
|
impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
||||||
todo!();
|
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> {
|
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
|
@ -130,6 +147,10 @@ impl<'d, T: Instance> UartRx<'d, T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
for b in buffer {
|
for b in buffer {
|
||||||
*b = loop {
|
*b = loop {
|
||||||
|
if r.uartfr().read().rxfe() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let dr = r.uartdr().read();
|
let dr = r.uartdr().read();
|
||||||
|
|
||||||
if dr.oe() {
|
if dr.oe() {
|
||||||
|
@ -140,7 +161,7 @@ impl<'d, T: Instance> UartRx<'d, T> {
|
||||||
return Err(Error::Parity);
|
return Err(Error::Parity);
|
||||||
} else if dr.fe() {
|
} else if dr.fe() {
|
||||||
return Err(Error::Framing);
|
return Err(Error::Framing);
|
||||||
} else if dr.fe() {
|
} else {
|
||||||
break dr.data();
|
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
|
/// Create a new UART without hardware flow control
|
||||||
pub fn new(
|
pub fn new_blocking(
|
||||||
uart: impl Peripheral<P = T> + 'd,
|
uart: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(tx, rx);
|
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)
|
/// 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,
|
uart: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<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,
|
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||||
|
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(tx, rx, cts, rts);
|
into_ref!(tx, rx, cts, rts);
|
||||||
|
@ -176,18 +213,72 @@ impl<'d, T: Instance> Uart<'d, T> {
|
||||||
uart,
|
uart,
|
||||||
rx.map_into(),
|
rx.map_into(),
|
||||||
tx.map_into(),
|
tx.map_into(),
|
||||||
Some(cts.map_into()),
|
|
||||||
Some(rts.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,
|
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(
|
fn new_inner(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
tx: PeripheralRef<'d, AnyPin>,
|
tx: PeripheralRef<'d, AnyPin>,
|
||||||
rx: PeripheralRef<'d, AnyPin>,
|
rx: PeripheralRef<'d, AnyPin>,
|
||||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
|
||||||
rts: 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,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(_uart);
|
into_ref!(_uart);
|
||||||
|
@ -195,6 +286,30 @@ impl<'d, T: Instance> Uart<'d, T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let r = T::regs();
|
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 clk_base = crate::clocks::clk_peri_freq();
|
||||||
|
|
||||||
let baud_rate_div = (8 * clk_base) / config.baudrate;
|
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 {
|
let (pen, eps) = match config.parity {
|
||||||
Parity::ParityNone => (false, false),
|
Parity::ParityNone => (false, false),
|
||||||
Parity::ParityEven => (true, true),
|
|
||||||
Parity::ParityOdd => (true, false),
|
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| {
|
r.uartlcr_h().write(|w| {
|
||||||
w.set_wlen(config.data_bits.bits());
|
w.set_wlen(config.data_bits.bits());
|
||||||
w.set_stp2(config.stop_bits == StopBits::STOP2);
|
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_ctsen(cts.is_some());
|
||||||
w.set_rtsen(rts.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 {
|
Self {
|
||||||
tx: UartTx::new(),
|
tx: UartTx::new(tx_dma),
|
||||||
rx: UartRx::new(),
|
rx: UartRx::new(rx_dma),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||||
self.tx.write(buffer).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.tx.blocking_write(buffer)
|
self.tx.blocking_write(buffer)
|
||||||
}
|
}
|
||||||
|
@ -263,30 +371,39 @@ impl<'d, T: Instance> Uart<'d, T> {
|
||||||
self.tx.blocking_flush()
|
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> {
|
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
self.rx.blocking_read(buffer)
|
self.rx.blocking_read(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split the Uart into a transmitter and receiver, which is
|
/// Split the Uart into a transmitter and receiver, which is particuarly
|
||||||
/// particuarly useful when having two tasks correlating to
|
/// useful when having two tasks correlating to transmitting and receiving.
|
||||||
/// transmitting and receiving.
|
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
|
||||||
pub fn split(self) -> (UartTx<'d, T>, UartRx<'d, T>) {
|
|
||||||
(self.tx, self.rx)
|
(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 {
|
mod eh02 {
|
||||||
use super::*;
|
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;
|
type Error = Error;
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if r.uartfr().read().rxfe() {
|
||||||
|
return Err(nb::Error::WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
let dr = r.uartdr().read();
|
let dr = r.uartdr().read();
|
||||||
|
|
||||||
if dr.oe() {
|
if dr.oe() {
|
||||||
|
@ -297,16 +414,14 @@ mod eh02 {
|
||||||
Err(nb::Error::Other(Error::Parity))
|
Err(nb::Error::Other(Error::Parity))
|
||||||
} else if dr.fe() {
|
} else if dr.fe() {
|
||||||
Err(nb::Error::Other(Error::Framing))
|
Err(nb::Error::Other(Error::Framing))
|
||||||
} else if dr.fe() {
|
|
||||||
Ok(dr.data())
|
|
||||||
} else {
|
} else {
|
||||||
Err(nb::Error::WouldBlock)
|
Ok(dr.data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
type Error = Error;
|
||||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.blocking_write(buffer)
|
self.blocking_write(buffer)
|
||||||
|
@ -316,14 +431,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;
|
type Error = Error;
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
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;
|
type Error = Error;
|
||||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.blocking_write(buffer)
|
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;
|
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;
|
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;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,7 +481,7 @@ cfg_if::cfg_if! {
|
||||||
if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] {
|
if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] {
|
||||||
use core::future::Future;
|
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<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
||||||
|
|
||||||
|
@ -419,7 +534,12 @@ cfg_if::cfg_if! {
|
||||||
mod sealed {
|
mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub trait Mode {}
|
||||||
|
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
|
const TX_DREQ: u8;
|
||||||
|
const RX_DREQ: u8;
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart;
|
fn regs() -> pac::uart::Uart;
|
||||||
}
|
}
|
||||||
pub trait TxPin<T: Instance> {}
|
pub trait TxPin<T: Instance> {}
|
||||||
|
@ -428,11 +548,29 @@ mod sealed {
|
||||||
pub trait RtsPin<T: Instance> {}
|
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 {}
|
pub trait Instance: sealed::Instance {}
|
||||||
|
|
||||||
macro_rules! impl_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 {
|
impl sealed::Instance for peripherals::$inst {
|
||||||
|
const TX_DREQ: u8 = $tx_dreq;
|
||||||
|
const RX_DREQ: u8 = $rx_dreq;
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart {
|
fn regs() -> pac::uart::Uart {
|
||||||
pac::$inst
|
pac::$inst
|
||||||
}
|
}
|
||||||
|
@ -441,8 +579,8 @@ macro_rules! impl_instance {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_instance!(UART0, UART0);
|
impl_instance!(UART0, UART0, 20, 21);
|
||||||
impl_instance!(UART1, UART1);
|
impl_instance!(UART1, UART1, 22, 23);
|
||||||
|
|
||||||
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
|
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
|
||||||
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
|
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use {defmt_rtt as _, panic_probe as _};
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
let config = uart::Config::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();
|
uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
41
tests/rp/src/bin/dma_copy_async.rs
Normal file
41
tests/rp/src/bin/dma_copy_async.rs
Normal file
|
@ -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();
|
||||||
|
}
|
32
tests/rp/src/bin/uart.rs
Normal file
32
tests/rp/src/bin/uart.rs
Normal file
|
@ -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();
|
||||||
|
}
|
32
tests/rp/src/bin/uart_dma.rs
Normal file
32
tests/rp/src/bin/uart_dma.rs
Normal file
|
@ -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();
|
||||||
|
}
|
Loading…
Reference in a new issue