diff options
| author | lights0123 <[email protected]> | 2023-12-26 16:34:04 -0500 |
|---|---|---|
| committer | lights0123 <[email protected]> | 2023-12-26 16:35:36 -0500 |
| commit | dc295fa1db1245ca5ea5241104140ae1e62ea5ac (patch) | |
| tree | 74d9c816a1d4b7061b475e1fe2e37238771040a0 /embassy-stm32 | |
| parent | eebfee189a592427423d3a3ad22132d59926a0e8 (diff) | |
stm32: add half duplex USART driver
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 87 |
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(); |
