From 58ec674c7ef90a9f921b410f60c3cacaa7d1e8ff Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Mon, 15 Aug 2022 09:13:21 +0300 Subject: [PATCH] Serial Tx, Rx containing pins --- CHANGELOG.md | 1 + src/serial.rs | 225 +++++++++++++++++++++++++++++++++++++++++++ src/serial/hal_02.rs | 58 ++++++++++- src/serial/hal_1.rs | 54 ++++++++++- 4 files changed, 333 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fc95b716..dde5ebc63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Serial Tx, Rx containing pins - Implementation of From trait for Pin-to-PartiallyErasedPin [#507] - Implementation of From trait for Pin-to-ErasedPin [#507] - Implementation of From trait for PartiallyErasedPin-to-ErasedPin [#507] diff --git a/src/serial.rs b/src/serial.rs index b182318a2..795399097 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -332,6 +332,119 @@ impl AsMut> for Serial { } } + +/// Serial receiver containing RX pin +pub struct URx { + _usart: PhantomData, + pin: RX, + _word: PhantomData, +} + +/// Serial transmitter containing TX pin +pub struct UTx { + usart: USART, + pin: TX, + _word: PhantomData, +} + +impl URx { + fn new(pin: RX) -> Self { + Self { + _usart: PhantomData, + pin, + _word: PhantomData, + } + } + + pub fn erase(self) -> Rx { + Rx::new() + } + + /// Start listening for an rx not empty interrupt event + /// + /// Note, you will also have to enable the corresponding interrupt + /// in the NVIC to start receiving events. + pub fn listen(&mut self) { + unsafe { (*USART::ptr()).cr1.modify(|_, w| w.rxneie().set_bit()) } + } + + /// Stop listening for the rx not empty interrupt event + pub fn unlisten(&mut self) { + unsafe { (*USART::ptr()).cr1.modify(|_, w| w.rxneie().clear_bit()) } + } + + /// Start listening for a line idle interrupt event + /// + /// Note, you will also have to enable the corresponding interrupt + /// in the NVIC to start receiving events. + pub fn listen_idle(&mut self) { + unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()) } + } + + /// Stop listening for the line idle interrupt event + pub fn unlisten_idle(&mut self) { + unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()) } + } + + /// Return true if the line idle status is set + pub fn is_idle(&self) -> bool { + unsafe { (*USART::ptr()).sr.read().idle().bit_is_set() } + } + + /// Return true if the rx register is not empty (and can be read) + pub fn is_rx_not_empty(&self) -> bool { + unsafe { (*USART::ptr()).sr.read().rxne().bit_is_set() } + } + + /// Clear idle line interrupt flag + pub fn clear_idle_interrupt(&self) { + unsafe { + let _ = (*USART::ptr()).sr.read(); + let _ = (*USART::ptr()).dr.read(); + } + } +} + +impl UTx { + fn new(usart: USART, pin: TX) -> Self { + Self { + usart, + pin, + _word: PhantomData, + } + } + + pub fn erase(self) -> Tx { + Tx::new() + } + + pub fn join(self, rx: URx) -> Serial + where + (TX, RX): Pins + { + Serial { usart: self.usart, pins: (self.pin, rx.pin), tx: Tx::new(), rx: Rx::new() } + } + + /// Start listening for a tx empty interrupt event + /// + /// Note, you will also have to enable the corresponding interrupt + /// in the NVIC to start receiving events. + // TODO: replace with "self.usart" + pub fn listen(&mut self) { + unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().set_bit()) } + } + + /// Stop listening for the tx empty interrupt event + pub fn unlisten(&mut self) { + unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().clear_bit()) } + } + + /// Return true if the tx register is empty (and can accept data) + pub fn is_tx_empty(&self) -> bool { + unsafe { (*USART::ptr()).sr.read().txe().bit_is_set() } + } +} + pub trait SerialExt: Sized + Instance { fn serial( self, @@ -614,6 +727,12 @@ impl Serial { } } +impl Serial { + pub fn split_nondestructive(self) -> (UTx, URx) { + (UTx::new(self.usart, self.pins.0), URx::new(self.pins.1)) + } +} + impl Serial { /// Converts this Serial into a version that can read and write `u16` values instead of `u8`s /// @@ -912,3 +1031,109 @@ impl Tx { nb::block!(self.flush()) } } + +impl fmt::Write for UTx { + fn write_str(&mut self, s: &str) -> fmt::Result { + s.bytes() + .try_for_each(|c| block!(self.write(c))) + .map_err(|_| fmt::Error) + } +} + +impl URx { + fn read(&mut self) -> nb::Result { + // Delegate to the Read implementation, then truncate to 8 bits + Rx::::new().read().map(|word16| word16 as u8) + } +} + +impl URx { + fn read(&mut self) -> nb::Result { + // NOTE(unsafe) atomic read with no side effects + let sr = unsafe { (*USART::ptr()).sr.read() }; + + // Any error requires the dr to be read to clear + if sr.pe().bit_is_set() + || sr.fe().bit_is_set() + || sr.nf().bit_is_set() + || sr.ore().bit_is_set() + { + unsafe { (*USART::ptr()).dr.read() }; + } + + Err(if sr.pe().bit_is_set() { + Error::Parity.into() + } else if sr.fe().bit_is_set() { + Error::FrameFormat.into() + } else if sr.nf().bit_is_set() { + Error::Noise.into() + } else if sr.ore().bit_is_set() { + Error::Overrun.into() + } else if sr.rxne().bit_is_set() { + // NOTE(unsafe) atomic read from stateless register + return Ok(unsafe { &*USART::ptr() }.dr.read().dr().bits()); + } else { + nb::Error::WouldBlock + }) + } +} + +impl UTx { + fn write(&mut self, word: u8) -> nb::Result<(), Error> { + // Delegate to u16 version + Tx::::new().write(u16::from(word)) + } + + fn flush(&mut self) -> nb::Result<(), Error> { + // Delegate to u16 version + Tx::::new().flush() + } + + fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Error> { + for &b in bytes { + nb::block!(self.write(b))?; + } + Ok(()) + } + + fn bflush(&mut self) -> Result<(), Error> { + nb::block!(self.flush()) + } +} + +impl UTx { + fn write(&mut self, word: u16) -> nb::Result<(), Error> { + // NOTE(unsafe) atomic read with no side effects + let sr = unsafe { (*USART::ptr()).sr.read() }; + + if sr.txe().bit_is_set() { + // NOTE(unsafe) atomic write to stateless register + unsafe { &*USART::ptr() }.dr.write(|w| w.dr().bits(word)); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + + fn flush(&mut self) -> nb::Result<(), Error> { + // NOTE(unsafe) atomic read with no side effects + let sr = unsafe { (*USART::ptr()).sr.read() }; + + if sr.tc().bit_is_set() { + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + + fn bwrite_all(&mut self, buffer: &[u16]) -> Result<(), Error> { + for &b in buffer { + nb::block!(self.write(b))?; + } + Ok(()) + } + + fn bflush(&mut self) -> Result<(), Error> { + nb::block!(self.flush()) + } +} diff --git a/src/serial/hal_02.rs b/src/serial/hal_02.rs index ecea3d771..c58b7bc53 100644 --- a/src/serial/hal_02.rs +++ b/src/serial/hal_02.rs @@ -1,5 +1,5 @@ mod nb { - use super::super::{Error, Instance, Rx, Serial, Tx}; + use super::super::{Error, Instance, Rx, Serial, Tx, URx, UTx}; use embedded_hal::serial::{Read, Write}; impl Read for Serial @@ -22,6 +22,14 @@ mod nb { } } + impl Read for URx { + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.read() + } + } + /// Reads 9-bit words from the UART/USART /// /// If the UART/USART was configured with `WordLength::DataBits9`, the returned value will contain @@ -35,6 +43,14 @@ mod nb { } } + impl Read for URx { + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.read() + } + } + impl Write for Serial where USART: Instance, @@ -51,7 +67,7 @@ mod nb { } } - impl Write for Tx { + impl Write for UTx { type Error = Error; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { @@ -79,10 +95,22 @@ mod nb { self.flush() } } + + impl Write for UTx { + type Error = Error; + + fn write(&mut self, word: u16) -> nb::Result<(), Self::Error> { + self.write(word) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.flush() + } + } } mod blocking { - use super::super::{Error, Instance, Serial, Tx}; + use super::super::{Error, Instance, Serial, Tx, UTx}; use embedded_hal::blocking::serial::Write; impl Write for Tx { @@ -97,6 +125,18 @@ mod blocking { } } + impl Write for UTx { + type Error = Error; + + fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + self.bwrite_all(bytes) + } + + fn bflush(&mut self) -> Result<(), Self::Error> { + self.bflush() + } + } + impl Write for Serial { type Error = Error; @@ -121,6 +161,18 @@ mod blocking { } } + impl Write for UTx { + type Error = Error; + + fn bwrite_all(&mut self, slice: &[u16]) -> Result<(), Self::Error> { + self.bwrite_all(slice) + } + + fn bflush(&mut self) -> Result<(), Self::Error> { + self.bflush() + } + } + impl Write for Serial { type Error = Error; diff --git a/src/serial/hal_1.rs b/src/serial/hal_1.rs index 4647952df..e44c1cbcf 100644 --- a/src/serial/hal_1.rs +++ b/src/serial/hal_1.rs @@ -12,8 +12,16 @@ impl ErrorType for super::Tx { type Error = super::Error; } +impl ErrorType for super::URx { + type Error = super::Error; +} + +impl ErrorType for super::UTx { + type Error = super::Error; +} + mod nb { - use super::super::{Error, Instance, Rx, Serial, Tx}; + use super::super::{Error, Instance, Rx, Serial, Tx, URx, UTx}; use embedded_hal_one::serial::{ nb::{Read, Write}, ErrorType, @@ -35,6 +43,12 @@ mod nb { } } + impl Read for URx { + fn read(&mut self) -> nb::Result { + self.read() + } + } + /// Reads 9-bit words from the UART/USART /// /// If the UART/USART was configured with `WordLength::DataBits9`, the returned value will contain @@ -46,6 +60,12 @@ mod nb { } } + impl Read for URx { + fn read(&mut self) -> nb::Result { + self.read() + } + } + impl Write for Serial where USART: Instance, @@ -70,6 +90,16 @@ mod nb { } } + impl Write for UTx { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.write(word) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.flush() + } + } + /// Writes 9-bit words to the UART/USART /// /// If the UART/USART was configured with `WordLength::DataBits9`, the 9 least significant bits will @@ -87,7 +117,7 @@ mod nb { } mod blocking { - use super::super::{Instance, Serial, Tx}; + use super::super::{Instance, Serial, Tx, UTx}; use super::ErrorType; use embedded_hal_one::serial::blocking::Write; @@ -115,6 +145,16 @@ mod blocking { } } + impl Write for UTx { + fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + self.bwrite_all(bytes) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.bflush() + } + } + impl Write for Tx { fn write(&mut self, slice: &[u16]) -> Result<(), Self::Error> { self.bwrite_all(slice) @@ -124,4 +164,14 @@ mod blocking { self.bflush() } } + + impl Write for UTx { + fn write(&mut self, slice: &[u16]) -> Result<(), Self::Error> { + self.bwrite_all(slice) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.bflush() + } + } }