diff options
| author | pennae <[email protected]> | 2023-05-15 15:21:05 +0200 |
|---|---|---|
| committer | pennae <[email protected]> | 2023-05-15 15:24:56 +0200 |
| commit | 14a5d03af2a74eccaa9930bdf81eef43791a4b33 (patch) | |
| tree | 3a0879c21cf09702c670b14672e62b940a2157f0 /embassy-rp/src/uart | |
| parent | 82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff) | |
rp: remove take!, add bind_interrupts!
Diffstat (limited to 'embassy-rp/src/uart')
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 209 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 101 |
2 files changed, 169 insertions, 141 deletions
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 9d3de1bd8..12d6b8d91 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -3,7 +3,7 @@ use core::slice; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{AtomicU8, Ordering}; | 5 | use atomic_polyfill::{AtomicU8, Ordering}; |
| 6 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | 6 | use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt}; |
| 7 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; | 7 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| @@ -52,7 +52,7 @@ pub struct BufferedUartTx<'d, T: Instance> { | |||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | pub(crate) fn init_buffers<'d, T: Instance + 'd>( | 54 | pub(crate) fn init_buffers<'d, T: Instance + 'd>( |
| 55 | irq: PeripheralRef<'d, T::Interrupt>, | 55 | _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 56 | tx_buffer: &'d mut [u8], | 56 | tx_buffer: &'d mut [u8], |
| 57 | rx_buffer: &'d mut [u8], | 57 | rx_buffer: &'d mut [u8], |
| 58 | ) { | 58 | ) { |
| @@ -79,24 +79,23 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>( | |||
| 79 | w.set_rtim(true); | 79 | w.set_rtim(true); |
| 80 | w.set_txim(true); | 80 | w.set_txim(true); |
| 81 | }); | 81 | }); |
| 82 | }; | ||
| 83 | 82 | ||
| 84 | irq.set_handler(on_interrupt::<T>); | 83 | T::Interrupt::steal().unpend(); |
| 85 | irq.unpend(); | 84 | T::Interrupt::steal().enable(); |
| 86 | irq.enable(); | 85 | }; |
| 87 | } | 86 | } |
| 88 | 87 | ||
| 89 | impl<'d, T: Instance> BufferedUart<'d, T> { | 88 | impl<'d, T: Instance> BufferedUart<'d, T> { |
| 90 | pub fn new( | 89 | pub fn new( |
| 91 | _uart: impl Peripheral<P = T> + 'd, | 90 | _uart: impl Peripheral<P = T> + 'd, |
| 92 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 91 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 93 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 92 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 94 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 93 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 95 | tx_buffer: &'d mut [u8], | 94 | tx_buffer: &'d mut [u8], |
| 96 | rx_buffer: &'d mut [u8], | 95 | rx_buffer: &'d mut [u8], |
| 97 | config: Config, | 96 | config: Config, |
| 98 | ) -> Self { | 97 | ) -> Self { |
| 99 | into_ref!(irq, tx, rx); | 98 | into_ref!(tx, rx); |
| 100 | 99 | ||
| 101 | super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config); | 100 | super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config); |
| 102 | init_buffers::<T>(irq, tx_buffer, rx_buffer); | 101 | init_buffers::<T>(irq, tx_buffer, rx_buffer); |
| @@ -109,7 +108,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> { | |||
| 109 | 108 | ||
| 110 | pub fn new_with_rtscts( | 109 | pub fn new_with_rtscts( |
| 111 | _uart: impl Peripheral<P = T> + 'd, | 110 | _uart: impl Peripheral<P = T> + 'd, |
| 112 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 111 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 113 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 112 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 114 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 113 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 115 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 114 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| @@ -118,7 +117,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> { | |||
| 118 | rx_buffer: &'d mut [u8], | 117 | rx_buffer: &'d mut [u8], |
| 119 | config: Config, | 118 | config: Config, |
| 120 | ) -> Self { | 119 | ) -> Self { |
| 121 | into_ref!(irq, tx, rx, cts, rts); | 120 | into_ref!(tx, rx, cts, rts); |
| 122 | 121 | ||
| 123 | super::Uart::<'d, T, Async>::init( | 122 | super::Uart::<'d, T, Async>::init( |
| 124 | Some(tx.map_into()), | 123 | Some(tx.map_into()), |
| @@ -163,12 +162,12 @@ impl<'d, T: Instance> BufferedUart<'d, T> { | |||
| 163 | impl<'d, T: Instance> BufferedUartRx<'d, T> { | 162 | impl<'d, T: Instance> BufferedUartRx<'d, T> { |
| 164 | pub fn new( | 163 | pub fn new( |
| 165 | _uart: impl Peripheral<P = T> + 'd, | 164 | _uart: impl Peripheral<P = T> + 'd, |
| 166 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 165 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 167 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 166 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 168 | rx_buffer: &'d mut [u8], | 167 | rx_buffer: &'d mut [u8], |
| 169 | config: Config, | 168 | config: Config, |
| 170 | ) -> Self { | 169 | ) -> Self { |
| 171 | into_ref!(irq, rx); | 170 | into_ref!(rx); |
| 172 | 171 | ||
| 173 | super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config); | 172 | super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config); |
| 174 | init_buffers::<T>(irq, &mut [], rx_buffer); | 173 | init_buffers::<T>(irq, &mut [], rx_buffer); |
| @@ -178,13 +177,13 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { | |||
| 178 | 177 | ||
| 179 | pub fn new_with_rts( | 178 | pub fn new_with_rts( |
| 180 | _uart: impl Peripheral<P = T> + 'd, | 179 | _uart: impl Peripheral<P = T> + 'd, |
| 181 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 180 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 182 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 181 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 183 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 182 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 184 | rx_buffer: &'d mut [u8], | 183 | rx_buffer: &'d mut [u8], |
| 185 | config: Config, | 184 | config: Config, |
| 186 | ) -> Self { | 185 | ) -> Self { |
| 187 | into_ref!(irq, rx, rts); | 186 | into_ref!(rx, rts); |
| 188 | 187 | ||
| 189 | super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config); | 188 | super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config); |
| 190 | init_buffers::<T>(irq, &mut [], rx_buffer); | 189 | init_buffers::<T>(irq, &mut [], rx_buffer); |
| @@ -312,12 +311,12 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { | |||
| 312 | impl<'d, T: Instance> BufferedUartTx<'d, T> { | 311 | impl<'d, T: Instance> BufferedUartTx<'d, T> { |
| 313 | pub fn new( | 312 | pub fn new( |
| 314 | _uart: impl Peripheral<P = T> + 'd, | 313 | _uart: impl Peripheral<P = T> + 'd, |
| 315 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 314 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 316 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 315 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 317 | tx_buffer: &'d mut [u8], | 316 | tx_buffer: &'d mut [u8], |
| 318 | config: Config, | 317 | config: Config, |
| 319 | ) -> Self { | 318 | ) -> Self { |
| 320 | into_ref!(irq, tx); | 319 | into_ref!(tx); |
| 321 | 320 | ||
| 322 | super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config); | 321 | super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config); |
| 323 | init_buffers::<T>(irq, tx_buffer, &mut []); | 322 | init_buffers::<T>(irq, tx_buffer, &mut []); |
| @@ -327,13 +326,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 327 | 326 | ||
| 328 | pub fn new_with_cts( | 327 | pub fn new_with_cts( |
| 329 | _uart: impl Peripheral<P = T> + 'd, | 328 | _uart: impl Peripheral<P = T> + 'd, |
| 330 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 329 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 331 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 330 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 332 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | 331 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |
| 333 | tx_buffer: &'d mut [u8], | 332 | tx_buffer: &'d mut [u8], |
| 334 | config: Config, | 333 | config: Config, |
| 335 | ) -> Self { | 334 | ) -> Self { |
| 336 | into_ref!(irq, tx, cts); | 335 | into_ref!(tx, cts); |
| 337 | 336 | ||
| 338 | super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config); | 337 | super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config); |
| 339 | init_buffers::<T>(irq, tx_buffer, &mut []); | 338 | init_buffers::<T>(irq, tx_buffer, &mut []); |
| @@ -482,97 +481,107 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { | |||
| 482 | } | 481 | } |
| 483 | } | 482 | } |
| 484 | 483 | ||
| 485 | pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) { | 484 | pub struct BufferedInterruptHandler<T: Instance> { |
| 486 | let r = T::regs(); | 485 | _uart: PhantomData<T>, |
| 487 | let s = T::buffered_state(); | 486 | } |
| 488 | 487 | ||
| 489 | unsafe { | 488 | impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> { |
| 490 | // Clear TX and error interrupt flags | 489 | unsafe fn on_interrupt() { |
| 491 | // RX interrupt flags are cleared by reading from the FIFO. | 490 | let r = T::regs(); |
| 492 | let ris = r.uartris().read(); | 491 | if r.uartdmacr().read().rxdmae() { |
| 493 | r.uarticr().write(|w| { | 492 | return; |
| 494 | w.set_txic(ris.txris()); | 493 | } |
| 495 | w.set_feic(ris.feris()); | ||
| 496 | w.set_peic(ris.peris()); | ||
| 497 | w.set_beic(ris.beris()); | ||
| 498 | w.set_oeic(ris.oeris()); | ||
| 499 | }); | ||
| 500 | 494 | ||
| 501 | trace!("on_interrupt ris={:#X}", ris.0); | 495 | let s = T::buffered_state(); |
| 502 | 496 | ||
| 503 | // Errors | 497 | unsafe { |
| 504 | if ris.feris() { | 498 | // Clear TX and error interrupt flags |
| 505 | warn!("Framing error"); | 499 | // RX interrupt flags are cleared by reading from the FIFO. |
| 506 | } | 500 | let ris = r.uartris().read(); |
| 507 | if ris.peris() { | 501 | r.uarticr().write(|w| { |
| 508 | warn!("Parity error"); | 502 | w.set_txic(ris.txris()); |
| 509 | } | 503 | w.set_feic(ris.feris()); |
| 510 | if ris.beris() { | 504 | w.set_peic(ris.peris()); |
| 511 | warn!("Break error"); | 505 | w.set_beic(ris.beris()); |
| 512 | } | 506 | w.set_oeic(ris.oeris()); |
| 513 | if ris.oeris() { | 507 | }); |
| 514 | warn!("Overrun error"); | ||
| 515 | } | ||
| 516 | 508 | ||
| 517 | // RX | 509 | trace!("on_interrupt ris={:#X}", ris.0); |
| 518 | let mut rx_writer = s.rx_buf.writer(); | 510 | |
| 519 | let rx_buf = rx_writer.push_slice(); | 511 | // Errors |
| 520 | let mut n_read = 0; | 512 | if ris.feris() { |
| 521 | let mut error = false; | 513 | warn!("Framing error"); |
| 522 | for rx_byte in rx_buf { | ||
| 523 | if r.uartfr().read().rxfe() { | ||
| 524 | break; | ||
| 525 | } | 514 | } |
| 526 | let dr = r.uartdr().read(); | 515 | if ris.peris() { |
| 527 | if (dr.0 >> 8) != 0 { | 516 | warn!("Parity error"); |
| 528 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); | 517 | } |
| 529 | error = true; | 518 | if ris.beris() { |
| 530 | // only fill the buffer with valid characters. the current character is fine | 519 | warn!("Break error"); |
| 531 | // if the error is an overrun, but if we add it to the buffer we'll report | 520 | } |
| 532 | // the overrun one character too late. drop it instead and pretend we were | 521 | if ris.oeris() { |
| 533 | // a bit slower at draining the rx fifo than we actually were. | 522 | warn!("Overrun error"); |
| 534 | // this is consistent with blocking uart error reporting. | ||
| 535 | break; | ||
| 536 | } | 523 | } |
| 537 | *rx_byte = dr.data(); | ||
| 538 | n_read += 1; | ||
| 539 | } | ||
| 540 | if n_read > 0 { | ||
| 541 | rx_writer.push_done(n_read); | ||
| 542 | s.rx_waker.wake(); | ||
| 543 | } else if error { | ||
| 544 | s.rx_waker.wake(); | ||
| 545 | } | ||
| 546 | // Disable any further RX interrupts when the buffer becomes full or | ||
| 547 | // errors have occurred. This lets us buffer additional errors in the | ||
| 548 | // fifo without needing more error storage locations, and most applications | ||
| 549 | // will want to do a full reset of their uart state anyway once an error | ||
| 550 | // has happened. | ||
| 551 | if s.rx_buf.is_full() || error { | ||
| 552 | r.uartimsc().write_clear(|w| { | ||
| 553 | w.set_rxim(true); | ||
| 554 | w.set_rtim(true); | ||
| 555 | }); | ||
| 556 | } | ||
| 557 | 524 | ||
| 558 | // TX | 525 | // RX |
| 559 | let mut tx_reader = s.tx_buf.reader(); | 526 | let mut rx_writer = s.rx_buf.writer(); |
| 560 | let tx_buf = tx_reader.pop_slice(); | 527 | let rx_buf = rx_writer.push_slice(); |
| 561 | let mut n_written = 0; | 528 | let mut n_read = 0; |
| 562 | for tx_byte in tx_buf.iter_mut() { | 529 | let mut error = false; |
| 563 | if r.uartfr().read().txff() { | 530 | for rx_byte in rx_buf { |
| 564 | break; | 531 | if r.uartfr().read().rxfe() { |
| 532 | break; | ||
| 533 | } | ||
| 534 | let dr = r.uartdr().read(); | ||
| 535 | if (dr.0 >> 8) != 0 { | ||
| 536 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); | ||
| 537 | error = true; | ||
| 538 | // only fill the buffer with valid characters. the current character is fine | ||
| 539 | // if the error is an overrun, but if we add it to the buffer we'll report | ||
| 540 | // the overrun one character too late. drop it instead and pretend we were | ||
| 541 | // a bit slower at draining the rx fifo than we actually were. | ||
| 542 | // this is consistent with blocking uart error reporting. | ||
| 543 | break; | ||
| 544 | } | ||
| 545 | *rx_byte = dr.data(); | ||
| 546 | n_read += 1; | ||
| 565 | } | 547 | } |
| 566 | r.uartdr().write(|w| w.set_data(*tx_byte)); | 548 | if n_read > 0 { |
| 567 | n_written += 1; | 549 | rx_writer.push_done(n_read); |
| 568 | } | 550 | s.rx_waker.wake(); |
| 569 | if n_written > 0 { | 551 | } else if error { |
| 570 | tx_reader.pop_done(n_written); | 552 | s.rx_waker.wake(); |
| 571 | s.tx_waker.wake(); | 553 | } |
| 554 | // Disable any further RX interrupts when the buffer becomes full or | ||
| 555 | // errors have occurred. This lets us buffer additional errors in the | ||
| 556 | // fifo without needing more error storage locations, and most applications | ||
| 557 | // will want to do a full reset of their uart state anyway once an error | ||
| 558 | // has happened. | ||
| 559 | if s.rx_buf.is_full() || error { | ||
| 560 | r.uartimsc().write_clear(|w| { | ||
| 561 | w.set_rxim(true); | ||
| 562 | w.set_rtim(true); | ||
| 563 | }); | ||
| 564 | } | ||
| 565 | |||
| 566 | // TX | ||
| 567 | let mut tx_reader = s.tx_buf.reader(); | ||
| 568 | let tx_buf = tx_reader.pop_slice(); | ||
| 569 | let mut n_written = 0; | ||
| 570 | for tx_byte in tx_buf.iter_mut() { | ||
| 571 | if r.uartfr().read().txff() { | ||
| 572 | break; | ||
| 573 | } | ||
| 574 | r.uartdr().write(|w| w.set_data(*tx_byte)); | ||
| 575 | n_written += 1; | ||
| 576 | } | ||
| 577 | if n_written > 0 { | ||
| 578 | tx_reader.pop_done(n_written); | ||
| 579 | s.tx_waker.wake(); | ||
| 580 | } | ||
| 581 | // The TX interrupt only triggers once when the FIFO threshold is | ||
| 582 | // crossed. No need to disable it when the buffer becomes empty | ||
| 583 | // as it does re-trigger anymore once we have cleared it. | ||
| 572 | } | 584 | } |
| 573 | // The TX interrupt only triggers once when the FIFO threshold is | ||
| 574 | // crossed. No need to disable it when the buffer becomes empty | ||
| 575 | // as it does re-trigger anymore once we have cleared it. | ||
| 576 | } | 585 | } |
| 577 | } | 586 | } |
| 578 | 587 | ||
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index a0ee6b4ce..7234336b4 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -3,7 +3,7 @@ use core::marker::PhantomData; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{AtomicU16, Ordering}; | 5 | use atomic_polyfill::{AtomicU16, Ordering}; |
| 6 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | 6 | use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt}; |
| 7 | use embassy_futures::select::{select, Either}; | 7 | use embassy_futures::select::{select, Either}; |
| 8 | use embassy_hal_common::{into_ref, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -20,7 +20,7 @@ use crate::{pac, peripherals, Peripheral, RegExt}; | |||
| 20 | #[cfg(feature = "nightly")] | 20 | #[cfg(feature = "nightly")] |
| 21 | mod buffered; | 21 | mod buffered; |
| 22 | #[cfg(feature = "nightly")] | 22 | #[cfg(feature = "nightly")] |
| 23 | pub use buffered::{BufferedUart, BufferedUartRx, BufferedUartTx}; | 23 | pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; |
| 24 | 24 | ||
| 25 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 25 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 26 | pub enum DataBits { | 26 | pub enum DataBits { |
| @@ -203,11 +203,9 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> { | |||
| 203 | #[cfg(feature = "nightly")] | 203 | #[cfg(feature = "nightly")] |
| 204 | pub fn into_buffered( | 204 | pub fn into_buffered( |
| 205 | self, | 205 | self, |
| 206 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 206 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 207 | tx_buffer: &'d mut [u8], | 207 | tx_buffer: &'d mut [u8], |
| 208 | ) -> BufferedUartTx<'d, T> { | 208 | ) -> BufferedUartTx<'d, T> { |
| 209 | into_ref!(irq); | ||
| 210 | |||
| 211 | buffered::init_buffers::<T>(irq, tx_buffer, &mut []); | 209 | buffered::init_buffers::<T>(irq, tx_buffer, &mut []); |
| 212 | 210 | ||
| 213 | BufferedUartTx { phantom: PhantomData } | 211 | BufferedUartTx { phantom: PhantomData } |
| @@ -235,25 +233,24 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 235 | pub fn new( | 233 | pub fn new( |
| 236 | _uart: impl Peripheral<P = T> + 'd, | 234 | _uart: impl Peripheral<P = T> + 'd, |
| 237 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 235 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 238 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 236 | _irq: impl Binding<T::Interrupt, InterruptHandler<T>>, |
| 239 | rx_dma: impl Peripheral<P = impl Channel> + 'd, | 237 | rx_dma: impl Peripheral<P = impl Channel> + 'd, |
| 240 | config: Config, | 238 | config: Config, |
| 241 | ) -> Self { | 239 | ) -> Self { |
| 242 | into_ref!(rx, irq, rx_dma); | 240 | into_ref!(rx, rx_dma); |
| 243 | Uart::<T, M>::init(None, Some(rx.map_into()), None, None, config); | 241 | Uart::<T, M>::init(None, Some(rx.map_into()), None, None, config); |
| 244 | Self::new_inner(Some(irq), Some(rx_dma.map_into())) | 242 | Self::new_inner(true, Some(rx_dma.map_into())) |
| 245 | } | 243 | } |
| 246 | 244 | ||
| 247 | fn new_inner(irq: Option<PeripheralRef<'d, T::Interrupt>>, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self { | 245 | fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self { |
| 248 | debug_assert_eq!(irq.is_some(), rx_dma.is_some()); | 246 | debug_assert_eq!(has_irq, rx_dma.is_some()); |
| 249 | if let Some(irq) = irq { | 247 | if has_irq { |
| 250 | unsafe { | 248 | unsafe { |
| 251 | // disable all error interrupts initially | 249 | // disable all error interrupts initially |
| 252 | T::regs().uartimsc().write(|w| w.0 = 0); | 250 | T::regs().uartimsc().write(|w| w.0 = 0); |
| 251 | T::Interrupt::steal().unpend(); | ||
| 252 | T::Interrupt::steal().enable(); | ||
| 253 | } | 253 | } |
| 254 | irq.set_handler(on_interrupt::<T>); | ||
| 255 | irq.unpend(); | ||
| 256 | irq.enable(); | ||
| 257 | } | 254 | } |
| 258 | Self { | 255 | Self { |
| 259 | rx_dma, | 256 | rx_dma, |
| @@ -299,6 +296,12 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { | |||
| 299 | if let Some(_) = self.rx_dma { | 296 | if let Some(_) = self.rx_dma { |
| 300 | unsafe { | 297 | unsafe { |
| 301 | T::Interrupt::steal().disable(); | 298 | T::Interrupt::steal().disable(); |
| 299 | // clear dma flags. irq handlers use these to disambiguate among themselves. | ||
| 300 | T::regs().uartdmacr().write_clear(|reg| { | ||
| 301 | reg.set_rxdmae(true); | ||
| 302 | reg.set_txdmae(true); | ||
| 303 | reg.set_dmaonerr(true); | ||
| 304 | }); | ||
| 302 | } | 305 | } |
| 303 | } | 306 | } |
| 304 | } | 307 | } |
| @@ -312,33 +315,41 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> { | |||
| 312 | ) -> Self { | 315 | ) -> Self { |
| 313 | into_ref!(rx); | 316 | into_ref!(rx); |
| 314 | Uart::<T, Blocking>::init(None, Some(rx.map_into()), None, None, config); | 317 | Uart::<T, Blocking>::init(None, Some(rx.map_into()), None, None, config); |
| 315 | Self::new_inner(None, None) | 318 | Self::new_inner(false, None) |
| 316 | } | 319 | } |
| 317 | 320 | ||
| 318 | #[cfg(feature = "nightly")] | 321 | #[cfg(feature = "nightly")] |
| 319 | pub fn into_buffered( | 322 | pub fn into_buffered( |
| 320 | self, | 323 | self, |
| 321 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 324 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 322 | rx_buffer: &'d mut [u8], | 325 | rx_buffer: &'d mut [u8], |
| 323 | ) -> BufferedUartRx<'d, T> { | 326 | ) -> BufferedUartRx<'d, T> { |
| 324 | into_ref!(irq); | ||
| 325 | |||
| 326 | buffered::init_buffers::<T>(irq, &mut [], rx_buffer); | 327 | buffered::init_buffers::<T>(irq, &mut [], rx_buffer); |
| 327 | 328 | ||
| 328 | BufferedUartRx { phantom: PhantomData } | 329 | BufferedUartRx { phantom: PhantomData } |
| 329 | } | 330 | } |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 332 | unsafe fn on_interrupt<T: Instance>(_: *mut ()) { | 333 | pub struct InterruptHandler<T: Instance> { |
| 333 | let uart = T::regs(); | 334 | _uart: PhantomData<T>, |
| 334 | let state = T::dma_state(); | 335 | } |
| 335 | let errs = uart.uartris().read(); | 336 | |
| 336 | state.rx_errs.store(errs.0 as u16, Ordering::Relaxed); | 337 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { |
| 337 | state.rx_err_waker.wake(); | 338 | unsafe fn on_interrupt() { |
| 338 | // disable the error interrupts instead of clearing the flags. clearing the | 339 | let uart = T::regs(); |
| 339 | // flags would allow the dma transfer to continue, potentially signaling | 340 | if !uart.uartdmacr().read().rxdmae() { |
| 340 | // completion before we can check for errors that happened *during* the transfer. | 341 | return; |
| 341 | uart.uartimsc().write_clear(|w| w.0 = errs.0); | 342 | } |
| 343 | |||
| 344 | let state = T::dma_state(); | ||
| 345 | let errs = uart.uartris().read(); | ||
| 346 | state.rx_errs.store(errs.0 as u16, Ordering::Relaxed); | ||
| 347 | state.rx_err_waker.wake(); | ||
| 348 | // disable the error interrupts instead of clearing the flags. clearing the | ||
| 349 | // flags would allow the dma transfer to continue, potentially signaling | ||
| 350 | // completion before we can check for errors that happened *during* the transfer. | ||
| 351 | uart.uartimsc().write_clear(|w| w.0 = errs.0); | ||
| 352 | } | ||
| 342 | } | 353 | } |
| 343 | 354 | ||
| 344 | impl<'d, T: Instance> UartRx<'d, T, Async> { | 355 | impl<'d, T: Instance> UartRx<'d, T, Async> { |
| @@ -428,7 +439,17 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { | |||
| 428 | config: Config, | 439 | config: Config, |
| 429 | ) -> Self { | 440 | ) -> Self { |
| 430 | into_ref!(tx, rx); | 441 | into_ref!(tx, rx); |
| 431 | Self::new_inner(uart, tx.map_into(), rx.map_into(), None, None, None, None, None, config) | 442 | Self::new_inner( |
| 443 | uart, | ||
| 444 | tx.map_into(), | ||
| 445 | rx.map_into(), | ||
| 446 | None, | ||
| 447 | None, | ||
| 448 | false, | ||
| 449 | None, | ||
| 450 | None, | ||
| 451 | config, | ||
| 452 | ) | ||
| 432 | } | 453 | } |
| 433 | 454 | ||
| 434 | /// Create a new UART with hardware flow control (RTS/CTS) | 455 | /// Create a new UART with hardware flow control (RTS/CTS) |
| @@ -447,7 +468,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { | |||
| 447 | rx.map_into(), | 468 | rx.map_into(), |
| 448 | Some(rts.map_into()), | 469 | Some(rts.map_into()), |
| 449 | Some(cts.map_into()), | 470 | Some(cts.map_into()), |
| 450 | None, | 471 | false, |
| 451 | None, | 472 | None, |
| 452 | None, | 473 | None, |
| 453 | config, | 474 | config, |
| @@ -457,12 +478,10 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { | |||
| 457 | #[cfg(feature = "nightly")] | 478 | #[cfg(feature = "nightly")] |
| 458 | pub fn into_buffered( | 479 | pub fn into_buffered( |
| 459 | self, | 480 | self, |
| 460 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 481 | irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, |
| 461 | tx_buffer: &'d mut [u8], | 482 | tx_buffer: &'d mut [u8], |
| 462 | rx_buffer: &'d mut [u8], | 483 | rx_buffer: &'d mut [u8], |
| 463 | ) -> BufferedUart<'d, T> { | 484 | ) -> BufferedUart<'d, T> { |
| 464 | into_ref!(irq); | ||
| 465 | |||
| 466 | buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer); | 485 | buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer); |
| 467 | 486 | ||
| 468 | BufferedUart { | 487 | BufferedUart { |
| @@ -478,19 +497,19 @@ impl<'d, T: Instance> Uart<'d, T, Async> { | |||
| 478 | uart: impl Peripheral<P = T> + 'd, | 497 | uart: impl Peripheral<P = T> + 'd, |
| 479 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 498 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 480 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 499 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 481 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 500 | _irq: impl Binding<T::Interrupt, InterruptHandler<T>>, |
| 482 | tx_dma: impl Peripheral<P = impl Channel> + 'd, | 501 | tx_dma: impl Peripheral<P = impl Channel> + 'd, |
| 483 | rx_dma: impl Peripheral<P = impl Channel> + 'd, | 502 | rx_dma: impl Peripheral<P = impl Channel> + 'd, |
| 484 | config: Config, | 503 | config: Config, |
| 485 | ) -> Self { | 504 | ) -> Self { |
| 486 | into_ref!(tx, rx, irq, tx_dma, rx_dma); | 505 | into_ref!(tx, rx, tx_dma, rx_dma); |
| 487 | Self::new_inner( | 506 | Self::new_inner( |
| 488 | uart, | 507 | uart, |
| 489 | tx.map_into(), | 508 | tx.map_into(), |
| 490 | rx.map_into(), | 509 | rx.map_into(), |
| 491 | None, | 510 | None, |
| 492 | None, | 511 | None, |
| 493 | Some(irq), | 512 | true, |
| 494 | Some(tx_dma.map_into()), | 513 | Some(tx_dma.map_into()), |
| 495 | Some(rx_dma.map_into()), | 514 | Some(rx_dma.map_into()), |
| 496 | config, | 515 | config, |
| @@ -504,19 +523,19 @@ impl<'d, T: Instance> Uart<'d, T, Async> { | |||
| 504 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 523 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 505 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 524 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 506 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | 525 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |
| 507 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 526 | _irq: impl Binding<T::Interrupt, InterruptHandler<T>>, |
| 508 | tx_dma: impl Peripheral<P = impl Channel> + 'd, | 527 | tx_dma: impl Peripheral<P = impl Channel> + 'd, |
| 509 | rx_dma: impl Peripheral<P = impl Channel> + 'd, | 528 | rx_dma: impl Peripheral<P = impl Channel> + 'd, |
| 510 | config: Config, | 529 | config: Config, |
| 511 | ) -> Self { | 530 | ) -> Self { |
| 512 | into_ref!(tx, rx, cts, rts, irq, tx_dma, rx_dma); | 531 | into_ref!(tx, rx, cts, rts, tx_dma, rx_dma); |
| 513 | Self::new_inner( | 532 | Self::new_inner( |
| 514 | uart, | 533 | uart, |
| 515 | tx.map_into(), | 534 | tx.map_into(), |
| 516 | rx.map_into(), | 535 | rx.map_into(), |
| 517 | Some(rts.map_into()), | 536 | Some(rts.map_into()), |
| 518 | Some(cts.map_into()), | 537 | Some(cts.map_into()), |
| 519 | Some(irq), | 538 | true, |
| 520 | Some(tx_dma.map_into()), | 539 | Some(tx_dma.map_into()), |
| 521 | Some(rx_dma.map_into()), | 540 | Some(rx_dma.map_into()), |
| 522 | config, | 541 | config, |
| @@ -531,7 +550,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | |||
| 531 | mut rx: PeripheralRef<'d, AnyPin>, | 550 | mut rx: PeripheralRef<'d, AnyPin>, |
| 532 | mut rts: Option<PeripheralRef<'d, AnyPin>>, | 551 | mut rts: Option<PeripheralRef<'d, AnyPin>>, |
| 533 | mut cts: Option<PeripheralRef<'d, AnyPin>>, | 552 | mut cts: Option<PeripheralRef<'d, AnyPin>>, |
| 534 | irq: Option<PeripheralRef<'d, T::Interrupt>>, | 553 | has_irq: bool, |
| 535 | tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | 554 | tx_dma: Option<PeripheralRef<'d, AnyChannel>>, |
| 536 | rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | 555 | rx_dma: Option<PeripheralRef<'d, AnyChannel>>, |
| 537 | config: Config, | 556 | config: Config, |
| @@ -546,7 +565,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | |||
| 546 | 565 | ||
| 547 | Self { | 566 | Self { |
| 548 | tx: UartTx::new_inner(tx_dma), | 567 | tx: UartTx::new_inner(tx_dma), |
| 549 | rx: UartRx::new_inner(irq, rx_dma), | 568 | rx: UartRx::new_inner(has_irq, rx_dma), |
| 550 | } | 569 | } |
| 551 | } | 570 | } |
| 552 | 571 | ||
