diff options
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 69 | ||||
| -rw-r--r-- | tests/rp/.cargo/config.toml | 1 | ||||
| -rw-r--r-- | tests/stm32/.cargo/config.toml | 1 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart.rs | 7 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart_dma.rs | 17 |
5 files changed, 82 insertions, 13 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 6f838cce5..333e01e36 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -69,6 +69,12 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) { | |||
| 69 | // disable idle line detection | 69 | // disable idle line detection |
| 70 | w.set_idleie(false); | 70 | w.set_idleie(false); |
| 71 | }); | 71 | }); |
| 72 | } else if cr1.tcie() && sr.tc() { | ||
| 73 | // Transmission complete detected | ||
| 74 | r.cr1().modify(|w| { | ||
| 75 | // disable Transmission complete interrupt | ||
| 76 | w.set_tcie(false); | ||
| 77 | }); | ||
| 72 | } else if cr1.rxneie() { | 78 | } else if cr1.rxneie() { |
| 73 | // We cannot check the RXNE flag as it is auto-cleared by the DMA controller | 79 | // We cannot check the RXNE flag as it is auto-cleared by the DMA controller |
| 74 | 80 | ||
| @@ -420,7 +426,7 @@ impl<'d> UartTx<'d, Async> { | |||
| 420 | 426 | ||
| 421 | /// Wait until transmission complete | 427 | /// Wait until transmission complete |
| 422 | pub async fn flush(&mut self) -> Result<(), Error> { | 428 | pub async fn flush(&mut self) -> Result<(), Error> { |
| 423 | self.blocking_flush() | 429 | flush(&self.info, &self.state).await |
| 424 | } | 430 | } |
| 425 | } | 431 | } |
| 426 | 432 | ||
| @@ -531,16 +537,40 @@ impl<'d, M: Mode> UartTx<'d, M> { | |||
| 531 | } | 537 | } |
| 532 | } | 538 | } |
| 533 | 539 | ||
| 534 | fn blocking_flush(info: &Info) -> Result<(), Error> { | 540 | /// Wait until transmission complete |
| 541 | async fn flush(info: &Info, state: &State) -> Result<(), Error> { | ||
| 535 | let r = info.regs; | 542 | let r = info.regs; |
| 536 | while !sr(r).read().tc() {} | 543 | if r.cr1().read().te() && !sr(r).read().tc() { |
| 544 | r.cr1().modify(|w| { | ||
| 545 | // enable Transmission Complete interrupt | ||
| 546 | w.set_tcie(true); | ||
| 547 | }); | ||
| 548 | |||
| 549 | compiler_fence(Ordering::SeqCst); | ||
| 537 | 550 | ||
| 538 | // Disable Transmitter and enable receiver after transmission complete for Half-Duplex mode | 551 | // future which completes when Transmission complete is detected |
| 539 | if r.cr3().read().hdsel() { | 552 | let abort = poll_fn(move |cx| { |
| 540 | r.cr1().modify(|reg| { | 553 | state.rx_waker.register(cx.waker()); |
| 541 | reg.set_te(false); | 554 | |
| 542 | reg.set_re(true); | 555 | let sr = sr(r).read(); |
| 556 | if sr.tc() { | ||
| 557 | // Transmission complete detected | ||
| 558 | return Poll::Ready(()); | ||
| 559 | } | ||
| 560 | |||
| 561 | Poll::Pending | ||
| 543 | }); | 562 | }); |
| 563 | |||
| 564 | abort.await; | ||
| 565 | } | ||
| 566 | |||
| 567 | Ok(()) | ||
| 568 | } | ||
| 569 | |||
| 570 | fn blocking_flush(info: &Info) -> Result<(), Error> { | ||
| 571 | let r = info.regs; | ||
| 572 | if r.cr1().read().te() { | ||
| 573 | while !sr(r).read().tc() {} | ||
| 544 | } | 574 | } |
| 545 | 575 | ||
| 546 | Ok(()) | 576 | Ok(()) |
| @@ -621,7 +651,13 @@ impl<'d> UartRx<'d, Async> { | |||
| 621 | // Call flush for Half-Duplex mode if some bytes were written and flush was not called. | 651 | // Call flush for Half-Duplex mode if some bytes were written and flush was not called. |
| 622 | // It prevents reading of bytes which have just been written. | 652 | // It prevents reading of bytes which have just been written. |
| 623 | if r.cr3().read().hdsel() && r.cr1().read().te() { | 653 | if r.cr3().read().hdsel() && r.cr1().read().te() { |
| 624 | blocking_flush(self.info)?; | 654 | flush(&self.info, &self.state).await?; |
| 655 | |||
| 656 | // Disable Transmitter and enable Receiver after flush | ||
| 657 | r.cr1().modify(|reg| { | ||
| 658 | reg.set_re(true); | ||
| 659 | reg.set_te(false); | ||
| 660 | }); | ||
| 625 | } | 661 | } |
| 626 | 662 | ||
| 627 | // make sure USART state is restored to neutral state when this future is dropped | 663 | // 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> { | |||
| 960 | // It prevents reading of bytes which have just been written. | 996 | // It prevents reading of bytes which have just been written. |
| 961 | if r.cr3().read().hdsel() && r.cr1().read().te() { | 997 | if r.cr3().read().hdsel() && r.cr1().read().te() { |
| 962 | blocking_flush(self.info)?; | 998 | blocking_flush(self.info)?; |
| 999 | |||
| 1000 | // Disable Transmitter and enable Receiver after flush | ||
| 1001 | r.cr1().modify(|reg| { | ||
| 1002 | reg.set_re(true); | ||
| 1003 | reg.set_te(false); | ||
| 1004 | }); | ||
| 963 | } | 1005 | } |
| 964 | 1006 | ||
| 965 | for b in buffer { | 1007 | for b in buffer { |
| @@ -1155,6 +1197,11 @@ impl<'d> Uart<'d, Async> { | |||
| 1155 | self.tx.write(buffer).await | 1197 | self.tx.write(buffer).await |
| 1156 | } | 1198 | } |
| 1157 | 1199 | ||
| 1200 | /// Wait until transmission complete | ||
| 1201 | pub async fn flush(&mut self) -> Result<(), Error> { | ||
| 1202 | self.tx.flush().await | ||
| 1203 | } | ||
| 1204 | |||
| 1158 | /// Perform an asynchronous read into `buffer` | 1205 | /// Perform an asynchronous read into `buffer` |
| 1159 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 1206 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 1160 | self.rx.read(buffer).await | 1207 | self.rx.read(buffer).await |
| @@ -1733,7 +1780,7 @@ impl embedded_io_async::Write for Uart<'_, Async> { | |||
| 1733 | } | 1780 | } |
| 1734 | 1781 | ||
| 1735 | async fn flush(&mut self) -> Result<(), Self::Error> { | 1782 | async fn flush(&mut self) -> Result<(), Self::Error> { |
| 1736 | self.blocking_flush() | 1783 | self.flush().await |
| 1737 | } | 1784 | } |
| 1738 | } | 1785 | } |
| 1739 | 1786 | ||
| @@ -1744,7 +1791,7 @@ impl embedded_io_async::Write for UartTx<'_, Async> { | |||
| 1744 | } | 1791 | } |
| 1745 | 1792 | ||
| 1746 | async fn flush(&mut self) -> Result<(), Self::Error> { | 1793 | async fn flush(&mut self) -> Result<(), Self::Error> { |
| 1747 | self.blocking_flush() | 1794 | self.flush().await |
| 1748 | } | 1795 | } |
| 1749 | } | 1796 | } |
| 1750 | 1797 | ||
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index de7bb0e56..4337924cc 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml | |||
| @@ -11,7 +11,6 @@ runner = "teleprobe client run" | |||
| 11 | rustflags = [ | 11 | rustflags = [ |
| 12 | # Code-size optimizations. | 12 | # Code-size optimizations. |
| 13 | #"-Z", "trap-unreachable=no", | 13 | #"-Z", "trap-unreachable=no", |
| 14 | "-C", "inline-threshold=5", | ||
| 15 | "-C", "no-vectorize-loops", | 14 | "-C", "no-vectorize-loops", |
| 16 | ] | 15 | ] |
| 17 | 16 | ||
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 8752da59b..d94342598 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml | |||
| @@ -9,7 +9,6 @@ runner = "teleprobe client run" | |||
| 9 | rustflags = [ | 9 | rustflags = [ |
| 10 | # Code-size optimizations. | 10 | # Code-size optimizations. |
| 11 | #"-Z", "trap-unreachable=no", | 11 | #"-Z", "trap-unreachable=no", |
| 12 | "-C", "inline-threshold=5", | ||
| 13 | "-C", "no-vectorize-loops", | 12 | "-C", "no-vectorize-loops", |
| 14 | ] | 13 | ] |
| 15 | 14 | ||
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 53da30fff..2f601ad0e 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs | |||
| @@ -33,6 +33,13 @@ async fn main(_spawner: Spawner) { | |||
| 33 | let mut buf = [0; 2]; | 33 | let mut buf = [0; 2]; |
| 34 | usart.blocking_read(&mut buf).unwrap(); | 34 | usart.blocking_read(&mut buf).unwrap(); |
| 35 | assert_eq!(buf, data); | 35 | assert_eq!(buf, data); |
| 36 | |||
| 37 | // Test flush doesn't hang. | ||
| 38 | usart.blocking_write(&data).unwrap(); | ||
| 39 | usart.blocking_flush().unwrap(); | ||
| 40 | |||
| 41 | // Test flush doesn't hang if there's nothing to flush | ||
| 42 | usart.blocking_flush().unwrap(); | ||
| 36 | } | 43 | } |
| 37 | 44 | ||
| 38 | // Test error handling with with an overflow error | 45 | // Test error handling with with an overflow error |
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index 266b81809..a34498376 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs | |||
| @@ -51,6 +51,23 @@ async fn main(_spawner: Spawner) { | |||
| 51 | assert_eq!(tx_buf, rx_buf); | 51 | assert_eq!(tx_buf, rx_buf); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | // Test flush doesn't hang. Check multiple combinations of async+blocking. | ||
| 55 | tx.write(&tx_buf).await.unwrap(); | ||
| 56 | tx.flush().await.unwrap(); | ||
| 57 | tx.flush().await.unwrap(); | ||
| 58 | |||
| 59 | tx.write(&tx_buf).await.unwrap(); | ||
| 60 | tx.blocking_flush().unwrap(); | ||
| 61 | tx.flush().await.unwrap(); | ||
| 62 | |||
| 63 | tx.blocking_write(&tx_buf).unwrap(); | ||
| 64 | tx.blocking_flush().unwrap(); | ||
| 65 | tx.flush().await.unwrap(); | ||
| 66 | |||
| 67 | tx.blocking_write(&tx_buf).unwrap(); | ||
| 68 | tx.flush().await.unwrap(); | ||
| 69 | tx.blocking_flush().unwrap(); | ||
| 70 | |||
| 54 | info!("Test OK"); | 71 | info!("Test OK"); |
| 55 | cortex_m::asm::bkpt(); | 72 | cortex_m::asm::bkpt(); |
| 56 | } | 73 | } |
