diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-01-20 01:50:55 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-01-20 01:50:55 +0000 |
| commit | 43b6258a69b12e6b01f8d1f69626174579420c81 (patch) | |
| tree | e6c4f42821e2ffe80d0ea82371e30b5cf0ed811d | |
| parent | da3884ff688236c2e3930556d6d4cc11e5880870 (diff) | |
| parent | ec2e3de0f493cd0cc116f5f67a814ae7c457d9b1 (diff) | |
Merge pull request #2416 from andresv/stm32-fix-buffered-uart-flush
stm32: fix buffered uart flush
| -rw-r--r-- | embassy-stm32/src/usart/buffered.rs | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index f8e0bfda5..c78752883 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; |
| @@ -46,8 +47,10 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 46 | let mut rx_writer = state.rx_buf.writer(); | 47 | let mut rx_writer = state.rx_buf.writer(); |
| 47 | let buf = rx_writer.push_slice(); | 48 | let buf = rx_writer.push_slice(); |
| 48 | if !buf.is_empty() { | 49 | if !buf.is_empty() { |
| 49 | buf[0] = dr.unwrap(); | 50 | if let Some(byte) = dr { |
| 50 | rx_writer.push_done(1); | 51 | buf[0] = byte; |
| 52 | rx_writer.push_done(1); | ||
| 53 | } | ||
| 51 | } else { | 54 | } else { |
| 52 | // FIXME: Should we disable any further RX interrupts when the buffer becomes full. | 55 | // FIXME: Should we disable any further RX interrupts when the buffer becomes full. |
| 53 | } | 56 | } |
| @@ -61,6 +64,22 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 61 | state.rx_waker.wake(); | 64 | state.rx_waker.wake(); |
| 62 | } | 65 | } |
| 63 | 66 | ||
| 67 | // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC) | ||
| 68 | // indicates that all bytes are pushed out from the FIFO. | ||
| 69 | // For other usart variants it shows that last byte from the buffer was just sent. | ||
| 70 | if sr_val.tc() { | ||
| 71 | // For others it is cleared above with `clear_interrupt_flags`. | ||
| 72 | #[cfg(any(usart_v1, usart_v2))] | ||
| 73 | sr(r).modify(|w| w.set_tc(false)); | ||
| 74 | |||
| 75 | r.cr1().modify(|w| { | ||
| 76 | w.set_tcie(false); | ||
| 77 | }); | ||
| 78 | |||
| 79 | state.tx_done.store(true, Ordering::Release); | ||
| 80 | state.tx_waker.wake(); | ||
| 81 | } | ||
| 82 | |||
| 64 | // TX | 83 | // TX |
| 65 | if sr(r).read().txe() { | 84 | if sr(r).read().txe() { |
| 66 | let mut tx_reader = state.tx_buf.reader(); | 85 | let mut tx_reader = state.tx_buf.reader(); |
| @@ -69,11 +88,18 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 69 | r.cr1().modify(|w| { | 88 | r.cr1().modify(|w| { |
| 70 | w.set_txeie(true); | 89 | w.set_txeie(true); |
| 71 | }); | 90 | }); |
| 91 | |||
| 92 | // Enable transmission complete interrupt when last byte is going to be sent out. | ||
| 93 | if buf.len() == 1 { | ||
| 94 | r.cr1().modify(|w| { | ||
| 95 | w.set_tcie(true); | ||
| 96 | }); | ||
| 97 | } | ||
| 98 | |||
| 72 | tdr(r).write_volatile(buf[0].into()); | 99 | tdr(r).write_volatile(buf[0].into()); |
| 73 | tx_reader.pop_done(1); | 100 | tx_reader.pop_done(1); |
| 74 | state.tx_waker.wake(); | ||
| 75 | } else { | 101 | } else { |
| 76 | // Disable interrupt until we have something to transmit again | 102 | // Disable interrupt until we have something to transmit again. |
| 77 | r.cr1().modify(|w| { | 103 | r.cr1().modify(|w| { |
| 78 | w.set_txeie(false); | 104 | w.set_txeie(false); |
| 79 | }); | 105 | }); |
| @@ -90,6 +116,7 @@ pub(crate) mod sealed { | |||
| 90 | pub(crate) rx_buf: RingBuffer, | 116 | pub(crate) rx_buf: RingBuffer, |
| 91 | pub(crate) tx_waker: AtomicWaker, | 117 | pub(crate) tx_waker: AtomicWaker, |
| 92 | pub(crate) tx_buf: RingBuffer, | 118 | pub(crate) tx_buf: RingBuffer, |
| 119 | pub(crate) tx_done: AtomicBool, | ||
| 93 | } | 120 | } |
| 94 | 121 | ||
| 95 | impl State { | 122 | impl State { |
| @@ -100,6 +127,7 @@ pub(crate) mod sealed { | |||
| 100 | tx_buf: RingBuffer::new(), | 127 | tx_buf: RingBuffer::new(), |
| 101 | rx_waker: AtomicWaker::new(), | 128 | rx_waker: AtomicWaker::new(), |
| 102 | tx_waker: AtomicWaker::new(), | 129 | tx_waker: AtomicWaker::new(), |
| 130 | tx_done: AtomicBool::new(true), | ||
| 103 | } | 131 | } |
| 104 | } | 132 | } |
| 105 | } | 133 | } |
| @@ -366,6 +394,8 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 366 | async fn write(&self, buf: &[u8]) -> Result<usize, Error> { | 394 | async fn write(&self, buf: &[u8]) -> Result<usize, Error> { |
| 367 | poll_fn(move |cx| { | 395 | poll_fn(move |cx| { |
| 368 | let state = T::buffered_state(); | 396 | let state = T::buffered_state(); |
| 397 | state.tx_done.store(false, Ordering::Release); | ||
| 398 | |||
| 369 | let empty = state.tx_buf.is_empty(); | 399 | let empty = state.tx_buf.is_empty(); |
| 370 | 400 | ||
| 371 | let mut tx_writer = unsafe { state.tx_buf.writer() }; | 401 | let mut tx_writer = unsafe { state.tx_buf.writer() }; |
| @@ -391,7 +421,8 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 391 | async fn flush(&self) -> Result<(), Error> { | 421 | async fn flush(&self) -> Result<(), Error> { |
| 392 | poll_fn(move |cx| { | 422 | poll_fn(move |cx| { |
| 393 | let state = T::buffered_state(); | 423 | let state = T::buffered_state(); |
| 394 | if !state.tx_buf.is_empty() { | 424 | |
| 425 | if !state.tx_done.load(Ordering::Acquire) { | ||
| 395 | state.tx_waker.register(cx.waker()); | 426 | state.tx_waker.register(cx.waker()); |
| 396 | return Poll::Pending; | 427 | return Poll::Pending; |
| 397 | } | 428 | } |
