aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-01-01 22:55:06 +0000
committerGitHub <[email protected]>2024-01-01 22:55:06 +0000
commit9c2d2ff64d302437e2e0568372c76bf37bbfacf4 (patch)
treeb45d030cd837c08ded6738c76c26273bb921de32 /embassy-stm32
parentc046f6422bd50c95f24ece8a7870cce3cb15b373 (diff)
parentdc295fa1db1245ca5ea5241104140ae1e62ea5ac (diff)
Merge pull request #2358 from lights0123/half-duplex
stm32: add half duplex USART driver
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/src/usart/mod.rs87
1 files changed, 81 insertions, 6 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 8a0c85d2c..ea727b010 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -743,7 +743,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
743 T::enable_and_reset(); 743 T::enable_and_reset();
744 T::enable_and_reset(); 744 T::enable_and_reset();
745 745
746 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 746 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
747 } 747 }
748 748
749 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 749 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
@@ -770,7 +770,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
770 w.set_rtse(true); 770 w.set_rtse(true);
771 w.set_ctse(true); 771 w.set_ctse(true);
772 }); 772 });
773 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 773 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
774 } 774 }
775 775
776 #[cfg(not(any(usart_v1, usart_v2)))] 776 #[cfg(not(any(usart_v1, usart_v2)))]
@@ -795,10 +795,76 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
795 T::regs().cr3().write(|w| { 795 T::regs().cr3().write(|w| {
796 w.set_dem(true); 796 w.set_dem(true);
797 }); 797 });
798 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 798 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
799 } 799 }
800 800
801 fn new_inner( 801 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
802 ///
803 /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin.
804 /// There is no functional difference between these methods, as both allow bidirectional communication.
805 ///
806 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
807 /// I/O in idle or in reception.
808 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
809 /// on the line must be managed by software (for instance by using a centralized arbiter).
810 #[cfg(not(any(usart_v1, usart_v2)))]
811 #[doc(alias("HDSEL"))]
812 pub fn new_half_duplex(
813 peri: impl Peripheral<P = T> + 'd,
814 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
815 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
816 tx_dma: impl Peripheral<P = TxDma> + 'd,
817 rx_dma: impl Peripheral<P = RxDma> + 'd,
818 mut config: Config,
819 ) -> Result<Self, ConfigError> {
820 // UartRx and UartTx have one refcount ea.
821 T::enable_and_reset();
822 T::enable_and_reset();
823
824 config.swap_rx_tx = false;
825
826 into_ref!(peri, tx, tx_dma, rx_dma);
827
828 T::regs().cr3().write(|w| w.set_hdsel(true));
829 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
830
831 Self::new_inner(peri, tx_dma, rx_dma, config)
832 }
833
834 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
835 ///
836 /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin.
837 /// There is no functional difference between these methods, as both allow bidirectional communication.
838 ///
839 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
840 /// I/O in idle or in reception.
841 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
842 /// on the line must be managed by software (for instance by using a centralized arbiter).
843 #[cfg(not(any(usart_v1, usart_v2)))]
844 #[doc(alias("HDSEL"))]
845 pub fn new_half_duplex_on_rx(
846 peri: impl Peripheral<P = T> + 'd,
847 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
848 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
849 tx_dma: impl Peripheral<P = TxDma> + 'd,
850 rx_dma: impl Peripheral<P = RxDma> + 'd,
851 mut config: Config,
852 ) -> Result<Self, ConfigError> {
853 // UartRx and UartTx have one refcount ea.
854 T::enable_and_reset();
855 T::enable_and_reset();
856
857 config.swap_rx_tx = true;
858
859 into_ref!(peri, rx, tx_dma, rx_dma);
860
861 T::regs().cr3().write(|w| w.set_hdsel(true));
862 rx.set_as_af(rx.af_num(), AFType::OutputPushPull);
863
864 Self::new_inner(peri, tx_dma, rx_dma, config)
865 }
866
867 fn new_inner_configure(
802 peri: impl Peripheral<P = T> + 'd, 868 peri: impl Peripheral<P = T> + 'd,
803 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 869 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
804 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 870 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@@ -808,8 +874,6 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
808 ) -> Result<Self, ConfigError> { 874 ) -> Result<Self, ConfigError> {
809 into_ref!(peri, rx, tx, tx_dma, rx_dma); 875 into_ref!(peri, rx, tx, tx_dma, rx_dma);
810 876
811 let r = T::regs();
812
813 // Some chips do not have swap_rx_tx bit 877 // Some chips do not have swap_rx_tx bit
814 cfg_if::cfg_if! { 878 cfg_if::cfg_if! {
815 if #[cfg(any(usart_v3, usart_v4))] { 879 if #[cfg(any(usart_v3, usart_v4))] {
@@ -827,6 +891,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
827 } 891 }
828 } 892 }
829 893
894 Self::new_inner(peri, tx_dma, rx_dma, config)
895 }
896
897 fn new_inner(
898 peri: PeripheralRef<'d, T>,
899 tx_dma: PeripheralRef<'d, TxDma>,
900 rx_dma: PeripheralRef<'d, RxDma>,
901 config: Config,
902 ) -> Result<Self, ConfigError> {
903 let r = T::regs();
904
830 configure(r, &config, T::frequency(), T::KIND, true, true)?; 905 configure(r, &config, T::frequency(), T::KIND, true, true)?;
831 906
832 T::Interrupt::unpend(); 907 T::Interrupt::unpend();