Skip to content

Commit 2638439

Browse files
authored
Add USART methods to check for error (#160)
This is useful to handle cases where multiple errors have occurred. Previously, it wouldn't have been necessary to detect and handle all those errors, without trying to read again.
1 parent 4c9c96f commit 2638439

File tree

1 file changed

+48
-19
lines changed

1 file changed

+48
-19
lines changed

src/serial.rs

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,16 @@ macro_rules! hal {
363363
}
364364
}
365365

366+
/// Check for, and return, any errors
367+
///
368+
/// See [`Rx::check_for_error`].
369+
pub fn check_for_error() -> Result<(), Error> {
370+
let mut rx: Rx<pac::$USARTX> = Rx {
371+
_usart: PhantomData,
372+
};
373+
rx.check_for_error()
374+
}
375+
366376
/// Stops listening for an interrupt event
367377
pub fn unlisten(&mut self, event: Event) {
368378
match event {
@@ -417,32 +427,19 @@ macro_rules! hal {
417427
type Error = Error;
418428

419429
fn read(&mut self) -> nb::Result<u8, Error> {
430+
self.check_for_error()?;
431+
420432
// NOTE(unsafe) atomic read with no side effects
421433
let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() };
422434

423-
// NOTE(unsafe): Only used for atomic writes, to clear error flags.
424-
let icr = unsafe { &(*pac::$USARTX::ptr()).icr };
425-
426-
Err(if isr.pe().bit_is_set() {
427-
icr.write(|w| w.pecf().clear());
428-
nb::Error::Other(Error::Parity)
429-
} else if isr.fe().bit_is_set() {
430-
icr.write(|w| w.fecf().clear());
431-
nb::Error::Other(Error::Framing)
432-
} else if isr.nf().bit_is_set() {
433-
icr.write(|w| w.ncf().clear());
434-
nb::Error::Other(Error::Noise)
435-
} else if isr.ore().bit_is_set() {
436-
icr.write(|w| w.orecf().clear());
437-
nb::Error::Other(Error::Overrun)
438-
} else if isr.rxne().bit_is_set() {
435+
if isr.rxne().bit_is_set() {
439436
// NOTE(read_volatile) see `write_volatile` below
440437
return Ok(unsafe {
441438
ptr::read_volatile(&(*pac::$USARTX::ptr()).rdr as *const _ as *const _)
442439
});
443-
} else {
444-
nb::Error::WouldBlock
445-
})
440+
}
441+
442+
Err(nb::Error::WouldBlock)
446443
}
447444
}
448445

@@ -643,6 +640,38 @@ macro_rules! hal {
643640
false
644641
}
645642
}
643+
644+
/// Check for, and return, any errors
645+
///
646+
/// The `read` methods can only return one error at a time, but
647+
/// there might actually be multiple errors. This method will
648+
/// return and clear a currently active error. Once it returns
649+
/// `Ok(())`, it should be possible to proceed with the next
650+
/// `read` call unimpeded.
651+
pub fn check_for_error(&mut self) -> Result<(), Error> {
652+
// NOTE(unsafe): Only used for atomic access.
653+
let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() };
654+
let icr = unsafe { &(*pac::$USARTX::ptr()).icr };
655+
656+
if isr.pe().bit_is_set() {
657+
icr.write(|w| w.pecf().clear());
658+
return Err(Error::Parity);
659+
}
660+
if isr.fe().bit_is_set() {
661+
icr.write(|w| w.fecf().clear());
662+
return Err(Error::Framing);
663+
}
664+
if isr.nf().bit_is_set() {
665+
icr.write(|w| w.ncf().clear());
666+
return Err(Error::Noise);
667+
}
668+
if isr.ore().bit_is_set() {
669+
icr.write(|w| w.orecf().clear());
670+
return Err(Error::Overrun);
671+
}
672+
673+
Ok(())
674+
}
646675
}
647676

648677
impl Tx<pac::$USARTX> {

0 commit comments

Comments
 (0)