Handle Uarte RX errors

This commit is contained in:
Justin Beaurivage 2024-01-30 17:06:57 -05:00
parent dcce40c8a2
commit 7ff21e8b8b
2 changed files with 85 additions and 11 deletions

View file

@ -133,6 +133,7 @@ embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.6.1" }
defmt = { version = "0.3", optional = true }
bitflags = "2.4.2"
log = { version = "0.4.14", optional = true }
cortex-m-rt = ">=0.6.15,<0.8"
cortex-m = "0.7.6"

View file

@ -52,6 +52,39 @@ impl Default for Config {
}
}
bitflags::bitflags! {
/// Error source flags
pub struct ErrorSource: u32 {
/// Buffer overrun
const OVERRUN = 0x01;
/// Parity error
const PARITY = 0x02;
/// Framing error
const FRAMING = 0x04;
/// Break condition
const BREAK = 0x08;
}
}
impl TryFrom<ErrorSource> for () {
type Error = Error;
#[inline]
fn try_from(errors: ErrorSource) -> Result<Self, Self::Error> {
if errors.contains(ErrorSource::OVERRUN) {
Err(Error::Overrun)
} else if errors.contains(ErrorSource::PARITY) {
Err(Error::Parity)
} else if errors.contains(ErrorSource::FRAMING) {
Err(Error::Framing)
} else if errors.contains(ErrorSource::BREAK) {
Err(Error::Break)
} else {
Ok(())
}
}
}
/// UART error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -61,6 +94,14 @@ pub enum Error {
BufferTooLong,
/// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
BufferNotInRAM,
/// Framing Error
Framing,
/// Parity Error
Parity,
/// Buffer Overrun
Overrun,
/// Break condition
Break,
}
/// Interrupt handler.
@ -73,9 +114,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
let r = T::regs();
let s = T::state();
if r.events_endrx.read().bits() != 0 {
let endrx = r.events_endrx.read().bits();
let error = r.events_error.read().bits();
if endrx != 0 || error != 0 {
s.endrx_waker.wake();
r.intenclr.write(|w| w.endrx().clear());
if endrx != 0 {
r.intenclr.write(|w| w.endrx().clear());
}
if error != 0 {
r.intenclr.write(|w| w.error().clear());
}
}
if r.events_endtx.read().bits() != 0 {
s.endtx_waker.wake();
@ -486,6 +534,13 @@ impl<'d, T: Instance> UarteRx<'d, T> {
Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config)
}
fn read_and_clear_errors(&mut self) -> Result<(), Error> {
let r = T::regs();
let err_bits = r.errorsrc.read().bits();
r.errorsrc.write(|w| unsafe { w.bits(err_bits) });
ErrorSource::from_bits_truncate(err_bits).try_into()
}
fn new_inner(
uarte: impl Peripheral<P = T> + 'd,
rxd: PeripheralRef<'d, AnyPin>,
@ -572,7 +627,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
/// Read bytes until the buffer is filled.
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
if buffer.len() == 0 {
if buffer.is_empty() {
return Ok(());
}
if buffer.len() > EASY_DMA_SIZE {
@ -588,8 +643,13 @@ impl<'d, T: Instance> UarteRx<'d, T> {
let drop = OnDrop::new(move || {
trace!("read drop: stopping");
r.intenclr.write(|w| w.endrx().clear());
r.intenclr.write(|w| {
w.endrx().clear();
w.error().clear()
});
r.events_rxto.reset();
r.events_error.reset();
r.errorsrc.reset();
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
while r.events_endrx.read().bits() == 0 {}
@ -601,17 +661,26 @@ impl<'d, T: Instance> UarteRx<'d, T> {
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
r.events_endrx.reset();
r.intenset.write(|w| w.endrx().set());
r.events_error.reset();
r.intenset.write(|w| {
w.endrx().set();
w.error().set()
});
compiler_fence(Ordering::SeqCst);
trace!("startrx");
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
poll_fn(|cx| {
let result = poll_fn(|cx| {
s.endrx_waker.register(cx.waker());
let maybe_err = self.read_and_clear_errors();
if let Err(e) = maybe_err {
return Poll::Ready(Err(e));
}
if r.events_endrx.read().bits() != 0 {
return Poll::Ready(());
return Poll::Ready(Ok(()));
}
Poll::Pending
})
@ -621,7 +690,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
r.events_rxstarted.reset();
drop.defuse();
Ok(())
result
}
/// Read bytes until the buffer is filled.
@ -642,19 +711,23 @@ impl<'d, T: Instance> UarteRx<'d, T> {
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
r.events_endrx.reset();
r.intenclr.write(|w| w.endrx().clear());
r.events_error.reset();
r.intenclr.write(|w| {
w.endrx().clear();
w.error().clear()
});
compiler_fence(Ordering::SeqCst);
trace!("startrx");
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
while r.events_endrx.read().bits() == 0 {}
while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
compiler_fence(Ordering::SeqCst);
r.events_rxstarted.reset();
Ok(())
self.read_and_clear_errors()
}
}