Stm32: implement async flush for UART

This commit is contained in:
Роман Кривенков 2024-09-16 11:02:27 +04:00
parent c84495ef2e
commit 6862ac56cb

View File

@ -69,6 +69,12 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) {
// disable idle line detection
w.set_idleie(false);
});
} else if cr1.tcie() && sr.tc() {
// Transmission complete detected
r.cr1().modify(|w| {
// disable Transmission complete interrupt
w.set_tcie(false);
});
} else if cr1.rxneie() {
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
@ -420,7 +426,7 @@ impl<'d> UartTx<'d, Async> {
/// Wait until transmission complete
pub async fn flush(&mut self) -> Result<(), Error> {
self.blocking_flush()
flush(&self.info, &self.state).await
}
}
@ -531,16 +537,40 @@ impl<'d, M: Mode> UartTx<'d, M> {
}
}
/// Wait until transmission complete
async fn flush(info: &Info, state: &State) -> Result<(), Error> {
let r = info.regs;
if r.cr1().read().te() && !sr(r).read().tc() {
r.cr1().modify(|w| {
// enable Transmission Complete interrupt
w.set_tcie(true);
});
compiler_fence(Ordering::SeqCst);
// future which completes when Transmission complete is detected
let abort = poll_fn(move |cx| {
state.rx_waker.register(cx.waker());
let sr = sr(r).read();
if sr.tc() {
// Transmission complete detected
return Poll::Ready(());
}
Poll::Pending
});
abort.await;
}
Ok(())
}
fn blocking_flush(info: &Info) -> Result<(), Error> {
let r = info.regs;
if r.cr1().read().te() {
while !sr(r).read().tc() {}
// Disable Transmitter and enable receiver after transmission complete for Half-Duplex mode
if r.cr3().read().hdsel() {
r.cr1().modify(|reg| {
reg.set_te(false);
reg.set_re(true);
});
}
Ok(())
@ -621,7 +651,13 @@ impl<'d> UartRx<'d, Async> {
// Call flush for Half-Duplex mode if some bytes were written and flush was not called.
// It prevents reading of bytes which have just been written.
if r.cr3().read().hdsel() && r.cr1().read().te() {
blocking_flush(self.info)?;
flush(&self.info, &self.state).await?;
// Disable Transmitter and enable Receiver after flush
r.cr1().modify(|reg| {
reg.set_re(true);
reg.set_te(false);
});
}
// make sure USART state is restored to neutral state when this future is dropped
@ -960,6 +996,12 @@ impl<'d, M: Mode> UartRx<'d, M> {
// It prevents reading of bytes which have just been written.
if r.cr3().read().hdsel() && r.cr1().read().te() {
blocking_flush(self.info)?;
// Disable Transmitter and enable Receiver after flush
r.cr1().modify(|reg| {
reg.set_re(true);
reg.set_te(false);
});
}
for b in buffer {
@ -1155,6 +1197,11 @@ impl<'d> Uart<'d, Async> {
self.tx.write(buffer).await
}
/// Wait until transmission complete
pub async fn flush(&mut self) -> Result<(), Error> {
self.tx.flush().await
}
/// Perform an asynchronous read into `buffer`
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.read(buffer).await
@ -1733,7 +1780,7 @@ impl embedded_io_async::Write for Uart<'_, Async> {
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
self.flush().await
}
}
@ -1744,7 +1791,7 @@ impl embedded_io_async::Write for UartTx<'_, Async> {
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
self.flush().await
}
}