embassy_stm32/usart/ringbuffered.rs
1 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
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 embassy_hal_internal::PeripheralRef;
use embedded_io_async::ReadReady;
use futures_util::future::{select, Either};
use super::{
clear_interrupt_flags, 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, Sr};
/// Rx-only Ring-buffered UART Driver
///
/// Created with [UartRx::into_ring_buffered]
pub struct RingBufferedUartRx<'d> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
rx: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
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 [`read()`] 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);
}
/// Read bytes that are readily available in the ring buffer.
/// If no bytes are currently available in the buffer the call waits until the some
/// bytes are available (at least one byte and at most half the buffer size)
///
/// Background receive is started if `start()` has not been previously called.
///
/// Receive in the background is terminated if an error is returned.
/// It must then manually be started again by calling `start()` or by re-calling `read()`.
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let r = self.info.regs;
// Start DMA and Uart if it was not already started,
// otherwise check for errors in status register.
let sr = clear_idle_flag(r);
if !r.cr3().read().dmar() {
self.start_uart();
} else {
check_for_errors(sr)?;
}
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);
// Critical section is needed so that IDLE isn't set after
// our read but before we clear it.
let sr = critical_section::with(|_| clear_idle_flag(self.info.regs));
check_for_errors(sr)?;
if sr.idle() {
// Idle line is detected
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
});
let mut dma_init = false;
// Future which completes when there is dma is half full or full
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);
}
}
/// Return an error result if the Sr register has errors
fn check_for_errors(s: Sr) -> Result<(), Error> {
if s.pe() {
Err(Error::Parity)
} else if s.fe() {
Err(Error::Framing)
} else if s.ne() {
Err(Error::Noise)
} else if s.ore() {
Err(Error::Overrun)
} else {
Ok(())
}
}
/// Clear IDLE and return the Sr register
fn clear_idle_flag(r: Regs) -> Sr {
// SAFETY: read only and we only use Rx related flags
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
r.cr1().modify(|w| w.set_idleie(true));
sr
}
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<usize, Self::Error> {
self.read(buf).await
}
}
impl ReadReady for RingBufferedUartRx<'_> {
fn read_ready(&mut self) -> Result<bool, Self::Error> {
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)
}
}