diff options
| author | tact1m4n3 <[email protected]> | 2024-05-17 21:07:32 +0300 |
|---|---|---|
| committer | tact1m4n3 <[email protected]> | 2024-05-17 21:51:45 +0300 |
| commit | 5b2535c8a2e27e6f6f9707d05dc69aa3a603c480 (patch) | |
| tree | b4add7a286db42d5d88470932994b0192bd40c72 /embassy-rp/src/uart | |
| parent | 17dde65ac2cbac36b4cd70ea01a2a51acac00026 (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.rs | 146 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 8 |
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 | ||
| 52 | pub(crate) fn init_buffers<'d, T: Instance + 'd>( | 52 | pub(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 | } |
