aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-01-20 01:50:55 +0000
committerGitHub <[email protected]>2024-01-20 01:50:55 +0000
commit43b6258a69b12e6b01f8d1f69626174579420c81 (patch)
treee6c4f42821e2ffe80d0ea82371e30b5cf0ed811d
parentda3884ff688236c2e3930556d6d4cc11e5880870 (diff)
parentec2e3de0f493cd0cc116f5f67a814ae7c457d9b1 (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.rs41
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 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::slice; 2use core::slice;
3use core::sync::atomic::{AtomicBool, Ordering};
3use core::task::Poll; 4use core::task::Poll;
4 5
5use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 6use 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 }