Skip to content

Commit

Permalink
Stm32: implement async flush for UART
Browse files Browse the repository at this point in the history
  • Loading branch information
qwerty19106 committed Sep 27, 2024
1 parent a7d1abf commit 1f4a7d5
Showing 1 changed file with 59 additions and 9 deletions.
68 changes: 59 additions & 9 deletions embassy-stm32/src/usart/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -416,7 +422,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
}
}

Expand Down Expand Up @@ -527,13 +533,40 @@ impl<'d, M: Mode> UartTx<'d, M> {
}
}

fn blocking_flush(info: &Info) -> Result<(), Error> {
/// Wait until transmission complete
async fn flush(info: &Info, state: &State) -> Result<(), Error> {
let r = info.regs;
while !sr(r).read().tc() {}
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;
}

// Enable Receiver after transmission complete for Half-Duplex mode
if r.cr3().read().hdsel() {
r.cr1().modify(|reg| reg.set_re(true));
Ok(())
}

fn blocking_flush(info: &Info) -> Result<(), Error> {
let r = info.regs;
if r.cr1().read().te() {
while !sr(r).read().tc() {}
}

Ok(())
Expand Down Expand Up @@ -614,7 +647,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
Expand Down Expand Up @@ -953,6 +992,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 {
Expand Down Expand Up @@ -1148,6 +1193,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
Expand Down Expand Up @@ -1726,7 +1776,7 @@ impl embedded_io_async::Write for Uart<'_, Async> {
}

async fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
self.flush().await
}
}

Expand All @@ -1737,7 +1787,7 @@ impl embedded_io_async::Write for UartTx<'_, Async> {
}

async fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
self.flush().await
}
}

Expand Down

0 comments on commit 1f4a7d5

Please sign in to comment.