aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-11-14 00:00:12 +0100
committerDario Nieuwenhuis <[email protected]>2023-11-14 00:22:17 +0100
commitc46418f123820e375778e65a90e8589d7d665311 (patch)
tree3c5c5fbb16410f6450a8660c22bf73ae4263046c
parent19ff043acd2108c7896fb8f959569c997ad345e1 (diff)
nrf/buffered_uarte: fix hang when buffer full due to PPI missing the endrx event.
Fixes #2181
-rw-r--r--embassy-nrf/src/buffered_uarte.rs79
1 files changed, 58 insertions, 21 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index ec84640d3..e4b556f06 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -12,7 +12,7 @@ use core::cmp::min;
12use core::future::poll_fn; 12use core::future::poll_fn;
13use core::marker::PhantomData; 13use core::marker::PhantomData;
14use core::slice; 14use core::slice;
15use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; 15use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, AtomicUsize, Ordering};
16use core::task::Poll; 16use core::task::Poll;
17 17
18use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 18use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
@@ -41,7 +41,9 @@ mod sealed {
41 41
42 pub rx_waker: AtomicWaker, 42 pub rx_waker: AtomicWaker,
43 pub rx_buf: RingBuffer, 43 pub rx_buf: RingBuffer,
44 pub rx_bufs: AtomicU8, 44 pub rx_started: AtomicBool,
45 pub rx_started_count: AtomicU8,
46 pub rx_ended_count: AtomicU8,
45 pub rx_ppi_ch: AtomicU8, 47 pub rx_ppi_ch: AtomicU8,
46 } 48 }
47} 49}
@@ -65,7 +67,9 @@ impl State {
65 67
66 rx_waker: AtomicWaker::new(), 68 rx_waker: AtomicWaker::new(),
67 rx_buf: RingBuffer::new(), 69 rx_buf: RingBuffer::new(),
68 rx_bufs: AtomicU8::new(0), 70 rx_started: AtomicBool::new(false),
71 rx_started_count: AtomicU8::new(0),
72 rx_ended_count: AtomicU8::new(0),
69 rx_ppi_ch: AtomicU8::new(0), 73 rx_ppi_ch: AtomicU8::new(0),
70 } 74 }
71 } 75 }
@@ -104,28 +108,20 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
104 s.rx_waker.wake(); 108 s.rx_waker.wake();
105 } 109 }
106 110
107 // If not RXing, start. 111 if r.events_endrx.read().bits() != 0 {
108 if s.rx_bufs.load(Ordering::Relaxed) == 0 { 112 //trace!(" irq_rx: endrx");
109 let (ptr, len) = rx.push_buf(); 113 r.events_endrx.reset();
110 if len >= half_len {
111 //trace!(" irq_rx: starting {:?}", half_len);
112 s.rx_bufs.store(1, Ordering::Relaxed);
113
114 // Set up the DMA read
115 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
116 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
117 114
118 // Start UARTE Receive transaction 115 let val = s.rx_ended_count.load(Ordering::Relaxed);
119 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 116 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
120 rx.push_done(half_len);
121 r.intenset.write(|w| w.rxstarted().set());
122 }
123 } 117 }
124 118
125 if r.events_rxstarted.read().bits() != 0 { 119 if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) {
126 //trace!(" irq_rx: rxstarted"); 120 //trace!(" irq_rx: rxstarted");
127 let (ptr, len) = rx.push_buf(); 121 let (ptr, len) = rx.push_buf();
128 if len >= half_len { 122 if len >= half_len {
123 r.events_rxstarted.reset();
124
129 //trace!(" irq_rx: starting second {:?}", half_len); 125 //trace!(" irq_rx: starting second {:?}", half_len);
130 126
131 // Set up the DMA read 127 // Set up the DMA read
@@ -134,11 +130,50 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
134 130
135 let chn = s.rx_ppi_ch.load(Ordering::Relaxed); 131 let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
136 132
133 // Enable endrx -> startrx PPI channel.
134 // From this point on, if endrx happens, startrx is automatically fired.
137 ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); 135 ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
138 136
137 // It is possible that endrx happened BEFORE enabling the PPI. In this case
138 // the PPI channel doesn't trigger, and we'd hang. We have to detect this
139 // and manually start.
140
141 // check again in case endrx has happened between the last check and now.
142 if r.events_endrx.read().bits() != 0 {
143 //trace!(" irq_rx: endrx");
144 r.events_endrx.reset();
145
146 let val = s.rx_ended_count.load(Ordering::Relaxed);
147 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
148 }
149
150 let rx_ended = s.rx_ended_count.load(Ordering::Relaxed);
151 let rx_started = s.rx_started_count.load(Ordering::Relaxed);
152
153 // If we started the same amount of transfers as ended, the last rxend has
154 // already occured.
155 let rxend_happened = rx_started == rx_ended;
156
157 // Check if the PPI channel is still enabled. The PPI channel disables itself
158 // when it fires, so if it's still enabled it hasn't fired.
159 let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0;
160
161 // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed.
162 // this condition also naturally matches if `!started`, needed to kickstart the DMA.
163 if rxend_happened && ppi_ch_enabled {
164 //trace!("manually starting.");
165
166 // disable the ppi ch, it's of no use anymore.
167 ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) });
168
169 // manually start
170 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
171 }
172
139 rx.push_done(half_len); 173 rx.push_done(half_len);
140 174
141 r.events_rxstarted.reset(); 175 s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed);
176 s.rx_started.store(true, Ordering::Relaxed);
142 } else { 177 } else {
143 //trace!(" irq_rx: rxstarted no buf"); 178 //trace!(" irq_rx: rxstarted no buf");
144 r.intenclr.write(|w| w.rxstarted().clear()); 179 r.intenclr.write(|w| w.rxstarted().clear());
@@ -305,7 +340,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
305 // Initialize state 340 // Initialize state
306 let s = U::buffered_state(); 341 let s = U::buffered_state();
307 s.tx_count.store(0, Ordering::Relaxed); 342 s.tx_count.store(0, Ordering::Relaxed);
308 s.rx_bufs.store(0, Ordering::Relaxed); 343 s.rx_started_count.store(0, Ordering::Relaxed);
344 s.rx_ended_count.store(0, Ordering::Relaxed);
309 let len = tx_buffer.len(); 345 let len = tx_buffer.len();
310 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 346 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
311 let len = rx_buffer.len(); 347 let len = rx_buffer.len();
@@ -335,6 +371,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
335 w.endtx().set(); 371 w.endtx().set();
336 w.rxstarted().set(); 372 w.rxstarted().set();
337 w.error().set(); 373 w.error().set();
374 w.endrx().set();
338 w 375 w
339 }); 376 });
340 377