diff --git a/src/serial.rs b/src/serial.rs index d4192bb2..f20a236e 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -195,6 +195,12 @@ pub struct Tx { pin: USART::Tx, } +pub struct HalfDuplex { + _word: PhantomData, + usart: USART, + pin: USART::Tx, +} + pub trait SerialExt: Sized + Instance { fn serial( self, @@ -203,6 +209,13 @@ pub trait SerialExt: Sized + Instance { clocks: &Clocks, ) -> Result, config::InvalidConfig>; + fn half_duplex( + self, + tx_pin: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig>; + fn tx( self, tx_pin: impl Into>, @@ -244,6 +257,17 @@ impl Serial { } } +impl HalfDuplex { + pub fn new( + usart: USART, + tx_pin: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result { + ::RB::half_duplex(usart, tx_pin, config, clocks) + } +} + impl Serial { pub fn split(self) -> (Tx, Rx) { (self.tx, self.rx) diff --git a/src/serial/uart_impls.rs b/src/serial/uart_impls.rs index 7a5c7bb9..f5e96713 100644 --- a/src/serial/uart_impls.rs +++ b/src/serial/uart_impls.rs @@ -4,7 +4,8 @@ use enumflags2::BitFlags; use nb::block; use super::{ - config, CFlag, Error, Event, Flag, Rx, RxISR, RxListen, Serial, SerialExt, Tx, TxISR, TxListen, + config, CFlag, Error, Event, Flag, HalfDuplex, Rx, RxISR, RxListen, Serial, SerialExt, Tx, + TxISR, TxListen, }; use crate::dma::{ traits::{DMASet, PeriAddress}, @@ -50,6 +51,13 @@ pub trait RegisterBlockImpl: crate::Sealed { clocks: &Clocks, ) -> Result, config::InvalidConfig>; + fn half_duplex, WORD>( + uart: UART, + pins: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig>; + fn read_u16(&self) -> nb::Result; fn write_u16(&self, word: u16) -> nb::Result<(), Error>; @@ -153,6 +161,55 @@ pub trait RegisterBlockImpl: crate::Sealed { macro_rules! uartCommon { () => { + fn half_duplex, WORD>( + uart: UART, + tx_pin: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig> { + use self::config::*; + + let config = config.into(); + unsafe { + // Enable clock. + UART::enable_unchecked(); + UART::reset_unchecked(); + } + + let pclk_freq = UART::clock(clocks).raw(); + let baud = config.baudrate.0; + + let (over8, div) = Self::calculate_brr(pclk_freq, baud)?; + + uart.brr().write(|w| unsafe { w.bits(div) }); + + // Reset other registers to disable advanced USART features + uart.cr2().reset(); + + uart.cr3().write(|w| w.hdsel().half_duplex()); + + // Enable transmission and receiving + // and configure frame + + uart.cr1().write(|w| { + w.ue().set_bit(); + w.over8().bit(over8); + w.te().set_bit(); + w.re().set_bit(); + w.m().bit(config.wordlength == WordLength::DataBits9); + w.pce().bit(config.parity != Parity::ParityNone); + w.ps().bit(config.parity == Parity::ParityOdd) + }); + + let serial = HalfDuplex { + _word: core::marker::PhantomData, + usart: uart, + pin: tx_pin.into(), + }; + serial.usart.set_stopbits(config.stopbits); + Ok(serial) + } + fn read_u16(&self) -> nb::Result { // NOTE(unsafe) atomic read with no side effects let sr = self.sr().read(); @@ -577,6 +634,65 @@ impl crate::Listen for Serial { } } +impl RxISR for HalfDuplex { + fn is_idle(&self) -> bool { + self.usart.is_idle() + } + + fn is_rx_not_empty(&self) -> bool { + self.usart.is_rx_not_empty() + } + + /// This clears `Idle`, `Overrun`, `Noise`, `FrameError` and `ParityError` flags + fn clear_idle_interrupt(&self) { + self.usart.clear_idle_interrupt(); + } +} + +impl TxISR for HalfDuplex { + fn is_tx_empty(&self) -> bool { + self.usart.is_tx_empty() + } +} + +impl crate::ClearFlags for HalfDuplex { + type Flag = CFlag; + + #[inline(always)] + fn clear_flags(&mut self, flags: impl Into>) { + self.usart.clear_flags(flags.into()) + } +} + +impl crate::ReadFlags for HalfDuplex { + type Flag = Flag; + + #[inline(always)] + fn flags(&self) -> BitFlags { + self.usart.flags() + } +} + +impl crate::Listen for HalfDuplex { + type Event = Event; + + #[inline(always)] + fn listen(&mut self, event: impl Into>) { + self.usart.listen_event(None, Some(event.into())); + } + + #[inline(always)] + fn listen_only(&mut self, event: impl Into>) { + self.usart + .listen_event(Some(BitFlags::ALL), Some(event.into())); + } + + #[inline(always)] + fn unlisten(&mut self, event: impl Into>) { + self.usart.listen_event(Some(event.into()), None); + } +} + impl fmt::Write for Serial where Tx: fmt::Write, @@ -603,6 +719,15 @@ impl SerialExt for UART { ) -> Result, config::InvalidConfig> { Serial::new(self, pins, config, clocks) } + + fn half_duplex( + self, + tx_pin: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig> { + HalfDuplex::new(self, tx_pin, config, clocks) + } } impl Serial {