mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 14:22:33 +00:00
Merge pull request #3379 from qwerty19106/stm32_async_flush
Stm32: implement async flush for UART
This commit is contained in:
commit
4f08d5bc5f
@ -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;
|
||||
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);
|
||||
});
|
||||
if r.cr1().read().te() {
|
||||
while !sr(r).read().tc() {}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ runner = "teleprobe client run"
|
||||
rustflags = [
|
||||
# Code-size optimizations.
|
||||
#"-Z", "trap-unreachable=no",
|
||||
"-C", "inline-threshold=5",
|
||||
"-C", "no-vectorize-loops",
|
||||
]
|
||||
|
||||
|
@ -9,7 +9,6 @@ runner = "teleprobe client run"
|
||||
rustflags = [
|
||||
# Code-size optimizations.
|
||||
#"-Z", "trap-unreachable=no",
|
||||
"-C", "inline-threshold=5",
|
||||
"-C", "no-vectorize-loops",
|
||||
]
|
||||
|
||||
|
@ -33,6 +33,13 @@ async fn main(_spawner: Spawner) {
|
||||
let mut buf = [0; 2];
|
||||
usart.blocking_read(&mut buf).unwrap();
|
||||
assert_eq!(buf, data);
|
||||
|
||||
// Test flush doesn't hang.
|
||||
usart.blocking_write(&data).unwrap();
|
||||
usart.blocking_flush().unwrap();
|
||||
|
||||
// Test flush doesn't hang if there's nothing to flush
|
||||
usart.blocking_flush().unwrap();
|
||||
}
|
||||
|
||||
// Test error handling with with an overflow error
|
||||
|
@ -51,6 +51,23 @@ async fn main(_spawner: Spawner) {
|
||||
assert_eq!(tx_buf, rx_buf);
|
||||
}
|
||||
|
||||
// Test flush doesn't hang. Check multiple combinations of async+blocking.
|
||||
tx.write(&tx_buf).await.unwrap();
|
||||
tx.flush().await.unwrap();
|
||||
tx.flush().await.unwrap();
|
||||
|
||||
tx.write(&tx_buf).await.unwrap();
|
||||
tx.blocking_flush().unwrap();
|
||||
tx.flush().await.unwrap();
|
||||
|
||||
tx.blocking_write(&tx_buf).unwrap();
|
||||
tx.blocking_flush().unwrap();
|
||||
tx.flush().await.unwrap();
|
||||
|
||||
tx.blocking_write(&tx_buf).unwrap();
|
||||
tx.flush().await.unwrap();
|
||||
tx.blocking_flush().unwrap();
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user