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/mod.rs | |
| parent | 82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff) | |
rp: remove take!, add bind_interrupts!
Diffstat (limited to 'embassy-rp/src/uart/mod.rs')
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 101 |
1 files changed, 60 insertions, 41 deletions
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 | ||
