aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/usart/mod.rs11
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs88
2 files changed, 44 insertions, 55 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 675e90c7f..5b7f8dc26 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -18,11 +18,6 @@ use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}
18use crate::interrupt::typelevel::Interrupt as _; 18use crate::interrupt::typelevel::Interrupt as _;
19use crate::interrupt::{self, Interrupt, InterruptExt}; 19use crate::interrupt::{self, Interrupt, InterruptExt};
20use crate::mode::{Async, Blocking, Mode}; 20use crate::mode::{Async, Blocking, Mode};
21#[allow(unused_imports)]
22#[cfg(not(any(usart_v1, usart_v2)))]
23use crate::pac::usart::regs::Isr as Sr;
24#[cfg(any(usart_v1, usart_v2))]
25use crate::pac::usart::regs::Sr;
26#[cfg(not(any(usart_v1, usart_v2)))] 21#[cfg(not(any(usart_v1, usart_v2)))]
27use crate::pac::usart::Lpuart as Regs; 22use crate::pac::usart::Lpuart as Regs;
28#[cfg(any(usart_v1, usart_v2))] 23#[cfg(any(usart_v1, usart_v2))]
@@ -403,7 +398,7 @@ pub struct UartRx<'d, M: Mode> {
403 rx_dma: Option<ChannelAndRequest<'d>>, 398 rx_dma: Option<ChannelAndRequest<'d>>,
404 detect_previous_overrun: bool, 399 detect_previous_overrun: bool,
405 #[cfg(any(usart_v1, usart_v2))] 400 #[cfg(any(usart_v1, usart_v2))]
406 buffered_sr: stm32_metapac::usart::regs::Sr, 401 buffered_sr: regs::Sr,
407 _phantom: PhantomData<M>, 402 _phantom: PhantomData<M>,
408} 403}
409 404
@@ -950,7 +945,7 @@ impl<'d, M: Mode> UartRx<'d, M> {
950 rx_dma, 945 rx_dma,
951 detect_previous_overrun: config.detect_previous_overrun, 946 detect_previous_overrun: config.detect_previous_overrun,
952 #[cfg(any(usart_v1, usart_v2))] 947 #[cfg(any(usart_v1, usart_v2))]
953 buffered_sr: stm32_metapac::usart::regs::Sr(0), 948 buffered_sr: regs::Sr(0),
954 }; 949 };
955 this.enable_and_configure(&config)?; 950 this.enable_and_configure(&config)?;
956 Ok(this) 951 Ok(this)
@@ -1449,7 +1444,7 @@ impl<'d, M: Mode> Uart<'d, M> {
1449 rx_dma, 1444 rx_dma,
1450 detect_previous_overrun: config.detect_previous_overrun, 1445 detect_previous_overrun: config.detect_previous_overrun,
1451 #[cfg(any(usart_v1, usart_v2))] 1446 #[cfg(any(usart_v1, usart_v2))]
1452 buffered_sr: stm32_metapac::usart::regs::Sr(0), 1447 buffered_sr: regs::Sr(0),
1453 }, 1448 },
1454 }; 1449 };
1455 this.enable_and_configure(&config)?; 1450 this.enable_and_configure(&config)?;
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 3a7c3adf4..8e42d5917 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -7,16 +7,12 @@ use embassy_embedded_hal::SetConfig;
7use embedded_io_async::ReadReady; 7use embedded_io_async::ReadReady;
8use futures_util::future::{select, Either}; 8use futures_util::future::{select, Either};
9 9
10use super::{ 10use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx};
11 clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx,
12};
13use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
14use crate::gpio::{AnyPin, SealedPin as _}; 12use crate::gpio::{AnyPin, SealedPin as _};
15use crate::mode::Async; 13use crate::mode::Async;
16#[cfg(any(usart_v3, usart_v4))]
17use crate::pac::usart::regs;
18use crate::time::Hertz; 14use crate::time::Hertz;
19use crate::usart::{Regs, Sr}; 15use crate::usart::Regs;
20use crate::Peri; 16use crate::Peri;
21 17
22/// Rx-only Ring-buffered UART Driver 18/// Rx-only Ring-buffered UART Driver
@@ -99,8 +95,6 @@ impl<'d> RingBufferedUartRx<'d> {
99 // enable idle line interrupt 95 // enable idle line interrupt
100 w.set_idleie(true); 96 w.set_idleie(true);
101 }); 97 });
102 // Clear all potential error interrupt flags
103 clear_interrupt_flags(r, sr(r).read());
104 r.cr3().modify(|w| { 98 r.cr3().modify(|w| {
105 // enable Error Interrupt: (Frame error, Noise error, Overrun error) 99 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
106 w.set_eie(true); 100 w.set_eie(true);
@@ -134,17 +128,15 @@ impl<'d> RingBufferedUartRx<'d> {
134 } 128 }
135 129
136 /// (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), and 130 /// (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), and
137 /// check for errors in status register. Error flags are cleared in `start_uart()` so they need 131 /// check for errors in status register. Error flags are checked/cleared first.
138 /// to be read first without returning yet.
139 fn start_dma_or_check_errors(&mut self) -> Result<(), Error> { 132 fn start_dma_or_check_errors(&mut self) -> Result<(), Error> {
140 let r = self.info.regs; 133 let r = self.info.regs;
141 134
142 let sr = clear_idle_flag(r); 135 check_idle_and_errors(r)?;
143 let res = check_for_errors(sr);
144 if !r.cr3().read().dmar() { 136 if !r.cr3().read().dmar() {
145 self.start_uart(); 137 self.start_uart();
146 } 138 }
147 res 139 Ok(())
148 } 140 }
149 141
150 /// Read bytes that are readily available in the ring buffer. 142 /// Read bytes that are readily available in the ring buffer.
@@ -191,13 +183,7 @@ impl<'d> RingBufferedUartRx<'d> {
191 183
192 compiler_fence(Ordering::SeqCst); 184 compiler_fence(Ordering::SeqCst);
193 185
194 // Critical section is needed so that IDLE isn't set after 186 if check_idle_and_errors(self.info.regs)? {
195 // our read but before we clear it.
196 let sr = critical_section::with(|_| clear_idle_flag(self.info.regs));
197
198 check_for_errors(sr)?;
199
200 if sr.idle() {
201 // Idle line is detected 187 // Idle line is detected
202 Poll::Ready(Ok(())) 188 Poll::Ready(Ok(()))
203 } else { 189 } else {
@@ -240,41 +226,49 @@ impl Drop for RingBufferedUartRx<'_> {
240 } 226 }
241} 227}
242 228
243/// Return an error result if the Sr register has errors 229/// Check and clear idle and error interrupts, return true if idle, Err(e) on error
244fn check_for_errors(s: Sr) -> Result<(), Error> { 230///
245 if s.pe() { 231/// All flags are read and cleared in a single step, respectively. When more than one flag is set
232/// at the same time, all flags will be cleared but only one flag will be reported. So the other
233/// flag(s) will gone missing unnoticed. The error flags are checked first, the idle flag last.
234///
235/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags
236/// are cleared by a single read to the RDR register.
237fn check_idle_and_errors(r: Regs) -> Result<bool, Error> {
238 // Critical section is required so that the flags aren't set after read and before clear
239 let sr = critical_section::with(|_| {
240 // SAFETY: read only and we only use Rx related flags
241 let sr = sr(r).read();
242
243 #[cfg(any(usart_v3, usart_v4))]
244 r.icr().write(|w| {
245 w.set_idle(true);
246 w.set_pe(true);
247 w.set_fe(true);
248 w.set_ne(true);
249 w.set_ore(true);
250 });
251 #[cfg(not(any(usart_v3, usart_v4)))]
252 unsafe {
253 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
254 rdr(r).read_volatile()
255 };
256 sr
257 });
258 if sr.pe() {
246 Err(Error::Parity) 259 Err(Error::Parity)
247 } else if s.fe() { 260 } else if sr.fe() {
248 Err(Error::Framing) 261 Err(Error::Framing)
249 } else if s.ne() { 262 } else if sr.ne() {
250 Err(Error::Noise) 263 Err(Error::Noise)
251 } else if s.ore() { 264 } else if sr.ore() {
252 Err(Error::Overrun) 265 Err(Error::Overrun)
253 } else { 266 } else {
254 Ok(()) 267 r.cr1().modify(|w| w.set_idleie(true));
268 Ok(sr.idle())
255 } 269 }
256} 270}
257 271
258/// Clear IDLE and return the Sr register
259fn clear_idle_flag(r: Regs) -> Sr {
260 // SAFETY: read only and we only use Rx related flags
261
262 let sr = sr(r).read();
263
264 // This read also clears the error and idle interrupt flags on v1.
265 unsafe { rdr(r).read_volatile() };
266 #[cfg(any(usart_v3, usart_v4))]
267 {
268 let mut clear_idle = regs::Icr(0);
269 clear_idle.set_idle(true);
270 r.icr().write_value(clear_idle);
271 }
272
273 r.cr1().modify(|w| w.set_idleie(true));
274
275 sr
276}
277
278impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> { 272impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> {
279 type Error = Error; 273 type Error = Error;
280} 274}