Add Uart trait, implement it for nrf.

This commit is contained in:
Dario Nieuwenhuis 2021-01-02 19:59:37 +01:00
parent 1d53985abe
commit 0ab88ea279
4 changed files with 73 additions and 49 deletions

View File

@ -10,6 +10,7 @@ use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy::uart::Uart;
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::{interrupt, pac, rtc, uarte}; use embassy_nrf::{interrupt, pac, rtc, uarte};
use futures::future::{select, Either}; use futures::future::{select, Either};
@ -24,7 +25,7 @@ async fn run(mut uart: uarte::Uarte<pac::UARTE0>) {
let mut buf = [0; 8]; let mut buf = [0; 8];
buf.copy_from_slice(b"Hello!\r\n"); buf.copy_from_slice(b"Hello!\r\n");
uart.send(&buf).await; unwrap!(uart.send(&buf).await);
info!("wrote hello in uart!"); info!("wrote hello in uart!");
loop { loop {
@ -54,7 +55,7 @@ async fn run(mut uart: uarte::Uarte<pac::UARTE0>) {
info!("read done, got {:[u8]}", received); info!("read done, got {:[u8]}", received);
// Echo back received data // Echo back received data
uart.send(received).await; unwrap!(uart.send(received).await);
} }
} }
} }

View File

@ -139,51 +139,10 @@ where
self.instance.enable.write(|w| w.enable().enabled()); self.instance.enable.write(|w| w.enable().enabled());
} }
/// Sends serial data.
///
/// `tx_buffer` is marked as static as per `embedded-dma` requirements.
/// It it safe to use a buffer with a non static lifetime if memory is not
/// reused until the future has finished.
pub fn send<'a>(&'a mut self, tx_buffer: &'a [u8]) -> SendFuture<'a, T> {
// Panic if TX is running which can happen if the user has called
// `mem::forget()` on a previous future after polling it once.
assert!(!self.tx_started());
self.enable();
SendFuture {
uarte: self,
buf: tx_buffer,
}
}
fn tx_started(&self) -> bool { fn tx_started(&self) -> bool {
self.instance.events_txstarted.read().bits() != 0 self.instance.events_txstarted.read().bits() != 0
} }
/// Receives serial data.
///
/// The future is pending until the buffer is completely filled.
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
/// unfinished transfers after a timeout to prevent lockup when no more data
/// is incoming.
///
/// `rx_buffer` is marked as static as per `embedded-dma` requirements.
/// It it safe to use a buffer with a non static lifetime if memory is not
/// reused until the future has finished.
pub fn receive<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> ReceiveFuture<'a, T> {
// Panic if RX is running which can happen if the user has called
// `mem::forget()` on a previous future after polling it once.
assert!(!self.rx_started());
self.enable();
ReceiveFuture {
uarte: self,
buf: rx_buffer,
}
}
fn rx_started(&self) -> bool { fn rx_started(&self) -> bool {
self.instance.events_rxstarted.read().bits() != 0 self.instance.events_rxstarted.read().bits() != 0
} }
@ -231,6 +190,52 @@ where
} }
} }
impl<T: Instance> embassy::uart::Uart for Uarte<T> {
type ReceiveFuture<'a> = ReceiveFuture<'a, T>;
type SendFuture<'a> = SendFuture<'a, T>;
/// Sends serial data.
///
/// `tx_buffer` is marked as static as per `embedded-dma` requirements.
/// It it safe to use a buffer with a non static lifetime if memory is not
/// reused until the future has finished.
fn send<'a>(&'a mut self, tx_buffer: &'a [u8]) -> SendFuture<'a, T> {
// Panic if TX is running which can happen if the user has called
// `mem::forget()` on a previous future after polling it once.
assert!(!self.tx_started());
self.enable();
SendFuture {
uarte: self,
buf: tx_buffer,
}
}
/// Receives serial data.
///
/// The future is pending until the buffer is completely filled.
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
/// unfinished transfers after a timeout to prevent lockup when no more data
/// is incoming.
///
/// `rx_buffer` is marked as static as per `embedded-dma` requirements.
/// It it safe to use a buffer with a non static lifetime if memory is not
/// reused until the future has finished.
fn receive<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> ReceiveFuture<'a, T> {
// Panic if RX is running which can happen if the user has called
// `mem::forget()` on a previous future after polling it once.
assert!(!self.rx_started());
self.enable();
ReceiveFuture {
uarte: self,
buf: rx_buffer,
}
}
}
/// Future for the [`Uarte::send()`] method. /// Future for the [`Uarte::send()`] method.
pub struct SendFuture<'a, T> pub struct SendFuture<'a, T>
where where
@ -263,9 +268,9 @@ impl<'a, T> Future for SendFuture<'a, T>
where where
T: Instance, T: Instance,
{ {
type Output = (); type Output = Result<(), embassy::uart::Error>;
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
if !uarte.tx_started() { if !uarte.tx_started() {
@ -289,7 +294,7 @@ where
uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); uarte.tasks_starttx.write(|w| unsafe { w.bits(1) });
} }
T::state().tx_done.poll_wait(cx) T::state().tx_done.poll_wait(cx).map(|()| Ok(()))
} }
} }
@ -324,7 +329,7 @@ impl<'a, T> Future for ReceiveFuture<'a, T>
where where
T: Instance, T: Instance,
{ {
type Output = (); type Output = Result<(), embassy::uart::Error>;
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
@ -349,7 +354,7 @@ where
uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); uarte.tasks_startrx.write(|w| unsafe { w.bits(1) });
} }
T::state().rx_done.poll_wait(cx).map(|_| ()) T::state().rx_done.poll_wait(cx).map(|_| Ok(()))
} }
} }
@ -370,7 +375,9 @@ mod private {
pub trait Sealed {} pub trait Sealed {}
} }
pub trait Instance: Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed { pub trait Instance:
Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed + 'static
{
type Interrupt: OwnedInterrupt; type Interrupt: OwnedInterrupt;
#[doc(hidden)] #[doc(hidden)]

View File

@ -12,4 +12,5 @@ pub mod interrupt;
pub mod io; pub mod io;
pub mod rand; pub mod rand;
pub mod time; pub mod time;
pub mod uart;
pub mod util; pub mod util;

15
embassy/src/uart.rs Normal file
View File

@ -0,0 +1,15 @@
use core::future::Future;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
Other,
}
pub trait Uart {
type ReceiveFuture<'a>: Future<Output = Result<(), Error>>;
type SendFuture<'a>: Future<Output = Result<(), Error>>;
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>;
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
}