diff options
| author | Andres Vahter <[email protected]> | 2024-01-08 17:33:11 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-01-20 00:15:39 +0100 |
| commit | ec47e931acbc4a4b1a9f0781e9317f1e680427eb (patch) | |
| tree | 90bab6d627cb7bd270e36799b49a3d54ffcae40e | |
| parent | a2eb46e9e458abec477a118ddbec12ae3f9f0900 (diff) | |
stm32: fix buffered uart flush
usart_v4 uses internal FIFO and therefore actually all bytes are not yet sent out although state.tx_buf.is_empty()
| -rw-r--r-- | embassy-stm32/src/usart/buffered.rs | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index f8e0bfda5..e050f8e0f 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | use core::future::poll_fn; | 1 | use core::future::poll_fn; |
| 2 | use core::slice; | 2 | use core::slice; |
| 3 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 3 | use core::task::Poll; | 4 | use core::task::Poll; |
| 4 | 5 | ||
| 5 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; |
| @@ -61,6 +62,18 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 61 | state.rx_waker.wake(); | 62 | state.rx_waker.wake(); |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 65 | // With `usart_v4` hardware FIFO is enabled, making `state.tx_buf` | ||
| 66 | // insufficient to determine if all bytes are sent out. | ||
| 67 | // Transmission complete (TC) interrupt here indicates that all bytes are pushed out from the FIFO. | ||
| 68 | #[cfg(usart_v4)] | ||
| 69 | if sr_val.tc() { | ||
| 70 | r.cr1().modify(|w| { | ||
| 71 | w.set_tcie(false); | ||
| 72 | }); | ||
| 73 | state.tx_done.store(true, Ordering::Release); | ||
| 74 | state.rx_waker.wake(); | ||
| 75 | } | ||
| 76 | |||
| 64 | // TX | 77 | // TX |
| 65 | if sr(r).read().txe() { | 78 | if sr(r).read().txe() { |
| 66 | let mut tx_reader = state.tx_buf.reader(); | 79 | let mut tx_reader = state.tx_buf.reader(); |
| @@ -69,6 +82,12 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 69 | r.cr1().modify(|w| { | 82 | r.cr1().modify(|w| { |
| 70 | w.set_txeie(true); | 83 | w.set_txeie(true); |
| 71 | }); | 84 | }); |
| 85 | |||
| 86 | #[cfg(usart_v4)] | ||
| 87 | r.cr1().modify(|w| { | ||
| 88 | w.set_tcie(true); | ||
| 89 | }); | ||
| 90 | |||
| 72 | tdr(r).write_volatile(buf[0].into()); | 91 | tdr(r).write_volatile(buf[0].into()); |
| 73 | tx_reader.pop_done(1); | 92 | tx_reader.pop_done(1); |
| 74 | state.tx_waker.wake(); | 93 | state.tx_waker.wake(); |
| @@ -90,6 +109,7 @@ pub(crate) mod sealed { | |||
| 90 | pub(crate) rx_buf: RingBuffer, | 109 | pub(crate) rx_buf: RingBuffer, |
| 91 | pub(crate) tx_waker: AtomicWaker, | 110 | pub(crate) tx_waker: AtomicWaker, |
| 92 | pub(crate) tx_buf: RingBuffer, | 111 | pub(crate) tx_buf: RingBuffer, |
| 112 | pub(crate) tx_done: AtomicBool, | ||
| 93 | } | 113 | } |
| 94 | 114 | ||
| 95 | impl State { | 115 | impl State { |
| @@ -100,6 +120,7 @@ pub(crate) mod sealed { | |||
| 100 | tx_buf: RingBuffer::new(), | 120 | tx_buf: RingBuffer::new(), |
| 101 | rx_waker: AtomicWaker::new(), | 121 | rx_waker: AtomicWaker::new(), |
| 102 | tx_waker: AtomicWaker::new(), | 122 | tx_waker: AtomicWaker::new(), |
| 123 | tx_done: AtomicBool::new(true), | ||
| 103 | } | 124 | } |
| 104 | } | 125 | } |
| 105 | } | 126 | } |
| @@ -366,6 +387,8 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 366 | async fn write(&self, buf: &[u8]) -> Result<usize, Error> { | 387 | async fn write(&self, buf: &[u8]) -> Result<usize, Error> { |
| 367 | poll_fn(move |cx| { | 388 | poll_fn(move |cx| { |
| 368 | let state = T::buffered_state(); | 389 | let state = T::buffered_state(); |
| 390 | state.tx_done.store(false, Ordering::Release); | ||
| 391 | |||
| 369 | let empty = state.tx_buf.is_empty(); | 392 | let empty = state.tx_buf.is_empty(); |
| 370 | 393 | ||
| 371 | let mut tx_writer = unsafe { state.tx_buf.writer() }; | 394 | let mut tx_writer = unsafe { state.tx_buf.writer() }; |
| @@ -391,6 +414,13 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 391 | async fn flush(&self) -> Result<(), Error> { | 414 | async fn flush(&self) -> Result<(), Error> { |
| 392 | poll_fn(move |cx| { | 415 | poll_fn(move |cx| { |
| 393 | let state = T::buffered_state(); | 416 | let state = T::buffered_state(); |
| 417 | |||
| 418 | #[cfg(usart_v4)] | ||
| 419 | if !state.tx_done.load(Ordering::Acquire) { | ||
| 420 | state.tx_waker.register(cx.waker()); | ||
| 421 | return Poll::Pending; | ||
| 422 | } | ||
| 423 | #[cfg(not(usart_v4))] | ||
| 394 | if !state.tx_buf.is_empty() { | 424 | if !state.tx_buf.is_empty() { |
| 395 | state.tx_waker.register(cx.waker()); | 425 | state.tx_waker.register(cx.waker()); |
| 396 | return Poll::Pending; | 426 | return Poll::Pending; |
