aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Vahter <[email protected]>2024-01-08 17:33:11 +0200
committerDario Nieuwenhuis <[email protected]>2024-01-20 00:15:39 +0100
commitec47e931acbc4a4b1a9f0781e9317f1e680427eb (patch)
tree90bab6d627cb7bd270e36799b49a3d54ffcae40e
parenta2eb46e9e458abec477a118ddbec12ae3f9f0900 (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.rs30
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 @@
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;
@@ -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;