diff options
Diffstat (limited to 'embassy-stm32/src/usart/mod.rs')
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 93 |
1 files changed, 85 insertions, 8 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ff211e0c9..d2c361c61 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -4,15 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; | 7 | use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering, compiler_fence}; |
| 8 | use core::task::Poll; | 8 | use core::task::Poll; |
| 9 | 9 | ||
| 10 | use embassy_embedded_hal::SetConfig; | 10 | use embassy_embedded_hal::SetConfig; |
| 11 | use embassy_hal_internal::drop::OnDrop; | ||
| 12 | use embassy_hal_internal::PeripheralType; | 11 | use embassy_hal_internal::PeripheralType; |
| 12 | use embassy_hal_internal::drop::OnDrop; | ||
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | use futures_util::future::{select, Either}; | 14 | use futures_util::future::{Either, select}; |
| 15 | 15 | ||
| 16 | use crate::Peri; | ||
| 16 | use crate::dma::ChannelAndRequest; | 17 | use crate::dma::ChannelAndRequest; |
| 17 | use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; | 18 | use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; |
| 18 | use crate::interrupt::typelevel::Interrupt as _; | 19 | use crate::interrupt::typelevel::Interrupt as _; |
| @@ -25,7 +26,6 @@ use crate::pac::usart::Usart as Regs; | |||
| 25 | use crate::pac::usart::{regs, vals}; | 26 | use crate::pac::usart::{regs, vals}; |
| 26 | use crate::rcc::{RccInfo, SealedRccPeripheral}; | 27 | use crate::rcc::{RccInfo, SealedRccPeripheral}; |
| 27 | use crate::time::Hertz; | 28 | use crate::time::Hertz; |
| 28 | use crate::Peri; | ||
| 29 | 29 | ||
| 30 | /// Interrupt handler. | 30 | /// Interrupt handler. |
| 31 | pub struct InterruptHandler<T: Instance> { | 31 | pub struct InterruptHandler<T: Instance> { |
| @@ -185,6 +185,12 @@ pub enum ConfigError { | |||
| 185 | RxOrTxNotEnabled, | 185 | RxOrTxNotEnabled, |
| 186 | /// Data bits and parity combination not supported | 186 | /// Data bits and parity combination not supported |
| 187 | DataParityNotSupported, | 187 | DataParityNotSupported, |
| 188 | /// DE assertion time too high | ||
| 189 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 190 | DeAssertionTimeTooHigh, | ||
| 191 | /// DE deassertion time too high | ||
| 192 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 193 | DeDeassertionTimeTooHigh, | ||
| 188 | } | 194 | } |
| 189 | 195 | ||
| 190 | #[non_exhaustive] | 196 | #[non_exhaustive] |
| @@ -206,6 +212,21 @@ pub struct Config { | |||
| 206 | /// If false: the error is ignored and cleared | 212 | /// If false: the error is ignored and cleared |
| 207 | pub detect_previous_overrun: bool, | 213 | pub detect_previous_overrun: bool, |
| 208 | 214 | ||
| 215 | /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx` | ||
| 216 | /// typically only wake/return after line idle or after the buffer is at least half full | ||
| 217 | /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions | ||
| 218 | /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances. | ||
| 219 | /// | ||
| 220 | /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are | ||
| 221 | /// available in the buffer, in addition to waking/returning when the conditions described | ||
| 222 | /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx` | ||
| 223 | /// will trigger an interrupt for every received word to check the buffer level, which may | ||
| 224 | /// impact performance at high data rates. | ||
| 225 | /// | ||
| 226 | /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either | ||
| 227 | /// return a single word, a full buffer, or after line idle. | ||
| 228 | pub eager_reads: Option<usize>, | ||
| 229 | |||
| 209 | /// Set this to true if the line is considered noise free. | 230 | /// Set this to true if the line is considered noise free. |
| 210 | /// This will increase the receiver’s tolerance to clock deviations, | 231 | /// This will increase the receiver’s tolerance to clock deviations, |
| 211 | /// but will effectively disable noise detection. | 232 | /// but will effectively disable noise detection. |
| @@ -239,6 +260,14 @@ pub struct Config { | |||
| 239 | /// Set the pin configuration for the DE pin. | 260 | /// Set the pin configuration for the DE pin. |
| 240 | pub de_config: OutputConfig, | 261 | pub de_config: OutputConfig, |
| 241 | 262 | ||
| 263 | /// Set DE assertion time before the first start bit, 0-31 16ths of a bit period. | ||
| 264 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 265 | pub de_assertion_time: u8, | ||
| 266 | |||
| 267 | /// Set DE deassertion time after the last stop bit, 0-31 16ths of a bit period. | ||
| 268 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 269 | pub de_deassertion_time: u8, | ||
| 270 | |||
| 242 | // private: set by new_half_duplex, not by the user. | 271 | // private: set by new_half_duplex, not by the user. |
| 243 | duplex: Duplex, | 272 | duplex: Duplex, |
| 244 | } | 273 | } |
| @@ -270,6 +299,7 @@ impl Default for Config { | |||
| 270 | parity: Parity::ParityNone, | 299 | parity: Parity::ParityNone, |
| 271 | // historical behavior | 300 | // historical behavior |
| 272 | detect_previous_overrun: false, | 301 | detect_previous_overrun: false, |
| 302 | eager_reads: None, | ||
| 273 | #[cfg(not(usart_v1))] | 303 | #[cfg(not(usart_v1))] |
| 274 | assume_noise_free: false, | 304 | assume_noise_free: false, |
| 275 | #[cfg(any(usart_v3, usart_v4))] | 305 | #[cfg(any(usart_v3, usart_v4))] |
| @@ -283,6 +313,10 @@ impl Default for Config { | |||
| 283 | tx_config: OutputConfig::PushPull, | 313 | tx_config: OutputConfig::PushPull, |
| 284 | rts_config: OutputConfig::PushPull, | 314 | rts_config: OutputConfig::PushPull, |
| 285 | de_config: OutputConfig::PushPull, | 315 | de_config: OutputConfig::PushPull, |
| 316 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 317 | de_assertion_time: 0, | ||
| 318 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 319 | de_deassertion_time: 0, | ||
| 286 | duplex: Duplex::Full, | 320 | duplex: Duplex::Full, |
| 287 | } | 321 | } |
| 288 | } | 322 | } |
| @@ -457,6 +491,8 @@ impl<'d> UartTx<'d, Async> { | |||
| 457 | 491 | ||
| 458 | /// Initiate an asynchronous UART write | 492 | /// Initiate an asynchronous UART write |
| 459 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 493 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 494 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 495 | |||
| 460 | let r = self.info.regs; | 496 | let r = self.info.regs; |
| 461 | 497 | ||
| 462 | half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); | 498 | half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); |
| @@ -474,6 +510,8 @@ impl<'d> UartTx<'d, Async> { | |||
| 474 | 510 | ||
| 475 | /// Wait until transmission complete | 511 | /// Wait until transmission complete |
| 476 | pub async fn flush(&mut self) -> Result<(), Error> { | 512 | pub async fn flush(&mut self) -> Result<(), Error> { |
| 513 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 514 | |||
| 477 | flush(&self.info, &self.state).await | 515 | flush(&self.info, &self.state).await |
| 478 | } | 516 | } |
| 479 | } | 517 | } |
| @@ -535,7 +573,7 @@ impl<'d, M: Mode> UartTx<'d, M> { | |||
| 535 | let state = self.state; | 573 | let state = self.state; |
| 536 | state.tx_rx_refcount.store(1, Ordering::Relaxed); | 574 | state.tx_rx_refcount.store(1, Ordering::Relaxed); |
| 537 | 575 | ||
| 538 | info.rcc.enable_and_reset(); | 576 | info.rcc.enable_and_reset_without_stop(); |
| 539 | 577 | ||
| 540 | info.regs.cr3().modify(|w| { | 578 | info.regs.cr3().modify(|w| { |
| 541 | w.set_ctse(self.cts.is_some()); | 579 | w.set_ctse(self.cts.is_some()); |
| @@ -692,6 +730,8 @@ impl<'d> UartRx<'d, Async> { | |||
| 692 | 730 | ||
| 693 | /// Initiate an asynchronous UART read | 731 | /// Initiate an asynchronous UART read |
| 694 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 732 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 733 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 734 | |||
| 695 | self.inner_read(buffer, false).await?; | 735 | self.inner_read(buffer, false).await?; |
| 696 | 736 | ||
| 697 | Ok(()) | 737 | Ok(()) |
| @@ -699,6 +739,8 @@ impl<'d> UartRx<'d, Async> { | |||
| 699 | 739 | ||
| 700 | /// Initiate an asynchronous read with idle line detection enabled | 740 | /// Initiate an asynchronous read with idle line detection enabled |
| 701 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 741 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 742 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 743 | |||
| 702 | self.inner_read(buffer, true).await | 744 | self.inner_read(buffer, true).await |
| 703 | } | 745 | } |
| 704 | 746 | ||
| @@ -966,8 +1008,11 @@ impl<'d, M: Mode> UartRx<'d, M> { | |||
| 966 | let info = self.info; | 1008 | let info = self.info; |
| 967 | let state = self.state; | 1009 | let state = self.state; |
| 968 | state.tx_rx_refcount.store(1, Ordering::Relaxed); | 1010 | state.tx_rx_refcount.store(1, Ordering::Relaxed); |
| 1011 | state | ||
| 1012 | .eager_reads | ||
| 1013 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); | ||
| 969 | 1014 | ||
| 970 | info.rcc.enable_and_reset(); | 1015 | info.rcc.enable_and_reset_without_stop(); |
| 971 | 1016 | ||
| 972 | info.regs.cr3().write(|w| { | 1017 | info.regs.cr3().write(|w| { |
| 973 | w.set_rtse(self.rts.is_some()); | 1018 | w.set_rtse(self.rts.is_some()); |
| @@ -982,6 +1027,9 @@ impl<'d, M: Mode> UartRx<'d, M> { | |||
| 982 | 1027 | ||
| 983 | /// Reconfigure the driver | 1028 | /// Reconfigure the driver |
| 984 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 1029 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 1030 | self.state | ||
| 1031 | .eager_reads | ||
| 1032 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); | ||
| 985 | reconfigure(self.info, self.kernel_clock, config) | 1033 | reconfigure(self.info, self.kernel_clock, config) |
| 986 | } | 1034 | } |
| 987 | 1035 | ||
| @@ -1103,7 +1151,7 @@ fn drop_tx_rx(info: &Info, state: &State) { | |||
| 1103 | refcount == 1 | 1151 | refcount == 1 |
| 1104 | }); | 1152 | }); |
| 1105 | if is_last_drop { | 1153 | if is_last_drop { |
| 1106 | info.rcc.disable(); | 1154 | info.rcc.disable_without_stop(); |
| 1107 | } | 1155 | } |
| 1108 | } | 1156 | } |
| 1109 | 1157 | ||
| @@ -1462,8 +1510,11 @@ impl<'d, M: Mode> Uart<'d, M> { | |||
| 1462 | let info = self.rx.info; | 1510 | let info = self.rx.info; |
| 1463 | let state = self.rx.state; | 1511 | let state = self.rx.state; |
| 1464 | state.tx_rx_refcount.store(2, Ordering::Relaxed); | 1512 | state.tx_rx_refcount.store(2, Ordering::Relaxed); |
| 1513 | state | ||
| 1514 | .eager_reads | ||
| 1515 | .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); | ||
| 1465 | 1516 | ||
| 1466 | info.rcc.enable_and_reset(); | 1517 | info.rcc.enable_and_reset_without_stop(); |
| 1467 | 1518 | ||
| 1468 | info.regs.cr3().write(|w| { | 1519 | info.regs.cr3().write(|w| { |
| 1469 | w.set_rtse(self.rx.rts.is_some()); | 1520 | w.set_rtse(self.rx.rts.is_some()); |
| @@ -1690,6 +1741,16 @@ fn configure( | |||
| 1690 | return Err(ConfigError::RxOrTxNotEnabled); | 1741 | return Err(ConfigError::RxOrTxNotEnabled); |
| 1691 | } | 1742 | } |
| 1692 | 1743 | ||
| 1744 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 1745 | let dem = r.cr3().read().dem(); | ||
| 1746 | |||
| 1747 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 1748 | if config.de_assertion_time > 31 { | ||
| 1749 | return Err(ConfigError::DeAssertionTimeTooHigh); | ||
| 1750 | } else if config.de_deassertion_time > 31 { | ||
| 1751 | return Err(ConfigError::DeDeassertionTimeTooHigh); | ||
| 1752 | } | ||
| 1753 | |||
| 1693 | // UART must be disabled during configuration. | 1754 | // UART must be disabled during configuration. |
| 1694 | r.cr1().modify(|w| { | 1755 | r.cr1().modify(|w| { |
| 1695 | w.set_ue(false); | 1756 | w.set_ue(false); |
| @@ -1738,6 +1799,20 @@ fn configure( | |||
| 1738 | w.set_re(enable_rx); | 1799 | w.set_re(enable_rx); |
| 1739 | } | 1800 | } |
| 1740 | 1801 | ||
| 1802 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 1803 | if dem { | ||
| 1804 | w.set_deat(if over8 { | ||
| 1805 | config.de_assertion_time / 2 | ||
| 1806 | } else { | ||
| 1807 | config.de_assertion_time | ||
| 1808 | }); | ||
| 1809 | w.set_dedt(if over8 { | ||
| 1810 | config.de_assertion_time / 2 | ||
| 1811 | } else { | ||
| 1812 | config.de_assertion_time | ||
| 1813 | }); | ||
| 1814 | } | ||
| 1815 | |||
| 1741 | // configure word size and parity, since the parity bit is inserted into the MSB position, | 1816 | // configure word size and parity, since the parity bit is inserted into the MSB position, |
| 1742 | // it increases the effective word size | 1817 | // it increases the effective word size |
| 1743 | match (config.parity, config.data_bits) { | 1818 | match (config.parity, config.data_bits) { |
| @@ -2022,6 +2097,7 @@ struct State { | |||
| 2022 | rx_waker: AtomicWaker, | 2097 | rx_waker: AtomicWaker, |
| 2023 | tx_waker: AtomicWaker, | 2098 | tx_waker: AtomicWaker, |
| 2024 | tx_rx_refcount: AtomicU8, | 2099 | tx_rx_refcount: AtomicU8, |
| 2100 | eager_reads: AtomicUsize, | ||
| 2025 | } | 2101 | } |
| 2026 | 2102 | ||
| 2027 | impl State { | 2103 | impl State { |
| @@ -2030,6 +2106,7 @@ impl State { | |||
| 2030 | rx_waker: AtomicWaker::new(), | 2106 | rx_waker: AtomicWaker::new(), |
| 2031 | tx_waker: AtomicWaker::new(), | 2107 | tx_waker: AtomicWaker::new(), |
| 2032 | tx_rx_refcount: AtomicU8::new(0), | 2108 | tx_rx_refcount: AtomicU8::new(0), |
| 2109 | eager_reads: AtomicUsize::new(0), | ||
| 2033 | } | 2110 | } |
| 2034 | } | 2111 | } |
| 2035 | } | 2112 | } |
