From 2ec81419fa7ca1d1d4c797c1d416c1f226aefb33 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Sat, 21 Dec 2024 22:01:36 +0100 Subject: [PATCH] stm32/usart: configurable readback in half-duplex mode --- embassy-stm32/src/usart/mod.rs | 54 +++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2d801e6bf..98b5c9cfe 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -125,6 +125,33 @@ pub enum StopBits { STOP1P5, } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Enables or disables receiver so written data are read back in half-duplex mode +pub enum HalfDuplexReadback { + /// Disables receiver so written data are not read back + NoReadback, + /// Enables receiver so written data are read back + Readback, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Duplex mode +pub enum Duplex { + /// Full duplex + Full, + /// Half duplex with possibility to read back written data + Half(HalfDuplexReadback), +} + +impl Duplex { + /// Returns true if half-duplex + fn is_half(&self) -> bool { + matches!(self, Duplex::Half(_)) + } +} + #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -181,7 +208,7 @@ pub struct Config { pub rx_pull: Pull, // private: set by new_half_duplex, not by the user. - half_duplex: bool, + duplex: Duplex, } impl Config { @@ -220,7 +247,7 @@ impl Default for Config { #[cfg(any(usart_v3, usart_v4))] invert_rx: false, rx_pull: Pull::None, - half_duplex: false, + duplex: Duplex::Full, } } } @@ -308,6 +335,7 @@ pub struct UartTx<'d, M: Mode> { cts: Option>, de: Option>, tx_dma: Option>, + duplex: Duplex, _phantom: PhantomData, } @@ -413,7 +441,7 @@ impl<'d> UartTx<'d, Async> { let mut cr1 = r.cr1().read(); if r.cr3().read().hdsel() && !cr1.te() { cr1.set_te(true); - cr1.set_re(false); + cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); r.cr1().write_value(cr1); } @@ -485,6 +513,7 @@ impl<'d, M: Mode> UartTx<'d, M> { cts, de: None, tx_dma, + duplex: config.duplex, _phantom: PhantomData, }; this.enable_and_configure(&config)?; @@ -519,7 +548,7 @@ impl<'d, M: Mode> UartTx<'d, M> { let mut cr1 = r.cr1().read(); if r.cr3().read().hdsel() && !cr1.te() { cr1.set_te(true); - cr1.set_re(false); + cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); r.cr1().write_value(cr1); } @@ -1149,13 +1178,14 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { config.swap_rx_tx = false; } - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1188,10 +1218,11 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1307,13 +1338,14 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { config.swap_rx_tx = false; } - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1343,10 +1375,11 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1388,6 +1421,7 @@ impl<'d, M: Mode> Uart<'d, M> { cts, de, tx_dma, + duplex: config.duplex, }, rx: UartRx { _phantom: PhantomData, @@ -1667,14 +1701,14 @@ fn configure( r.cr3().modify(|w| { #[cfg(not(usart_v1))] w.set_onebit(config.assume_noise_free); - w.set_hdsel(config.half_duplex); + w.set_hdsel(config.duplex.is_half()); }); r.cr1().write(|w| { // enable uart w.set_ue(true); - if config.half_duplex { + if config.duplex.is_half() { // The te and re bits will be set by write, read and flush methods. // Receiver should be enabled by default for Half-Duplex. w.set_te(false);