mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +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
|
// disable idle line detection
|
||||||
w.set_idleie(false);
|
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() {
|
} else if cr1.rxneie() {
|
||||||
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
|
// 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
|
/// Wait until transmission complete
|
||||||
pub async fn flush(&mut self) -> Result<(), Error> {
|
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> {
|
fn blocking_flush(info: &Info) -> Result<(), Error> {
|
||||||
let r = info.regs;
|
let r = info.regs;
|
||||||
while !sr(r).read().tc() {}
|
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(())
|
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.
|
// 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.
|
// It prevents reading of bytes which have just been written.
|
||||||
if r.cr3().read().hdsel() && r.cr1().read().te() {
|
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
|
// 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.
|
// It prevents reading of bytes which have just been written.
|
||||||
if r.cr3().read().hdsel() && r.cr1().read().te() {
|
if r.cr3().read().hdsel() && r.cr1().read().te() {
|
||||||
blocking_flush(self.info)?;
|
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 {
|
for b in buffer {
|
||||||
@ -1155,6 +1197,11 @@ impl<'d> Uart<'d, Async> {
|
|||||||
self.tx.write(buffer).await
|
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`
|
/// Perform an asynchronous read into `buffer`
|
||||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
self.rx.read(buffer).await
|
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> {
|
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> {
|
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
self.blocking_flush()
|
self.flush().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ runner = "teleprobe client run"
|
|||||||
rustflags = [
|
rustflags = [
|
||||||
# Code-size optimizations.
|
# Code-size optimizations.
|
||||||
#"-Z", "trap-unreachable=no",
|
#"-Z", "trap-unreachable=no",
|
||||||
"-C", "inline-threshold=5",
|
|
||||||
"-C", "no-vectorize-loops",
|
"-C", "no-vectorize-loops",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ runner = "teleprobe client run"
|
|||||||
rustflags = [
|
rustflags = [
|
||||||
# Code-size optimizations.
|
# Code-size optimizations.
|
||||||
#"-Z", "trap-unreachable=no",
|
#"-Z", "trap-unreachable=no",
|
||||||
"-C", "inline-threshold=5",
|
|
||||||
"-C", "no-vectorize-loops",
|
"-C", "no-vectorize-loops",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -33,6 +33,13 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
usart.blocking_read(&mut buf).unwrap();
|
usart.blocking_read(&mut buf).unwrap();
|
||||||
assert_eq!(buf, data);
|
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
|
// Test error handling with with an overflow error
|
||||||
|
@ -51,6 +51,23 @@ async fn main(_spawner: Spawner) {
|
|||||||
assert_eq!(tx_buf, rx_buf);
|
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");
|
info!("Test OK");
|
||||||
cortex_m::asm::bkpt();
|
cortex_m::asm::bkpt();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user