From 8b49765392a5b503a284c18dee8fa99b8c098a2a Mon Sep 17 00:00:00 2001 From: Stephan Date: Sun, 29 Dec 2024 00:11:28 +0100 Subject: [PATCH] implement embedded-io for uart --- pic32-hal/Cargo.toml | 3 +- pic32-hal/src/uart.rs | 158 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/pic32-hal/Cargo.toml b/pic32-hal/Cargo.toml index 30d9725..95c76f7 100644 --- a/pic32-hal/Cargo.toml +++ b/pic32-hal/Cargo.toml @@ -19,9 +19,10 @@ pic32mx47x = ["pic32mx470/pic32mx47xfxxxl", "device-selected"] device-selected = [] [dependencies] -nb = "1.0.0" +nb = "1.1.0" embedded-hal = "1.0.0" embedded_hal_0_2 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] } +embedded-io = "0.6.1" mips-mcu = "0.3.0" mips-rt = "0.3.0" critical-section = "1.0.0" diff --git a/pic32-hal/src/uart.rs b/pic32-hal/src/uart.rs index 2d53fcd..ef55a1c 100644 --- a/pic32-hal/src/uart.rs +++ b/pic32-hal/src/uart.rs @@ -1,5 +1,6 @@ //! UART driver +use core::convert::Infallible; use core::fmt; use core::marker::PhantomData; @@ -8,6 +9,7 @@ use crate::pac::{UART1, UART2}; use crate::pps::{input, output, IsConnected, MappedPin}; use embedded_hal_0_2::prelude::*; +use embedded_io::{ReadReady, WriteReady}; use nb::block; /// Uart @@ -27,6 +29,28 @@ pub struct Tx { _uart: PhantomData, } +/// UART read errors +#[derive(Debug)] +pub enum ReadError { + /// RX FIFO overrun + Overrun, + + /// Parity error + Parity, + + /// Framing error + Framing, + + /// Break detected + Break, +} + +impl embedded_io::Error for ReadError { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + macro_rules! uart_impl { ($Id:ident, $Uart:ident, $Rx:ty, $Tx:ty) => { impl Uart<$Uart, MappedPin, MappedPin> { @@ -140,6 +164,140 @@ macro_rules! uart_impl { result } } + + impl embedded_io::ErrorType for Tx<$Uart> { + type Error = Infallible; + } + + impl embedded_io::WriteReady for Tx<$Uart> { + fn write_ready(&mut self) -> Result { + let utxbf = unsafe { (*$Uart::ptr()).sta.read().utxbf().bit() }; + Ok(!utxbf) + } + } + + impl embedded_io::Write for Tx<$Uart> { + fn write(&mut self, buf: &[u8]) -> Result { + while !self.write_ready()? {} + let mut len = 0; + for byte in buf { + if !self.write_ready()? { + break; + } + unsafe { + (*$Uart::ptr()) + .txreg + .write(|w| w.txreg().bits(*byte as u16)); + } + len += 1; + } + Ok(len) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + loop { + let trmt = unsafe { (*$Uart::ptr()).sta.read().trmt().bit() }; + if !trmt { + break; + } + } + Ok(()) + } + } + + impl embedded_io::ErrorType for Rx<$Uart> { + type Error = ReadError; + } + + impl embedded_io::ReadReady for Rx<$Uart> { + fn read_ready(&mut self) -> Result { + let data_avail = unsafe { (*$Uart::ptr()).sta.read().urxda().bit() }; + Ok(data_avail) + } + } + + impl embedded_io::Read for Rx<$Uart> { + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + // check for FIFO overrun + if unsafe { (*$Uart::ptr()).sta.read().oerr().bit() } { + // clear overrun error condition and RX FIFO + unsafe { + (*$Uart::ptr()).staclr.write(|w| w.oerr().bit(true)); + } + return Err(ReadError::Overrun); + } + + // wait until data is available + while !self.read_ready()? {} + + // read as many bytes as possible without blocking + let mut len = 0; + for bufbyte in buf { + if !self.read_ready()? { + break; + } + // check for framing error or break skipping the erroneous byte + if unsafe { (*$Uart::ptr()).sta.read().ferr().bit() } { + let word = unsafe { (*$Uart::ptr()).rxreg.read().bits() }; + if word == 0 { + return Err(ReadError::Break); + } else { + return Err(ReadError::Framing); + } + } + // check for parity error skipping the erroneous byte + if unsafe { (*$Uart::ptr()).sta.read().perr().bit() } { + let _skip = unsafe { (*$Uart::ptr()).rxreg.read().bits() }; + return Err(ReadError::Parity); + } + *bufbyte = unsafe { (*$Uart::ptr()).rxreg.read().bits() } as u8; + len += 1; + } + Ok(len) + } + } + + impl embedded_io::ErrorType for Uart<$Uart, RX, TX> { + type Error = ReadError; + } + + impl embedded_io::WriteReady for Uart<$Uart, RX, TX> { + fn write_ready(&mut self) -> Result { + let mut tx: Tx<$Uart> = Tx { _uart: PhantomData }; + Ok(tx.write_ready().unwrap_or(false)) + } + } + + impl embedded_io::Write for Uart<$Uart, RX, TX> { + fn write(&mut self, buf: &[u8]) -> Result { + let mut tx: Tx<$Uart> = Tx { _uart: PhantomData }; + Ok(embedded_io::Write::write(&mut tx, buf).unwrap_or(0)) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + let mut tx: Tx<$Uart> = Tx { _uart: PhantomData }; + let _ = embedded_io::Write::flush(&mut tx); + Ok(()) + } + } + + impl embedded_io::ReadReady for Uart<$Uart, RX, TX> { + fn read_ready(&mut self) -> Result { + let mut rx: Rx<$Uart> = Rx { _uart: PhantomData }; + rx.read_ready() + } + } + + impl embedded_io::Read for Uart<$Uart, RX, TX> { + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut rx: Rx<$Uart> = Rx { _uart: PhantomData }; + embedded_io::Read::read(&mut rx, buf) + } + } }; }