use core::future::poll_fn; use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; use crate::time::Hertz; use crate::usart::Regs; use crate::Peri; /// Rx-only Ring-buffered UART Driver /// /// Created with [UartRx::into_ring_buffered] /// /// ### Notes on 'waiting for bytes' /// /// The `read(buf)` (but not `read()`) and `read_exact(buf)` functions /// may need to wait for bytes to arrive, if the ring buffer does not /// contain enough bytes to fill the buffer passed by the caller of /// the function, or is empty. /// /// Waiting for bytes operates in one of two modes, depending on /// the behavior of the sender and the size of the buffer passed /// to the function: /// /// - If the sender sends intermittently, the 'idle line' /// condition will be detected when the sender stops, and any /// bytes in the ring buffer will be returned. If there are no /// bytes in the buffer, the check will be repeated each time the /// 'idle line' condition is detected, so if the sender sends just /// a single byte, it will be returned once the 'idle line' /// condition is detected. /// /// - If the sender sends continuously, the call will wait until /// the DMA controller indicates that it has written to either the /// middle byte or last byte of the ring buffer ('half transfer' /// or 'transfer complete', respectively). This does not indicate /// the buffer is half-full or full, though, because the DMA /// controller does not detect those conditions; it sends an /// interrupt when those specific buffer addresses have been /// written. /// /// In both cases this will result in variable latency due to the /// buffering effect. For example, if the baudrate is 2400 bps, and /// the configuration is 8 data bits, no parity bit, and one stop bit, /// then a byte will be received every ~4.16ms. If the ring buffer is /// 32 bytes, then a 'wait for bytes' delay may have to wait for 16 /// bytes in the worst case, resulting in a delay (latency) of /// ~62.46ms for the first byte in the ring buffer. If the sender /// sends only 6 bytes and then stops, but the buffer was empty when /// the read function was called, then those bytes may not be returned /// until ~24.96ms after the first byte was received (time for 5 /// additional bytes plus the 'idle frame' which triggers the 'idle /// line' condition). /// /// Applications subject to this latency must be careful if they /// also apply timeouts during reception, as it may appear (to /// them) that the sender has stopped sending when it did not. In /// the example above, a 50ms timeout (12 bytes at 2400bps) might /// seem to be reasonable to detect that the sender has stopped /// sending, but would be falsely triggered in the worst-case /// buffer delay scenario. /// /// Note: This latency is caused by the limited capabilities of the /// STM32 DMA controller; since it cannot generate an interrupt when /// it stores a byte into an empty ring buffer, or in any other /// configurable conditions, it is not possible to take notice of the /// contents of the ring buffer more quickly without introducing /// polling. As a result the latency can be reduced by calling the /// read functions repeatedly with smaller buffers to receive the /// available bytes, as each call to a read function will explicitly /// check the ring buffer for available bytes. pub struct RingBufferedUartRx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, rx: Option>, rts: Option>, ring_buf: ReadableRingBuffer<'d, u8>, } impl<'d> SetConfig for RingBufferedUartRx<'d> { type Config = Config; type ConfigError = ConfigError; fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { self.set_config(config) } } impl<'d> UartRx<'d, Async> { /// Turn the `UartRx` into a buffered uart which can continously receive in the background /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the /// DMA controller, and must be large enough to prevent overflows. pub fn into_ring_buffered(mut self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); let opts = Default::default(); // Safety: we forget the struct before this function returns. let rx_dma = self.rx_dma.as_mut().unwrap(); let request = rx_dma.request; let rx_dma = unsafe { rx_dma.channel.clone_unchecked() }; let info = self.info; let state = self.state; let kernel_clock = self.kernel_clock; let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) }; let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; // Don't disable the clock mem::forget(self); RingBufferedUartRx { info, state, kernel_clock, rx, rts, ring_buf, } } } impl<'d> RingBufferedUartRx<'d> { /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.info, self.kernel_clock, config) } /// Configure and start the DMA backed UART receiver /// /// Note: This is also done automatically by the read functions if /// required. pub fn start_uart(&mut self) { // Clear the buffer so that it is ready to receive data compiler_fence(Ordering::SeqCst); self.ring_buf.start(); let r = self.info.regs; // clear all interrupts and DMA Rx Request r.cr1().modify(|w| { // disable RXNE interrupt w.set_rxneie(false); // enable parity interrupt if not ParityNone w.set_peie(w.pce()); // enable idle line interrupt w.set_idleie(true); }); r.cr3().modify(|w| { // enable Error Interrupt: (Frame error, Noise error, Overrun error) w.set_eie(true); // enable DMA Rx Request w.set_dmar(true); }); } /// Stop DMA backed UART receiver fn stop_uart(&mut self) { self.ring_buf.request_pause(); let r = self.info.regs; // clear all interrupts and DMA Rx Request r.cr1().modify(|w| { // disable RXNE interrupt w.set_rxneie(false); // disable parity interrupt w.set_peie(false); // disable idle line interrupt w.set_idleie(false); }); r.cr3().modify(|w| { // disable Error Interrupt: (Frame error, Noise error, Overrun error) w.set_eie(false); // disable DMA Rx Request w.set_dmar(false); }); compiler_fence(Ordering::SeqCst); } /// (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), and /// check for errors in status register. Error flags are checked/cleared first. fn start_dma_or_check_errors(&mut self) -> Result<(), Error> { let r = self.info.regs; check_idle_and_errors(r)?; if !r.cr3().read().dmar() { self.start_uart(); } Ok(()) } /// Read bytes that are available in the ring buffer, or wait for /// bytes to become available and return them. /// /// Background reception is started if necessary (if `start_uart()` had /// not previously been called, or if an error was detected which /// caused background reception to be stopped). /// /// Background reception is terminated when an error is returned. /// It must be started again by calling `start_uart()` or by /// calling a read function again. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.start_dma_or_check_errors()?; // In half-duplex mode, we need to disable the Transmitter and enable the Receiver // since they can't operate simultaneously on the shared line let r = self.info.regs; if r.cr3().read().hdsel() && r.cr1().read().te() { r.cr1().modify(|reg| { reg.set_re(true); reg.set_te(false); }); } loop { match self.ring_buf.read(buf) { Ok((0, _)) => {} Ok((len, _)) => { return Ok(len); } Err(_) => { self.stop_uart(); return Err(Error::Overrun); } } match self.wait_for_data_or_idle().await { Ok(_) => {} Err(err) => { self.stop_uart(); return Err(err); } } } } /// Wait for uart idle or dma half-full or full async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { compiler_fence(Ordering::SeqCst); // Future which completes when idle line is detected let s = self.state; let uart = poll_fn(|cx| { s.rx_waker.register(cx.waker()); compiler_fence(Ordering::SeqCst); if check_idle_and_errors(self.info.regs)? { // Idle line is detected Poll::Ready(Ok(())) } else { Poll::Pending } }); let mut dma_init = false; // Future which completes when the DMA controller indicates it // has written to the ring buffer's middle byte, or last byte let dma = poll_fn(|cx| { self.ring_buf.set_waker(cx.waker()); let status = match dma_init { false => Poll::Pending, true => Poll::Ready(()), }; dma_init = true; status }); match select(uart, dma).await { Either::Left((result, _)) => result, Either::Right(((), _)) => Ok(()), } } /// Set baudrate pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { set_baudrate(self.info, self.kernel_clock, baudrate) } } impl Drop for RingBufferedUartRx<'_> { fn drop(&mut self) { self.stop_uart(); self.rx.as_ref().map(|x| x.set_as_disconnected()); self.rts.as_ref().map(|x| x.set_as_disconnected()); super::drop_tx_rx(self.info, self.state); } } /// Check and clear idle and error interrupts, return true if idle, Err(e) on error /// /// All flags are read and cleared in a single step, respectively. When more than one flag is set /// at the same time, all flags will be cleared but only one flag will be reported. So the other /// flag(s) will gone missing unnoticed. The error flags are checked first, the idle flag last. /// /// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags /// are cleared by a single read to the RDR register. fn check_idle_and_errors(r: Regs) -> Result { // Critical section is required so that the flags aren't set after read and before clear let sr = critical_section::with(|_| { // SAFETY: read only and we only use Rx related flags let sr = sr(r).read(); #[cfg(any(usart_v3, usart_v4))] r.icr().write(|w| { w.set_idle(true); w.set_pe(true); w.set_fe(true); w.set_ne(true); w.set_ore(true); }); #[cfg(not(any(usart_v3, usart_v4)))] unsafe { // This read also clears the error and idle interrupt flags on v1 (TODO and v2?) rdr(r).read_volatile() }; sr }); if sr.pe() { Err(Error::Parity) } else if sr.fe() { Err(Error::Framing) } else if sr.ne() { Err(Error::Noise) } else if sr.ore() { Err(Error::Overrun) } else { r.cr1().modify(|w| w.set_idleie(true)); Ok(sr.idle()) } } impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> { type Error = Error; } impl embedded_io_async::Read for RingBufferedUartRx<'_> { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read(buf).await } } impl embedded_hal_nb::serial::Read for RingBufferedUartRx<'_> { fn read(&mut self) -> nb::Result { self.start_dma_or_check_errors()?; let mut buf = [0u8; 1]; match self.ring_buf.read(&mut buf) { Ok((0, _)) => Err(nb::Error::WouldBlock), Ok((len, _)) => { assert!(len == 1); Ok(buf[0]) } Err(_) => { self.stop_uart(); Err(nb::Error::Other(Error::Overrun)) } } } } impl embedded_hal_nb::serial::ErrorType for RingBufferedUartRx<'_> { type Error = Error; } impl ReadReady for RingBufferedUartRx<'_> { fn read_ready(&mut self) -> Result { let len = self.ring_buf.len().map_err(|e| match e { crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun, crate::dma::ringbuffer::Error::DmaUnsynced => { error!( "Ringbuffer error: DmaUNsynced, driver implementation is probably bugged please open an issue" ); // we report this as overrun since its recoverable in the same way Self::Error::Overrun } })?; Ok(len > 0) } }