diff --git a/examples/embassy/Cargo.toml b/examples/embassy/Cargo.toml index d6a0297..8f685ee 100644 --- a/examples/embassy/Cargo.toml +++ b/examples/embassy/Cargo.toml @@ -28,8 +28,8 @@ embassy-executor = { version = "0.7", features = [ "executor-interrupt" ]} -va416xx-hal = { version = "0.4.1" } -va416xx-embassy = { version = "0.1", default-features = false } +va416xx-hal = { version = "0.5", path = "../../va416xx-hal" } +va416xx-embassy = { version = "0.1", default-features = false, path = "../../va416xx-embassy" } [features] default = ["ticks-hz-1_000", "va416xx-embassy/irq-tim14-tim15"] diff --git a/examples/embassy/src/bin/uart-echo-with-irq.rs b/examples/embassy/src/bin/uart-echo-with-irq.rs index a4efdc8..a0b0cbf 100644 --- a/examples/embassy/src/bin/uart-echo-with-irq.rs +++ b/examples/embassy/src/bin/uart-echo-with-irq.rs @@ -132,7 +132,7 @@ fn UART0_RX() { RX.lock(|static_rx| { let mut rx_borrow = static_rx.borrow_mut(); let rx_mut_ref = rx_borrow.as_mut().unwrap(); - let result = rx_mut_ref.irq_handler(&mut buf); + let result = rx_mut_ref.on_interrupt(&mut buf); read_len = result.bytes_read; if result.errors.is_some() { errors = result.errors; diff --git a/examples/rtic/Cargo.toml b/examples/rtic/Cargo.toml index b9ba6aa..c35d7da 100644 --- a/examples/rtic/Cargo.toml +++ b/examples/rtic/Cargo.toml @@ -11,7 +11,7 @@ rtt-target = { version = "0.6" } rtic-sync = { version = "1.3", features = ["defmt-03"] } panic-rtt-target = { version = "0.2" } -va416xx-hal = { version = "0.4", features = ["va41630"] } +va416xx-hal = { version = "0.5", features = ["va41630"], path = "../../va416xx-hal" } [dependencies.rtic] version = "2" diff --git a/examples/simple/Cargo.toml b/examples/simple/Cargo.toml index 1cf95d2..3b0e540 100644 --- a/examples/simple/Cargo.toml +++ b/examples/simple/Cargo.toml @@ -16,7 +16,7 @@ embedded-io = "0.6" panic-halt = "1" accelerometer = "0.12" -va416xx-hal = { version = "0.4", features = ["va41630"] } +va416xx-hal = { version = "0.5", features = ["va41630"], path = "../../va416xx-hal" } [dependencies.vorago-peb1] path = "../../vorago-peb1" diff --git a/va416xx-embassy/CHANGELOG.md b/va416xx-embassy/CHANGELOG.md index abffd66..895b12e 100644 --- a/va416xx-embassy/CHANGELOG.md +++ b/va416xx-embassy/CHANGELOG.md @@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] +## [v0.1.1] 2025-03-07 + +- Bumped allowed HAL dependency to v0.5 + ## [v0.1.0] 2025-02-18 Initial release + +[unreleased]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-embassy-v0.1.1...HEAD +[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-embassy-v0.1.0...va416xx-embassy-v0.1.1 +[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/tag/va416xx-embassy-v0.1.0 diff --git a/va416xx-embassy/Cargo.toml b/va416xx-embassy/Cargo.toml index 537c362..66cdb6c 100644 --- a/va416xx-embassy/Cargo.toml +++ b/va416xx-embassy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "va416xx-embassy" -version = "0.1.0" +version = "0.1.1" edition = "2021" authors = ["Robin Mueller "] description = "Embassy-rs support for the Vorago VA416xx family of microcontrollers" @@ -21,7 +21,7 @@ portable-atomic = "1" once_cell = { version = "1", default-features = false, features = ["critical-section"] } -va416xx-hal = { version = "0.4.1" } +va416xx-hal = { version = "0.5", path = "../va416xx-hal" } [features] default = ["irq-tim14-tim15"] diff --git a/va416xx-hal/CHANGELOG.md b/va416xx-hal/CHANGELOG.md index 67c831d..df3c743 100644 --- a/va416xx-hal/CHANGELOG.md +++ b/va416xx-hal/CHANGELOG.md @@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v0.5.0] 2025-03-07 + +- Bugfix for I2C `TimingCfg::reg` +- Simplified UART error handling. All APIs are now infallible because writing to a FIFO or + reading from a FIFO never fails. Users can either poll errors using `Rx::poll_errors` or + `Uart::poll_rx_errors` / `UartBase::poll_rx_errors`, or detect errors using the provided + interrupt handlers. + # [v0.4.1] 2025-02-18 - Chip selection is not enforced anymore, but advised through documentation. This makes using @@ -101,3 +109,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [v0.1.0] 2024-07-01 - Initial release with basic HAL drivers + +[unreleased]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-hal-v0.5.0...HEAD +[v0.5.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-hal-v0.4.1...va416xx-hal-v0.5.0 +[v0.4.1]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-hal-v0.4.0...va416xx-hal-v0.4.1 +[v0.4.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-hal-v0.3.0...va416xx-hal-v0.4.0 +[v0.3.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-hal-v0.2.0...va108xx-hal-v0.3.0 +[v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/va416xx-hal-v0.1.0...va108xx-hal-v0.2.0 +[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/tag/va416xx-hal-v0.1.0 diff --git a/va416xx-hal/Cargo.toml b/va416xx-hal/Cargo.toml index 5fb9def..adcb078 100644 --- a/va416xx-hal/Cargo.toml +++ b/va416xx-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "va416xx-hal" -version = "0.4.1" +version = "0.5.0" authors = ["Robin Mueller "] edition = "2021" description = "HAL for the Vorago VA416xx family of MCUs" diff --git a/va416xx-hal/src/i2c.rs b/va416xx-hal/src/i2c.rs index 383758a..23fdc93 100644 --- a/va416xx-hal/src/i2c.rs +++ b/va416xx-hal/src/i2c.rs @@ -212,13 +212,13 @@ impl TimingCfg { } pub fn reg(&self) -> u32 { - (self.tbuf as u32) << 28 - | (self.thd_sta as u32) << 24 - | (self.tsu_sta as u32) << 20 - | (self.tsu_sto as u32) << 16 - | (self.tlow as u32) << 12 - | (self.thigh as u32) << 8 - | (self.tf as u32) << 4 + ((self.tbuf as u32) << 28) + | ((self.thd_sta as u32) << 24) + | ((self.tsu_sta as u32) << 20) + | ((self.tsu_sto as u32) << 16) + | ((self.tlow as u32) << 12) + | ((self.thigh as u32) << 8) + | ((self.tf as u32) << 4) | (self.tr as u32) } } @@ -390,7 +390,7 @@ impl I2cBase { if let Some(max_words) = max_words { self.i2c .s0_maxwords() - .write(|w| unsafe { w.bits(1 << 31 | max_words as u32) }); + .write(|w| unsafe { w.bits((1 << 31) | max_words as u32) }); } let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr); // The first bit is the read/write value. Normally, both read and write are matched @@ -451,7 +451,7 @@ impl I2cBase { let clk_div = self.calc_clk_div(speed_mode)?; self.i2c .clkscale() - .write(|w| unsafe { w.bits((speed_mode as u32) << 31 | clk_div as u32) }); + .write(|w| unsafe { w.bits(((speed_mode as u32) << 31) | clk_div as u32) }); Ok(()) } diff --git a/va416xx-hal/src/uart/mod.rs b/va416xx-hal/src/uart/mod.rs index 1e8d03f..cd18c79 100644 --- a/va416xx-hal/src/uart/mod.rs +++ b/va416xx-hal/src/uart/mod.rs @@ -82,56 +82,6 @@ impl RxPin for Pin {} #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TransferPendingError; -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RxError { - Overrun, - Framing, - Parity, -} -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { - Rx(RxError), - BreakCondition, -} - -impl From for Error { - fn from(value: RxError) -> Self { - Self::Rx(value) - } -} - -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other - } -} - -impl embedded_io::Error for RxError { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other - } -} -impl embedded_hal_nb::serial::Error for RxError { - fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { - match self { - RxError::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, - RxError::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, - RxError::Parity => embedded_hal_nb::serial::ErrorKind::Parity, - } - } -} - -impl embedded_hal_nb::serial::Error for Error { - fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { - match self { - Error::Rx(rx_error) => embedded_hal_nb::serial::Error::kind(rx_error), - Error::BreakCondition => embedded_hal_nb::serial::ErrorKind::Other, - } - } -} - #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Event { @@ -626,22 +576,27 @@ impl UartBase { self.uart } + /// Poll receiver errors. + pub fn poll_rx_errors(&self) -> Option { + self.rx.poll_errors() + } + pub fn split(self) -> (Tx, Rx) { (self.tx, self.rx) } } impl embedded_io::ErrorType for UartBase { - type Error = Error; + type Error = Infallible; } impl embedded_hal_nb::serial::ErrorType for UartBase { - type Error = Error; + type Error = Infallible; } impl embedded_hal_nb::serial::Read for UartBase { fn read(&mut self) -> nb::Result { - self.rx.read().map_err(|e| e.map(Error::Rx)) + self.rx.read() } } @@ -729,6 +684,8 @@ impl, RxPinInst: RxPin, UartInstanc delegate::delegate! { to self.inner { + /// Poll receiver errors. + pub fn poll_rx_errors(&self) -> Option; #[inline] pub fn enable_rx(&mut self); #[inline] @@ -813,6 +770,23 @@ impl Rx { &self.0 } + pub fn poll_errors(&self) -> Option { + let mut errors = UartErrors::default(); + + let uart = unsafe { &(*Uart::ptr()) }; + let status_reader = uart.rxstatus().read(); + if status_reader.rxovr().bit_is_set() { + errors.overflow = true; + } else if status_reader.rxfrm().bit_is_set() { + errors.framing = true; + } else if status_reader.rxpar().bit_is_set() { + errors.parity = true; + } else { + return None; + }; + Some(errors) + } + #[inline] pub fn clear_fifo(&self) { self.0.fifo_clr().write(|w| w.rxfifo().set_bit()); @@ -874,34 +848,15 @@ impl Rx { } impl embedded_io::ErrorType for Rx { - type Error = RxError; + type Error = Infallible; } impl embedded_hal_nb::serial::ErrorType for Rx { - type Error = RxError; + type Error = Infallible; } impl embedded_hal_nb::serial::Read for Rx { fn read(&mut self) -> nb::Result { - let uart = unsafe { &(*Uart::ptr()) }; - let status_reader = uart.rxstatus().read(); - let err = if status_reader.rxovr().bit_is_set() { - Some(RxError::Overrun) - } else if status_reader.rxfrm().bit_is_set() { - Some(RxError::Framing) - } else if status_reader.rxpar().bit_is_set() { - Some(RxError::Parity) - } else { - None - }; - if let Some(err) = err { - // The status code is always related to the next bit for the framing - // and parity status bits. We have to read the DATA register - // so that the next status reflects the next DATA word - // For overrun error, we read as well to clear the peripheral - self.read_fifo_unchecked(); - return Err(err.into()); - } self.read_fifo().map(|val| (val & 0xff) as u8).map_err(|e| { if let nb::Error::Other(_) = e { unreachable!() @@ -913,16 +868,18 @@ impl embedded_hal_nb::serial::Read for Rx { impl embedded_io::Read for Rx { fn read(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Ok(0); - } - + let mut read = 0; for byte in buf.iter_mut() { - let w = nb::block!(>::read(self))?; - *byte = w; + match >::read(self) { + Ok(w) => { + *byte = w; + read += 1; + } + Err(nb::Error::WouldBlock) => break, + } } - Ok(buf.len()) + Ok(read) } } @@ -1182,7 +1139,7 @@ impl RxWithInterrupt { /// This function will not disable the RX interrupts, so you don't need to call any other /// API after calling this function to continue emptying the FIFO. RX errors are handled /// as partial errors and are returned as part of the [IrqResult]. - pub fn irq_handler(&mut self, buf: &mut [u8; 16]) -> IrqResult { + pub fn on_interrupt(&mut self, buf: &mut [u8; 16]) -> IrqResult { let mut result = IrqResult::default(); let irq_end = self.uart().irq_end().read(); @@ -1203,15 +1160,10 @@ impl RxWithInterrupt { // Timeout, empty the FIFO completely. if irq_end.irq_rx_to().bit_is_set() { - loop { - // While there is data in the FIFO, write it into the reception buffer - let read_result = self.0.read(); - if let Some(byte) = self.read_handler(&mut result.errors, &read_result) { - buf[result.bytes_read] = byte; - result.bytes_read += 1; - } else { - break; - } + // While there is data in the FIFO, write it into the reception buffer + while let Ok(byte) = self.0.read_fifo() { + buf[result.bytes_read] = byte as u8; + result.bytes_read += 1; } } @@ -1239,7 +1191,7 @@ impl RxWithInterrupt { /// If passed buffer is equal to or larger than the specified maximum length, an /// [BufferTooShortError] will be returned. Other RX errors are treated as partial errors /// and returned inside the [IrqResultMaxSizeOrTimeout] structure. - pub fn irq_handler_max_size_or_timeout_based( + pub fn on_interrupt_max_size_or_timeout_based( &mut self, context: &mut IrqContextTimeoutOrMaxSize, buf: &mut [u8], @@ -1288,12 +1240,13 @@ impl RxWithInterrupt { if context.rx_idx == context.max_len { break; } - let read_result = self.0.read(); - if let Some(byte) = self.read_handler(&mut result.errors, &read_result) { - buf[context.rx_idx] = byte; - context.rx_idx += 1; - } else { - break; + // While there is data in the FIFO, write it into the reception buffer + match self.0.read() { + Ok(byte) => { + buf[result.bytes_read] = byte; + result.bytes_read += 1; + } + Err(_) => break, } } self.irq_completion_handler_max_size_timeout(&mut result, context); @@ -1312,29 +1265,6 @@ impl RxWithInterrupt { Ok(result) } - fn read_handler( - &self, - errors: &mut Option, - read_res: &nb::Result, - ) -> Option { - match read_res { - Ok(byte) => Some(*byte), - Err(nb::Error::WouldBlock) => None, - Err(nb::Error::Other(e)) => { - // Ensure `errors` is Some(IrqUartError), initializing if it's None - let err = errors.get_or_insert(UartErrors::default()); - - // Now we can safely modify fields inside `err` - match e { - RxError::Overrun => err.overflow = true, - RxError::Framing => err.framing = true, - RxError::Parity => err.parity = true, - } - None - } - } - } - fn check_for_errors(&self, errors: &mut Option) { let rx_status = self.uart().rxstatus().read(); diff --git a/va416xx-hal/src/uart/rx_asynch.rs b/va416xx-hal/src/uart/rx_asynch.rs index d70e6ac..5e409b5 100644 --- a/va416xx-hal/src/uart/rx_asynch.rs +++ b/va416xx-hal/src/uart/rx_asynch.rs @@ -28,7 +28,7 @@ use va416xx::uart0 as uart_base; use crate::enable_nvic_interrupt; -use super::{Bank, Instance, Rx, RxError, UartErrors}; +use super::{Bank, Instance, Rx, UartErrors}; static UART_RX_WAKERS: [AtomicWaker; 3] = [const { AtomicWaker::new() }; 3]; static RX_READ_ACTIVE: [AtomicBool; 3] = [const { AtomicBool::new(false) }; 3]; @@ -48,7 +48,7 @@ impl RxFuture { } impl Future for RxFuture { - type Output = Result<(), RxError>; + type Output = Result<(), Infallible>; fn poll( self: core::pin::Pin<&mut Self>, diff --git a/vorago-peb1/CHANGELOG.md b/vorago-peb1/CHANGELOG.md index 3a27d2a..350ba7b 100644 --- a/vorago-peb1/CHANGELOG.md +++ b/vorago-peb1/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v0.1.2] 2025-03-07 + +- Bump allowed HAL version to v0.5 + # [v0.1.1] 2025-02-18 - Bump allowed HAL version to v0.4 @@ -15,3 +19,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [v0.1.0] 2024-10-01 - Initial release + +[unreleased]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/vorago-peb1-v0.1.2...HEAD +[v0.1.2]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/vorago-peb1-v0.1.1...vorago-peb1-v0.1.2 +[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/compare/vorago-peb1-v0.1.0...vorago-peb1-v0.1.1 +[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/tag/vorago-peb1-v0.1.0 diff --git a/vorago-peb1/Cargo.toml b/vorago-peb1/Cargo.toml index b285611..69d0cc5 100644 --- a/vorago-peb1/Cargo.toml +++ b/vorago-peb1/Cargo.toml @@ -16,7 +16,7 @@ cortex-m-rt = "0.7" embedded-hal = "1" lis2dh12 = { version = "0.7", features = ["out_f32"] } -va416xx-hal = { version = ">=0.3, <=0.4", features = ["va41630"] } +va416xx-hal = { version = ">=0.3, <=0.5", features = ["va41630"] } [features] rt = ["va416xx-hal/rt"]