Skip to content

Commit eaef3d2

Browse files
committed
simplfied UART error handling
1 parent c693530 commit eaef3d2

File tree

4 files changed

+87
-137
lines changed

4 files changed

+87
-137
lines changed

va108xx-hal/CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88

99
## [unreleased]
1010

11+
## [v0.11.0] 2025-03-07
12+
13+
## Changed
14+
15+
- Bugfix for I2C `TimingCfg::reg`
16+
- Simplified UART error handling. All APIs are now infallible because writing to a FIFO or
17+
reading from a FIFO never fails. Users can either poll errors using `Rx::poll_errors` or
18+
`Uart::poll_rx_errors` / `UartBase::poll_rx_errors`, or detect errors using the provided
19+
interrupt handlers.
20+
1121
## [v0.10.0] 2025-02-17
1222

1323
## Added
@@ -241,3 +251,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
241251
- RTT example application
242252
- Added basic test binary in form of an example
243253
- README with basic instructions how to set up own binary crate
254+
255+
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.11.0...HEAD
256+
[v0.11.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.10.0...va108xx-hal-v0.11.0
257+
[v0.10.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.9.0...va108xx-hal-v0.10.0
258+
[v0.9.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.8.0...va108xx-hal-v0.9.0
259+
[v0.8.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.7.0...va108xx-hal-v0.8.0
260+
[v0.7.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.6.0...va108xx-hal-v0.7.0
261+
[v0.6.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/tag/va108xx-hal-v0.6.0

va108xx-hal/src/i2c.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,13 @@ impl TimingCfg {
198198
}
199199

200200
pub fn reg(&self) -> u32 {
201-
(self.tbuf as u32) << 28
202-
| (self.thd_sta as u32) << 24
203-
| (self.tsu_sta as u32) << 20
204-
| (self.tsu_sto as u32) << 16
205-
| (self.tlow as u32) << 12
206-
| (self.thigh as u32) << 8
207-
| (self.tf as u32) << 4
201+
((self.tbuf as u32) << 28)
202+
| ((self.thd_sta as u32) << 24)
203+
| ((self.tsu_sta as u32) << 20)
204+
| ((self.tsu_sto as u32) << 16)
205+
| ((self.tlow as u32) << 12)
206+
| ((self.thigh as u32) << 8)
207+
| ((self.tf as u32) << 4)
208208
| (self.tr as u32)
209209
}
210210
}
@@ -376,7 +376,7 @@ impl<I2c: Instance> I2cBase<I2c> {
376376
if let Some(max_words) = max_words {
377377
self.i2c
378378
.s0_maxwords()
379-
.write(|w| unsafe { w.bits(1 << 31 | max_words as u32) });
379+
.write(|w| unsafe { w.bits((1 << 31) | max_words as u32) });
380380
}
381381
let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr);
382382
// The first bit is the read/write value. Normally, both read and write are matched
@@ -437,7 +437,7 @@ impl<I2c: Instance> I2cBase<I2c> {
437437
let clk_div = self.calc_clk_div(speed_mode)?;
438438
self.i2c
439439
.clkscale()
440-
.write(|w| unsafe { w.bits((speed_mode as u32) << 31 | clk_div as u32) });
440+
.write(|w| unsafe { w.bits(((speed_mode as u32) << 31) | clk_div as u32) });
441441
Ok(())
442442
}
443443

va108xx-hal/src/uart/mod.rs

+58-126
Original file line numberDiff line numberDiff line change
@@ -64,55 +64,6 @@ pub struct NoInterruptIdWasSet;
6464
#[error("transer is pending")]
6565
pub struct TransferPendingError;
6666

67-
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
68-
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69-
pub enum RxError {
70-
#[error("overrun error")]
71-
Overrun,
72-
#[error("framing error")]
73-
Framing,
74-
#[error("parity error")]
75-
Parity,
76-
}
77-
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
78-
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79-
pub enum Error {
80-
#[error("rx error: {0}")]
81-
Rx(#[from] RxError),
82-
#[error("break condition")]
83-
BreakCondition,
84-
}
85-
86-
impl embedded_io::Error for Error {
87-
fn kind(&self) -> embedded_io::ErrorKind {
88-
embedded_io::ErrorKind::Other
89-
}
90-
}
91-
92-
impl embedded_io::Error for RxError {
93-
fn kind(&self) -> embedded_io::ErrorKind {
94-
embedded_io::ErrorKind::Other
95-
}
96-
}
97-
impl embedded_hal_nb::serial::Error for RxError {
98-
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
99-
match self {
100-
RxError::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
101-
RxError::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
102-
RxError::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
103-
}
104-
}
105-
}
106-
107-
impl embedded_hal_nb::serial::Error for Error {
108-
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
109-
match self {
110-
Error::Rx(rx_error) => embedded_hal_nb::serial::Error::kind(rx_error),
111-
Error::BreakCondition => embedded_hal_nb::serial::ErrorKind::Other,
112-
}
113-
}
114-
}
115-
11667
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
11768
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11869
pub enum Event {
@@ -363,7 +314,7 @@ impl UartErrors {
363314
impl UartErrors {
364315
#[inline(always)]
365316
pub fn error(&self) -> bool {
366-
self.overflow || self.framing || self.parity
317+
self.overflow || self.framing || self.parity || self.other
367318
}
368319
}
369320

@@ -585,22 +536,27 @@ impl<Uart: Instance> UartBase<Uart> {
585536
self.uart
586537
}
587538

539+
/// Poll receiver errors.
540+
pub fn poll_rx_errors(&self) -> Option<UartErrors> {
541+
self.rx.poll_errors()
542+
}
543+
588544
pub fn split(self) -> (Tx<Uart>, Rx<Uart>) {
589545
(self.tx, self.rx)
590546
}
591547
}
592548

593549
impl<UartInstance> embedded_io::ErrorType for UartBase<UartInstance> {
594-
type Error = Error;
550+
type Error = Infallible;
595551
}
596552

597553
impl<UartInstance> embedded_hal_nb::serial::ErrorType for UartBase<UartInstance> {
598-
type Error = Error;
554+
type Error = Infallible;
599555
}
600556

601557
impl<Uart: Instance> embedded_hal_nb::serial::Read<u8> for UartBase<Uart> {
602558
fn read(&mut self) -> nb::Result<u8, Self::Error> {
603-
self.rx.read().map_err(|e| e.map(Error::Rx))
559+
self.rx.read()
604560
}
605561
}
606562

@@ -711,6 +667,11 @@ where
711667
self
712668
}
713669

670+
/// Poll receiver errors.
671+
pub fn poll_rx_errors(&self) -> Option<UartErrors> {
672+
self.inner.poll_rx_errors()
673+
}
674+
714675
#[inline]
715676
pub fn enable_rx(&mut self) {
716677
self.inner.enable_rx();
@@ -825,6 +786,23 @@ impl<Uart: Instance> Rx<Uart> {
825786
&self.0
826787
}
827788

789+
pub fn poll_errors(&self) -> Option<UartErrors> {
790+
let mut errors = UartErrors::default();
791+
792+
let uart = unsafe { &(*Uart::ptr()) };
793+
let status_reader = uart.rxstatus().read();
794+
if status_reader.rxovr().bit_is_set() {
795+
errors.overflow = true;
796+
} else if status_reader.rxfrm().bit_is_set() {
797+
errors.framing = true;
798+
} else if status_reader.rxpar().bit_is_set() {
799+
errors.parity = true;
800+
} else {
801+
return None;
802+
};
803+
Some(errors)
804+
}
805+
828806
#[inline]
829807
pub fn clear_fifo(&self) {
830808
self.0.fifo_clr().write(|w| w.rxfifo().set_bit());
@@ -887,34 +865,15 @@ impl<Uart: Instance> Rx<Uart> {
887865
}
888866

889867
impl<Uart> embedded_io::ErrorType for Rx<Uart> {
890-
type Error = RxError;
868+
type Error = Infallible;
891869
}
892870

893871
impl<Uart> embedded_hal_nb::serial::ErrorType for Rx<Uart> {
894-
type Error = RxError;
872+
type Error = Infallible;
895873
}
896874

897875
impl<Uart: Instance> embedded_hal_nb::serial::Read<u8> for Rx<Uart> {
898876
fn read(&mut self) -> nb::Result<u8, Self::Error> {
899-
let uart = unsafe { &(*Uart::ptr()) };
900-
let status_reader = uart.rxstatus().read();
901-
let err = if status_reader.rxovr().bit_is_set() {
902-
Some(RxError::Overrun)
903-
} else if status_reader.rxfrm().bit_is_set() {
904-
Some(RxError::Framing)
905-
} else if status_reader.rxpar().bit_is_set() {
906-
Some(RxError::Parity)
907-
} else {
908-
None
909-
};
910-
if let Some(err) = err {
911-
// The status code is always related to the next bit for the framing
912-
// and parity status bits. We have to read the DATA register
913-
// so that the next status reflects the next DATA word
914-
// For overrun error, we read as well to clear the peripheral
915-
self.read_fifo_unchecked();
916-
return Err(err.into());
917-
}
918877
self.read_fifo().map(|val| (val & 0xff) as u8).map_err(|e| {
919878
if let nb::Error::Other(_) = e {
920879
unreachable!()
@@ -926,16 +885,18 @@ impl<Uart: Instance> embedded_hal_nb::serial::Read<u8> for Rx<Uart> {
926885

927886
impl<Uart: Instance> embedded_io::Read for Rx<Uart> {
928887
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
929-
if buf.is_empty() {
930-
return Ok(0);
931-
}
932-
888+
let mut read = 0;
933889
for byte in buf.iter_mut() {
934-
let w = nb::block!(<Self as embedded_hal_nb::serial::Read<u8>>::read(self))?;
935-
*byte = w;
890+
match <Self as embedded_hal_nb::serial::Read<u8>>::read(self) {
891+
Ok(w) => {
892+
*byte = w;
893+
read += 1;
894+
}
895+
Err(nb::Error::WouldBlock) => break,
896+
}
936897
}
937898

938-
Ok(buf.len())
899+
Ok(read)
939900
}
940901
}
941902

@@ -1090,14 +1051,12 @@ impl<Uart: Instance> embedded_hal_nb::serial::Write<u8> for Tx<Uart> {
10901051

10911052
impl<Uart: Instance> embedded_io::Write for Tx<Uart> {
10921053
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1093-
if buf.is_empty() {
1094-
return Ok(0);
1095-
}
1096-
1054+
let mut written = 0;
10971055
for byte in buf.iter() {
1098-
nb::block!(<Self as embedded_hal_nb::serial::Write<u8>>::write(
1099-
self, *byte
1100-
))?;
1056+
match <Self as embedded_hal_nb::serial::Write<u8>>::write(self, *byte) {
1057+
Ok(_) => written += 1,
1058+
Err(nb::Error::WouldBlock) => return Ok(written),
1059+
}
11011060
}
11021061

11031062
Ok(buf.len())
@@ -1218,15 +1177,10 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
12181177

12191178
// Timeout, empty the FIFO completely.
12201179
if irq_end.irq_rx_to().bit_is_set() {
1221-
loop {
1222-
// While there is data in the FIFO, write it into the reception buffer
1223-
let read_result = self.0.read();
1224-
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
1225-
buf[result.bytes_read] = byte;
1226-
result.bytes_read += 1;
1227-
} else {
1228-
break;
1229-
}
1180+
// While there is data in the FIFO, write it into the reception buffer
1181+
while let Ok(byte) = self.0.read_fifo() {
1182+
buf[result.bytes_read] = byte as u8;
1183+
result.bytes_read += 1;
12301184
}
12311185
}
12321186

@@ -1303,12 +1257,13 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
13031257
if context.rx_idx == context.max_len {
13041258
break;
13051259
}
1306-
let read_result = self.0.read();
1307-
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
1308-
buf[context.rx_idx] = byte;
1309-
context.rx_idx += 1;
1310-
} else {
1311-
break;
1260+
// While there is data in the FIFO, write it into the reception buffer
1261+
match self.0.read() {
1262+
Ok(byte) => {
1263+
buf[result.bytes_read] = byte;
1264+
result.bytes_read += 1;
1265+
}
1266+
Err(_) => break,
13121267
}
13131268
}
13141269
self.irq_completion_handler_max_size_timeout(&mut result, context);
@@ -1327,29 +1282,6 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
13271282
Ok(result)
13281283
}
13291284

1330-
fn read_handler(
1331-
&self,
1332-
errors: &mut Option<UartErrors>,
1333-
read_res: &nb::Result<u8, RxError>,
1334-
) -> Option<u8> {
1335-
match read_res {
1336-
Ok(byte) => Some(*byte),
1337-
Err(nb::Error::WouldBlock) => None,
1338-
Err(nb::Error::Other(e)) => {
1339-
// Ensure `errors` is Some(IrqUartError), initializing if it's None
1340-
let err = errors.get_or_insert(UartErrors::default());
1341-
1342-
// Now we can safely modify fields inside `err`
1343-
match e {
1344-
RxError::Overrun => err.overflow = true,
1345-
RxError::Framing => err.framing = true,
1346-
RxError::Parity => err.parity = true,
1347-
}
1348-
None
1349-
}
1350-
}
1351-
}
1352-
13531285
fn check_for_errors(&self, errors: &mut Option<UartErrors>) {
13541286
let rx_status = self.uart().rxstatus().read();
13551287

va108xx-hal/src/uart/rx_asynch.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use embedded_io::ErrorType;
2626
use portable_atomic::AtomicBool;
2727
use va108xx::uarta as uart_base;
2828

29-
use super::{Bank, Instance, Rx, RxError, UartErrors};
29+
use super::{Bank, Instance, Rx, UartErrors};
3030

3131
static UART_RX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
3232
static RX_READ_ACTIVE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
@@ -46,7 +46,7 @@ impl RxFuture {
4646
}
4747

4848
impl Future for RxFuture {
49-
type Output = Result<(), RxError>;
49+
type Output = Result<(), Infallible>;
5050

5151
fn poll(
5252
self: core::pin::Pin<&mut Self>,

0 commit comments

Comments
 (0)