From 9611e7c9f2609271af2ead7e91e6ee918d3dadd3 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 26 Aug 2022 09:05:12 +0200 Subject: [PATCH 01/16] Add BufferedUart implementation, and feature-guard time-driver initialization, to free up TIMER peripheral if not used with embassy executor --- embassy-rp/Cargo.toml | 45 ++-- embassy-rp/src/lib.rs | 2 + embassy-rp/src/uart/buffered.rs | 286 ++++++++++++++++++++++++ embassy-rp/src/{uart.rs => uart/mod.rs} | 84 ++++++- 4 files changed, 401 insertions(+), 16 deletions(-) create mode 100644 embassy-rp/src/uart/buffered.rs rename embassy-rp/src/{uart.rs => uart/mod.rs} (87%) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index ccb2f652..92780ee3 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -7,9 +7,7 @@ edition = "2021" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/" features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] -flavors = [ - { name = "rp2040", target = "thumbv6m-none-eabi" }, -] +flavors = [{ name = "rp2040", target = "thumbv6m-none-eabi" }] [features] defmt = ["dep:defmt", "embassy-usb?/defmt"] @@ -20,8 +18,16 @@ defmt = ["dep:defmt", "embassy-usb?/defmt"] # There are no plans to make this stable. unstable-pac = [] +time-driver = [] + # Enable nightly-only features -nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"] +nightly = [ + "embassy-executor/nightly", + "embedded-hal-1", + "embedded-hal-async", + "embassy-embedded-hal/nightly", + "dep:embassy-usb", +] # Implement embedded-hal 1.0 alpha traits. # Implement embedded-hal-async traits if `nightly` is set as well. @@ -30,11 +36,15 @@ unstable-traits = ["embedded-hal-1"] [dependencies] embassy-sync = { version = "0.1.0", path = "../embassy-sync" } embassy-executor = { version = "0.1.0", path = "../embassy-executor" } -embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } -embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} -embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } -embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } -embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } +embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ + "tick-hz-1_000_000", +] } +embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = [ + "prio-bits-2", +] } +embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } +embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-usb = { version = "0.1.0", path = "../embassy-usb", optional = true } atomic-polyfill = "1.0.1" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } @@ -43,11 +53,18 @@ cfg-if = "1.0.0" cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" critical-section = "1.1" -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +futures = { version = "0.3.17", default-features = false, features = [ + "async-await", +] } +embedded-io = { version = "0.3.0", features = ["async"], optional = true } -rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } +rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev = "017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = [ + "rt", +] } #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } -embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } -embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} -embedded-hal-async = { version = "0.1.0-alpha.1", optional = true} +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ + "unproven", +] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true } +embedded-hal-async = { version = "0.1.0-alpha.1", optional = true } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index aebbbf56..8dcefece 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -8,6 +8,7 @@ pub mod dma; pub mod gpio; pub mod interrupt; pub mod spi; +#[cfg(feature = "time-driver")] pub mod timer; pub mod uart; #[cfg(feature = "nightly")] @@ -108,6 +109,7 @@ pub fn init(_config: config::Config) -> Peripherals { unsafe { clocks::init(); + #[cfg(feature = "time-driver")] timer::init(); dma::init(); } diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs new file mode 100644 index 00000000..c31af801 --- /dev/null +++ b/embassy-rp/src/uart/buffered.rs @@ -0,0 +1,286 @@ +use core::future::Future; +use core::task::Poll; + +use atomic_polyfill::{compiler_fence, Ordering}; +use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; +use embassy_hal_common::ring_buffer::RingBuffer; +use embassy_sync::waitqueue::WakerRegistration; +use futures::future::poll_fn; + +use super::*; + +pub struct State<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> State<'d, T> { + pub fn new() -> Self { + Self(StateStorage::new()) + } +} + +struct StateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + rx_waker: WakerRegistration, + rx: RingBuffer<'d>, + + tx_waker: WakerRegistration, + tx: RingBuffer<'d>, +} + +unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} + +pub struct BufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, StateInner<'d, T>>, +} + +impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} + +impl<'d, T: Instance> BufferedUart<'d, T> { + pub fn new( + state: &'d mut State<'d, T>, + _uart: Uart<'d, T, M>, + irq: impl Peripheral

+ 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + ) -> BufferedUart<'d, T> { + into_ref!(irq); + + let r = T::regs(); + unsafe { + r.uartimsc().modify(|w| { + // TODO: Should and more or fewer interrupts be enabled? + w.set_rxim(true); + w.set_rtim(true); + }); + } + + Self { + inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { + phantom: PhantomData, + tx: RingBuffer::new(tx_buffer), + tx_waker: WakerRegistration::new(), + + rx: RingBuffer::new(rx_buffer), + rx_waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> StateInner<'d, T> +where + Self: 'd, +{ + fn on_rx(&mut self) { + let r = T::regs(); + unsafe { + let ris = r.uartris().read(); + // Clear interrupt flags + r.uarticr().write(|w| { + w.set_rxic(true); + w.set_rtic(true); + }); + + if ris.rxris() { + if ris.peris() { + warn!("Parity error"); + } + if ris.feris() { + warn!("Framing error"); + } + if ris.beris() { + warn!("Break error"); + } + if ris.oeris() { + warn!("Overrun error"); + } + + let buf = self.rx.push_buf(); + if !buf.is_empty() { + buf[0] = r.uartdr().read().data(); + self.rx.push(1); + } else { + warn!("RX buffer full, discard received byte"); + } + + if self.rx.is_full() { + self.rx_waker.wake(); + } + } + + if ris.rtris() { + self.rx_waker.wake(); + }; + } + } + + fn on_tx(&mut self) { + let r = T::regs(); + unsafe { + let ris = r.uartris().read(); + // Clear interrupt flags + r.uarticr().write(|w| { + w.set_rtic(true); + }); + + if ris.txris() { + let buf = self.tx.pop_buf(); + if !buf.is_empty() { + r.uartimsc().modify(|w| { + w.set_txim(true); + }); + r.uartdr().write(|w| w.set_data(buf[0].into())); + self.tx.pop(1); + self.tx_waker.wake(); + } else { + // Disable interrupt until we have something to transmit again + r.uartimsc().modify(|w| { + w.set_txim(false); + }); + } + } + } + } +} + +impl<'d, T: Instance> PeripheralState for StateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { + self.on_rx(); + self.on_tx(); + } +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { + type Error = Error; +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + let mut do_pend = false; + let res = self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let data = state.rx.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if state.rx.is_full() { + do_pend = true; + } + state.rx.pop(len); + + return Poll::Ready(Ok(len)); + } + + state.rx_waker.register(cx.waker()); + Poll::Pending + }); + + if do_pend { + self.inner.pend(); + } + + res + }) + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { + type FillBufFuture<'a> = impl Future> + where + Self: 'a; + + fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let buf = state.rx.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + state.rx_waker.register(cx.waker()); + Poll::>::Pending + }) + }) + } + + fn consume(&mut self, amt: usize) { + let signal = self.inner.with(|state| { + let full = state.rx.is_full(); + state.rx.pop(amt); + full + }); + if signal { + self.inner.pend(); + } + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { + type WriteFuture<'a> = impl Future> + where + Self: 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + let (poll, empty) = self.inner.with(|state| { + let empty = state.tx.is_empty(); + let tx_buf = state.tx.push_buf(); + if tx_buf.is_empty() { + state.tx_waker.register(cx.waker()); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.tx.push(n); + + (Poll::Ready(Ok(n)), empty) + }); + if empty { + self.inner.pend(); + } + poll + }) + } + + type FlushFuture<'a> = impl Future> + where + Self: 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + if !state.tx.is_empty() { + state.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + }) + } +} diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs similarity index 87% rename from embassy-rp/src/uart.rs rename to embassy-rp/src/uart/mod.rs index 987b716b..3b71d87b 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart/mod.rs @@ -475,6 +475,76 @@ mod eh1 { impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { type Error = Error; } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> { + fn read(&mut self) -> nb::Result { + let r = T::regs(); + unsafe { + let dr = r.uartdr().read(); + + if dr.oe() { + Err(nb::Error::Other(Error::Overrun)) + } else if dr.be() { + Err(nb::Error::Other(Error::Break)) + } else if dr.pe() { + 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) + } + } + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> { + fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { + self.blocking_write(&[char]).map_err(nb::Error::Other) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.blocking_flush().map_err(nb::Error::Other) + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> { + fn read(&mut self) -> Result> { + embedded_hal_02::serial::Read::read(&mut self.rx) + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> { + fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { + self.blocking_write(&[char]).map_err(nb::Error::Other) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.blocking_flush().map_err(nb::Error::Other) + } + } + } #[cfg(all( @@ -532,6 +602,12 @@ mod eha { } } +#[cfg(feature = "nightly")] +mod buffered; +#[cfg(feature = "nightly")] +pub use buffered::*; + + mod sealed { use super::*; @@ -541,6 +617,8 @@ mod sealed { const TX_DREQ: u8; const RX_DREQ: u8; + type Interrupt: crate::interrupt::Interrupt; + fn regs() -> pac::uart::Uart; } pub trait TxPin {} @@ -571,6 +649,8 @@ macro_rules! impl_instance { impl sealed::Instance for peripherals::$inst { const TX_DREQ: u8 = $tx_dreq; const RX_DREQ: u8 = $rx_dreq; + + type Interrupt = crate::interrupt::$irq; fn regs() -> pac::uart::Uart { pac::$inst @@ -580,8 +660,8 @@ macro_rules! impl_instance { }; } -impl_instance!(UART0, UART0, 20, 21); -impl_instance!(UART1, UART1, 22, 23); +impl_instance!(UART0, UART0_IRQ, 20, 21); +impl_instance!(UART1, UART1_IRQ, 22, 23); pub trait TxPin: sealed::TxPin + crate::gpio::Pin {} pub trait RxPin: sealed::RxPin + crate::gpio::Pin {} From 31d85da78a06cdee6ec037d73b12537d3c906725 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Sep 2022 10:36:27 +0200 Subject: [PATCH 02/16] Add bufferedUart, including a split version for only Rx or Tx --- embassy-rp/src/uart/buffered.rs | 379 ++++++++++++++++++++++++++------ embassy-rp/src/uart/mod.rs | 2 +- 2 files changed, 315 insertions(+), 66 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index c31af801..3eb96e3d 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -9,31 +9,70 @@ use futures::future::poll_fn; use super::*; -pub struct State<'d, T: Instance>(StateStorage>); +pub struct State<'d, T: Instance>(StateStorage>); impl<'d, T: Instance> State<'d, T> { - pub fn new() -> Self { + pub const fn new() -> Self { Self(StateStorage::new()) } } -struct StateInner<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, - - rx_waker: WakerRegistration, - rx: RingBuffer<'d>, - - tx_waker: WakerRegistration, - tx: RingBuffer<'d>, +pub struct RxState<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> RxState<'d, T> { + pub const fn new() -> Self { + Self(StateStorage::new()) + } } -unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} -unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} +pub struct TxState<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> TxState<'d, T> { + pub const fn new() -> Self { + Self(StateStorage::new()) + } +} + +struct RxStateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + waker: WakerRegistration, + buf: RingBuffer<'d>, +} + +struct TxStateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + waker: WakerRegistration, + buf: RingBuffer<'d>, +} + +struct FullStateInner<'d, T: Instance> { + rx: RxStateInner<'d, T>, + tx: TxStateInner<'d, T>, +} + +unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {} + +unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {} + +unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {} pub struct BufferedUart<'d, T: Instance> { - inner: PeripheralMutex<'d, StateInner<'d, T>>, + inner: PeripheralMutex<'d, FullStateInner<'d, T>>, +} + +pub struct RxBufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, RxStateInner<'d, T>>, +} + +pub struct TxBufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, TxStateInner<'d, T>>, } impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} +impl<'d, T: Instance> Unpin for RxBufferedUart<'d, T> {} +impl<'d, T: Instance> Unpin for TxBufferedUart<'d, T> {} impl<'d, T: Instance> BufferedUart<'d, T> { pub fn new( @@ -55,66 +94,158 @@ impl<'d, T: Instance> BufferedUart<'d, T> { } Self { - inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { - phantom: PhantomData, - tx: RingBuffer::new(tx_buffer), - tx_waker: WakerRegistration::new(), - - rx: RingBuffer::new(rx_buffer), - rx_waker: WakerRegistration::new(), + inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner { + tx: TxStateInner { + phantom: PhantomData, + waker: WakerRegistration::new(), + buf: RingBuffer::new(tx_buffer), + }, + rx: RxStateInner { + phantom: PhantomData, + waker: WakerRegistration::new(), + buf: RingBuffer::new(rx_buffer), + }, }), } } } -impl<'d, T: Instance> StateInner<'d, T> +impl<'d, T: Instance> RxBufferedUart<'d, T> { + pub fn new( + state: &'d mut RxState<'d, T>, + _uart: UartRx<'d, T, M>, + irq: impl Peripheral

+ 'd, + rx_buffer: &'d mut [u8], + ) -> RxBufferedUart<'d, T> { + into_ref!(irq); + + let r = T::regs(); + unsafe { + r.uartimsc().modify(|w| { + // TODO: Should and more or fewer interrupts be enabled? + w.set_rxim(true); + w.set_rtim(true); + }); + } + + Self { + inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner { + phantom: PhantomData, + + buf: RingBuffer::new(rx_buffer), + waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> TxBufferedUart<'d, T> { + pub fn new( + state: &'d mut TxState<'d, T>, + _uart: UartTx<'d, T, M>, + irq: impl Peripheral

+ 'd, + tx_buffer: &'d mut [u8], + ) -> TxBufferedUart<'d, T> { + into_ref!(irq); + + let r = T::regs(); + unsafe { + r.uartimsc().modify(|w| { + // TODO: Should and more or fewer interrupts be enabled? + w.set_rxim(true); + w.set_rtim(true); + }); + } + + Self { + inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner { + phantom: PhantomData, + + buf: RingBuffer::new(tx_buffer), + waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T> where Self: 'd, { - fn on_rx(&mut self) { + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { + self.rx.on_interrupt(); + self.tx.on_interrupt(); + } +} + +impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { let r = T::regs(); unsafe { - let ris = r.uartris().read(); + let ris = r.uartmis().read(); // Clear interrupt flags - r.uarticr().write(|w| { + r.uarticr().modify(|w| { w.set_rxic(true); w.set_rtic(true); }); - if ris.rxris() { - if ris.peris() { + if ris.rxmis() { + if ris.pemis() { warn!("Parity error"); + r.uarticr().modify(|w| { + w.set_peic(true); + }); } - if ris.feris() { + if ris.femis() { warn!("Framing error"); + r.uarticr().modify(|w| { + w.set_feic(true); + }); } - if ris.beris() { + if ris.bemis() { warn!("Break error"); + r.uarticr().modify(|w| { + w.set_beic(true); + }); } - if ris.oeris() { + if ris.oemis() { warn!("Overrun error"); + r.uarticr().modify(|w| { + w.set_oeic(true); + }); } - let buf = self.rx.push_buf(); + let buf = self.buf.push_buf(); if !buf.is_empty() { buf[0] = r.uartdr().read().data(); - self.rx.push(1); + self.buf.push(1); } else { warn!("RX buffer full, discard received byte"); } - if self.rx.is_full() { - self.rx_waker.wake(); + if self.buf.is_full() { + self.waker.wake(); } } - if ris.rtris() { - self.rx_waker.wake(); + if ris.rtmis() { + self.waker.wake(); }; } } +} - fn on_tx(&mut self) { +impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { let r = T::regs(); unsafe { let ris = r.uartris().read(); @@ -124,14 +255,14 @@ where }); if ris.txris() { - let buf = self.tx.pop_buf(); + let buf = self.buf.pop_buf(); if !buf.is_empty() { r.uartimsc().modify(|w| { w.set_txim(true); }); r.uartdr().write(|w| w.set_data(buf[0].into())); - self.tx.pop(1); - self.tx_waker.wake(); + self.buf.pop(1); + self.waker.wake(); } else { // Disable interrupt until we have something to transmit again r.uartimsc().modify(|w| { @@ -143,17 +274,6 @@ where } } -impl<'d, T: Instance> PeripheralState for StateInner<'d, T> -where - Self: 'd, -{ - type Interrupt = T::Interrupt; - fn on_interrupt(&mut self) { - self.on_rx(); - self.on_tx(); - } -} - impl embedded_io::Error for Error { fn kind(&self) -> embedded_io::ErrorKind { embedded_io::ErrorKind::Other @@ -164,8 +284,16 @@ impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { type Error = Error; } +impl<'d, T: Instance> embedded_io::Io for RxBufferedUart<'d, T> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::Io for TxBufferedUart<'d, T> { + type Error = Error; +} + impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { - type ReadFuture<'a> = impl Future> + type ReadFuture<'a> = impl Future> where Self: 'a; @@ -176,20 +304,58 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { compiler_fence(Ordering::SeqCst); // We have data ready in buffer? Return it. - let data = state.rx.pop_buf(); + let data = state.rx.buf.pop_buf(); if !data.is_empty() { let len = data.len().min(buf.len()); buf[..len].copy_from_slice(&data[..len]); - if state.rx.is_full() { + if state.rx.buf.is_full() { do_pend = true; } - state.rx.pop(len); + state.rx.buf.pop(len); return Poll::Ready(Ok(len)); } - state.rx_waker.register(cx.waker()); + state.rx.waker.register(cx.waker()); + Poll::Pending + }); + + if do_pend { + self.inner.pend(); + } + + res + }) + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Read for RxBufferedUart<'d, T> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + let mut do_pend = false; + let res = self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let data = state.buf.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if state.buf.is_full() { + do_pend = true; + } + state.buf.pop(len); + + return Poll::Ready(Ok(len)); + } + + state.waker.register(cx.waker()); Poll::Pending }); @@ -213,7 +379,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> compiler_fence(Ordering::SeqCst); // We have data ready in buffer? Return it. - let buf = state.rx.pop_buf(); + let buf = state.rx.buf.pop_buf(); if !buf.is_empty() { let buf: &[u8] = buf; // Safety: buffer lives as long as uart @@ -221,7 +387,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> return Poll::Ready(Ok(buf)); } - state.rx_waker.register(cx.waker()); + state.rx.waker.register(cx.waker()); Poll::>::Pending }) }) @@ -229,8 +395,45 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> fn consume(&mut self, amt: usize) { let signal = self.inner.with(|state| { - let full = state.rx.is_full(); - state.rx.pop(amt); + let full = state.rx.buf.is_full(); + state.rx.buf.pop(amt); + full + }); + if signal { + self.inner.pend(); + } + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for RxBufferedUart<'d, T> { + type FillBufFuture<'a> = impl Future> + where + Self: 'a; + + fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let buf = state.buf.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + state.waker.register(cx.waker()); + Poll::>::Pending + }) + }) + } + + fn consume(&mut self, amt: usize) { + let signal = self.inner.with(|state| { + let full = state.buf.is_full(); + state.buf.pop(amt); full }); if signal { @@ -247,16 +450,16 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { poll_fn(move |cx| { let (poll, empty) = self.inner.with(|state| { - let empty = state.tx.is_empty(); - let tx_buf = state.tx.push_buf(); + let empty = state.tx.buf.is_empty(); + let tx_buf = state.tx.buf.push_buf(); if tx_buf.is_empty() { - state.tx_waker.register(cx.waker()); + state.tx.waker.register(cx.waker()); return (Poll::Pending, empty); } let n = core::cmp::min(tx_buf.len(), buf.len()); tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.push(n); + state.tx.buf.push(n); (Poll::Ready(Ok(n)), empty) }); @@ -274,8 +477,54 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { poll_fn(move |cx| { self.inner.with(|state| { - if !state.tx.is_empty() { - state.tx_waker.register(cx.waker()); + if !state.tx.buf.is_empty() { + state.tx.waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + }) + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> { + type WriteFuture<'a> = impl Future> + where + Self: 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + let (poll, empty) = self.inner.with(|state| { + let empty = state.buf.is_empty(); + let tx_buf = state.buf.push_buf(); + if tx_buf.is_empty() { + state.waker.register(cx.waker()); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.buf.push(n); + + (Poll::Ready(Ok(n)), empty) + }); + if empty { + self.inner.pend(); + } + poll + }) + } + + type FlushFuture<'a> = impl Future> + where + Self: 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + if !state.buf.is_empty() { + state.waker.register(cx.waker()); return Poll::Pending; } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 3b71d87b..67e24b60 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -343,7 +343,7 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { w.set_stp2(config.stop_bits == StopBits::STOP2); w.set_pen(pen); w.set_eps(eps); - w.set_fen(true); + w.set_fen(false); }); r.uartcr().write(|w| { From b2d0f8d5903f868277732b4b12365945783d1720 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Sep 2022 10:49:47 +0200 Subject: [PATCH 03/16] Formatting --- embassy-rp/src/uart/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 67e24b60..76ecdf7a 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -544,7 +544,6 @@ mod eh1 { self.blocking_flush().map_err(nb::Error::Other) } } - } #[cfg(all( @@ -607,7 +606,6 @@ mod buffered; #[cfg(feature = "nightly")] pub use buffered::*; - mod sealed { use super::*; @@ -649,7 +647,7 @@ macro_rules! impl_instance { impl sealed::Instance for peripherals::$inst { const TX_DREQ: u8 = $tx_dreq; const RX_DREQ: u8 = $rx_dreq; - + type Interrupt = crate::interrupt::$irq; fn regs() -> pac::uart::Uart { From c495c765df42ca273da55b320c869b0aaabc6ef8 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Sep 2022 12:28:35 +0200 Subject: [PATCH 04/16] Enable embedded-io on nightly --- embassy-rp/Cargo.toml | 44 ++++++++++++++----------------------------- embassy-rp/src/lib.rs | 2 -- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 92780ee3..3debca71 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -7,7 +7,9 @@ edition = "2021" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/" features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] -flavors = [{ name = "rp2040", target = "thumbv6m-none-eabi" }] +flavors = [ + { name = "rp2040", target = "thumbv6m-none-eabi" }, +] [features] defmt = ["dep:defmt", "embassy-usb?/defmt"] @@ -18,16 +20,8 @@ defmt = ["dep:defmt", "embassy-usb?/defmt"] # There are no plans to make this stable. unstable-pac = [] -time-driver = [] - # Enable nightly-only features -nightly = [ - "embassy-executor/nightly", - "embedded-hal-1", - "embedded-hal-async", - "embassy-embedded-hal/nightly", - "dep:embassy-usb", -] +nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb", "dep:embedded-io"] # Implement embedded-hal 1.0 alpha traits. # Implement embedded-hal-async traits if `nightly` is set as well. @@ -36,15 +30,11 @@ unstable-traits = ["embedded-hal-1"] [dependencies] embassy-sync = { version = "0.1.0", path = "../embassy-sync" } embassy-executor = { version = "0.1.0", path = "../embassy-executor" } -embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ - "tick-hz-1_000_000", -] } -embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = [ - "prio-bits-2", -] } -embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } -embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } -embassy-usb = { version = "0.1.0", path = "../embassy-usb", optional = true } +embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } +embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} +embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } +embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } atomic-polyfill = "1.0.1" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } @@ -53,18 +43,12 @@ cfg-if = "1.0.0" cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" critical-section = "1.1" -futures = { version = "0.3.17", default-features = false, features = [ - "async-await", -] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } embedded-io = { version = "0.3.0", features = ["async"], optional = true } -rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev = "017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = [ - "rt", -] } +rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } -embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ - "unproven", -] } -embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true } -embedded-hal-async = { version = "0.1.0-alpha.1", optional = true } +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} +embedded-hal-async = { version = "0.1.0-alpha.1", optional = true} diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 8dcefece..aebbbf56 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -8,7 +8,6 @@ pub mod dma; pub mod gpio; pub mod interrupt; pub mod spi; -#[cfg(feature = "time-driver")] pub mod timer; pub mod uart; #[cfg(feature = "nightly")] @@ -109,7 +108,6 @@ pub fn init(_config: config::Config) -> Peripherals { unsafe { clocks::init(); - #[cfg(feature = "time-driver")] timer::init(); dma::init(); } From 1d3e41f970c1b04fc98533a0a6d09cb5be85ff09 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 21 Sep 2022 06:00:35 +0200 Subject: [PATCH 05/16] Remove code-duplication in async bufferedUart implementations --- embassy-rp/src/uart/buffered.rs | 215 +++++++++++++------------------- 1 file changed, 89 insertions(+), 126 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 3eb96e3d..6d395b6f 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,5 +1,5 @@ use core::future::Future; -use core::task::Poll; +use core::task::{Poll, Waker}; use atomic_polyfill::{compiler_fence, Ordering}; use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; @@ -87,9 +87,9 @@ impl<'d, T: Instance> BufferedUart<'d, T> { let r = T::regs(); unsafe { r.uartimsc().modify(|w| { - // TODO: Should and more or fewer interrupts be enabled? w.set_rxim(true); w.set_rtim(true); + w.set_txim(true); }); } @@ -122,7 +122,6 @@ impl<'d, T: Instance> RxBufferedUart<'d, T> { let r = T::regs(); unsafe { r.uartimsc().modify(|w| { - // TODO: Should and more or fewer interrupts be enabled? w.set_rxim(true); w.set_rtim(true); }); @@ -151,9 +150,7 @@ impl<'d, T: Instance> TxBufferedUart<'d, T> { let r = T::regs(); unsafe { r.uartimsc().modify(|w| { - // TODO: Should and more or fewer interrupts be enabled? - w.set_rxim(true); - w.set_rtim(true); + w.set_txim(true); }); } @@ -179,6 +176,51 @@ where } } +impl<'d, T: Instance> RxStateInner<'d, T> +where + Self: 'd, +{ + fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll>, bool) { + // We have data ready in buffer? Return it. + let mut do_pend = false; + let data = self.buf.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if self.buf.is_full() { + do_pend = true; + } + self.buf.pop(len); + + return (Poll::Ready(Ok(len)), do_pend); + } + + self.waker.register(waker); + (Poll::Pending, do_pend) + } + + fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll> { + // We have data ready in buffer? Return it. + let buf = self.buf.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + self.waker.register(waker); + Poll::Pending + } + + fn consume(&mut self, amt: usize) -> bool { + let full = self.buf.is_full(); + self.buf.pop(amt); + full + } +} + impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> where Self: 'd, @@ -240,6 +282,35 @@ where } } +impl<'d, T: Instance> TxStateInner<'d, T> +where + Self: 'd, +{ + fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll>, bool) { + let empty = self.buf.is_empty(); + let tx_buf = self.buf.push_buf(); + if tx_buf.is_empty() { + self.waker.register(waker); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + self.buf.push(n); + + (Poll::Ready(Ok(n)), empty) + } + + fn flush(&mut self, waker: &Waker) -> Poll> { + if !self.buf.is_empty() { + self.waker.register(waker); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + } +} + impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> where Self: 'd, @@ -299,26 +370,9 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { poll_fn(move |cx| { - let mut do_pend = false; - let res = self.inner.with(|state| { + let (res, do_pend) = self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let data = state.rx.buf.pop_buf(); - if !data.is_empty() { - let len = data.len().min(buf.len()); - buf[..len].copy_from_slice(&data[..len]); - - if state.rx.buf.is_full() { - do_pend = true; - } - state.rx.buf.pop(len); - - return Poll::Ready(Ok(len)); - } - - state.rx.waker.register(cx.waker()); - Poll::Pending + state.rx.read(buf, cx.waker()) }); if do_pend { @@ -337,26 +391,9 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for RxBufferedUart<'d, T> { fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { poll_fn(move |cx| { - let mut do_pend = false; - let res = self.inner.with(|state| { + let (res, do_pend) = self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let data = state.buf.pop_buf(); - if !data.is_empty() { - let len = data.len().min(buf.len()); - buf[..len].copy_from_slice(&data[..len]); - - if state.buf.is_full() { - do_pend = true; - } - state.buf.pop(len); - - return Poll::Ready(Ok(len)); - } - - state.waker.register(cx.waker()); - Poll::Pending + state.read(buf, cx.waker()) }); if do_pend { @@ -377,28 +414,13 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> poll_fn(move |cx| { self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let buf = state.rx.buf.pop_buf(); - if !buf.is_empty() { - let buf: &[u8] = buf; - // Safety: buffer lives as long as uart - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); - } - - state.rx.waker.register(cx.waker()); - Poll::>::Pending + state.rx.fill_buf(cx.waker()) }) }) } fn consume(&mut self, amt: usize) { - let signal = self.inner.with(|state| { - let full = state.rx.buf.is_full(); - state.rx.buf.pop(amt); - full - }); + let signal = self.inner.with(|state| state.rx.consume(amt)); if signal { self.inner.pend(); } @@ -414,28 +436,13 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for RxBufferedUart<'d, T poll_fn(move |cx| { self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let buf = state.buf.pop_buf(); - if !buf.is_empty() { - let buf: &[u8] = buf; - // Safety: buffer lives as long as uart - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); - } - - state.waker.register(cx.waker()); - Poll::>::Pending + state.fill_buf(cx.waker()) }) }) } fn consume(&mut self, amt: usize) { - let signal = self.inner.with(|state| { - let full = state.buf.is_full(); - state.buf.pop(amt); - full - }); + let signal = self.inner.with(|state| state.consume(amt)); if signal { self.inner.pend(); } @@ -449,20 +456,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { poll_fn(move |cx| { - let (poll, empty) = self.inner.with(|state| { - let empty = state.tx.buf.is_empty(); - let tx_buf = state.tx.buf.push_buf(); - if tx_buf.is_empty() { - state.tx.waker.register(cx.waker()); - return (Poll::Pending, empty); - } - - let n = core::cmp::min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.buf.push(n); - - (Poll::Ready(Ok(n)), empty) - }); + let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker())); if empty { self.inner.pend(); } @@ -475,16 +469,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { Self: 'a; fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { - poll_fn(move |cx| { - self.inner.with(|state| { - if !state.tx.buf.is_empty() { - state.tx.waker.register(cx.waker()); - return Poll::Pending; - } - - Poll::Ready(Ok(())) - }) - }) + poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker()))) } } @@ -495,20 +480,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { poll_fn(move |cx| { - let (poll, empty) = self.inner.with(|state| { - let empty = state.buf.is_empty(); - let tx_buf = state.buf.push_buf(); - if tx_buf.is_empty() { - state.waker.register(cx.waker()); - return (Poll::Pending, empty); - } - - let n = core::cmp::min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.buf.push(n); - - (Poll::Ready(Ok(n)), empty) - }); + let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker())); if empty { self.inner.pend(); } @@ -521,15 +493,6 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> Self: 'a; fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { - poll_fn(move |cx| { - self.inner.with(|state| { - if !state.buf.is_empty() { - state.waker.register(cx.waker()); - return Poll::Pending; - } - - Poll::Ready(Ok(())) - }) - }) + poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker()))) } } From b743d9f48ce7635b720119336c1a711269f304ed Mon Sep 17 00:00:00 2001 From: Mathias Date: Mon, 26 Sep 2022 05:32:45 +0200 Subject: [PATCH 06/16] Add HIL test for bufferedUart --- embassy-rp/src/uart/buffered.rs | 3 +-- tests/rp/Cargo.toml | 1 + tests/rp/src/bin/uart_buffered.rs | 37 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/rp/src/bin/uart_buffered.rs diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 6d395b6f..9c4fbfeb 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,11 +1,10 @@ -use core::future::Future; +use core::future::{poll_fn, Future}; use core::task::{Poll, Waker}; use atomic_polyfill::{compiler_fence, Ordering}; use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::ring_buffer::RingBuffer; use embassy_sync::waitqueue::WakerRegistration; -use futures::future::poll_fn; use super::*; diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 4d6877cc..70fd9555 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -19,6 +19,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } embedded-hal-async = { version = "0.1.0-alpha.1" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +embedded-io = { version = "0.3.0", features = ["async"] } [profile.dev] debug = 2 diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs new file mode 100644 index 00000000..a0a3df8d --- /dev/null +++ b/tests/rp/src/bin/uart_buffered.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_rp::interrupt; +use embassy_rp::uart::{BufferedUart, Config, State, Uart}; +use embedded_io::asynch::{Read, Write}; +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 uart = Uart::new_blocking(uart, tx, rx, config); + + let irq = interrupt::take!(UART0_IRQ); + let tx_buf = &mut [0u8; 32]; + let rx_buf = &mut [0u8; 32]; + let mut state = State::new(); + let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf); + + 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(); +} From ee76831f93e792757bf43136be712c343c4d5336 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 26 Aug 2022 09:05:12 +0200 Subject: [PATCH 07/16] Add BufferedUart implementation, and feature-guard time-driver initialization, to free up TIMER peripheral if not used with embassy executor --- embassy-rp/Cargo.toml | 1 + embassy-rp/src/uart/buffered.rs | 286 ++++++++++++++++++++++++ embassy-rp/src/{uart.rs => uart/mod.rs} | 84 ++++++- 3 files changed, 369 insertions(+), 2 deletions(-) create mode 100644 embassy-rp/src/uart/buffered.rs rename embassy-rp/src/{uart.rs => uart/mod.rs} (87%) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index c43fd7e7..211b6a40 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -52,6 +52,7 @@ cortex-m = "0.7.6" critical-section = "1.1" futures = { version = "0.3.17", default-features = false, features = ["async-await"] } chrono = { version = "0.4", default-features = false, optional = true } +embedded-io = { version = "0.3.0", features = ["async"], optional = true } rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs new file mode 100644 index 00000000..c31af801 --- /dev/null +++ b/embassy-rp/src/uart/buffered.rs @@ -0,0 +1,286 @@ +use core::future::Future; +use core::task::Poll; + +use atomic_polyfill::{compiler_fence, Ordering}; +use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; +use embassy_hal_common::ring_buffer::RingBuffer; +use embassy_sync::waitqueue::WakerRegistration; +use futures::future::poll_fn; + +use super::*; + +pub struct State<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> State<'d, T> { + pub fn new() -> Self { + Self(StateStorage::new()) + } +} + +struct StateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + rx_waker: WakerRegistration, + rx: RingBuffer<'d>, + + tx_waker: WakerRegistration, + tx: RingBuffer<'d>, +} + +unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} + +pub struct BufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, StateInner<'d, T>>, +} + +impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} + +impl<'d, T: Instance> BufferedUart<'d, T> { + pub fn new( + state: &'d mut State<'d, T>, + _uart: Uart<'d, T, M>, + irq: impl Peripheral

+ 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + ) -> BufferedUart<'d, T> { + into_ref!(irq); + + let r = T::regs(); + unsafe { + r.uartimsc().modify(|w| { + // TODO: Should and more or fewer interrupts be enabled? + w.set_rxim(true); + w.set_rtim(true); + }); + } + + Self { + inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { + phantom: PhantomData, + tx: RingBuffer::new(tx_buffer), + tx_waker: WakerRegistration::new(), + + rx: RingBuffer::new(rx_buffer), + rx_waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> StateInner<'d, T> +where + Self: 'd, +{ + fn on_rx(&mut self) { + let r = T::regs(); + unsafe { + let ris = r.uartris().read(); + // Clear interrupt flags + r.uarticr().write(|w| { + w.set_rxic(true); + w.set_rtic(true); + }); + + if ris.rxris() { + if ris.peris() { + warn!("Parity error"); + } + if ris.feris() { + warn!("Framing error"); + } + if ris.beris() { + warn!("Break error"); + } + if ris.oeris() { + warn!("Overrun error"); + } + + let buf = self.rx.push_buf(); + if !buf.is_empty() { + buf[0] = r.uartdr().read().data(); + self.rx.push(1); + } else { + warn!("RX buffer full, discard received byte"); + } + + if self.rx.is_full() { + self.rx_waker.wake(); + } + } + + if ris.rtris() { + self.rx_waker.wake(); + }; + } + } + + fn on_tx(&mut self) { + let r = T::regs(); + unsafe { + let ris = r.uartris().read(); + // Clear interrupt flags + r.uarticr().write(|w| { + w.set_rtic(true); + }); + + if ris.txris() { + let buf = self.tx.pop_buf(); + if !buf.is_empty() { + r.uartimsc().modify(|w| { + w.set_txim(true); + }); + r.uartdr().write(|w| w.set_data(buf[0].into())); + self.tx.pop(1); + self.tx_waker.wake(); + } else { + // Disable interrupt until we have something to transmit again + r.uartimsc().modify(|w| { + w.set_txim(false); + }); + } + } + } + } +} + +impl<'d, T: Instance> PeripheralState for StateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { + self.on_rx(); + self.on_tx(); + } +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { + type Error = Error; +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + let mut do_pend = false; + let res = self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let data = state.rx.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if state.rx.is_full() { + do_pend = true; + } + state.rx.pop(len); + + return Poll::Ready(Ok(len)); + } + + state.rx_waker.register(cx.waker()); + Poll::Pending + }); + + if do_pend { + self.inner.pend(); + } + + res + }) + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { + type FillBufFuture<'a> = impl Future> + where + Self: 'a; + + fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let buf = state.rx.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + state.rx_waker.register(cx.waker()); + Poll::>::Pending + }) + }) + } + + fn consume(&mut self, amt: usize) { + let signal = self.inner.with(|state| { + let full = state.rx.is_full(); + state.rx.pop(amt); + full + }); + if signal { + self.inner.pend(); + } + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { + type WriteFuture<'a> = impl Future> + where + Self: 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + let (poll, empty) = self.inner.with(|state| { + let empty = state.tx.is_empty(); + let tx_buf = state.tx.push_buf(); + if tx_buf.is_empty() { + state.tx_waker.register(cx.waker()); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.tx.push(n); + + (Poll::Ready(Ok(n)), empty) + }); + if empty { + self.inner.pend(); + } + poll + }) + } + + type FlushFuture<'a> = impl Future> + where + Self: 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + if !state.tx.is_empty() { + state.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + }) + } +} diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs similarity index 87% rename from embassy-rp/src/uart.rs rename to embassy-rp/src/uart/mod.rs index 987b716b..3b71d87b 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart/mod.rs @@ -475,6 +475,76 @@ mod eh1 { impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { type Error = Error; } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> { + fn read(&mut self) -> nb::Result { + let r = T::regs(); + unsafe { + let dr = r.uartdr().read(); + + if dr.oe() { + Err(nb::Error::Other(Error::Overrun)) + } else if dr.be() { + Err(nb::Error::Other(Error::Break)) + } else if dr.pe() { + 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) + } + } + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> { + fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { + self.blocking_write(&[char]).map_err(nb::Error::Other) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.blocking_flush().map_err(nb::Error::Other) + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> { + fn read(&mut self) -> Result> { + embedded_hal_02::serial::Read::read(&mut self.rx) + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } + } + + impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> { + fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { + self.blocking_write(&[char]).map_err(nb::Error::Other) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.blocking_flush().map_err(nb::Error::Other) + } + } + } #[cfg(all( @@ -532,6 +602,12 @@ mod eha { } } +#[cfg(feature = "nightly")] +mod buffered; +#[cfg(feature = "nightly")] +pub use buffered::*; + + mod sealed { use super::*; @@ -541,6 +617,8 @@ mod sealed { const TX_DREQ: u8; const RX_DREQ: u8; + type Interrupt: crate::interrupt::Interrupt; + fn regs() -> pac::uart::Uart; } pub trait TxPin {} @@ -571,6 +649,8 @@ macro_rules! impl_instance { impl sealed::Instance for peripherals::$inst { const TX_DREQ: u8 = $tx_dreq; const RX_DREQ: u8 = $rx_dreq; + + type Interrupt = crate::interrupt::$irq; fn regs() -> pac::uart::Uart { pac::$inst @@ -580,8 +660,8 @@ macro_rules! impl_instance { }; } -impl_instance!(UART0, UART0, 20, 21); -impl_instance!(UART1, UART1, 22, 23); +impl_instance!(UART0, UART0_IRQ, 20, 21); +impl_instance!(UART1, UART1_IRQ, 22, 23); pub trait TxPin: sealed::TxPin + crate::gpio::Pin {} pub trait RxPin: sealed::RxPin + crate::gpio::Pin {} From f2239d34cc26bb147d136d312b8b6af1020d4e0f Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Sep 2022 10:36:27 +0200 Subject: [PATCH 08/16] Add bufferedUart, including a split version for only Rx or Tx --- embassy-rp/src/uart/buffered.rs | 379 ++++++++++++++++++++++++++------ embassy-rp/src/uart/mod.rs | 2 +- 2 files changed, 315 insertions(+), 66 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index c31af801..3eb96e3d 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -9,31 +9,70 @@ use futures::future::poll_fn; use super::*; -pub struct State<'d, T: Instance>(StateStorage>); +pub struct State<'d, T: Instance>(StateStorage>); impl<'d, T: Instance> State<'d, T> { - pub fn new() -> Self { + pub const fn new() -> Self { Self(StateStorage::new()) } } -struct StateInner<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, - - rx_waker: WakerRegistration, - rx: RingBuffer<'d>, - - tx_waker: WakerRegistration, - tx: RingBuffer<'d>, +pub struct RxState<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> RxState<'d, T> { + pub const fn new() -> Self { + Self(StateStorage::new()) + } } -unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} -unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} +pub struct TxState<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> TxState<'d, T> { + pub const fn new() -> Self { + Self(StateStorage::new()) + } +} + +struct RxStateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + waker: WakerRegistration, + buf: RingBuffer<'d>, +} + +struct TxStateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + waker: WakerRegistration, + buf: RingBuffer<'d>, +} + +struct FullStateInner<'d, T: Instance> { + rx: RxStateInner<'d, T>, + tx: TxStateInner<'d, T>, +} + +unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {} + +unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {} + +unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {} pub struct BufferedUart<'d, T: Instance> { - inner: PeripheralMutex<'d, StateInner<'d, T>>, + inner: PeripheralMutex<'d, FullStateInner<'d, T>>, +} + +pub struct RxBufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, RxStateInner<'d, T>>, +} + +pub struct TxBufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, TxStateInner<'d, T>>, } impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} +impl<'d, T: Instance> Unpin for RxBufferedUart<'d, T> {} +impl<'d, T: Instance> Unpin for TxBufferedUart<'d, T> {} impl<'d, T: Instance> BufferedUart<'d, T> { pub fn new( @@ -55,66 +94,158 @@ impl<'d, T: Instance> BufferedUart<'d, T> { } Self { - inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { - phantom: PhantomData, - tx: RingBuffer::new(tx_buffer), - tx_waker: WakerRegistration::new(), - - rx: RingBuffer::new(rx_buffer), - rx_waker: WakerRegistration::new(), + inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner { + tx: TxStateInner { + phantom: PhantomData, + waker: WakerRegistration::new(), + buf: RingBuffer::new(tx_buffer), + }, + rx: RxStateInner { + phantom: PhantomData, + waker: WakerRegistration::new(), + buf: RingBuffer::new(rx_buffer), + }, }), } } } -impl<'d, T: Instance> StateInner<'d, T> +impl<'d, T: Instance> RxBufferedUart<'d, T> { + pub fn new( + state: &'d mut RxState<'d, T>, + _uart: UartRx<'d, T, M>, + irq: impl Peripheral

+ 'd, + rx_buffer: &'d mut [u8], + ) -> RxBufferedUart<'d, T> { + into_ref!(irq); + + let r = T::regs(); + unsafe { + r.uartimsc().modify(|w| { + // TODO: Should and more or fewer interrupts be enabled? + w.set_rxim(true); + w.set_rtim(true); + }); + } + + Self { + inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner { + phantom: PhantomData, + + buf: RingBuffer::new(rx_buffer), + waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> TxBufferedUart<'d, T> { + pub fn new( + state: &'d mut TxState<'d, T>, + _uart: UartTx<'d, T, M>, + irq: impl Peripheral

+ 'd, + tx_buffer: &'d mut [u8], + ) -> TxBufferedUart<'d, T> { + into_ref!(irq); + + let r = T::regs(); + unsafe { + r.uartimsc().modify(|w| { + // TODO: Should and more or fewer interrupts be enabled? + w.set_rxim(true); + w.set_rtim(true); + }); + } + + Self { + inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner { + phantom: PhantomData, + + buf: RingBuffer::new(tx_buffer), + waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T> where Self: 'd, { - fn on_rx(&mut self) { + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { + self.rx.on_interrupt(); + self.tx.on_interrupt(); + } +} + +impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { let r = T::regs(); unsafe { - let ris = r.uartris().read(); + let ris = r.uartmis().read(); // Clear interrupt flags - r.uarticr().write(|w| { + r.uarticr().modify(|w| { w.set_rxic(true); w.set_rtic(true); }); - if ris.rxris() { - if ris.peris() { + if ris.rxmis() { + if ris.pemis() { warn!("Parity error"); + r.uarticr().modify(|w| { + w.set_peic(true); + }); } - if ris.feris() { + if ris.femis() { warn!("Framing error"); + r.uarticr().modify(|w| { + w.set_feic(true); + }); } - if ris.beris() { + if ris.bemis() { warn!("Break error"); + r.uarticr().modify(|w| { + w.set_beic(true); + }); } - if ris.oeris() { + if ris.oemis() { warn!("Overrun error"); + r.uarticr().modify(|w| { + w.set_oeic(true); + }); } - let buf = self.rx.push_buf(); + let buf = self.buf.push_buf(); if !buf.is_empty() { buf[0] = r.uartdr().read().data(); - self.rx.push(1); + self.buf.push(1); } else { warn!("RX buffer full, discard received byte"); } - if self.rx.is_full() { - self.rx_waker.wake(); + if self.buf.is_full() { + self.waker.wake(); } } - if ris.rtris() { - self.rx_waker.wake(); + if ris.rtmis() { + self.waker.wake(); }; } } +} - fn on_tx(&mut self) { +impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { let r = T::regs(); unsafe { let ris = r.uartris().read(); @@ -124,14 +255,14 @@ where }); if ris.txris() { - let buf = self.tx.pop_buf(); + let buf = self.buf.pop_buf(); if !buf.is_empty() { r.uartimsc().modify(|w| { w.set_txim(true); }); r.uartdr().write(|w| w.set_data(buf[0].into())); - self.tx.pop(1); - self.tx_waker.wake(); + self.buf.pop(1); + self.waker.wake(); } else { // Disable interrupt until we have something to transmit again r.uartimsc().modify(|w| { @@ -143,17 +274,6 @@ where } } -impl<'d, T: Instance> PeripheralState for StateInner<'d, T> -where - Self: 'd, -{ - type Interrupt = T::Interrupt; - fn on_interrupt(&mut self) { - self.on_rx(); - self.on_tx(); - } -} - impl embedded_io::Error for Error { fn kind(&self) -> embedded_io::ErrorKind { embedded_io::ErrorKind::Other @@ -164,8 +284,16 @@ impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { type Error = Error; } +impl<'d, T: Instance> embedded_io::Io for RxBufferedUart<'d, T> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::Io for TxBufferedUart<'d, T> { + type Error = Error; +} + impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { - type ReadFuture<'a> = impl Future> + type ReadFuture<'a> = impl Future> where Self: 'a; @@ -176,20 +304,58 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { compiler_fence(Ordering::SeqCst); // We have data ready in buffer? Return it. - let data = state.rx.pop_buf(); + let data = state.rx.buf.pop_buf(); if !data.is_empty() { let len = data.len().min(buf.len()); buf[..len].copy_from_slice(&data[..len]); - if state.rx.is_full() { + if state.rx.buf.is_full() { do_pend = true; } - state.rx.pop(len); + state.rx.buf.pop(len); return Poll::Ready(Ok(len)); } - state.rx_waker.register(cx.waker()); + state.rx.waker.register(cx.waker()); + Poll::Pending + }); + + if do_pend { + self.inner.pend(); + } + + res + }) + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Read for RxBufferedUart<'d, T> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + let mut do_pend = false; + let res = self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let data = state.buf.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if state.buf.is_full() { + do_pend = true; + } + state.buf.pop(len); + + return Poll::Ready(Ok(len)); + } + + state.waker.register(cx.waker()); Poll::Pending }); @@ -213,7 +379,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> compiler_fence(Ordering::SeqCst); // We have data ready in buffer? Return it. - let buf = state.rx.pop_buf(); + let buf = state.rx.buf.pop_buf(); if !buf.is_empty() { let buf: &[u8] = buf; // Safety: buffer lives as long as uart @@ -221,7 +387,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> return Poll::Ready(Ok(buf)); } - state.rx_waker.register(cx.waker()); + state.rx.waker.register(cx.waker()); Poll::>::Pending }) }) @@ -229,8 +395,45 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> fn consume(&mut self, amt: usize) { let signal = self.inner.with(|state| { - let full = state.rx.is_full(); - state.rx.pop(amt); + let full = state.rx.buf.is_full(); + state.rx.buf.pop(amt); + full + }); + if signal { + self.inner.pend(); + } + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for RxBufferedUart<'d, T> { + type FillBufFuture<'a> = impl Future> + where + Self: 'a; + + fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let buf = state.buf.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + state.waker.register(cx.waker()); + Poll::>::Pending + }) + }) + } + + fn consume(&mut self, amt: usize) { + let signal = self.inner.with(|state| { + let full = state.buf.is_full(); + state.buf.pop(amt); full }); if signal { @@ -247,16 +450,16 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { poll_fn(move |cx| { let (poll, empty) = self.inner.with(|state| { - let empty = state.tx.is_empty(); - let tx_buf = state.tx.push_buf(); + let empty = state.tx.buf.is_empty(); + let tx_buf = state.tx.buf.push_buf(); if tx_buf.is_empty() { - state.tx_waker.register(cx.waker()); + state.tx.waker.register(cx.waker()); return (Poll::Pending, empty); } let n = core::cmp::min(tx_buf.len(), buf.len()); tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.push(n); + state.tx.buf.push(n); (Poll::Ready(Ok(n)), empty) }); @@ -274,8 +477,54 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { poll_fn(move |cx| { self.inner.with(|state| { - if !state.tx.is_empty() { - state.tx_waker.register(cx.waker()); + if !state.tx.buf.is_empty() { + state.tx.waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + }) + } +} + +impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> { + type WriteFuture<'a> = impl Future> + where + Self: 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + let (poll, empty) = self.inner.with(|state| { + let empty = state.buf.is_empty(); + let tx_buf = state.buf.push_buf(); + if tx_buf.is_empty() { + state.waker.register(cx.waker()); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.buf.push(n); + + (Poll::Ready(Ok(n)), empty) + }); + if empty { + self.inner.pend(); + } + poll + }) + } + + type FlushFuture<'a> = impl Future> + where + Self: 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + if !state.buf.is_empty() { + state.waker.register(cx.waker()); return Poll::Pending; } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 3b71d87b..67e24b60 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -343,7 +343,7 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { w.set_stp2(config.stop_bits == StopBits::STOP2); w.set_pen(pen); w.set_eps(eps); - w.set_fen(true); + w.set_fen(false); }); r.uartcr().write(|w| { From d6af0f62860f79f790d6d1e042f36c8623328ab1 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Sep 2022 10:49:47 +0200 Subject: [PATCH 09/16] Formatting --- embassy-rp/src/uart/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 67e24b60..76ecdf7a 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -544,7 +544,6 @@ mod eh1 { self.blocking_flush().map_err(nb::Error::Other) } } - } #[cfg(all( @@ -607,7 +606,6 @@ mod buffered; #[cfg(feature = "nightly")] pub use buffered::*; - mod sealed { use super::*; @@ -649,7 +647,7 @@ macro_rules! impl_instance { impl sealed::Instance for peripherals::$inst { const TX_DREQ: u8 = $tx_dreq; const RX_DREQ: u8 = $rx_dreq; - + type Interrupt = crate::interrupt::$irq; fn regs() -> pac::uart::Uart { From 1db9e464ff13a05d1267bb33fde490bcce35af5a Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Sep 2022 12:28:35 +0200 Subject: [PATCH 10/16] Enable embedded-io on nightly --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 211b6a40..d0cf8025 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -27,7 +27,7 @@ intrinsics = [] rom-v2-intrinsics = [] # Enable nightly-only features -nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"] +nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb", "dep:embedded-io"] # Implement embedded-hal 1.0 alpha traits. # Implement embedded-hal-async traits if `nightly` is set as well. From b3dfd06dd6da3369813cf469a7fcd87c22047e87 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 21 Sep 2022 06:00:35 +0200 Subject: [PATCH 11/16] Remove code-duplication in async bufferedUart implementations --- embassy-rp/src/uart/buffered.rs | 215 +++++++++++++------------------- 1 file changed, 89 insertions(+), 126 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 3eb96e3d..6d395b6f 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,5 +1,5 @@ use core::future::Future; -use core::task::Poll; +use core::task::{Poll, Waker}; use atomic_polyfill::{compiler_fence, Ordering}; use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; @@ -87,9 +87,9 @@ impl<'d, T: Instance> BufferedUart<'d, T> { let r = T::regs(); unsafe { r.uartimsc().modify(|w| { - // TODO: Should and more or fewer interrupts be enabled? w.set_rxim(true); w.set_rtim(true); + w.set_txim(true); }); } @@ -122,7 +122,6 @@ impl<'d, T: Instance> RxBufferedUart<'d, T> { let r = T::regs(); unsafe { r.uartimsc().modify(|w| { - // TODO: Should and more or fewer interrupts be enabled? w.set_rxim(true); w.set_rtim(true); }); @@ -151,9 +150,7 @@ impl<'d, T: Instance> TxBufferedUart<'d, T> { let r = T::regs(); unsafe { r.uartimsc().modify(|w| { - // TODO: Should and more or fewer interrupts be enabled? - w.set_rxim(true); - w.set_rtim(true); + w.set_txim(true); }); } @@ -179,6 +176,51 @@ where } } +impl<'d, T: Instance> RxStateInner<'d, T> +where + Self: 'd, +{ + fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll>, bool) { + // We have data ready in buffer? Return it. + let mut do_pend = false; + let data = self.buf.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if self.buf.is_full() { + do_pend = true; + } + self.buf.pop(len); + + return (Poll::Ready(Ok(len)), do_pend); + } + + self.waker.register(waker); + (Poll::Pending, do_pend) + } + + fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll> { + // We have data ready in buffer? Return it. + let buf = self.buf.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + self.waker.register(waker); + Poll::Pending + } + + fn consume(&mut self, amt: usize) -> bool { + let full = self.buf.is_full(); + self.buf.pop(amt); + full + } +} + impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> where Self: 'd, @@ -240,6 +282,35 @@ where } } +impl<'d, T: Instance> TxStateInner<'d, T> +where + Self: 'd, +{ + fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll>, bool) { + let empty = self.buf.is_empty(); + let tx_buf = self.buf.push_buf(); + if tx_buf.is_empty() { + self.waker.register(waker); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + self.buf.push(n); + + (Poll::Ready(Ok(n)), empty) + } + + fn flush(&mut self, waker: &Waker) -> Poll> { + if !self.buf.is_empty() { + self.waker.register(waker); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + } +} + impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> where Self: 'd, @@ -299,26 +370,9 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { poll_fn(move |cx| { - let mut do_pend = false; - let res = self.inner.with(|state| { + let (res, do_pend) = self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let data = state.rx.buf.pop_buf(); - if !data.is_empty() { - let len = data.len().min(buf.len()); - buf[..len].copy_from_slice(&data[..len]); - - if state.rx.buf.is_full() { - do_pend = true; - } - state.rx.buf.pop(len); - - return Poll::Ready(Ok(len)); - } - - state.rx.waker.register(cx.waker()); - Poll::Pending + state.rx.read(buf, cx.waker()) }); if do_pend { @@ -337,26 +391,9 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for RxBufferedUart<'d, T> { fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { poll_fn(move |cx| { - let mut do_pend = false; - let res = self.inner.with(|state| { + let (res, do_pend) = self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let data = state.buf.pop_buf(); - if !data.is_empty() { - let len = data.len().min(buf.len()); - buf[..len].copy_from_slice(&data[..len]); - - if state.buf.is_full() { - do_pend = true; - } - state.buf.pop(len); - - return Poll::Ready(Ok(len)); - } - - state.waker.register(cx.waker()); - Poll::Pending + state.read(buf, cx.waker()) }); if do_pend { @@ -377,28 +414,13 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> poll_fn(move |cx| { self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let buf = state.rx.buf.pop_buf(); - if !buf.is_empty() { - let buf: &[u8] = buf; - // Safety: buffer lives as long as uart - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); - } - - state.rx.waker.register(cx.waker()); - Poll::>::Pending + state.rx.fill_buf(cx.waker()) }) }) } fn consume(&mut self, amt: usize) { - let signal = self.inner.with(|state| { - let full = state.rx.buf.is_full(); - state.rx.buf.pop(amt); - full - }); + let signal = self.inner.with(|state| state.rx.consume(amt)); if signal { self.inner.pend(); } @@ -414,28 +436,13 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for RxBufferedUart<'d, T poll_fn(move |cx| { self.inner.with(|state| { compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let buf = state.buf.pop_buf(); - if !buf.is_empty() { - let buf: &[u8] = buf; - // Safety: buffer lives as long as uart - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); - } - - state.waker.register(cx.waker()); - Poll::>::Pending + state.fill_buf(cx.waker()) }) }) } fn consume(&mut self, amt: usize) { - let signal = self.inner.with(|state| { - let full = state.buf.is_full(); - state.buf.pop(amt); - full - }); + let signal = self.inner.with(|state| state.consume(amt)); if signal { self.inner.pend(); } @@ -449,20 +456,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { poll_fn(move |cx| { - let (poll, empty) = self.inner.with(|state| { - let empty = state.tx.buf.is_empty(); - let tx_buf = state.tx.buf.push_buf(); - if tx_buf.is_empty() { - state.tx.waker.register(cx.waker()); - return (Poll::Pending, empty); - } - - let n = core::cmp::min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.buf.push(n); - - (Poll::Ready(Ok(n)), empty) - }); + let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker())); if empty { self.inner.pend(); } @@ -475,16 +469,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { Self: 'a; fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { - poll_fn(move |cx| { - self.inner.with(|state| { - if !state.tx.buf.is_empty() { - state.tx.waker.register(cx.waker()); - return Poll::Pending; - } - - Poll::Ready(Ok(())) - }) - }) + poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker()))) } } @@ -495,20 +480,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { poll_fn(move |cx| { - let (poll, empty) = self.inner.with(|state| { - let empty = state.buf.is_empty(); - let tx_buf = state.buf.push_buf(); - if tx_buf.is_empty() { - state.waker.register(cx.waker()); - return (Poll::Pending, empty); - } - - let n = core::cmp::min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.buf.push(n); - - (Poll::Ready(Ok(n)), empty) - }); + let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker())); if empty { self.inner.pend(); } @@ -521,15 +493,6 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> Self: 'a; fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { - poll_fn(move |cx| { - self.inner.with(|state| { - if !state.buf.is_empty() { - state.waker.register(cx.waker()); - return Poll::Pending; - } - - Poll::Ready(Ok(())) - }) - }) + poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker()))) } } From f76444bdc43f0a000b878dc52cb46ac06661a8b3 Mon Sep 17 00:00:00 2001 From: Mathias Date: Mon, 26 Sep 2022 05:32:45 +0200 Subject: [PATCH 12/16] Add HIL test for bufferedUart --- embassy-rp/src/uart/buffered.rs | 3 +-- tests/rp/Cargo.toml | 1 + tests/rp/src/bin/uart_buffered.rs | 37 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/rp/src/bin/uart_buffered.rs diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 6d395b6f..9c4fbfeb 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,11 +1,10 @@ -use core::future::Future; +use core::future::{poll_fn, Future}; use core::task::{Poll, Waker}; use atomic_polyfill::{compiler_fence, Ordering}; use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::ring_buffer::RingBuffer; use embassy_sync::waitqueue::WakerRegistration; -use futures::future::poll_fn; use super::*; diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 7e2717dd..50337375 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -20,6 +20,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } embedded-hal-async = { version = "0.1.0-alpha.1" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +embedded-io = { version = "0.3.0", features = ["async"] } [profile.dev] debug = 2 diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs new file mode 100644 index 00000000..a0a3df8d --- /dev/null +++ b/tests/rp/src/bin/uart_buffered.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_rp::interrupt; +use embassy_rp::uart::{BufferedUart, Config, State, Uart}; +use embedded_io::asynch::{Read, Write}; +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 uart = Uart::new_blocking(uart, tx, rx, config); + + let irq = interrupt::take!(UART0_IRQ); + let tx_buf = &mut [0u8; 32]; + let rx_buf = &mut [0u8; 32]; + let mut state = State::new(); + let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf); + + 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(); +} From c863acd24f6430950a7fdb5c527b33b42c305fec Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Sep 2022 20:36:06 +0200 Subject: [PATCH 13/16] rp: set correct teleprobe target for rpi-pico tests. --- tests/rp/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index 0330025e..9611db3a 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml @@ -3,7 +3,7 @@ build-std = ["core"] build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -#runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" +#runner = "teleprobe client run --target rpi-pico --elf" runner = "teleprobe local run --chip RP2040 --elf" rustflags = [ From 65907204d64f104bfa5bf1ea9d1da8cb9cc09d19 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 27 Sep 2022 05:51:31 +0200 Subject: [PATCH 14/16] Rename from {Rx,Tx}BufferedUart to BufferedUart{Rx,Tx} to be compliant with stm32 and nrf implementations --- embassy-rp/src/uart/buffered.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 9c4fbfeb..81ac61ee 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -61,17 +61,17 @@ pub struct BufferedUart<'d, T: Instance> { inner: PeripheralMutex<'d, FullStateInner<'d, T>>, } -pub struct RxBufferedUart<'d, T: Instance> { +pub struct BufferedUartRx<'d, T: Instance> { inner: PeripheralMutex<'d, RxStateInner<'d, T>>, } -pub struct TxBufferedUart<'d, T: Instance> { +pub struct BufferedUartTx<'d, T: Instance> { inner: PeripheralMutex<'d, TxStateInner<'d, T>>, } impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} -impl<'d, T: Instance> Unpin for RxBufferedUart<'d, T> {} -impl<'d, T: Instance> Unpin for TxBufferedUart<'d, T> {} +impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {} +impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {} impl<'d, T: Instance> BufferedUart<'d, T> { pub fn new( @@ -109,13 +109,13 @@ impl<'d, T: Instance> BufferedUart<'d, T> { } } -impl<'d, T: Instance> RxBufferedUart<'d, T> { +impl<'d, T: Instance> BufferedUartRx<'d, T> { pub fn new( state: &'d mut RxState<'d, T>, _uart: UartRx<'d, T, M>, irq: impl Peripheral

+ 'd, rx_buffer: &'d mut [u8], - ) -> RxBufferedUart<'d, T> { + ) -> BufferedUartRx<'d, T> { into_ref!(irq); let r = T::regs(); @@ -137,13 +137,13 @@ impl<'d, T: Instance> RxBufferedUart<'d, T> { } } -impl<'d, T: Instance> TxBufferedUart<'d, T> { +impl<'d, T: Instance> BufferedUartTx<'d, T> { pub fn new( state: &'d mut TxState<'d, T>, _uart: UartTx<'d, T, M>, irq: impl Peripheral

+ 'd, tx_buffer: &'d mut [u8], - ) -> TxBufferedUart<'d, T> { + ) -> BufferedUartTx<'d, T> { into_ref!(irq); let r = T::regs(); @@ -354,11 +354,11 @@ impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { type Error = Error; } -impl<'d, T: Instance> embedded_io::Io for RxBufferedUart<'d, T> { +impl<'d, T: Instance> embedded_io::Io for BufferedUartRx<'d, T> { type Error = Error; } -impl<'d, T: Instance> embedded_io::Io for TxBufferedUart<'d, T> { +impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> { type Error = Error; } @@ -383,7 +383,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { } } -impl<'d, T: Instance + 'd> embedded_io::asynch::Read for RxBufferedUart<'d, T> { +impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { type ReadFuture<'a> = impl Future> where Self: 'a; @@ -426,7 +426,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> } } -impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for RxBufferedUart<'d, T> { +impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { type FillBufFuture<'a> = impl Future> where Self: 'a; @@ -472,7 +472,7 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { } } -impl<'d, T: Instance + 'd> embedded_io::asynch::Write for TxBufferedUart<'d, T> { +impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { type WriteFuture<'a> = impl Future> where Self: 'a; From 93354b812c89c1b0d56f93181eae8484c625fe89 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 27 Sep 2022 05:51:38 +0200 Subject: [PATCH 15/16] Extend buffered-uart test to transmit 32 bytes --- tests/rp/src/bin/uart_buffered.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index a0a3df8d..4313ee3d 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -25,10 +25,16 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf); - let data = [0xC0, 0xDE]; + // Make sure we send more bytes than fits in the FIFO, to test the actual + // bufferedUart. + + let data = [ + 1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, + ]; uart.write(&data).await.unwrap(); - let mut buf = [0; 2]; + let mut buf = [0; 32]; uart.read(&mut buf).await.unwrap(); assert_eq!(buf, data); From e129a97d48a00d7923886ab3faa82357b2369f13 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 27 Sep 2022 07:45:10 +0200 Subject: [PATCH 16/16] Fix bufferedUart read and write tests --- embassy-rp/src/uart/buffered.rs | 88 ++++++++++++++----------------- embassy-rp/src/uart/mod.rs | 7 ++- tests/rp/src/bin/uart_buffered.rs | 9 ++-- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 81ac61ee..87e16f0e 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -228,39 +228,39 @@ where fn on_interrupt(&mut self) { let r = T::regs(); unsafe { - let ris = r.uartmis().read(); + let ris = r.uartris().read(); // Clear interrupt flags r.uarticr().modify(|w| { w.set_rxic(true); w.set_rtic(true); }); - if ris.rxmis() { - if ris.pemis() { - warn!("Parity error"); - r.uarticr().modify(|w| { - w.set_peic(true); - }); - } - if ris.femis() { - warn!("Framing error"); - r.uarticr().modify(|w| { - w.set_feic(true); - }); - } - if ris.bemis() { - warn!("Break error"); - r.uarticr().modify(|w| { - w.set_beic(true); - }); - } - if ris.oemis() { - warn!("Overrun error"); - r.uarticr().modify(|w| { - w.set_oeic(true); - }); - } + if ris.peris() { + warn!("Parity error"); + r.uarticr().modify(|w| { + w.set_peic(true); + }); + } + if ris.feris() { + warn!("Framing error"); + r.uarticr().modify(|w| { + w.set_feic(true); + }); + } + if ris.beris() { + warn!("Break error"); + r.uarticr().modify(|w| { + w.set_beic(true); + }); + } + if ris.oeris() { + warn!("Overrun error"); + r.uarticr().modify(|w| { + w.set_oeic(true); + }); + } + if !r.uartfr().read().rxfe() { let buf = self.buf.push_buf(); if !buf.is_empty() { buf[0] = r.uartdr().read().data(); @@ -274,7 +274,7 @@ where } } - if ris.rtmis() { + if ris.rtris() { self.waker.wake(); }; } @@ -318,27 +318,19 @@ where fn on_interrupt(&mut self) { let r = T::regs(); unsafe { - let ris = r.uartris().read(); - // Clear interrupt flags - r.uarticr().write(|w| { - w.set_rtic(true); - }); - - if ris.txris() { - let buf = self.buf.pop_buf(); - if !buf.is_empty() { - r.uartimsc().modify(|w| { - w.set_txim(true); - }); - r.uartdr().write(|w| w.set_data(buf[0].into())); - self.buf.pop(1); - self.waker.wake(); - } else { - // Disable interrupt until we have something to transmit again - r.uartimsc().modify(|w| { - w.set_txim(false); - }); - } + let buf = self.buf.pop_buf(); + if !buf.is_empty() { + r.uartimsc().modify(|w| { + w.set_txim(true); + }); + r.uartdr().write(|w| w.set_data(buf[0].into())); + self.buf.pop(1); + self.waker.wake(); + } else { + // Disable interrupt until we have something to transmit again + r.uartimsc().modify(|w| { + w.set_txim(false); + }); } } } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 76ecdf7a..d9285ee5 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -343,7 +343,12 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { w.set_stp2(config.stop_bits == StopBits::STOP2); w.set_pen(pen); w.set_eps(eps); - w.set_fen(false); + w.set_fen(true); + }); + + r.uartifls().write(|w| { + w.set_rxiflsel(0b000); + w.set_txiflsel(0b000); }); r.uartcr().write(|w| { diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index 4313ee3d..9cc20bb9 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -20,8 +20,8 @@ async fn main(_spawner: Spawner) { let uart = Uart::new_blocking(uart, tx, rx, config); let irq = interrupt::take!(UART0_IRQ); - let tx_buf = &mut [0u8; 32]; - let rx_buf = &mut [0u8; 32]; + let tx_buf = &mut [0u8; 16]; + let rx_buf = &mut [0u8; 16]; let mut state = State::new(); let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf); @@ -32,10 +32,11 @@ async fn main(_spawner: Spawner) { 1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ]; - uart.write(&data).await.unwrap(); + uart.write_all(&data).await.unwrap(); + info!("Done writing"); let mut buf = [0; 32]; - uart.read(&mut buf).await.unwrap(); + uart.read_exact(&mut buf).await.unwrap(); assert_eq!(buf, data); info!("Test OK");