From a7258927209827e27f4190af57020c2a8017dbaa Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 5 Aug 2024 15:37:03 -0400 Subject: [PATCH 1/4] Convert uart half_duplex to use open-drain pull-up --- embassy-stm32/src/usart/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 7ed3793a1..3283fb6b7 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1029,8 +1029,9 @@ impl<'d> Uart<'d, Async> { /// (when it is available for your chip). There is no functional difference between these methods, as both /// allow bidirectional communication. /// - /// The pin is always released when no data is transmitted. Thus, it acts as a standard - /// I/O in idle or in reception. + /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. It means that the I/O must be configured so that TX is + /// configured as alternate function open-drain with an external pull-up /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict /// on the line must be managed by software (for instance by using a centralized arbiter). #[doc(alias("HDSEL"))] @@ -1051,7 +1052,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(tx, AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up)), None, None, None, From 446169b2c1c85ced844e1a888d7fec75047e11c1 Mon Sep 17 00:00:00 2001 From: Karun Date: Tue, 6 Aug 2024 11:52:16 -0400 Subject: [PATCH 2/4] Add gpio version dependency Add configurable output type for half-duplex --- embassy-stm32/src/usart/mod.rs | 81 ++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 3283fb6b7..0c5bbf491 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -211,6 +211,19 @@ impl Default for Config { } } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Half duplex IO mode +pub enum HalfDuplexConfig { + /// Push pull allows for faster baudrates, may require series resistor + PushPull, + /// Open drain output using external pull up resistor + OpenDrainExternal, + #[cfg(not(gpio_v1))] + /// Open drain output using internal pull up resistor + OpenDrainInternal, +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1042,6 +1055,7 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1052,7 +1066,21 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up)), + new_pin!( + tx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, @@ -1080,6 +1108,7 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.half_duplex = true; @@ -1088,7 +1117,21 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + rx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, new_dma!(tx_dma), @@ -1193,6 +1236,7 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1203,7 +1247,21 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + tx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, @@ -1228,6 +1286,7 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.half_duplex = true; @@ -1236,7 +1295,21 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + rx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, From fcf9b3239e9c845d8f2b4eb5aea853f7ce377bf1 Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 19 Aug 2024 11:27:18 -0400 Subject: [PATCH 3/4] remove duplication --- embassy-stm32/src/usart/mod.rs | 77 +++++++--------------------------- 1 file changed, 16 insertions(+), 61 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0c5bbf491..4f2ff8b2a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; use futures_util::future::{select, Either}; use crate::dma::ChannelAndRequest; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; @@ -224,6 +224,17 @@ pub enum HalfDuplexConfig { OpenDrainInternal, } +impl HalfDuplexConfig { + pub fn af_type(self) -> gpio::AfType { + match self { + HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), + HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), + } + } +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1066,21 +1077,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!( - tx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(tx, half_duplex.af_type()), None, None, None, @@ -1117,21 +1114,7 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!( - rx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(rx, half_duplex.af_type()), None, None, new_dma!(tx_dma), @@ -1247,21 +1230,7 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!( - tx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(tx, half_duplex.af_type()), None, None, None, @@ -1295,21 +1264,7 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!( - rx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(rx, half_duplex.af_type()), None, None, None, From bbc06035c136887aad91a1944efcc4c98401866f Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 19 Aug 2024 12:15:39 -0400 Subject: [PATCH 4/4] make half duplex fn private --- embassy-stm32/src/usart/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 4f2ff8b2a..89d92dda2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -225,7 +225,7 @@ pub enum HalfDuplexConfig { } impl HalfDuplexConfig { - pub fn af_type(self) -> gpio::AfType { + fn af_type(self) -> gpio::AfType { match self { HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium),