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 | |
| parent | 82f7e104d90a6628d1873017ea5ef6a7afb3b3f7 (diff) | |
rp: remove take!, add bind_interrupts!
Diffstat (limited to 'embassy-rp/src')
| -rw-r--r-- | embassy-rp/src/adc.rs | 31 | ||||
| -rw-r--r-- | embassy-rp/src/i2c.rs | 34 | ||||
| -rw-r--r-- | embassy-rp/src/interrupt.rs | 37 | ||||
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 209 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 101 | ||||
| -rw-r--r-- | embassy-rp/src/usb.rs | 98 |
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; | |||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 3 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_hal_common::into_ref; | 6 | use embassy_cortex_m::interrupt::{Binding, Interrupt}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use embedded_hal_02::adc::{Channel, OneShot}; | 8 | use embedded_hal_02::adc::{Channel, OneShot}; |
| 9 | 9 | ||
| 10 | use crate::gpio::Pin; | 10 | use crate::gpio::Pin; |
| 11 | use crate::interrupt::{self, InterruptExt}; | 11 | use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO}; |
| 12 | use crate::peripherals::ADC; | 12 | use crate::peripherals::ADC; |
| 13 | use crate::{pac, peripherals, Peripheral}; | 13 | use crate::{pac, peripherals, Peripheral}; |
| 14 | static WAKER: AtomicWaker = AtomicWaker::new(); | 14 | static 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 | ||
| 163 | pub struct InterruptHandler { | ||
| 164 | _empty: (), | ||
| 165 | } | ||
| 166 | |||
| 167 | impl 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 | |||
| 168 | impl_pin!(PIN_26, 0); | 175 | impl_pin!(PIN_26, 0); |
| 169 | impl_pin!(PIN_27, 1); | 176 | impl_pin!(PIN_27, 1); |
| 170 | impl_pin!(PIN_28, 2); | 177 | impl_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; | |||
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use embassy_cortex_m::interrupt::InterruptExt; | 5 | use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt}; |
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 6 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use pac::i2c; | 8 | use 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 | ||
| 313 | pub struct InterruptHandler<T: Instance> { | ||
| 314 | _uart: PhantomData<T>, | ||
| 315 | } | ||
| 316 | |||
| 317 | impl<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 | |||
| 323 | impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | 327 | impl<'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 | //! | 2 | pub 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 | ||
| 7 | use embassy_cortex_m::interrupt::_export::declare; | 3 | use embassy_cortex_m::interrupt::_export::declare; |
| 8 | pub use embassy_cortex_m::interrupt::*; | 4 | pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; |
| 9 | 5 | ||
| 10 | use crate::pac::Interrupt as InterruptEnum; | 6 | use crate::pac::Interrupt as InterruptEnum; |
| 11 | declare!(TIMER_IRQ_0); | 7 | declare!(TIMER_IRQ_0); |
| @@ -40,3 +36,30 @@ declare!(SWI_IRQ_2); | |||
| 40 | declare!(SWI_IRQ_3); | 36 | declare!(SWI_IRQ_3); |
| 41 | declare!(SWI_IRQ_4); | 37 | declare!(SWI_IRQ_4); |
| 42 | declare!(SWI_IRQ_5); | 38 | declare!(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] | ||
| 47 | macro_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; | |||
| 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 | ||
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; | |||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 5 | use core::task::Poll; | 5 | use core::task::Poll; |
| 6 | 6 | ||
| 7 | use embassy_hal_common::into_ref; | 7 | use embassy_cortex_m::interrupt::{self, Binding}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | use embassy_usb_driver as driver; | 9 | use embassy_usb_driver as driver; |
| 10 | use embassy_usb_driver::{ | 10 | use embassy_usb_driver::{ |
| @@ -105,11 +105,11 @@ pub struct Driver<'d, T: Instance> { | |||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | impl<'d, T: Instance> Driver<'d, T> { | 107 | impl<'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 | ||
| 250 | pub struct InterruptHandler<T: Instance> { | ||
| 251 | _uart: PhantomData<T>, | ||
| 252 | } | ||
| 253 | |||
| 254 | impl<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 | |||
| 291 | impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | 295 | impl<'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>; |
