diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-05-14 20:20:45 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-14 20:20:45 +0000 |
| commit | cdd326284a4a8bd45e59d18822a6d7269030f1c0 (patch) | |
| tree | b4b6d24d72d5e9b794911e827a76c86dbb9792e3 | |
| parent | 82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff) | |
| parent | 3e9d5978c088a7d07af63e32a07583f2ff3ae7bb (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.rs | 93 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart.rs | 22 |
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 | ||
| 114 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | 116 | impl<'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; | |||
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | 10 | use embassy_stm32::interrupt; |
| 11 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Error, Uart}; |
| 12 | use embassy_time::{Duration, Instant}; | 12 | use embassy_time::{Duration, Instant}; |
| 13 | use example_common::*; | 13 | use 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 [ |
