aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp
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
parent82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff)
rp: remove take!, add bind_interrupts!
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/adc.rs31
-rw-r--r--embassy-rp/src/i2c.rs34
-rw-r--r--embassy-rp/src/interrupt.rs37
-rw-r--r--embassy-rp/src/uart/buffered.rs209
-rw-r--r--embassy-rp/src/uart/mod.rs101
-rw-r--r--embassy-rp/src/usb.rs98
6 files changed, 288 insertions, 222 deletions
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 145ba9c59..59c7a47ce 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -3,12 +3,12 @@ use core::marker::PhantomData;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_common::into_ref; 6use embassy_cortex_m::interrupt::{Binding, Interrupt};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embedded_hal_02::adc::{Channel, OneShot}; 8use embedded_hal_02::adc::{Channel, OneShot};
9 9
10use crate::gpio::Pin; 10use crate::gpio::Pin;
11use crate::interrupt::{self, InterruptExt}; 11use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO};
12use crate::peripherals::ADC; 12use crate::peripherals::ADC;
13use crate::{pac, peripherals, Peripheral}; 13use crate::{pac, peripherals, Peripheral};
14static WAKER: AtomicWaker = AtomicWaker::new(); 14static WAKER: AtomicWaker = AtomicWaker::new();
@@ -47,10 +47,9 @@ impl<'d> Adc<'d> {
47 47
48 pub fn new( 48 pub fn new(
49 _inner: impl Peripheral<P = ADC> + 'd, 49 _inner: impl Peripheral<P = ADC> + 'd,
50 irq: impl Peripheral<P = interrupt::ADC_IRQ_FIFO> + 'd, 50 _irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>,
51 _config: Config, 51 _config: Config,
52 ) -> Self { 52 ) -> Self {
53 into_ref!(irq);
54 unsafe { 53 unsafe {
55 let reset = Self::reset(); 54 let reset = Self::reset();
56 crate::reset::reset(reset); 55 crate::reset::reset(reset);
@@ -63,14 +62,10 @@ impl<'d> Adc<'d> {
63 } 62 }
64 63
65 // Setup IRQ 64 // Setup IRQ
66 irq.disable(); 65 unsafe {
67 irq.set_handler(|_| unsafe { 66 ADC_IRQ_FIFO::steal().unpend();
68 let r = Self::regs(); 67 ADC_IRQ_FIFO::steal().enable();
69 r.inte().write(|w| w.set_fifo(false)); 68 };
70 WAKER.wake();
71 });
72 irq.unpend();
73 irq.enable();
74 69
75 Self { phantom: PhantomData } 70 Self { phantom: PhantomData }
76 } 71 }
@@ -165,6 +160,18 @@ macro_rules! impl_pin {
165 }; 160 };
166} 161}
167 162
163pub struct InterruptHandler {
164 _empty: (),
165}
166
167impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler {
168 unsafe fn on_interrupt() {
169 let r = Adc::regs();
170 r.inte().write(|w| w.set_fifo(false));
171 WAKER.wake();
172 }
173}
174
168impl_pin!(PIN_26, 0); 175impl_pin!(PIN_26, 0);
169impl_pin!(PIN_27, 1); 176impl_pin!(PIN_27, 1);
170impl_pin!(PIN_28, 2); 177impl_pin!(PIN_28, 2);
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index d5dc94406..6ce77f073 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -2,7 +2,7 @@ use core::future;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_cortex_m::interrupt::InterruptExt; 5use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
6use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use pac::i2c; 8use pac::i2c;
@@ -75,23 +75,21 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
75 peri: impl Peripheral<P = T> + 'd, 75 peri: impl Peripheral<P = T> + 'd,
76 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 76 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
77 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 77 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
78 irq: impl Peripheral<P = T::Interrupt> + 'd, 78 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
79 config: Config, 79 config: Config,
80 ) -> Self { 80 ) -> Self {
81 into_ref!(scl, sda, irq); 81 into_ref!(scl, sda);
82 82
83 let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); 83 let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
84 84
85 irq.set_handler(Self::on_interrupt);
86 unsafe { 85 unsafe {
87 let i2c = T::regs(); 86 let i2c = T::regs();
88 87
89 // mask everything initially 88 // mask everything initially
90 i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); 89 i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
90 T::Interrupt::steal().unpend();
91 T::Interrupt::steal().enable();
91 } 92 }
92 irq.unpend();
93 debug_assert!(!irq.is_pending());
94 irq.enable();
95 93
96 i2c 94 i2c
97 } 95 }
@@ -115,14 +113,6 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
115 .await 113 .await
116 } 114 }
117 115
118 // Mask interrupts and wake any task waiting for this interrupt
119 unsafe fn on_interrupt(_: *mut ()) {
120 let i2c = T::regs();
121 i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
122
123 T::waker().wake();
124 }
125
126 async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { 116 async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
127 if buffer.is_empty() { 117 if buffer.is_empty() {
128 return Err(Error::InvalidReadBufferLength); 118 return Err(Error::InvalidReadBufferLength);
@@ -320,6 +310,20 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
320 } 310 }
321} 311}
322 312
313pub struct InterruptHandler<T: Instance> {
314 _uart: PhantomData<T>,
315}
316
317impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
318 // Mask interrupts and wake any task waiting for this interrupt
319 unsafe fn on_interrupt() {
320 let i2c = T::regs();
321 i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
322
323 T::waker().wake();
324 }
325}
326
323impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { 327impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
324 fn new_inner( 328 fn new_inner(
325 _peri: impl Peripheral<P = T> + 'd, 329 _peri: impl Peripheral<P = T> + 'd,
diff --git a/embassy-rp/src/interrupt.rs b/embassy-rp/src/interrupt.rs
index 989f5dc2d..1db13deef 100644
--- a/embassy-rp/src/interrupt.rs
+++ b/embassy-rp/src/interrupt.rs
@@ -1,11 +1,7 @@
1//! Interrupt management 1//! Interrupt definitions and macros to bind them.
2//! 2pub use cortex_m::interrupt::{CriticalSection, Mutex};
3//! This module implements an API for managing interrupts compatible with
4//! nrf_softdevice::interrupt. Intended for switching between the two at compile-time.
5
6// Re-exports
7use embassy_cortex_m::interrupt::_export::declare; 3use embassy_cortex_m::interrupt::_export::declare;
8pub use embassy_cortex_m::interrupt::*; 4pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
9 5
10use crate::pac::Interrupt as InterruptEnum; 6use crate::pac::Interrupt as InterruptEnum;
11declare!(TIMER_IRQ_0); 7declare!(TIMER_IRQ_0);
@@ -40,3 +36,30 @@ declare!(SWI_IRQ_2);
40declare!(SWI_IRQ_3); 36declare!(SWI_IRQ_3);
41declare!(SWI_IRQ_4); 37declare!(SWI_IRQ_4);
42declare!(SWI_IRQ_5); 38declare!(SWI_IRQ_5);
39
40/// Macro to bind interrupts to handlers.
41///
42/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
43/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
44/// prove at compile-time that the right interrupts have been bound.
45// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
46#[macro_export]
47macro_rules! bind_interrupts {
48 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
49 $vis struct $name;
50
51 $(
52 #[allow(non_snake_case)]
53 #[no_mangle]
54 unsafe extern "C" fn $irq() {
55 $(
56 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
57 )*
58 }
59
60 $(
61 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
62 )*
63 )*
64 };
65}
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;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicU8, Ordering}; 5use atomic_polyfill::{AtomicU8, Ordering};
6use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 6use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
7use embassy_hal_common::atomic_ring_buffer::RingBuffer; 7use embassy_hal_common::atomic_ring_buffer::RingBuffer;
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
@@ -52,7 +52,7 @@ pub struct BufferedUartTx<'d, T: Instance> {
52} 52}
53 53
54pub(crate) fn init_buffers<'d, T: Instance + 'd>( 54pub(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
89impl<'d, T: Instance> BufferedUart<'d, T> { 88impl<'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> {
163impl<'d, T: Instance> BufferedUartRx<'d, T> { 162impl<'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> {
312impl<'d, T: Instance> BufferedUartTx<'d, T> { 311impl<'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
485pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) { 484pub struct BufferedInterruptHandler<T: Instance> {
486 let r = T::regs(); 485 _uart: PhantomData<T>,
487 let s = T::buffered_state(); 486}
488 487
489 unsafe { 488impl<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;
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
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index a049e4769..fada2790f 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -4,7 +4,7 @@ use core::slice;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_hal_common::into_ref; 7use embassy_cortex_m::interrupt::{self, Binding};
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb_driver as driver; 9use embassy_usb_driver as driver;
10use embassy_usb_driver::{ 10use embassy_usb_driver::{
@@ -105,11 +105,11 @@ pub struct Driver<'d, T: Instance> {
105} 105}
106 106
107impl<'d, T: Instance> Driver<'d, T> { 107impl<'d, T: Instance> Driver<'d, T> {
108 pub fn new(_usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self { 108 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
109 into_ref!(irq); 109 unsafe {
110 irq.set_handler(Self::on_interrupt); 110 T::Interrupt::steal().unpend();
111 irq.unpend(); 111 T::Interrupt::steal().enable();
112 irq.enable(); 112 }
113 113
114 let regs = T::regs(); 114 let regs = T::regs();
115 unsafe { 115 unsafe {
@@ -149,47 +149,6 @@ impl<'d, T: Instance> Driver<'d, T> {
149 } 149 }
150 } 150 }
151 151
152 fn on_interrupt(_: *mut ()) {
153 unsafe {
154 let regs = T::regs();
155 //let x = regs.istr().read().0;
156 //trace!("USB IRQ: {:08x}", x);
157
158 let ints = regs.ints().read();
159
160 if ints.bus_reset() {
161 regs.inte().write_clear(|w| w.set_bus_reset(true));
162 BUS_WAKER.wake();
163 }
164 if ints.dev_resume_from_host() {
165 regs.inte().write_clear(|w| w.set_dev_resume_from_host(true));
166 BUS_WAKER.wake();
167 }
168 if ints.dev_suspend() {
169 regs.inte().write_clear(|w| w.set_dev_suspend(true));
170 BUS_WAKER.wake();
171 }
172 if ints.setup_req() {
173 regs.inte().write_clear(|w| w.set_setup_req(true));
174 EP_OUT_WAKERS[0].wake();
175 }
176
177 if ints.buff_status() {
178 let s = regs.buff_status().read();
179 regs.buff_status().write_value(s);
180
181 for i in 0..EP_COUNT {
182 if s.ep_in(i) {
183 EP_IN_WAKERS[i].wake();
184 }
185 if s.ep_out(i) {
186 EP_OUT_WAKERS[i].wake();
187 }
188 }
189 }
190 }
191 }
192
193 fn alloc_endpoint<D: Dir>( 152 fn alloc_endpoint<D: Dir>(
194 &mut self, 153 &mut self,
195 ep_type: EndpointType, 154 ep_type: EndpointType,
@@ -288,6 +247,51 @@ impl<'d, T: Instance> Driver<'d, T> {
288 } 247 }
289} 248}
290 249
250pub struct InterruptHandler<T: Instance> {
251 _uart: PhantomData<T>,
252}
253
254impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
255 unsafe fn on_interrupt() {
256 let regs = T::regs();
257 //let x = regs.istr().read().0;
258 //trace!("USB IRQ: {:08x}", x);
259
260 let ints = regs.ints().read();
261
262 if ints.bus_reset() {
263 regs.inte().write_clear(|w| w.set_bus_reset(true));
264 BUS_WAKER.wake();
265 }
266 if ints.dev_resume_from_host() {
267 regs.inte().write_clear(|w| w.set_dev_resume_from_host(true));
268 BUS_WAKER.wake();
269 }
270 if ints.dev_suspend() {
271 regs.inte().write_clear(|w| w.set_dev_suspend(true));
272 BUS_WAKER.wake();
273 }
274 if ints.setup_req() {
275 regs.inte().write_clear(|w| w.set_setup_req(true));
276 EP_OUT_WAKERS[0].wake();
277 }
278
279 if ints.buff_status() {
280 let s = regs.buff_status().read();
281 regs.buff_status().write_value(s);
282
283 for i in 0..EP_COUNT {
284 if s.ep_in(i) {
285 EP_IN_WAKERS[i].wake();
286 }
287 if s.ep_out(i) {
288 EP_OUT_WAKERS[i].wake();
289 }
290 }
291 }
292 }
293}
294
291impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { 295impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
292 type EndpointOut = Endpoint<'d, T, Out>; 296 type EndpointOut = Endpoint<'d, T, Out>;
293 type EndpointIn = Endpoint<'d, T, In>; 297 type EndpointIn = Endpoint<'d, T, In>;