diff options
| author | Daniel Trnka <[email protected]> | 2024-12-21 22:01:36 +0100 |
|---|---|---|
| committer | Daniel Trnka <[email protected]> | 2024-12-22 17:50:46 +0100 |
| commit | 2ec81419fa7ca1d1d4c797c1d416c1f226aefb33 (patch) | |
| tree | 9611485664a9316878caded0fdb58a4a0a04844e /embassy-stm32/src/usart | |
| parent | 6789b5141f9280f1e3d7c6dfcab1a07fe4620b43 (diff) | |
stm32/usart: configurable readback in half-duplex mode
Diffstat (limited to 'embassy-stm32/src/usart')
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 54 |
1 files 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 { | |||
| 125 | STOP1P5, | 125 | STOP1P5, |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
| 129 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 130 | /// Enables or disables receiver so written data are read back in half-duplex mode | ||
| 131 | pub enum HalfDuplexReadback { | ||
| 132 | /// Disables receiver so written data are not read back | ||
| 133 | NoReadback, | ||
| 134 | /// Enables receiver so written data are read back | ||
| 135 | Readback, | ||
| 136 | } | ||
| 137 | |||
| 138 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
| 139 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 140 | /// Duplex mode | ||
| 141 | pub enum Duplex { | ||
| 142 | /// Full duplex | ||
| 143 | Full, | ||
| 144 | /// Half duplex with possibility to read back written data | ||
| 145 | Half(HalfDuplexReadback), | ||
| 146 | } | ||
| 147 | |||
| 148 | impl Duplex { | ||
| 149 | /// Returns true if half-duplex | ||
| 150 | fn is_half(&self) -> bool { | ||
| 151 | matches!(self, Duplex::Half(_)) | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 128 | #[non_exhaustive] | 155 | #[non_exhaustive] |
| 129 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 156 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 130 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 157 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -181,7 +208,7 @@ pub struct Config { | |||
| 181 | pub rx_pull: Pull, | 208 | pub rx_pull: Pull, |
| 182 | 209 | ||
| 183 | // private: set by new_half_duplex, not by the user. | 210 | // private: set by new_half_duplex, not by the user. |
| 184 | half_duplex: bool, | 211 | duplex: Duplex, |
| 185 | } | 212 | } |
| 186 | 213 | ||
| 187 | impl Config { | 214 | impl Config { |
| @@ -220,7 +247,7 @@ impl Default for Config { | |||
| 220 | #[cfg(any(usart_v3, usart_v4))] | 247 | #[cfg(any(usart_v3, usart_v4))] |
| 221 | invert_rx: false, | 248 | invert_rx: false, |
| 222 | rx_pull: Pull::None, | 249 | rx_pull: Pull::None, |
| 223 | half_duplex: false, | 250 | duplex: Duplex::Full, |
| 224 | } | 251 | } |
| 225 | } | 252 | } |
| 226 | } | 253 | } |
| @@ -308,6 +335,7 @@ pub struct UartTx<'d, M: Mode> { | |||
| 308 | cts: Option<PeripheralRef<'d, AnyPin>>, | 335 | cts: Option<PeripheralRef<'d, AnyPin>>, |
| 309 | de: Option<PeripheralRef<'d, AnyPin>>, | 336 | de: Option<PeripheralRef<'d, AnyPin>>, |
| 310 | tx_dma: Option<ChannelAndRequest<'d>>, | 337 | tx_dma: Option<ChannelAndRequest<'d>>, |
| 338 | duplex: Duplex, | ||
| 311 | _phantom: PhantomData<M>, | 339 | _phantom: PhantomData<M>, |
| 312 | } | 340 | } |
| 313 | 341 | ||
| @@ -413,7 +441,7 @@ impl<'d> UartTx<'d, Async> { | |||
| 413 | let mut cr1 = r.cr1().read(); | 441 | let mut cr1 = r.cr1().read(); |
| 414 | if r.cr3().read().hdsel() && !cr1.te() { | 442 | if r.cr3().read().hdsel() && !cr1.te() { |
| 415 | cr1.set_te(true); | 443 | cr1.set_te(true); |
| 416 | cr1.set_re(false); | 444 | cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); |
| 417 | r.cr1().write_value(cr1); | 445 | r.cr1().write_value(cr1); |
| 418 | } | 446 | } |
| 419 | 447 | ||
| @@ -485,6 +513,7 @@ impl<'d, M: Mode> UartTx<'d, M> { | |||
| 485 | cts, | 513 | cts, |
| 486 | de: None, | 514 | de: None, |
| 487 | tx_dma, | 515 | tx_dma, |
| 516 | duplex: config.duplex, | ||
| 488 | _phantom: PhantomData, | 517 | _phantom: PhantomData, |
| 489 | }; | 518 | }; |
| 490 | this.enable_and_configure(&config)?; | 519 | this.enable_and_configure(&config)?; |
| @@ -519,7 +548,7 @@ impl<'d, M: Mode> UartTx<'d, M> { | |||
| 519 | let mut cr1 = r.cr1().read(); | 548 | let mut cr1 = r.cr1().read(); |
| 520 | if r.cr3().read().hdsel() && !cr1.te() { | 549 | if r.cr3().read().hdsel() && !cr1.te() { |
| 521 | cr1.set_te(true); | 550 | cr1.set_te(true); |
| 522 | cr1.set_re(false); | 551 | cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); |
| 523 | r.cr1().write_value(cr1); | 552 | r.cr1().write_value(cr1); |
| 524 | } | 553 | } |
| 525 | 554 | ||
| @@ -1149,13 +1178,14 @@ impl<'d> Uart<'d, Async> { | |||
| 1149 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, | 1178 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, |
| 1150 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, | 1179 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, |
| 1151 | mut config: Config, | 1180 | mut config: Config, |
| 1181 | readback: HalfDuplexReadback, | ||
| 1152 | half_duplex: HalfDuplexConfig, | 1182 | half_duplex: HalfDuplexConfig, |
| 1153 | ) -> Result<Self, ConfigError> { | 1183 | ) -> Result<Self, ConfigError> { |
| 1154 | #[cfg(not(any(usart_v1, usart_v2)))] | 1184 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 1155 | { | 1185 | { |
| 1156 | config.swap_rx_tx = false; | 1186 | config.swap_rx_tx = false; |
| 1157 | } | 1187 | } |
| 1158 | config.half_duplex = true; | 1188 | config.duplex = Duplex::Half(readback); |
| 1159 | 1189 | ||
| 1160 | Self::new_inner( | 1190 | Self::new_inner( |
| 1161 | peri, | 1191 | peri, |
| @@ -1188,10 +1218,11 @@ impl<'d> Uart<'d, Async> { | |||
| 1188 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, | 1218 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, |
| 1189 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, | 1219 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, |
| 1190 | mut config: Config, | 1220 | mut config: Config, |
| 1221 | readback: HalfDuplexReadback, | ||
| 1191 | half_duplex: HalfDuplexConfig, | 1222 | half_duplex: HalfDuplexConfig, |
| 1192 | ) -> Result<Self, ConfigError> { | 1223 | ) -> Result<Self, ConfigError> { |
| 1193 | config.swap_rx_tx = true; | 1224 | config.swap_rx_tx = true; |
| 1194 | config.half_duplex = true; | 1225 | config.duplex = Duplex::Half(readback); |
| 1195 | 1226 | ||
| 1196 | Self::new_inner( | 1227 | Self::new_inner( |
| 1197 | peri, | 1228 | peri, |
| @@ -1307,13 +1338,14 @@ impl<'d> Uart<'d, Blocking> { | |||
| 1307 | peri: impl Peripheral<P = T> + 'd, | 1338 | peri: impl Peripheral<P = T> + 'd, |
| 1308 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 1339 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 1309 | mut config: Config, | 1340 | mut config: Config, |
| 1341 | readback: HalfDuplexReadback, | ||
| 1310 | half_duplex: HalfDuplexConfig, | 1342 | half_duplex: HalfDuplexConfig, |
| 1311 | ) -> Result<Self, ConfigError> { | 1343 | ) -> Result<Self, ConfigError> { |
| 1312 | #[cfg(not(any(usart_v1, usart_v2)))] | 1344 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 1313 | { | 1345 | { |
| 1314 | config.swap_rx_tx = false; | 1346 | config.swap_rx_tx = false; |
| 1315 | } | 1347 | } |
| 1316 | config.half_duplex = true; | 1348 | config.duplex = Duplex::Half(readback); |
| 1317 | 1349 | ||
| 1318 | Self::new_inner( | 1350 | Self::new_inner( |
| 1319 | peri, | 1351 | peri, |
| @@ -1343,10 +1375,11 @@ impl<'d> Uart<'d, Blocking> { | |||
| 1343 | peri: impl Peripheral<P = T> + 'd, | 1375 | peri: impl Peripheral<P = T> + 'd, |
| 1344 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 1376 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 1345 | mut config: Config, | 1377 | mut config: Config, |
| 1378 | readback: HalfDuplexReadback, | ||
| 1346 | half_duplex: HalfDuplexConfig, | 1379 | half_duplex: HalfDuplexConfig, |
| 1347 | ) -> Result<Self, ConfigError> { | 1380 | ) -> Result<Self, ConfigError> { |
| 1348 | config.swap_rx_tx = true; | 1381 | config.swap_rx_tx = true; |
| 1349 | config.half_duplex = true; | 1382 | config.duplex = Duplex::Half(readback); |
| 1350 | 1383 | ||
| 1351 | Self::new_inner( | 1384 | Self::new_inner( |
| 1352 | peri, | 1385 | peri, |
| @@ -1388,6 +1421,7 @@ impl<'d, M: Mode> Uart<'d, M> { | |||
| 1388 | cts, | 1421 | cts, |
| 1389 | de, | 1422 | de, |
| 1390 | tx_dma, | 1423 | tx_dma, |
| 1424 | duplex: config.duplex, | ||
| 1391 | }, | 1425 | }, |
| 1392 | rx: UartRx { | 1426 | rx: UartRx { |
| 1393 | _phantom: PhantomData, | 1427 | _phantom: PhantomData, |
| @@ -1667,14 +1701,14 @@ fn configure( | |||
| 1667 | r.cr3().modify(|w| { | 1701 | r.cr3().modify(|w| { |
| 1668 | #[cfg(not(usart_v1))] | 1702 | #[cfg(not(usart_v1))] |
| 1669 | w.set_onebit(config.assume_noise_free); | 1703 | w.set_onebit(config.assume_noise_free); |
| 1670 | w.set_hdsel(config.half_duplex); | 1704 | w.set_hdsel(config.duplex.is_half()); |
| 1671 | }); | 1705 | }); |
| 1672 | 1706 | ||
| 1673 | r.cr1().write(|w| { | 1707 | r.cr1().write(|w| { |
| 1674 | // enable uart | 1708 | // enable uart |
| 1675 | w.set_ue(true); | 1709 | w.set_ue(true); |
| 1676 | 1710 | ||
| 1677 | if config.half_duplex { | 1711 | if config.duplex.is_half() { |
| 1678 | // The te and re bits will be set by write, read and flush methods. | 1712 | // The te and re bits will be set by write, read and flush methods. |
| 1679 | // Receiver should be enabled by default for Half-Duplex. | 1713 | // Receiver should be enabled by default for Half-Duplex. |
| 1680 | w.set_te(false); | 1714 | w.set_te(false); |
