stm32 uart: fix flush for non usart_v4 variants

Byte was written to TDR and right after that waker was called. This means `flush` would see that `tx_buf` is empty and can return Ready although actually hardware was still writing this last byte to the wire.
With this change non `usart_v4 ` variants would also use TC interrupt to check when last byte was sent out.
This commit is contained in:
Andres Vahter 2024-01-09 14:47:30 +02:00 committed by Dario Nieuwenhuis
parent 17d6e4eefe
commit c936d66934

View file

@ -62,10 +62,9 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
state.rx_waker.wake();
}
// With `usart_v4` hardware FIFO is enabled, making `state.tx_buf` insufficient
// to determine if all bytes are sent out.
// Transmission complete (TC) interrupt here indicates that all bytes are pushed out from the FIFO.
#[cfg(usart_v4)]
// With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
// indicates that all bytes are pushed out from the FIFO.
// For other usart variants it shows that last byte from the buffer was just sent.
if sr_val.tc() {
r.cr1().modify(|w| {
w.set_tcie(false);
@ -83,17 +82,15 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
w.set_txeie(true);
});
#[cfg(usart_v4)]
r.cr1().modify(|w| {
w.set_tcie(true);
});
// Enable transmission complete interrupt when last byte is going to be sent out.
if buf.len() == 1 {
r.cr1().modify(|w| {
w.set_tcie(true);
});
}
tdr(r).write_volatile(buf[0].into());
tx_reader.pop_done(1);
// Notice that in case of `usart_v4` waker is called when TC interrupt happens.
#[cfg(not(usart_v4))]
state.tx_waker.wake();
} else {
// Disable interrupt until we have something to transmit again.
r.cr1().modify(|w| {
@ -418,16 +415,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
poll_fn(move |cx| {
let state = T::buffered_state();
#[cfg(usart_v4)]
if !state.tx_done.load(Ordering::Acquire) {
state.tx_waker.register(cx.waker());
return Poll::Pending;
}
#[cfg(not(usart_v4))]
if !state.tx_buf.is_empty() {
state.tx_waker.register(cx.waker());
return Poll::Pending;
}
Poll::Ready(Ok(()))
})