aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/uart
diff options
context:
space:
mode:
authortact1m4n3 <[email protected]>2024-05-17 21:07:32 +0300
committertact1m4n3 <[email protected]>2024-05-17 21:51:45 +0300
commit5b2535c8a2e27e6f6f9707d05dc69aa3a603c480 (patch)
treeb4add7a286db42d5d88470932994b0192bd40c72 /embassy-rp/src/uart
parent17dde65ac2cbac36b4cd70ea01a2a51acac00026 (diff)
fix(embassy-rp): fix drop implementation of BufferedUartRx and BufferedUartTx
Diffstat (limited to 'embassy-rp/src/uart')
-rw-r--r--embassy-rp/src/uart/buffered.rs146
-rw-r--r--embassy-rp/src/uart/mod.rs8
2 files changed, 82 insertions, 72 deletions
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index da1157984..c94164040 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -51,14 +51,20 @@ pub struct BufferedUartTx<'d, T: Instance> {
51 51
52pub(crate) fn init_buffers<'d, T: Instance + 'd>( 52pub(crate) fn init_buffers<'d, T: Instance + 'd>(
53 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 53 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
54 tx_buffer: &'d mut [u8], 54 tx_buffer: Option<&'d mut [u8]>,
55 rx_buffer: &'d mut [u8], 55 rx_buffer: Option<&'d mut [u8]>,
56) { 56) {
57 let state = T::buffered_state(); 57 let state = T::buffered_state();
58 let len = tx_buffer.len(); 58
59 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 59 if let Some(tx_buffer) = tx_buffer {
60 let len = rx_buffer.len(); 60 let len = tx_buffer.len();
61 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 61 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
62 }
63
64 if let Some(rx_buffer) = rx_buffer {
65 let len = rx_buffer.len();
66 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
67 }
62 68
63 // From the datasheet: 69 // From the datasheet:
64 // "The transmit interrupt is based on a transition through a level, rather 70 // "The transmit interrupt is based on a transition through a level, rather
@@ -95,7 +101,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
95 into_ref!(tx, rx); 101 into_ref!(tx, rx);
96 102
97 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config); 103 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config);
98 init_buffers::<T>(irq, tx_buffer, rx_buffer); 104 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
99 105
100 Self { 106 Self {
101 rx: BufferedUartRx { phantom: PhantomData }, 107 rx: BufferedUartRx { phantom: PhantomData },
@@ -124,7 +130,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
124 Some(cts.map_into()), 130 Some(cts.map_into()),
125 config, 131 config,
126 ); 132 );
127 init_buffers::<T>(irq, tx_buffer, rx_buffer); 133 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
128 134
129 Self { 135 Self {
130 rx: BufferedUartRx { phantom: PhantomData }, 136 rx: BufferedUartRx { phantom: PhantomData },
@@ -175,7 +181,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
175 into_ref!(rx); 181 into_ref!(rx);
176 182
177 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config); 183 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config);
178 init_buffers::<T>(irq, &mut [], rx_buffer); 184 init_buffers::<T>(irq, None, Some(rx_buffer));
179 185
180 Self { phantom: PhantomData } 186 Self { phantom: PhantomData }
181 } 187 }
@@ -192,7 +198,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
192 into_ref!(rx, rts); 198 into_ref!(rx, rts);
193 199
194 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config); 200 super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config);
195 init_buffers::<T>(irq, &mut [], rx_buffer); 201 init_buffers::<T>(irq, None, Some(rx_buffer));
196 202
197 Self { phantom: PhantomData } 203 Self { phantom: PhantomData }
198 } 204 }
@@ -323,7 +329,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
323 into_ref!(tx); 329 into_ref!(tx);
324 330
325 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config); 331 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config);
326 init_buffers::<T>(irq, tx_buffer, &mut []); 332 init_buffers::<T>(irq, Some(tx_buffer), None);
327 333
328 Self { phantom: PhantomData } 334 Self { phantom: PhantomData }
329 } 335 }
@@ -340,12 +346,12 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
340 into_ref!(tx, cts); 346 into_ref!(tx, cts);
341 347
342 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config); 348 super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config);
343 init_buffers::<T>(irq, tx_buffer, &mut []); 349 init_buffers::<T>(irq, Some(tx_buffer), None);
344 350
345 Self { phantom: PhantomData } 351 Self { phantom: PhantomData }
346 } 352 }
347 353
348 fn write<'a>(buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a { 354 fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ {
349 poll_fn(move |cx| { 355 poll_fn(move |cx| {
350 if buf.is_empty() { 356 if buf.is_empty() {
351 return Poll::Ready(Ok(0)); 357 return Poll::Ready(Ok(0));
@@ -459,9 +465,9 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
459 let state = T::buffered_state(); 465 let state = T::buffered_state();
460 unsafe { state.rx_buf.deinit() } 466 unsafe { state.rx_buf.deinit() }
461 467
462 // TX is inactive if the the buffer is not available. 468 // TX is inactive if the buffer is not available.
463 // We can now unregister the interrupt handler 469 // We can now unregister the interrupt handler
464 if state.tx_buf.is_empty() { 470 if !state.tx_buf.is_available() {
465 T::Interrupt::disable(); 471 T::Interrupt::disable();
466 } 472 }
467 } 473 }
@@ -472,9 +478,9 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
472 let state = T::buffered_state(); 478 let state = T::buffered_state();
473 unsafe { state.tx_buf.deinit() } 479 unsafe { state.tx_buf.deinit() }
474 480
475 // RX is inactive if the the buffer is not available. 481 // RX is inactive if the buffer is not available.
476 // We can now unregister the interrupt handler 482 // We can now unregister the interrupt handler
477 if state.rx_buf.is_empty() { 483 if !state.rx_buf.is_available() {
478 T::Interrupt::disable(); 484 T::Interrupt::disable();
479 } 485 }
480 } 486 }
@@ -520,64 +526,68 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
520 } 526 }
521 527
522 // RX 528 // RX
523 let mut rx_writer = unsafe { s.rx_buf.writer() }; 529 if s.rx_buf.is_available() {
524 let rx_buf = rx_writer.push_slice(); 530 let mut rx_writer = unsafe { s.rx_buf.writer() };
525 let mut n_read = 0; 531 let rx_buf = rx_writer.push_slice();
526 let mut error = false; 532 let mut n_read = 0;
527 for rx_byte in rx_buf { 533 let mut error = false;
528 if r.uartfr().read().rxfe() { 534 for rx_byte in rx_buf {
529 break; 535 if r.uartfr().read().rxfe() {
536 break;
537 }
538 let dr = r.uartdr().read();
539 if (dr.0 >> 8) != 0 {
540 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
541 error = true;
542 // only fill the buffer with valid characters. the current character is fine
543 // if the error is an overrun, but if we add it to the buffer we'll report
544 // the overrun one character too late. drop it instead and pretend we were
545 // a bit slower at draining the rx fifo than we actually were.
546 // this is consistent with blocking uart error reporting.
547 break;
548 }
549 *rx_byte = dr.data();
550 n_read += 1;
530 } 551 }
531 let dr = r.uartdr().read(); 552 if n_read > 0 {
532 if (dr.0 >> 8) != 0 { 553 rx_writer.push_done(n_read);
533 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); 554 s.rx_waker.wake();
534 error = true; 555 } else if error {
535 // only fill the buffer with valid characters. the current character is fine 556 s.rx_waker.wake();
536 // if the error is an overrun, but if we add it to the buffer we'll report 557 }
537 // the overrun one character too late. drop it instead and pretend we were 558 // Disable any further RX interrupts when the buffer becomes full or
538 // a bit slower at draining the rx fifo than we actually were. 559 // errors have occurred. This lets us buffer additional errors in the
539 // this is consistent with blocking uart error reporting. 560 // fifo without needing more error storage locations, and most applications
540 break; 561 // will want to do a full reset of their uart state anyway once an error
562 // has happened.
563 if s.rx_buf.is_full() || error {
564 r.uartimsc().write_clear(|w| {
565 w.set_rxim(true);
566 w.set_rtim(true);
567 });
541 } 568 }
542 *rx_byte = dr.data();
543 n_read += 1;
544 }
545 if n_read > 0 {
546 rx_writer.push_done(n_read);
547 s.rx_waker.wake();
548 } else if error {
549 s.rx_waker.wake();
550 }
551 // Disable any further RX interrupts when the buffer becomes full or
552 // errors have occurred. This lets us buffer additional errors in the
553 // fifo without needing more error storage locations, and most applications
554 // will want to do a full reset of their uart state anyway once an error
555 // has happened.
556 if s.rx_buf.is_full() || error {
557 r.uartimsc().write_clear(|w| {
558 w.set_rxim(true);
559 w.set_rtim(true);
560 });
561 } 569 }
562 570
563 // TX 571 // TX
564 let mut tx_reader = unsafe { s.tx_buf.reader() }; 572 if s.tx_buf.is_available() {
565 let tx_buf = tx_reader.pop_slice(); 573 let mut tx_reader = unsafe { s.tx_buf.reader() };
566 let mut n_written = 0; 574 let tx_buf = tx_reader.pop_slice();
567 for tx_byte in tx_buf.iter_mut() { 575 let mut n_written = 0;
568 if r.uartfr().read().txff() { 576 for tx_byte in tx_buf.iter_mut() {
569 break; 577 if r.uartfr().read().txff() {
578 break;
579 }
580 r.uartdr().write(|w| w.set_data(*tx_byte));
581 n_written += 1;
570 } 582 }
571 r.uartdr().write(|w| w.set_data(*tx_byte)); 583 if n_written > 0 {
572 n_written += 1; 584 tx_reader.pop_done(n_written);
573 } 585 s.tx_waker.wake();
574 if n_written > 0 { 586 }
575 tx_reader.pop_done(n_written); 587 // The TX interrupt only triggers once when the FIFO threshold is
576 s.tx_waker.wake(); 588 // crossed. No need to disable it when the buffer becomes empty
589 // as it does re-trigger anymore once we have cleared it.
577 } 590 }
578 // The TX interrupt only triggers once when the FIFO threshold is
579 // crossed. No need to disable it when the buffer becomes empty
580 // as it does re-trigger anymore once we have cleared it.
581 } 591 }
582} 592}
583 593
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index ee2dcb27d..30ece15bd 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -231,7 +231,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
231 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 231 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
232 tx_buffer: &'d mut [u8], 232 tx_buffer: &'d mut [u8],
233 ) -> BufferedUartTx<'d, T> { 233 ) -> BufferedUartTx<'d, T> {
234 buffered::init_buffers::<T>(irq, tx_buffer, &mut []); 234 buffered::init_buffers::<T>(irq, Some(tx_buffer), None);
235 235
236 BufferedUartTx { phantom: PhantomData } 236 BufferedUartTx { phantom: PhantomData }
237 } 237 }
@@ -352,7 +352,7 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
352 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 352 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
353 rx_buffer: &'d mut [u8], 353 rx_buffer: &'d mut [u8],
354 ) -> BufferedUartRx<'d, T> { 354 ) -> BufferedUartRx<'d, T> {
355 buffered::init_buffers::<T>(irq, &mut [], rx_buffer); 355 buffered::init_buffers::<T>(irq, None, Some(rx_buffer));
356 356
357 BufferedUartRx { phantom: PhantomData } 357 BufferedUartRx { phantom: PhantomData }
358 } 358 }
@@ -690,7 +690,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
690 tx_buffer: &'d mut [u8], 690 tx_buffer: &'d mut [u8],
691 rx_buffer: &'d mut [u8], 691 rx_buffer: &'d mut [u8],
692 ) -> BufferedUart<'d, T> { 692 ) -> BufferedUart<'d, T> {
693 buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer); 693 buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
694 694
695 BufferedUart { 695 BufferedUart {
696 rx: BufferedUartRx { phantom: PhantomData }, 696 rx: BufferedUartRx { phantom: PhantomData },
@@ -860,7 +860,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
860 }); 860 });
861 } 861 }
862 862
863 /// sets baudrate on runtime 863 /// sets baudrate on runtime
864 pub fn set_baudrate(&mut self, baudrate: u32) { 864 pub fn set_baudrate(&mut self, baudrate: u32) {
865 Self::set_baudrate_inner(baudrate); 865 Self::set_baudrate_inner(baudrate);
866 } 866 }