aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/uart
diff options
context:
space:
mode:
authorTimo Kröger <[email protected]>2023-01-04 16:40:54 +0100
committerTimo Kröger <[email protected]>2023-01-04 16:53:43 +0100
commit840a75674b632485d5b45cfece27870ded0edfcd (patch)
tree601ddeda75fa7293fcab49dc6fc96794fe3dbf3b /embassy-rp/src/uart
parenta24037edf9d04087111c1d1dc71c92cc0ad83709 (diff)
rp: Disable RX interrupts when ring buffer is full
When data is in the RX fifo the RX timeout interrupt goes high again even after clearing it. The result is a deadlock because execution is stuck in the interrupt handler. No other code can run to clear the receive buffer. Enable and disable RX interrupts based on the buffer fill level. Use the same approach for the TX code path.
Diffstat (limited to 'embassy-rp/src/uart')
-rw-r--r--embassy-rp/src/uart/buffered.rs87
1 files changed, 35 insertions, 52 deletions
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 9164794b1..6465a20c6 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -49,15 +49,6 @@ fn init<'d, T: Instance + 'd>(
49 rx_buffer: &'d mut [u8], 49 rx_buffer: &'d mut [u8],
50 config: Config, 50 config: Config,
51) { 51) {
52 let regs = T::regs();
53 unsafe {
54 regs.uartimsc().modify(|w| {
55 w.set_rxim(true);
56 w.set_rtim(true);
57 w.set_txim(true);
58 });
59 }
60
61 super::Uart::<'d, T, Async>::init(tx, rx, rts, cts, config); 52 super::Uart::<'d, T, Async>::init(tx, rx, rts, cts, config);
62 53
63 let state = T::state(); 54 let state = T::state();
@@ -168,6 +159,8 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
168 159
169 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a { 160 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
170 poll_fn(move |cx| { 161 poll_fn(move |cx| {
162 unsafe { T::Interrupt::steal() }.pend();
163
171 let state = T::state(); 164 let state = T::state();
172 let mut rx_reader = unsafe { state.rx_buf.reader() }; 165 let mut rx_reader = unsafe { state.rx_buf.reader() };
173 let n = rx_reader.pop(|data| { 166 let n = rx_reader.pop(|data| {
@@ -186,6 +179,8 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
186 179
187 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> { 180 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> {
188 poll_fn(move |cx| { 181 poll_fn(move |cx| {
182 unsafe { T::Interrupt::steal() }.pend();
183
189 let state = T::state(); 184 let state = T::state();
190 let mut rx_reader = unsafe { state.rx_buf.reader() }; 185 let mut rx_reader = unsafe { state.rx_buf.reader() };
191 let (p, n) = rx_reader.pop_buf(); 186 let (p, n) = rx_reader.pop_buf();
@@ -310,40 +305,31 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
310 let s = T::state(); 305 let s = T::state();
311 306
312 unsafe { 307 unsafe {
313 // RX
314
315 let ris = r.uartris().read(); 308 let ris = r.uartris().read();
316 // Clear interrupt flags 309 let mut mis = r.uartimsc().read();
317 r.uarticr().write(|w| {
318 w.set_rxic(true);
319 w.set_rtic(true);
320 });
321 310
322 if ris.peris() { 311 // Errors
323 warn!("Parity error");
324 r.uarticr().write(|w| {
325 w.set_peic(true);
326 });
327 }
328 if ris.feris() { 312 if ris.feris() {
329 warn!("Framing error"); 313 warn!("Framing error");
330 r.uarticr().write(|w| { 314 }
331 w.set_feic(true); 315 if ris.peris() {
332 }); 316 warn!("Parity error");
333 } 317 }
334 if ris.beris() { 318 if ris.beris() {
335 warn!("Break error"); 319 warn!("Break error");
336 r.uarticr().write(|w| {
337 w.set_beic(true);
338 });
339 } 320 }
340 if ris.oeris() { 321 if ris.oeris() {
341 warn!("Overrun error"); 322 warn!("Overrun error");
342 r.uarticr().write(|w| {
343 w.set_oeic(true);
344 });
345 } 323 }
324 // Clear any error flags
325 r.uarticr().write(|w| {
326 w.set_feic(true);
327 w.set_peic(true);
328 w.set_beic(true);
329 w.set_oeic(true);
330 });
346 331
332 // RX
347 let mut rx_writer = s.rx_buf.writer(); 333 let mut rx_writer = s.rx_buf.writer();
348 let rx_buf = rx_writer.push_slice(); 334 let rx_buf = rx_writer.push_slice();
349 let mut n_read = 0; 335 let mut n_read = 0;
@@ -358,33 +344,30 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
358 rx_writer.push_done(n_read); 344 rx_writer.push_done(n_read);
359 s.rx_waker.wake(); 345 s.rx_waker.wake();
360 } 346 }
347 // Disable any further RX interrupts when the buffer becomes full.
348 mis.set_rxim(!s.rx_buf.is_full());
349 mis.set_rtim(!s.rx_buf.is_full());
361 350
362 // TX 351 // TX
363 let mut tx_reader = s.tx_buf.reader(); 352 let mut tx_reader = s.tx_buf.reader();
364 let tx_buf = tx_reader.pop_slice(); 353 let tx_buf = tx_reader.pop_slice();
365 if tx_buf.len() == 0 { 354 let mut n_written = 0;
366 // Disable interrupt until we have something to transmit again 355 for tx_byte in tx_buf.iter_mut() {
367 r.uartimsc().modify(|w| { 356 if r.uartfr().read().txff() {
368 w.set_txim(false); 357 break;
369 });
370 } else {
371 r.uartimsc().modify(|w| {
372 w.set_txim(true);
373 });
374
375 let mut n_written = 0;
376 for tx_byte in tx_buf.iter_mut() {
377 if r.uartfr().read().txff() {
378 break;
379 }
380 r.uartdr().write(|w| w.set_data(*tx_byte));
381 n_written += 1;
382 }
383 if n_written > 0 {
384 tx_reader.pop_done(n_written);
385 s.tx_waker.wake();
386 } 358 }
359 r.uartdr().write(|w| w.set_data(*tx_byte));
360 n_written += 1;
387 } 361 }
362 if n_written > 0 {
363 tx_reader.pop_done(n_written);
364 s.tx_waker.wake();
365 }
366 // Disable the TX interrupt when we do not have more data to send.
367 mis.set_txim(!s.tx_buf.is_empty());
368
369 // Update interrupt mask.
370 r.uartimsc().write_value(mis);
388 } 371 }
389} 372}
390 373