aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/uart/mod.rs
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-05-15 15:21:05 +0200
committerpennae <[email protected]>2023-05-15 15:24:56 +0200
commit14a5d03af2a74eccaa9930bdf81eef43791a4b33 (patch)
tree3a0879c21cf09702c670b14672e62b940a2157f0 /embassy-rp/src/uart/mod.rs
parent82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff)
rp: remove take!, add bind_interrupts!
Diffstat (limited to 'embassy-rp/src/uart/mod.rs')
-rw-r--r--embassy-rp/src/uart/mod.rs101
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;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicU16, Ordering}; 5use atomic_polyfill::{AtomicU16, Ordering};
6use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 6use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
7use embassy_futures::select::{select, Either}; 7use embassy_futures::select::{select, Either};
8use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
@@ -20,7 +20,7 @@ use crate::{pac, peripherals, Peripheral, RegExt};
20#[cfg(feature = "nightly")] 20#[cfg(feature = "nightly")]
21mod buffered; 21mod buffered;
22#[cfg(feature = "nightly")] 22#[cfg(feature = "nightly")]
23pub use buffered::{BufferedUart, BufferedUartRx, BufferedUartTx}; 23pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx};
24 24
25#[derive(Clone, Copy, PartialEq, Eq, Debug)] 25#[derive(Clone, Copy, PartialEq, Eq, Debug)]
26pub enum DataBits { 26pub 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
332unsafe fn on_interrupt<T: Instance>(_: *mut ()) { 333pub 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); 337impl<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
344impl<'d, T: Instance> UartRx<'d, T, Async> { 355impl<'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