diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-09-22 08:56:46 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-09-22 08:56:46 +0000 |
| commit | 233905e18cf1446ebba898185882e5fc002a9f20 (patch) | |
| tree | 7ff91b015fea166d9b6fa166cfd50c41327ea8f7 | |
| parent | afd8a869620f420f9ccae3b40654c4a515b78044 (diff) | |
| parent | 3aeeeb0d784d843b521b4b8b222114ef7ba71363 (diff) | |
Merge pull request #3356 from peterkrull/ringbuffered-uartrx-deadlock
stm32: Fix RingBufferedUartRx hard-resetting DMA after initial error
| -rw-r--r-- | embassy-stm32/src/dma/dma_bdma.rs | 54 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/ringbuffered.rs | 51 |
2 files changed, 72 insertions, 33 deletions
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index df041c4e9..d10b5554f 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs | |||
| @@ -493,6 +493,26 @@ impl AnyChannel { | |||
| 493 | } | 493 | } |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | fn request_pause(&self) { | ||
| 497 | let info = self.info(); | ||
| 498 | match self.info().dma { | ||
| 499 | #[cfg(dma)] | ||
| 500 | DmaInfo::Dma(r) => { | ||
| 501 | // Disable the channel without overwriting the existing configuration | ||
| 502 | r.st(info.num).cr().modify(|w| { | ||
| 503 | w.set_en(false); | ||
| 504 | }); | ||
| 505 | } | ||
| 506 | #[cfg(bdma)] | ||
| 507 | DmaInfo::Bdma(r) => { | ||
| 508 | // Disable the channel without overwriting the existing configuration | ||
| 509 | r.ch(info.num).cr().modify(|w| { | ||
| 510 | w.set_en(false); | ||
| 511 | }); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 496 | fn is_running(&self) -> bool { | 516 | fn is_running(&self) -> bool { |
| 497 | let info = self.info(); | 517 | let info = self.info(); |
| 498 | match self.info().dma { | 518 | match self.info().dma { |
| @@ -667,12 +687,22 @@ impl<'a> Transfer<'a> { | |||
| 667 | } | 687 | } |
| 668 | 688 | ||
| 669 | /// Request the transfer to stop. | 689 | /// Request the transfer to stop. |
| 690 | /// The configuration for this channel will **not be preserved**. If you need to restart the transfer | ||
| 691 | /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. | ||
| 670 | /// | 692 | /// |
| 671 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | 693 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. |
| 672 | pub fn request_stop(&mut self) { | 694 | pub fn request_stop(&mut self) { |
| 673 | self.channel.request_stop() | 695 | self.channel.request_stop() |
| 674 | } | 696 | } |
| 675 | 697 | ||
| 698 | /// Request the transfer to pause, keeping the existing configuration for this channel. | ||
| 699 | /// To restart the transfer, call [`start`](Self::start) again. | ||
| 700 | /// | ||
| 701 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 702 | pub fn request_pause(&mut self) { | ||
| 703 | self.channel.request_pause() | ||
| 704 | } | ||
| 705 | |||
| 676 | /// Return whether this transfer is still running. | 706 | /// Return whether this transfer is still running. |
| 677 | /// | 707 | /// |
| 678 | /// If this returns `false`, it can be because either the transfer finished, or | 708 | /// If this returns `false`, it can be because either the transfer finished, or |
| @@ -846,13 +876,23 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 846 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); | 876 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 847 | } | 877 | } |
| 848 | 878 | ||
| 849 | /// Request DMA to stop. | 879 | /// Request the DMA to stop. |
| 880 | /// The configuration for this channel will **not be preserved**. If you need to restart the transfer | ||
| 881 | /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. | ||
| 850 | /// | 882 | /// |
| 851 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | 883 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. |
| 852 | pub fn request_stop(&mut self) { | 884 | pub fn request_stop(&mut self) { |
| 853 | self.channel.request_stop() | 885 | self.channel.request_stop() |
| 854 | } | 886 | } |
| 855 | 887 | ||
| 888 | /// Request the transfer to pause, keeping the existing configuration for this channel. | ||
| 889 | /// To restart the transfer, call [`start`](Self::start) again. | ||
| 890 | /// | ||
| 891 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 892 | pub fn request_pause(&mut self) { | ||
| 893 | self.channel.request_pause() | ||
| 894 | } | ||
| 895 | |||
| 856 | /// Return whether DMA is still running. | 896 | /// Return whether DMA is still running. |
| 857 | /// | 897 | /// |
| 858 | /// If this returns `false`, it can be because either the transfer finished, or | 898 | /// If this returns `false`, it can be because either the transfer finished, or |
| @@ -977,13 +1017,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { | |||
| 977 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); | 1017 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 978 | } | 1018 | } |
| 979 | 1019 | ||
| 980 | /// Request DMA to stop. | 1020 | /// Request the DMA to stop. |
| 1021 | /// The configuration for this channel will **not be preserved**. If you need to restart the transfer | ||
| 1022 | /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. | ||
| 981 | /// | 1023 | /// |
| 982 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | 1024 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. |
| 983 | pub fn request_stop(&mut self) { | 1025 | pub fn request_stop(&mut self) { |
| 984 | self.channel.request_stop() | 1026 | self.channel.request_stop() |
| 985 | } | 1027 | } |
| 986 | 1028 | ||
| 1029 | /// Request the transfer to pause, keeping the existing configuration for this channel. | ||
| 1030 | /// To restart the transfer, call [`start`](Self::start) again. | ||
| 1031 | /// | ||
| 1032 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 1033 | pub fn request_pause(&mut self) { | ||
| 1034 | self.channel.request_pause() | ||
| 1035 | } | ||
| 1036 | |||
| 987 | /// Return whether DMA is still running. | 1037 | /// Return whether DMA is still running. |
| 988 | /// | 1038 | /// |
| 989 | /// If this returns `false`, it can be because either the transfer finished, or | 1039 | /// If this returns `false`, it can be because either the transfer finished, or |
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b0652046c..75834bf37 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs | |||
| @@ -71,34 +71,19 @@ impl<'d> UartRx<'d, Async> { | |||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | impl<'d> RingBufferedUartRx<'d> { | 73 | impl<'d> RingBufferedUartRx<'d> { |
| 74 | /// Clear the ring buffer and start receiving in the background | ||
| 75 | pub fn start(&mut self) -> Result<(), Error> { | ||
| 76 | // Clear the ring buffer so that it is ready to receive data | ||
| 77 | self.ring_buf.clear(); | ||
| 78 | |||
| 79 | self.setup_uart(); | ||
| 80 | |||
| 81 | Ok(()) | ||
| 82 | } | ||
| 83 | |||
| 84 | fn stop(&mut self, err: Error) -> Result<usize, Error> { | ||
| 85 | self.teardown_uart(); | ||
| 86 | |||
| 87 | Err(err) | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Reconfigure the driver | 74 | /// Reconfigure the driver |
| 91 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 75 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 92 | reconfigure(self.info, self.kernel_clock, config) | 76 | reconfigure(self.info, self.kernel_clock, config) |
| 93 | } | 77 | } |
| 94 | 78 | ||
| 95 | /// Start uart background receive | 79 | /// Configure and start the DMA backed UART receiver |
| 96 | fn setup_uart(&mut self) { | 80 | /// |
| 97 | // fence before starting DMA. | 81 | /// Note: This is also done automatically by [`read()`] if required. |
| 82 | pub fn start_uart(&mut self) { | ||
| 83 | // Clear the buffer so that it is ready to receive data | ||
| 98 | compiler_fence(Ordering::SeqCst); | 84 | compiler_fence(Ordering::SeqCst); |
| 99 | |||
| 100 | // start the dma controller | ||
| 101 | self.ring_buf.start(); | 85 | self.ring_buf.start(); |
| 86 | self.ring_buf.clear(); | ||
| 102 | 87 | ||
| 103 | let r = self.info.regs; | 88 | let r = self.info.regs; |
| 104 | // clear all interrupts and DMA Rx Request | 89 | // clear all interrupts and DMA Rx Request |
| @@ -118,9 +103,9 @@ impl<'d> RingBufferedUartRx<'d> { | |||
| 118 | }); | 103 | }); |
| 119 | } | 104 | } |
| 120 | 105 | ||
| 121 | /// Stop uart background receive | 106 | /// Stop DMA backed UART receiver |
| 122 | fn teardown_uart(&mut self) { | 107 | fn stop_uart(&mut self) { |
| 123 | self.ring_buf.request_stop(); | 108 | self.ring_buf.request_pause(); |
| 124 | 109 | ||
| 125 | let r = self.info.regs; | 110 | let r = self.info.regs; |
| 126 | // clear all interrupts and DMA Rx Request | 111 | // clear all interrupts and DMA Rx Request |
| @@ -153,13 +138,15 @@ impl<'d> RingBufferedUartRx<'d> { | |||
| 153 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { | 138 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { |
| 154 | let r = self.info.regs; | 139 | let r = self.info.regs; |
| 155 | 140 | ||
| 156 | // Start background receive if it was not already started | 141 | // Start DMA and Uart if it was not already started, |
| 142 | // otherwise check for errors in status register. | ||
| 143 | let sr = clear_idle_flag(r); | ||
| 157 | if !r.cr3().read().dmar() { | 144 | if !r.cr3().read().dmar() { |
| 158 | self.start()?; | 145 | self.start_uart(); |
| 146 | } else { | ||
| 147 | check_for_errors(sr)?; | ||
| 159 | } | 148 | } |
| 160 | 149 | ||
| 161 | check_for_errors(clear_idle_flag(r))?; | ||
| 162 | |||
| 163 | loop { | 150 | loop { |
| 164 | match self.ring_buf.read(buf) { | 151 | match self.ring_buf.read(buf) { |
| 165 | Ok((0, _)) => {} | 152 | Ok((0, _)) => {} |
| @@ -167,14 +154,16 @@ impl<'d> RingBufferedUartRx<'d> { | |||
| 167 | return Ok(len); | 154 | return Ok(len); |
| 168 | } | 155 | } |
| 169 | Err(_) => { | 156 | Err(_) => { |
| 170 | return self.stop(Error::Overrun); | 157 | self.stop_uart(); |
| 158 | return Err(Error::Overrun); | ||
| 171 | } | 159 | } |
| 172 | } | 160 | } |
| 173 | 161 | ||
| 174 | match self.wait_for_data_or_idle().await { | 162 | match self.wait_for_data_or_idle().await { |
| 175 | Ok(_) => {} | 163 | Ok(_) => {} |
| 176 | Err(err) => { | 164 | Err(err) => { |
| 177 | return self.stop(err); | 165 | self.stop_uart(); |
| 166 | return Err(err); | ||
| 178 | } | 167 | } |
| 179 | } | 168 | } |
| 180 | } | 169 | } |
| @@ -228,7 +217,7 @@ impl<'d> RingBufferedUartRx<'d> { | |||
| 228 | 217 | ||
| 229 | impl Drop for RingBufferedUartRx<'_> { | 218 | impl Drop for RingBufferedUartRx<'_> { |
| 230 | fn drop(&mut self) { | 219 | fn drop(&mut self) { |
| 231 | self.teardown_uart(); | 220 | self.stop_uart(); |
| 232 | self.rx.as_ref().map(|x| x.set_as_disconnected()); | 221 | self.rx.as_ref().map(|x| x.set_as_disconnected()); |
| 233 | self.rts.as_ref().map(|x| x.set_as_disconnected()); | 222 | self.rts.as_ref().map(|x| x.set_as_disconnected()); |
| 234 | super::drop_tx_rx(self.info, self.state); | 223 | super::drop_tx_rx(self.info, self.state); |
