aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-14 20:20:45 +0000
committerGitHub <[email protected]>2023-05-14 20:20:45 +0000
commitcdd326284a4a8bd45e59d18822a6d7269030f1c0 (patch)
treeb4b6d24d72d5e9b794911e827a76c86dbb9792e3
parent82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff)
parent3e9d5978c088a7d07af63e32a07583f2ff3ae7bb (diff)
Merge #1453
1453: stm32 uart: Fix error flag handling for blocking operations r=Dirbaio a=timokroeger Clear and report the error flags one by one and pop the data byte only after all error flags were handled. For v1/v2 we emulate the v3/v4 behaviour by buffering the status register because a read to the data register clears all flags at once which means we might loose all but the first error. Only tested on stm32f3 discovery board with loopback. Let‘s see what CI says for the other families. Fixes #1452 Co-authored-by: Timo Kröger <[email protected]>
-rw-r--r--embassy-stm32/src/usart/mod.rs93
-rw-r--r--tests/stm32/src/bin/usart.rs22
2 files changed, 82 insertions, 33 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index e946762af..b4373529c 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -109,6 +109,8 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
109 _peri: PeripheralRef<'d, T>, 109 _peri: PeripheralRef<'d, T>,
110 rx_dma: PeripheralRef<'d, RxDma>, 110 rx_dma: PeripheralRef<'d, RxDma>,
111 detect_previous_overrun: bool, 111 detect_previous_overrun: bool,
112 #[cfg(any(usart_v1, usart_v2))]
113 buffered_sr: stm32_metapac::usart::regs::Sr,
112} 114}
113 115
114impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { 116impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
@@ -275,6 +277,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
275 _peri: peri, 277 _peri: peri,
276 rx_dma, 278 rx_dma,
277 detect_previous_overrun: config.detect_previous_overrun, 279 detect_previous_overrun: config.detect_previous_overrun,
280 #[cfg(any(usart_v1, usart_v2))]
281 buffered_sr: stm32_metapac::usart::regs::Sr(0),
278 } 282 }
279 } 283 }
280 284
@@ -335,6 +339,59 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
335 } 339 }
336 } 340 }
337 341
342 #[cfg(any(usart_v1, usart_v2))]
343 unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
344 let r = T::regs();
345 loop {
346 // Handle all buffered error flags.
347 if self.buffered_sr.pe() {
348 self.buffered_sr.set_pe(false);
349 return Err(Error::Parity);
350 } else if self.buffered_sr.fe() {
351 self.buffered_sr.set_fe(false);
352 return Err(Error::Framing);
353 } else if self.buffered_sr.ne() {
354 self.buffered_sr.set_ne(false);
355 return Err(Error::Noise);
356 } else if self.buffered_sr.ore() {
357 self.buffered_sr.set_ore(false);
358 return Err(Error::Overrun);
359 } else if self.buffered_sr.rxne() {
360 self.buffered_sr.set_rxne(false);
361 return Ok(true);
362 } else {
363 // No error flags from previous iterations were set: Check the actual status register
364 let sr = r.sr().read();
365 if !sr.rxne() {
366 return Ok(false);
367 }
368
369 // Buffer the status register and let the loop handle the error flags.
370 self.buffered_sr = sr;
371 }
372 }
373 }
374
375 #[cfg(any(usart_v3, usart_v4))]
376 unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
377 let r = T::regs();
378 let sr = r.isr().read();
379 if sr.pe() {
380 r.icr().write(|w| w.set_pe(true));
381 return Err(Error::Parity);
382 } else if sr.fe() {
383 r.icr().write(|w| w.set_fe(true));
384 return Err(Error::Framing);
385 } else if sr.ne() {
386 r.icr().write(|w| w.set_ne(true));
387 return Err(Error::Noise);
388 } else if sr.ore() {
389 r.icr().write(|w| w.set_ore(true));
390 return Err(Error::Overrun);
391 }
392 Ok(sr.rxne())
393 }
394
338 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 395 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
339 where 396 where
340 RxDma: crate::usart::RxDma<T>, 397 RxDma: crate::usart::RxDma<T>,
@@ -347,20 +404,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
347 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 404 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
348 let r = T::regs(); 405 let r = T::regs();
349 unsafe { 406 unsafe {
350 let sr = sr(r).read(); 407 if self.check_rx_flags()? {
351 if sr.pe() {
352 rdr(r).read_volatile();
353 Err(nb::Error::Other(Error::Parity))
354 } else if sr.fe() {
355 rdr(r).read_volatile();
356 Err(nb::Error::Other(Error::Framing))
357 } else if sr.ne() {
358 rdr(r).read_volatile();
359 Err(nb::Error::Other(Error::Noise))
360 } else if sr.ore() {
361 rdr(r).read_volatile();
362 Err(nb::Error::Other(Error::Overrun))
363 } else if sr.rxne() {
364 Ok(rdr(r).read_volatile()) 408 Ok(rdr(r).read_volatile())
365 } else { 409 } else {
366 Err(nb::Error::WouldBlock) 410 Err(nb::Error::WouldBlock)
@@ -372,24 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
372 unsafe { 416 unsafe {
373 let r = T::regs(); 417 let r = T::regs();
374 for b in buffer { 418 for b in buffer {
375 loop { 419 while !self.check_rx_flags()? {}
376 let sr = sr(r).read();
377 if sr.pe() {
378 rdr(r).read_volatile();
379 return Err(Error::Parity);
380 } else if sr.fe() {
381 rdr(r).read_volatile();
382 return Err(Error::Framing);
383 } else if sr.ne() {
384 rdr(r).read_volatile();
385 return Err(Error::Noise);
386 } else if sr.ore() {
387 rdr(r).read_volatile();
388 return Err(Error::Overrun);
389 } else if sr.rxne() {
390 break;
391 }
392 }
393 *b = rdr(r).read_volatile(); 420 *b = rdr(r).read_volatile();
394 } 421 }
395 } 422 }
@@ -715,6 +742,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
715 _peri: peri, 742 _peri: peri,
716 rx_dma, 743 rx_dma,
717 detect_previous_overrun: config.detect_previous_overrun, 744 detect_previous_overrun: config.detect_previous_overrun,
745 #[cfg(any(usart_v1, usart_v2))]
746 buffered_sr: stm32_metapac::usart::regs::Sr(0),
718 }, 747 },
719 } 748 }
720 } 749 }
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index bda2ce9c2..0749f8406 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -8,7 +8,7 @@ use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::interrupt; 10use embassy_stm32::interrupt;
11use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Error, Uart};
12use embassy_time::{Duration, Instant}; 12use embassy_time::{Duration, Instant};
13use example_common::*; 13use example_common::*;
14 14
@@ -53,6 +53,26 @@ async fn main(_spawner: Spawner) {
53 assert_eq!(buf, data); 53 assert_eq!(buf, data);
54 } 54 }
55 55
56 // Test error handling with with an overflow error
57 {
58 let config = Config::default();
59 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config);
60
61 // Send enough bytes to fill the RX FIFOs off all USART versions.
62 let data = [0xC0, 0xDE, 0x12, 0x23, 0x34];
63 usart.blocking_write(&data).unwrap();
64 usart.blocking_flush().unwrap();
65
66 // The error should be reported first.
67 let mut buf = [0; 1];
68 let err = usart.blocking_read(&mut buf);
69 assert_eq!(err, Err(Error::Overrun));
70
71 // At least the first data byte should still be available on all USART versions.
72 usart.blocking_read(&mut buf).unwrap();
73 assert_eq!(buf[0], data[0]);
74 }
75
56 // Test that baudrate divider is calculated correctly. 76 // Test that baudrate divider is calculated correctly.
57 // Do it by comparing the time it takes to send a known number of bytes. 77 // Do it by comparing the time it takes to send a known number of bytes.
58 for baudrate in [ 78 for baudrate in [