aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-09-22 08:56:46 +0000
committerGitHub <[email protected]>2024-09-22 08:56:46 +0000
commit233905e18cf1446ebba898185882e5fc002a9f20 (patch)
tree7ff91b015fea166d9b6fa166cfd50c41327ea8f7
parentafd8a869620f420f9ccae3b40654c4a515b78044 (diff)
parent3aeeeb0d784d843b521b4b8b222114ef7ba71363 (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.rs54
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs51
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
73impl<'d> RingBufferedUartRx<'d> { 73impl<'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
229impl Drop for RingBufferedUartRx<'_> { 218impl 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);