From c4c0ef1cc59300a1dedb93a45ddeb8dcd11c7e41 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 25 Jul 2024 23:00:07 +0300 Subject: [PATCH 1/2] half-duplex init --- src/serial.rs | 24 ++++++++++++++ src/serial/uart_impls.rs | 67 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) 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..21adb421 100644 --- a/src/serial/uart_impls.rs +++ b/src/serial/uart_impls.rs @@ -4,7 +4,7 @@ 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 +50,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 +160,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(); @@ -603,6 +659,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 { From cbf1542650382d32c3d5f2b84942a9cb409ea5d1 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 28 Jul 2024 06:49:49 +0300 Subject: [PATCH 2/2] half-duplex isr --- src/serial/uart_impls.rs | 78 +++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/src/serial/uart_impls.rs b/src/serial/uart_impls.rs index 21adb421..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, HalfDuplex, 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}, @@ -167,29 +168,29 @@ macro_rules! uartCommon { 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); @@ -199,7 +200,7 @@ macro_rules! uartCommon { w.pce().bit(config.parity != Parity::ParityNone); w.ps().bit(config.parity == Parity::ParityOdd) }); - + let serial = HalfDuplex { _word: core::marker::PhantomData, usart: uart, @@ -633,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,