Merge pull request #1224 from embassy-rs/interrupt-binding
nrf: new interrupt binding traits/macro
This commit is contained in:
		| @@ -13,14 +13,44 @@ pub mod _export { | ||||
|     pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; | ||||
| } | ||||
|  | ||||
| /// Interrupt handler trait. | ||||
| /// | ||||
| /// Drivers that need to handle interrupts implement this trait. | ||||
| /// The user must ensure `on_interrupt()` is called every time the interrupt fires. | ||||
| /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. | ||||
| pub trait Handler<I: Interrupt> { | ||||
|     /// Interrupt handler function. | ||||
|     /// | ||||
|     /// Must be called every time the `I` interrupt fires, synchronously from | ||||
|     /// the interrupt handler context. | ||||
|     /// | ||||
|     /// # Safety | ||||
|     /// | ||||
|     /// This function must ONLY be called from the interrupt handler for `I`. | ||||
|     unsafe fn on_interrupt(); | ||||
| } | ||||
|  | ||||
| /// Compile-time assertion that an interrupt has been bound to a handler. | ||||
| /// | ||||
| /// For the vast majority of cases, you should use the `bind_interrupts!` | ||||
| /// macro instead of writing `unsafe impl`s of this trait. | ||||
| /// | ||||
| /// # Safety | ||||
| /// | ||||
| /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` | ||||
| /// to be called every time the `I` interrupt fires. | ||||
| /// | ||||
| /// This allows drivers to check bindings at compile-time. | ||||
| pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {} | ||||
|  | ||||
| /// Implementation detail, do not use outside embassy crates. | ||||
| #[doc(hidden)] | ||||
| pub struct Handler { | ||||
| pub struct DynHandler { | ||||
|     pub func: AtomicPtr<()>, | ||||
|     pub ctx: AtomicPtr<()>, | ||||
| } | ||||
|  | ||||
| impl Handler { | ||||
| impl DynHandler { | ||||
|     pub const fn new() -> Self { | ||||
|         Self { | ||||
|             func: AtomicPtr::new(ptr::null_mut()), | ||||
| @@ -51,7 +81,7 @@ pub unsafe trait Interrupt: Peripheral<P = Self> { | ||||
|  | ||||
|     /// Implementation detail, do not use outside embassy crates. | ||||
|     #[doc(hidden)] | ||||
|     unsafe fn __handler(&self) -> &'static Handler; | ||||
|     unsafe fn __handler(&self) -> &'static DynHandler; | ||||
| } | ||||
|  | ||||
| /// Represents additional behavior for all interrupts. | ||||
|   | ||||
| @@ -21,9 +21,9 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> { | ||||
|             unsafe fn steal() -> Self { | ||||
|                 Self(()) | ||||
|             } | ||||
|             unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::Handler { | ||||
|             unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler { | ||||
|                 #[export_name = #name_handler] | ||||
|                 static HANDLER: ::embassy_cortex_m::interrupt::Handler = ::embassy_cortex_m::interrupt::Handler::new(); | ||||
|                 static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new(); | ||||
|                 &HANDLER | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -30,7 +30,7 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> { | ||||
|             pub unsafe extern "C" fn trampoline() { | ||||
|                 extern "C" { | ||||
|                     #[link_name = #name_handler] | ||||
|                     static HANDLER: interrupt::Handler; | ||||
|                     static HANDLER: interrupt::DynHandler; | ||||
|                 } | ||||
|  | ||||
|                 let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
|  | ||||
| use core::cmp::min; | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::slice; | ||||
| use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; | ||||
| use core::task::Poll; | ||||
| @@ -23,7 +24,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari | ||||
|  | ||||
| use crate::gpio::sealed::Pin; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::interrupt::{self, InterruptExt}; | ||||
| use crate::ppi::{ | ||||
|     self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, | ||||
| }; | ||||
| @@ -71,211 +72,13 @@ impl State { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Buffered UARTE driver. | ||||
| pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { | ||||
|     _peri: PeripheralRef<'d, U>, | ||||
|     timer: Timer<'d, T>, | ||||
|     _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, | ||||
|     _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, | ||||
|     _ppi_group: PpiGroup<'d, AnyGroup>, | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<U: UarteInstance> { | ||||
|     _phantom: PhantomData<U>, | ||||
| } | ||||
|  | ||||
| impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} | ||||
|  | ||||
| impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | ||||
|     /// Create a new BufferedUarte without hardware flow control. | ||||
|     /// | ||||
|     /// # Panics | ||||
|     /// | ||||
|     /// Panics if `rx_buffer.len()` is odd. | ||||
|     pub fn new( | ||||
|         uarte: impl Peripheral<P = U> + 'd, | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_group: impl Peripheral<P = impl Group> + 'd, | ||||
|         irq: impl Peripheral<P = U::Interrupt> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|         rx_buffer: &'d mut [u8], | ||||
|         tx_buffer: &'d mut [u8], | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group); | ||||
|         Self::new_inner( | ||||
|             uarte, | ||||
|             timer, | ||||
|             ppi_ch1.map_into(), | ||||
|             ppi_ch2.map_into(), | ||||
|             ppi_group.map_into(), | ||||
|             irq, | ||||
|             rxd.map_into(), | ||||
|             txd.map_into(), | ||||
|             None, | ||||
|             None, | ||||
|             config, | ||||
|             rx_buffer, | ||||
|             tx_buffer, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     /// Create a new BufferedUarte with hardware flow control (RTS/CTS) | ||||
|     /// | ||||
|     /// # Panics | ||||
|     /// | ||||
|     /// Panics if `rx_buffer.len()` is odd. | ||||
|     pub fn new_with_rtscts( | ||||
|         uarte: impl Peripheral<P = U> + 'd, | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_group: impl Peripheral<P = impl Group> + 'd, | ||||
|         irq: impl Peripheral<P = U::Interrupt> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         cts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         rts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|         rx_buffer: &'d mut [u8], | ||||
|         tx_buffer: &'d mut [u8], | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); | ||||
|         Self::new_inner( | ||||
|             uarte, | ||||
|             timer, | ||||
|             ppi_ch1.map_into(), | ||||
|             ppi_ch2.map_into(), | ||||
|             ppi_group.map_into(), | ||||
|             irq, | ||||
|             rxd.map_into(), | ||||
|             txd.map_into(), | ||||
|             Some(cts.map_into()), | ||||
|             Some(rts.map_into()), | ||||
|             config, | ||||
|             rx_buffer, | ||||
|             tx_buffer, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         peri: impl Peripheral<P = U> + 'd, | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, | ||||
|         ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, | ||||
|         ppi_group: PeripheralRef<'d, AnyGroup>, | ||||
|         irq: impl Peripheral<P = U::Interrupt> + 'd, | ||||
|         rxd: PeripheralRef<'d, AnyPin>, | ||||
|         txd: PeripheralRef<'d, AnyPin>, | ||||
|         cts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         rts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|         rx_buffer: &'d mut [u8], | ||||
|         tx_buffer: &'d mut [u8], | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, timer, irq); | ||||
|  | ||||
|         assert!(rx_buffer.len() % 2 == 0); | ||||
|  | ||||
|         let r = U::regs(); | ||||
|  | ||||
|         rxd.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | ||||
|  | ||||
|         txd.set_high(); | ||||
|         txd.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | ||||
|  | ||||
|         if let Some(pin) = &cts { | ||||
|             pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | ||||
|  | ||||
|         if let Some(pin) = &rts { | ||||
|             pin.set_high(); | ||||
|             pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||||
|  | ||||
|         // Initialize state | ||||
|         let s = U::buffered_state(); | ||||
|         s.tx_count.store(0, Ordering::Relaxed); | ||||
|         s.rx_bufs.store(0, Ordering::Relaxed); | ||||
|         let len = tx_buffer.len(); | ||||
|         unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; | ||||
|         let len = rx_buffer.len(); | ||||
|         unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; | ||||
|  | ||||
|         // Configure | ||||
|         r.config.write(|w| { | ||||
|             w.hwfc().bit(false); | ||||
|             w.parity().variant(config.parity); | ||||
|             w | ||||
|         }); | ||||
|         r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | ||||
|  | ||||
|         // clear errors | ||||
|         let errors = r.errorsrc.read().bits(); | ||||
|         r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||||
|  | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_txstarted.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_endtx.reset(); | ||||
|  | ||||
|         // Enable interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(!0) }); | ||||
|         r.intenset.write(|w| { | ||||
|             w.endtx().set(); | ||||
|             w.rxstarted().set(); | ||||
|             w.error().set(); | ||||
|             w | ||||
|         }); | ||||
|  | ||||
|         // Enable UARTE instance | ||||
|         apply_workaround_for_enable_anomaly(&r); | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|  | ||||
|         // Configure byte counter. | ||||
|         let mut timer = Timer::new_counter(timer); | ||||
|         timer.cc(1).write(rx_buffer.len() as u32 * 2); | ||||
|         timer.cc(1).short_compare_clear(); | ||||
|         timer.clear(); | ||||
|         timer.start(); | ||||
|  | ||||
|         let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); | ||||
|         ppi_ch1.enable(); | ||||
|  | ||||
|         s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); | ||||
|         let mut ppi_group = PpiGroup::new(ppi_group); | ||||
|         let mut ppi_ch2 = Ppi::new_one_to_two( | ||||
|             ppi_ch2, | ||||
|             Event::from_reg(&r.events_endrx), | ||||
|             Task::from_reg(&r.tasks_startrx), | ||||
|             ppi_group.task_disable_all(), | ||||
|         ); | ||||
|         ppi_ch2.disable(); | ||||
|         ppi_group.add_channel(&ppi_ch2); | ||||
|  | ||||
|         irq.disable(); | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.pend(); | ||||
|         irq.enable(); | ||||
|  | ||||
|         Self { | ||||
|             _peri: peri, | ||||
|             timer, | ||||
|             _ppi_ch1: ppi_ch1, | ||||
|             _ppi_ch2: ppi_ch2, | ||||
|             _ppi_group: ppi_group, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn pend_irq() { | ||||
|         unsafe { <U::Interrupt as Interrupt>::steal() }.pend() | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
| impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         //trace!("irq: start"); | ||||
|         let r = U::regs(); | ||||
|         let s = U::buffered_state(); | ||||
| @@ -374,6 +177,206 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | ||||
|  | ||||
|         //trace!("irq: end"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Buffered UARTE driver. | ||||
| pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { | ||||
|     _peri: PeripheralRef<'d, U>, | ||||
|     timer: Timer<'d, T>, | ||||
|     _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, | ||||
|     _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, | ||||
|     _ppi_group: PpiGroup<'d, AnyGroup>, | ||||
| } | ||||
|  | ||||
| impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} | ||||
|  | ||||
| impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | ||||
|     /// Create a new BufferedUarte without hardware flow control. | ||||
|     /// | ||||
|     /// # Panics | ||||
|     /// | ||||
|     /// Panics if `rx_buffer.len()` is odd. | ||||
|     pub fn new( | ||||
|         uarte: impl Peripheral<P = U> + 'd, | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_group: impl Peripheral<P = impl Group> + 'd, | ||||
|         _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|         rx_buffer: &'d mut [u8], | ||||
|         tx_buffer: &'d mut [u8], | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group); | ||||
|         Self::new_inner( | ||||
|             uarte, | ||||
|             timer, | ||||
|             ppi_ch1.map_into(), | ||||
|             ppi_ch2.map_into(), | ||||
|             ppi_group.map_into(), | ||||
|             rxd.map_into(), | ||||
|             txd.map_into(), | ||||
|             None, | ||||
|             None, | ||||
|             config, | ||||
|             rx_buffer, | ||||
|             tx_buffer, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     /// Create a new BufferedUarte with hardware flow control (RTS/CTS) | ||||
|     /// | ||||
|     /// # Panics | ||||
|     /// | ||||
|     /// Panics if `rx_buffer.len()` is odd. | ||||
|     pub fn new_with_rtscts( | ||||
|         uarte: impl Peripheral<P = U> + 'd, | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||||
|         ppi_group: impl Peripheral<P = impl Group> + 'd, | ||||
|         _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         cts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         rts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|         rx_buffer: &'d mut [u8], | ||||
|         tx_buffer: &'d mut [u8], | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); | ||||
|         Self::new_inner( | ||||
|             uarte, | ||||
|             timer, | ||||
|             ppi_ch1.map_into(), | ||||
|             ppi_ch2.map_into(), | ||||
|             ppi_group.map_into(), | ||||
|             rxd.map_into(), | ||||
|             txd.map_into(), | ||||
|             Some(cts.map_into()), | ||||
|             Some(rts.map_into()), | ||||
|             config, | ||||
|             rx_buffer, | ||||
|             tx_buffer, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         peri: impl Peripheral<P = U> + 'd, | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, | ||||
|         ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, | ||||
|         ppi_group: PeripheralRef<'d, AnyGroup>, | ||||
|         rxd: PeripheralRef<'d, AnyPin>, | ||||
|         txd: PeripheralRef<'d, AnyPin>, | ||||
|         cts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         rts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|         rx_buffer: &'d mut [u8], | ||||
|         tx_buffer: &'d mut [u8], | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, timer); | ||||
|  | ||||
|         assert!(rx_buffer.len() % 2 == 0); | ||||
|  | ||||
|         let r = U::regs(); | ||||
|  | ||||
|         rxd.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | ||||
|  | ||||
|         txd.set_high(); | ||||
|         txd.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | ||||
|  | ||||
|         if let Some(pin) = &cts { | ||||
|             pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | ||||
|  | ||||
|         if let Some(pin) = &rts { | ||||
|             pin.set_high(); | ||||
|             pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||||
|         } | ||||
|         r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||||
|  | ||||
|         // Initialize state | ||||
|         let s = U::buffered_state(); | ||||
|         s.tx_count.store(0, Ordering::Relaxed); | ||||
|         s.rx_bufs.store(0, Ordering::Relaxed); | ||||
|         let len = tx_buffer.len(); | ||||
|         unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; | ||||
|         let len = rx_buffer.len(); | ||||
|         unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; | ||||
|  | ||||
|         // Configure | ||||
|         r.config.write(|w| { | ||||
|             w.hwfc().bit(false); | ||||
|             w.parity().variant(config.parity); | ||||
|             w | ||||
|         }); | ||||
|         r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | ||||
|  | ||||
|         // clear errors | ||||
|         let errors = r.errorsrc.read().bits(); | ||||
|         r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||||
|  | ||||
|         r.events_rxstarted.reset(); | ||||
|         r.events_txstarted.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_endrx.reset(); | ||||
|         r.events_endtx.reset(); | ||||
|  | ||||
|         // Enable interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(!0) }); | ||||
|         r.intenset.write(|w| { | ||||
|             w.endtx().set(); | ||||
|             w.rxstarted().set(); | ||||
|             w.error().set(); | ||||
|             w | ||||
|         }); | ||||
|  | ||||
|         // Enable UARTE instance | ||||
|         apply_workaround_for_enable_anomaly(&r); | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|  | ||||
|         // Configure byte counter. | ||||
|         let mut timer = Timer::new_counter(timer); | ||||
|         timer.cc(1).write(rx_buffer.len() as u32 * 2); | ||||
|         timer.cc(1).short_compare_clear(); | ||||
|         timer.clear(); | ||||
|         timer.start(); | ||||
|  | ||||
|         let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); | ||||
|         ppi_ch1.enable(); | ||||
|  | ||||
|         s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); | ||||
|         let mut ppi_group = PpiGroup::new(ppi_group); | ||||
|         let mut ppi_ch2 = Ppi::new_one_to_two( | ||||
|             ppi_ch2, | ||||
|             Event::from_reg(&r.events_endrx), | ||||
|             Task::from_reg(&r.tasks_startrx), | ||||
|             ppi_group.task_disable_all(), | ||||
|         ); | ||||
|         ppi_ch2.disable(); | ||||
|         ppi_group.add_channel(&ppi_ch2); | ||||
|  | ||||
|         unsafe { U::Interrupt::steal() }.pend(); | ||||
|         unsafe { U::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         Self { | ||||
|             _peri: peri, | ||||
|             timer, | ||||
|             _ppi_ch1: ppi_ch1, | ||||
|             _ppi_ch2: ppi_ch2, | ||||
|             _ppi_group: ppi_group, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn pend_irq() { | ||||
|         unsafe { <U::Interrupt as Interrupt>::steal() }.pend() | ||||
|     } | ||||
|  | ||||
|     /// Adjust the baud rate to the provided value. | ||||
|     pub fn set_baudrate(&mut self, baudrate: Baudrate) { | ||||
|   | ||||
| @@ -140,6 +140,10 @@ impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | ||||
|  | ||||
| impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|   | ||||
| @@ -148,6 +148,12 @@ impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
|  | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|   | ||||
| @@ -150,6 +150,12 @@ impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
|  | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|   | ||||
| @@ -153,6 +153,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
| impl_timer!(TIMER3, TIMER3, TIMER3, extended); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
|   | ||||
| @@ -146,6 +146,9 @@ embassy_hal_common::peripherals! { | ||||
|  | ||||
|     // I2S | ||||
|     I2S, | ||||
|  | ||||
|     // PDM | ||||
|     PDM, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
| @@ -168,6 +171,12 @@ impl_pwm!(PWM0, PWM0, PWM0); | ||||
| impl_pwm!(PWM1, PWM1, PWM1); | ||||
| impl_pwm!(PWM2, PWM2, PWM2); | ||||
|  | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|   | ||||
| @@ -197,6 +197,12 @@ impl_pwm!(PWM1, PWM1, PWM1); | ||||
| impl_pwm!(PWM2, PWM2, PWM2); | ||||
| impl_pwm!(PWM3, PWM3, PWM3); | ||||
|  | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|   | ||||
| @@ -208,6 +208,12 @@ impl_timer!(TIMER4, TIMER4, TIMER4, extended); | ||||
|  | ||||
| impl_qspi!(QSPI, QSPI, QSPI); | ||||
|  | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
|  | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
|   | ||||
| @@ -34,10 +34,10 @@ pub mod pac { | ||||
|         nvmc_ns as nvmc, | ||||
|         oscillators_ns as oscillators, | ||||
|         p0_ns as p0, | ||||
|         pdm0_ns as pdm0, | ||||
|         pdm0_ns as pdm, | ||||
|         power_ns as power, | ||||
|         pwm0_ns as pwm0, | ||||
|         qdec0_ns as qdec0, | ||||
|         qdec0_ns as qdec, | ||||
|         qspi_ns as qspi, | ||||
|         regulators_ns as regulators, | ||||
|         reset_ns as reset, | ||||
| @@ -253,6 +253,13 @@ embassy_hal_common::peripherals! { | ||||
|     // QSPI | ||||
|     QSPI, | ||||
|  | ||||
|     // PDM | ||||
|     PDM0, | ||||
|  | ||||
|     // QDEC | ||||
|     QDEC0, | ||||
|     QDEC1, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
| @@ -398,6 +405,11 @@ impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| impl_qspi!(QSPI, QSPI, QSPI); | ||||
|  | ||||
| impl_pdm!(PDM0, PDM0, PDM0); | ||||
|  | ||||
| impl_qdec!(QDEC0, QDEC0, QDEC0); | ||||
| impl_qdec!(QDEC1, QDEC1, QDEC1); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| #[cfg(feature = "nfc-pins-as-gpio")] | ||||
|   | ||||
| @@ -127,6 +127,9 @@ embassy_hal_common::peripherals! { | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // RNG | ||||
|     RNG, | ||||
|  | ||||
|     // PWM | ||||
|     PWM0, | ||||
|     PWM1, | ||||
| @@ -252,6 +255,8 @@ impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| impl_rng!(RNG, RNG, RNG); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
|   | ||||
| @@ -301,6 +301,8 @@ impl_pwm!(PWM1, PWM1, PWM1); | ||||
| impl_pwm!(PWM2, PWM2, PWM2); | ||||
| impl_pwm!(PWM3, PWM3, PWM3); | ||||
|  | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|   | ||||
| @@ -14,7 +14,7 @@ use embassy_hal_common::drop::OnDrop; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
|  | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||
| use crate::interrupt::Interrupt; | ||||
| use crate::interrupt::{self, Interrupt}; | ||||
| use crate::pac::i2s::RegisterBlock; | ||||
| use crate::util::{slice_in_ram_or, slice_ptr_parts}; | ||||
| use crate::{Peripheral, EASY_DMA_SIZE}; | ||||
| @@ -363,10 +363,39 @@ impl From<Channels> for u8 { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let device = Device::<T>::new(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if device.is_tx_ptr_updated() { | ||||
|             trace!("TX INT"); | ||||
|             s.tx_waker.wake(); | ||||
|             device.disable_tx_ptr_interrupt(); | ||||
|         } | ||||
|  | ||||
|         if device.is_rx_ptr_updated() { | ||||
|             trace!("RX INT"); | ||||
|             s.rx_waker.wake(); | ||||
|             device.disable_rx_ptr_interrupt(); | ||||
|         } | ||||
|  | ||||
|         if device.is_stopped() { | ||||
|             trace!("STOPPED INT"); | ||||
|             s.stop_waker.wake(); | ||||
|             device.disable_stopped_interrupt(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// I2S driver. | ||||
| pub struct I2S<'d, T: Instance> { | ||||
|     i2s: PeripheralRef<'d, T>, | ||||
|     irq: PeripheralRef<'d, T::Interrupt>, | ||||
|     mck: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     sck: PeripheralRef<'d, AnyPin>, | ||||
|     lrck: PeripheralRef<'d, AnyPin>, | ||||
| @@ -378,19 +407,18 @@ pub struct I2S<'d, T: Instance> { | ||||
|  | ||||
| impl<'d, T: Instance> I2S<'d, T> { | ||||
|     /// Create a new I2S in master mode | ||||
|     pub fn master( | ||||
|     pub fn new_master( | ||||
|         i2s: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         mck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         lrck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         master_clock: MasterClock, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(i2s, irq, mck, sck, lrck); | ||||
|         into_ref!(i2s, mck, sck, lrck); | ||||
|         Self { | ||||
|             i2s, | ||||
|             irq, | ||||
|             mck: Some(mck.map_into()), | ||||
|             sck: sck.map_into(), | ||||
|             lrck: lrck.map_into(), | ||||
| @@ -402,17 +430,16 @@ impl<'d, T: Instance> I2S<'d, T> { | ||||
|     } | ||||
|  | ||||
|     /// Create a new I2S in slave mode | ||||
|     pub fn slave( | ||||
|     pub fn new_slave( | ||||
|         i2s: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         lrck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(i2s, irq, sck, lrck); | ||||
|         into_ref!(i2s, sck, lrck); | ||||
|         Self { | ||||
|             i2s, | ||||
|             irq, | ||||
|             mck: None, | ||||
|             sck: sck.map_into(), | ||||
|             lrck: lrck.map_into(), | ||||
| @@ -537,9 +564,8 @@ impl<'d, T: Instance> I2S<'d, T> { | ||||
|     } | ||||
|  | ||||
|     fn setup_interrupt(&self) { | ||||
|         self.irq.set_handler(Self::on_interrupt); | ||||
|         self.irq.unpend(); | ||||
|         self.irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         let device = Device::<T>::new(); | ||||
|         device.disable_tx_ptr_interrupt(); | ||||
| @@ -555,29 +581,6 @@ impl<'d, T: Instance> I2S<'d, T> { | ||||
|         device.enable_stopped_interrupt(); | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let device = Device::<T>::new(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if device.is_tx_ptr_updated() { | ||||
|             trace!("TX INT"); | ||||
|             s.tx_waker.wake(); | ||||
|             device.disable_tx_ptr_interrupt(); | ||||
|         } | ||||
|  | ||||
|         if device.is_rx_ptr_updated() { | ||||
|             trace!("RX INT"); | ||||
|             s.rx_waker.wake(); | ||||
|             device.disable_rx_ptr_interrupt(); | ||||
|         } | ||||
|  | ||||
|         if device.is_stopped() { | ||||
|             trace!("STOPPED INT"); | ||||
|             s.stop_waker.wake(); | ||||
|             device.disable_stopped_interrupt(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async fn stop() { | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
| @@ -1168,7 +1171,7 @@ pub(crate) mod sealed { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// I2S peripehral instance. | ||||
| /// I2S peripheral instance. | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||||
|     /// Interrupt for this peripheral. | ||||
|     type Interrupt: Interrupt; | ||||
|   | ||||
| @@ -47,19 +47,21 @@ pub mod nvmc; | ||||
| #[cfg(any( | ||||
|     feature = "nrf52810", | ||||
|     feature = "nrf52811", | ||||
|     feature = "nrf52832", | ||||
|     feature = "nrf52833", | ||||
|     feature = "nrf52840", | ||||
|     feature = "_nrf5340-app", | ||||
|     feature = "_nrf9160" | ||||
| ))] | ||||
| pub mod pdm; | ||||
| pub mod ppi; | ||||
| #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] | ||||
| pub mod pwm; | ||||
| #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] | ||||
| #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] | ||||
| pub mod qdec; | ||||
| #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] | ||||
| pub mod qspi; | ||||
| #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | ||||
| #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] | ||||
| pub mod rng; | ||||
| #[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] | ||||
| pub mod saadc; | ||||
| @@ -95,14 +97,39 @@ pub mod wdt; | ||||
| #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] | ||||
| mod chip; | ||||
|  | ||||
| pub use chip::EASY_DMA_SIZE; | ||||
|  | ||||
| pub mod interrupt { | ||||
|     //! nRF interrupts for cortex-m devices. | ||||
|     //! Interrupt definitions and macros to bind them. | ||||
|     pub use cortex_m::interrupt::{CriticalSection, Mutex}; | ||||
|     pub use embassy_cortex_m::interrupt::*; | ||||
|     pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; | ||||
|  | ||||
|     pub use crate::chip::irqs::*; | ||||
|  | ||||
|     /// Macro to bind interrupts to handlers. | ||||
|     /// | ||||
|     /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||||
|     /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | ||||
|     /// prove at compile-time that the right interrupts have been bound. | ||||
|     // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. | ||||
|     #[macro_export] | ||||
|     macro_rules! bind_interrupts { | ||||
|         ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | ||||
|             $vis struct $name; | ||||
|  | ||||
|             $( | ||||
|                 #[allow(non_snake_case)] | ||||
|                 #[no_mangle] | ||||
|                 unsafe extern "C" fn $irq() { | ||||
|                     $( | ||||
|                         <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); | ||||
|                     )* | ||||
|                 } | ||||
|  | ||||
|                 $( | ||||
|                     unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} | ||||
|                 )* | ||||
|             )* | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Reexports | ||||
| @@ -111,7 +138,7 @@ pub mod interrupt { | ||||
| pub use chip::pac; | ||||
| #[cfg(not(feature = "unstable-pac"))] | ||||
| pub(crate) use chip::pac; | ||||
| pub use chip::{peripherals, Peripherals}; | ||||
| pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; | ||||
| pub use embassy_cortex_m::executor; | ||||
| pub use embassy_cortex_m::interrupt::_export::interrupt; | ||||
| pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||||
|   | ||||
| @@ -1,25 +1,37 @@ | ||||
| //! Pulse Density Modulation (PDM) mirophone driver. | ||||
|  | ||||
| #![macro_use] | ||||
|  | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_cortex_m::interrupt::Interrupt; | ||||
| use embassy_hal_common::drop::OnDrop; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| use futures::future::poll_fn; | ||||
|  | ||||
| use crate::chip::EASY_DMA_SIZE; | ||||
| use crate::gpio::sealed::Pin; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||
| use crate::interrupt::{self, InterruptExt}; | ||||
| use crate::peripherals::PDM; | ||||
| use crate::{pac, Peripheral}; | ||||
| use crate::Peripheral; | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         T::regs().intenclr.write(|w| w.end().clear()); | ||||
|         T::state().waker.wake(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// PDM microphone interface | ||||
| pub struct Pdm<'d> { | ||||
|     irq: PeripheralRef<'d, interrupt::PDM>, | ||||
|     phantom: PhantomData<&'d PDM>, | ||||
| pub struct Pdm<'d, T: Instance> { | ||||
|     _peri: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| /// PDM error. | ||||
| @@ -35,32 +47,30 @@ pub enum Error { | ||||
|     NotRunning, | ||||
| } | ||||
|  | ||||
| static WAKER: AtomicWaker = AtomicWaker::new(); | ||||
| static DUMMY_BUFFER: [i16; 1] = [0; 1]; | ||||
|  | ||||
| impl<'d> Pdm<'d> { | ||||
| impl<'d, T: Instance> Pdm<'d, T> { | ||||
|     /// Create PDM driver | ||||
|     pub fn new( | ||||
|         pdm: impl Peripheral<P = PDM> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::PDM> + 'd, | ||||
|         pdm: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         clk: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         din: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(clk, din); | ||||
|         Self::new_inner(pdm, irq, clk.map_into(), din.map_into(), config) | ||||
|         into_ref!(pdm, clk, din); | ||||
|         Self::new_inner(pdm, clk.map_into(), din.map_into(), config) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         _pdm: impl Peripheral<P = PDM> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::PDM> + 'd, | ||||
|         pdm: PeripheralRef<'d, T>, | ||||
|         clk: PeripheralRef<'d, AnyPin>, | ||||
|         din: PeripheralRef<'d, AnyPin>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(irq); | ||||
|         into_ref!(pdm); | ||||
|  | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // setup gpio pins | ||||
|         din.conf().write(|w| w.input().set_bit()); | ||||
| @@ -84,26 +94,18 @@ impl<'d> Pdm<'d> { | ||||
|         r.gainr.write(|w| w.gainr().default_gain()); | ||||
|  | ||||
|         // IRQ | ||||
|         irq.disable(); | ||||
|         irq.set_handler(|_| { | ||||
|             let r = Self::regs(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             WAKER.wake(); | ||||
|         }); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         r.enable.write(|w| w.enable().set_bit()); | ||||
|  | ||||
|         Self { | ||||
|             phantom: PhantomData, | ||||
|             irq, | ||||
|         } | ||||
|         Self { _peri: pdm } | ||||
|     } | ||||
|  | ||||
|     /// Start sampling microphon data into a dummy buffer | ||||
|     /// Usefull to start the microphon and keep it active between recording samples | ||||
|     pub async fn start(&mut self) { | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // start dummy sampling because microphon needs some setup time | ||||
|         r.sample | ||||
| @@ -113,13 +115,13 @@ impl<'d> Pdm<'d> { | ||||
|             .maxcnt | ||||
|             .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||||
|  | ||||
|         r.tasks_start.write(|w| w.tasks_start().set_bit()); | ||||
|         r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||
|     } | ||||
|  | ||||
|     /// Stop sampling microphon data inta a dummy buffer | ||||
|     pub async fn stop(&mut self) { | ||||
|         let r = Self::regs(); | ||||
|         r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | ||||
|         let r = T::regs(); | ||||
|         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|         r.events_started.reset(); | ||||
|     } | ||||
|  | ||||
| @@ -132,9 +134,9 @@ impl<'d> Pdm<'d> { | ||||
|             return Err(Error::BufferTooLong); | ||||
|         } | ||||
|  | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         if r.events_started.read().events_started().bit_is_clear() { | ||||
|         if r.events_started.read().bits() == 0 { | ||||
|             return Err(Error::NotRunning); | ||||
|         } | ||||
|  | ||||
| @@ -179,7 +181,7 @@ impl<'d> Pdm<'d> { | ||||
|     } | ||||
|  | ||||
|     async fn wait_for_sample() { | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         r.events_end.reset(); | ||||
|         r.intenset.write(|w| w.end().set()); | ||||
| @@ -187,8 +189,8 @@ impl<'d> Pdm<'d> { | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|         poll_fn(|cx| { | ||||
|             WAKER.register(cx.waker()); | ||||
|             if r.events_end.read().events_end().bit_is_set() { | ||||
|             T::state().waker.register(cx.waker()); | ||||
|             if r.events_end.read().bits() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
|             Poll::Pending | ||||
| @@ -197,10 +199,6 @@ impl<'d> Pdm<'d> { | ||||
|  | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|     } | ||||
|  | ||||
|     fn regs() -> &'static pac::pdm::RegisterBlock { | ||||
|         unsafe { &*pac::PDM::ptr() } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// PDM microphone driver Config | ||||
| @@ -238,13 +236,11 @@ pub enum Edge { | ||||
|     LeftFalling, | ||||
| } | ||||
|  | ||||
| impl<'d> Drop for Pdm<'d> { | ||||
| impl<'d, T: Instance> Drop for Pdm<'d, T> { | ||||
|     fn drop(&mut self) { | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | ||||
|  | ||||
|         self.irq.disable(); | ||||
|         r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|  | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|  | ||||
| @@ -252,3 +248,48 @@ impl<'d> Drop for Pdm<'d> { | ||||
|         r.psel.clk.reset(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
|     /// Peripheral static state | ||||
|     pub struct State { | ||||
|         pub waker: AtomicWaker, | ||||
|     } | ||||
|  | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 waker: AtomicWaker::new(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static crate::pac::pdm::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// PDM peripheral instance. | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||||
|     /// Interrupt for this peripheral. | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_pdm { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::pdm::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::pdm::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::pdm::sealed::State { | ||||
|                 static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl crate::pdm::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,22 @@ | ||||
| //! Quadrature decoder (QDEC) driver. | ||||
|  | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_cortex_m::interrupt::Interrupt; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::peripherals::QDEC; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| use crate::{interrupt, Peripheral}; | ||||
|  | ||||
| /// Quadrature decoder driver. | ||||
| pub struct Qdec<'d> { | ||||
|     _p: PeripheralRef<'d, QDEC>, | ||||
| pub struct Qdec<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| /// QDEC config | ||||
| @@ -44,44 +46,52 @@ impl Default for Config { | ||||
|     } | ||||
| } | ||||
|  | ||||
| static WAKER: AtomicWaker = AtomicWaker::new(); | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<'d> Qdec<'d> { | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         T::regs().intenclr.write(|w| w.reportrdy().clear()); | ||||
|         T::state().waker.wake(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Qdec<'d, T> { | ||||
|     /// Create a new QDEC. | ||||
|     pub fn new( | ||||
|         qdec: impl Peripheral<P = QDEC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||||
|         qdec: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         a: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         b: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(a, b); | ||||
|         Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config) | ||||
|         into_ref!(qdec, a, b); | ||||
|         Self::new_inner(qdec, a.map_into(), b.map_into(), None, config) | ||||
|     } | ||||
|  | ||||
|     /// Create a new QDEC, with a pin for LED output. | ||||
|     pub fn new_with_led( | ||||
|         qdec: impl Peripheral<P = QDEC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||||
|         qdec: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         a: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         b: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         led: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(a, b, led); | ||||
|         Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config) | ||||
|         into_ref!(qdec, a, b, led); | ||||
|         Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         p: impl Peripheral<P = QDEC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||||
|         p: PeripheralRef<'d, T>, | ||||
|         a: PeripheralRef<'d, AnyPin>, | ||||
|         b: PeripheralRef<'d, AnyPin>, | ||||
|         led: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(p, irq); | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // Select pins. | ||||
|         a.conf().write(|w| w.input().connect().pull().pullup()); | ||||
| @@ -124,20 +134,15 @@ impl<'d> Qdec<'d> { | ||||
|             SamplePeriod::_131ms => w.sampleper()._131ms(), | ||||
|         }); | ||||
|  | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         // Enable peripheral | ||||
|         r.enable.write(|w| w.enable().set_bit()); | ||||
|  | ||||
|         // Start sampling | ||||
|         unsafe { r.tasks_start.write(|w| w.bits(1)) }; | ||||
|  | ||||
|         irq.disable(); | ||||
|         irq.set_handler(|_| { | ||||
|             let r = Self::regs(); | ||||
|             r.intenclr.write(|w| w.reportrdy().clear()); | ||||
|             WAKER.wake(); | ||||
|         }); | ||||
|         irq.enable(); | ||||
|  | ||||
|         Self { _p: p } | ||||
|     } | ||||
|  | ||||
| @@ -155,12 +160,12 @@ impl<'d> Qdec<'d> { | ||||
|     /// let delta = q.read().await; | ||||
|     /// ``` | ||||
|     pub async fn read(&mut self) -> i16 { | ||||
|         let t = Self::regs(); | ||||
|         let t = T::regs(); | ||||
|         t.intenset.write(|w| w.reportrdy().set()); | ||||
|         unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; | ||||
|  | ||||
|         let value = poll_fn(|cx| { | ||||
|             WAKER.register(cx.waker()); | ||||
|             T::state().waker.register(cx.waker()); | ||||
|             if t.events_reportrdy.read().bits() == 0 { | ||||
|                 return Poll::Pending; | ||||
|             } else { | ||||
| @@ -172,10 +177,6 @@ impl<'d> Qdec<'d> { | ||||
|         .await; | ||||
|         value | ||||
|     } | ||||
|  | ||||
|     fn regs() -> &'static pac::qdec::RegisterBlock { | ||||
|         unsafe { &*pac::QDEC::ptr() } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Sample period | ||||
| @@ -236,3 +237,48 @@ pub enum LedPolarity { | ||||
|     /// Active low (a low output turns on the LED). | ||||
|     ActiveLow, | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
|     /// Peripheral static state | ||||
|     pub struct State { | ||||
|         pub waker: AtomicWaker, | ||||
|     } | ||||
|  | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 waker: AtomicWaker::new(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static crate::pac::qdec::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// qdec peripheral instance. | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||||
|     /// Interrupt for this peripheral. | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_qdec { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::qdec::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::qdec::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::qdec::sealed::State { | ||||
|                 static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl crate::qdec::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::ptr; | ||||
| use core::task::Poll; | ||||
|  | ||||
| @@ -11,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | ||||
|  | ||||
| use crate::gpio::{self, Pin as GpioPin}; | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| pub use crate::pac::qspi::ifconfig0::{ | ||||
|     ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, | ||||
| }; | ||||
| pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; | ||||
| use crate::{pac, Peripheral}; | ||||
| use crate::Peripheral; | ||||
|  | ||||
| /// Deep power-down config. | ||||
| pub struct DeepPowerDownConfig { | ||||
| @@ -114,9 +115,26 @@ pub enum Error { | ||||
|     // TODO add "not in data memory" error and check for it | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_ready.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.ready().clear()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// QSPI flash driver. | ||||
| pub struct Qspi<'d, T: Instance> { | ||||
|     irq: PeripheralRef<'d, T::Interrupt>, | ||||
|     _peri: PeripheralRef<'d, T>, | ||||
|     dpm_enabled: bool, | ||||
|     capacity: u32, | ||||
| } | ||||
| @@ -124,8 +142,8 @@ pub struct Qspi<'d, T: Instance> { | ||||
| impl<'d, T: Instance> Qspi<'d, T> { | ||||
|     /// Create a new QSPI driver. | ||||
|     pub fn new( | ||||
|         _qspi: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         qspi: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         csn: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         io0: impl Peripheral<P = impl GpioPin> + 'd, | ||||
| @@ -134,7 +152,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         io3: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(irq, sck, csn, io0, io1, io2, io3); | ||||
|         into_ref!(qspi, sck, csn, io0, io1, io2, io3); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -189,16 +207,15 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|             w | ||||
|         }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         // Enable it | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|  | ||||
|         let res = Self { | ||||
|             _peri: qspi, | ||||
|             dpm_enabled: config.deep_power_down.is_some(), | ||||
|             irq, | ||||
|             capacity: config.capacity, | ||||
|         }; | ||||
|  | ||||
| @@ -212,16 +229,6 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         res | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_ready.read().bits() != 0 { | ||||
|             s.ready_waker.wake(); | ||||
|             r.intenclr.write(|w| w.ready().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Do a custom QSPI instruction. | ||||
|     pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { | ||||
|         let ondrop = OnDrop::new(Self::blocking_wait_ready); | ||||
| @@ -310,7 +317,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | ||||
|         poll_fn(move |cx| { | ||||
|             let r = T::regs(); | ||||
|             let s = T::state(); | ||||
|             s.ready_waker.register(cx.waker()); | ||||
|             s.waker.register(cx.waker()); | ||||
|             if r.events_ready.read().bits() != 0 { | ||||
|                 return Poll::Ready(()); | ||||
|             } | ||||
| @@ -525,8 +532,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { | ||||
|  | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|  | ||||
|         self.irq.disable(); | ||||
|  | ||||
|         // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, | ||||
|         // leaving it floating, the flash chip might read it as zero which would cause it to | ||||
|         // spuriously exit DPM. | ||||
| @@ -624,27 +629,27 @@ mod _eh1 { | ||||
| pub(crate) mod sealed { | ||||
|     use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
|     use super::*; | ||||
|  | ||||
|     /// Peripheral static state | ||||
|     pub struct State { | ||||
|         pub ready_waker: AtomicWaker, | ||||
|         pub waker: AtomicWaker, | ||||
|     } | ||||
|  | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 ready_waker: AtomicWaker::new(), | ||||
|                 waker: AtomicWaker::new(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static pac::qspi::RegisterBlock; | ||||
|         fn regs() -> &'static crate::pac::qspi::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// QSPI peripheral instance. | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||||
|     /// Interrupt for this peripheral. | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
| @@ -652,7 +657,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | ||||
| macro_rules! impl_qspi { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::qspi::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::qspi::RegisterBlock { | ||||
|             fn regs() -> &'static crate::pac::qspi::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::qspi::sealed::State { | ||||
|   | ||||
| @@ -1,83 +1,48 @@ | ||||
| //! Random Number Generator (RNG) driver. | ||||
|  | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::ptr; | ||||
| use core::sync::atomic::{AtomicPtr, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_cortex_m::interrupt::Interrupt; | ||||
| use embassy_hal_common::drop::OnDrop; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::peripherals::RNG; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| use crate::{interrupt, Peripheral}; | ||||
|  | ||||
| impl RNG { | ||||
|     fn regs() -> &'static pac::rng::RegisterBlock { | ||||
|         unsafe { &*pac::RNG::ptr() } | ||||
|     } | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| static STATE: State = State { | ||||
|     ptr: AtomicPtr::new(ptr::null_mut()), | ||||
|     end: AtomicPtr::new(ptr::null_mut()), | ||||
|     waker: AtomicWaker::new(), | ||||
| }; | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let s = T::state(); | ||||
|         let r = T::regs(); | ||||
|  | ||||
| struct State { | ||||
|     ptr: AtomicPtr<u8>, | ||||
|     end: AtomicPtr<u8>, | ||||
|     waker: AtomicWaker, | ||||
| } | ||||
|  | ||||
| /// A wrapper around an nRF RNG peripheral. | ||||
| /// | ||||
| /// It has a non-blocking API, and a blocking api through `rand`. | ||||
| pub struct Rng<'d> { | ||||
|     irq: PeripheralRef<'d, interrupt::RNG>, | ||||
| } | ||||
|  | ||||
| impl<'d> Rng<'d> { | ||||
|     /// Creates a new RNG driver from the `RNG` peripheral and interrupt. | ||||
|     /// | ||||
|     /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, | ||||
|     /// e.g. using `mem::forget`. | ||||
|     /// | ||||
|     /// The synchronous API is safe. | ||||
|     pub fn new(_rng: impl Peripheral<P = RNG> + 'd, irq: impl Peripheral<P = interrupt::RNG> + 'd) -> Self { | ||||
|         into_ref!(irq); | ||||
|  | ||||
|         let this = Self { irq }; | ||||
|  | ||||
|         this.stop(); | ||||
|         this.disable_irq(); | ||||
|  | ||||
|         this.irq.set_handler(Self::on_interrupt); | ||||
|         this.irq.unpend(); | ||||
|         this.irq.enable(); | ||||
|  | ||||
|         this | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         // Clear the event. | ||||
|         RNG::regs().events_valrdy.reset(); | ||||
|         r.events_valrdy.reset(); | ||||
|  | ||||
|         // Mutate the slice within a critical section, | ||||
|         // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. | ||||
|         let (ptr, end) = critical_section::with(|_| { | ||||
|             let ptr = STATE.ptr.load(Ordering::Relaxed); | ||||
|             let ptr = s.ptr.load(Ordering::Relaxed); | ||||
|             // We need to make sure we haven't already filled the whole slice, | ||||
|             // in case the interrupt fired again before the executor got back to the future. | ||||
|             let end = STATE.end.load(Ordering::Relaxed); | ||||
|             let end = s.end.load(Ordering::Relaxed); | ||||
|             if !ptr.is_null() && ptr != end { | ||||
|                 // If the future was dropped, the pointer would have been set to null, | ||||
|                 // so we're still good to mutate the slice. | ||||
|                 // The safety contract of `Rng::new` means that the future can't have been dropped | ||||
|                 // without calling its destructor. | ||||
|                 unsafe { | ||||
|                     *ptr = RNG::regs().value.read().value().bits(); | ||||
|                     *ptr = r.value.read().value().bits(); | ||||
|                 } | ||||
|             } | ||||
|             (ptr, end) | ||||
| @@ -90,15 +55,15 @@ impl<'d> Rng<'d> { | ||||
|         } | ||||
|  | ||||
|         let new_ptr = unsafe { ptr.add(1) }; | ||||
|         match STATE | ||||
|         match s | ||||
|             .ptr | ||||
|             .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed) | ||||
|         { | ||||
|             Ok(_) => { | ||||
|                 let end = STATE.end.load(Ordering::Relaxed); | ||||
|                 let end = s.end.load(Ordering::Relaxed); | ||||
|                 // It doesn't matter if `end` was changed under our feet, because then this will just be false. | ||||
|                 if new_ptr == end { | ||||
|                     STATE.waker.wake(); | ||||
|                     s.waker.wake(); | ||||
|                 } | ||||
|             } | ||||
|             Err(_) => { | ||||
| @@ -107,21 +72,53 @@ impl<'d> Rng<'d> { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A wrapper around an nRF RNG peripheral. | ||||
| /// | ||||
| /// It has a non-blocking API, and a blocking api through `rand`. | ||||
| pub struct Rng<'d, T: Instance> { | ||||
|     _peri: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Rng<'d, T> { | ||||
|     /// Creates a new RNG driver from the `RNG` peripheral and interrupt. | ||||
|     /// | ||||
|     /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, | ||||
|     /// e.g. using `mem::forget`. | ||||
|     /// | ||||
|     /// The synchronous API is safe. | ||||
|     pub fn new( | ||||
|         rng: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|     ) -> Self { | ||||
|         into_ref!(rng); | ||||
|  | ||||
|         let this = Self { _peri: rng }; | ||||
|  | ||||
|         this.stop(); | ||||
|         this.disable_irq(); | ||||
|  | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         this | ||||
|     } | ||||
|  | ||||
|     fn stop(&self) { | ||||
|         RNG::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | ||||
|     } | ||||
|  | ||||
|     fn start(&self) { | ||||
|         RNG::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | ||||
|         T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | ||||
|     } | ||||
|  | ||||
|     fn enable_irq(&self) { | ||||
|         RNG::regs().intenset.write(|w| w.valrdy().set()); | ||||
|         T::regs().intenset.write(|w| w.valrdy().set()); | ||||
|     } | ||||
|  | ||||
|     fn disable_irq(&self) { | ||||
|         RNG::regs().intenclr.write(|w| w.valrdy().clear()); | ||||
|         T::regs().intenclr.write(|w| w.valrdy().clear()); | ||||
|     } | ||||
|  | ||||
|     /// Enable or disable the RNG's bias correction. | ||||
| @@ -131,7 +128,7 @@ impl<'d> Rng<'d> { | ||||
|     /// | ||||
|     /// Defaults to disabled. | ||||
|     pub fn set_bias_correction(&self, enable: bool) { | ||||
|         RNG::regs().config.write(|w| w.dercen().bit(enable)) | ||||
|         T::regs().config.write(|w| w.dercen().bit(enable)) | ||||
|     } | ||||
|  | ||||
|     /// Fill the buffer with random bytes. | ||||
| @@ -140,11 +137,13 @@ impl<'d> Rng<'d> { | ||||
|             return; // Nothing to fill | ||||
|         } | ||||
|  | ||||
|         let s = T::state(); | ||||
|  | ||||
|         let range = dest.as_mut_ptr_range(); | ||||
|         // Even if we've preempted the interrupt, it can't preempt us again, | ||||
|         // so we don't need to worry about the order we write these in. | ||||
|         STATE.ptr.store(range.start, Ordering::Relaxed); | ||||
|         STATE.end.store(range.end, Ordering::Relaxed); | ||||
|         s.ptr.store(range.start, Ordering::Relaxed); | ||||
|         s.end.store(range.end, Ordering::Relaxed); | ||||
|  | ||||
|         self.enable_irq(); | ||||
|         self.start(); | ||||
| @@ -154,16 +153,16 @@ impl<'d> Rng<'d> { | ||||
|             self.disable_irq(); | ||||
|  | ||||
|             // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. | ||||
|             STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed); | ||||
|             STATE.end.store(ptr::null_mut(), Ordering::Relaxed); | ||||
|             s.ptr.store(ptr::null_mut(), Ordering::Relaxed); | ||||
|             s.end.store(ptr::null_mut(), Ordering::Relaxed); | ||||
|         }); | ||||
|  | ||||
|         poll_fn(|cx| { | ||||
|             STATE.waker.register(cx.waker()); | ||||
|             s.waker.register(cx.waker()); | ||||
|  | ||||
|             // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. | ||||
|             let end = STATE.end.load(Ordering::Relaxed); | ||||
|             let ptr = STATE.ptr.load(Ordering::Relaxed); | ||||
|             let end = s.end.load(Ordering::Relaxed); | ||||
|             let ptr = s.ptr.load(Ordering::Relaxed); | ||||
|  | ||||
|             if ptr == end { | ||||
|                 // We're done. | ||||
| @@ -183,7 +182,7 @@ impl<'d> Rng<'d> { | ||||
|         self.start(); | ||||
|  | ||||
|         for byte in dest.iter_mut() { | ||||
|             let regs = RNG::regs(); | ||||
|             let regs = T::regs(); | ||||
|             while regs.events_valrdy.read().bits() == 0 {} | ||||
|             regs.events_valrdy.reset(); | ||||
|             *byte = regs.value.read().value().bits(); | ||||
| @@ -193,13 +192,16 @@ impl<'d> Rng<'d> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d> Drop for Rng<'d> { | ||||
| impl<'d, T: Instance> Drop for Rng<'d, T> { | ||||
|     fn drop(&mut self) { | ||||
|         self.irq.disable() | ||||
|         self.stop(); | ||||
|         let s = T::state(); | ||||
|         s.ptr.store(ptr::null_mut(), Ordering::Relaxed); | ||||
|         s.end.store(ptr::null_mut(), Ordering::Relaxed); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d> rand_core::RngCore for Rng<'d> { | ||||
| impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> { | ||||
|     fn fill_bytes(&mut self, dest: &mut [u8]) { | ||||
|         self.blocking_fill_bytes(dest); | ||||
|     } | ||||
| @@ -223,4 +225,53 @@ impl<'d> rand_core::RngCore for Rng<'d> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d> rand_core::CryptoRng for Rng<'d> {} | ||||
| impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     /// Peripheral static state | ||||
|     pub struct State { | ||||
|         pub ptr: AtomicPtr<u8>, | ||||
|         pub end: AtomicPtr<u8>, | ||||
|         pub waker: AtomicWaker, | ||||
|     } | ||||
|  | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 ptr: AtomicPtr::new(ptr::null_mut()), | ||||
|                 end: AtomicPtr::new(ptr::null_mut()), | ||||
|                 waker: AtomicWaker::new(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static crate::pac::rng::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// RNG peripheral instance. | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||||
|     /// Interrupt for this peripheral. | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_rng { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::rng::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::rng::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::rng::sealed::State { | ||||
|                 static STATE: crate::rng::sealed::State = crate::rng::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl crate::rng::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ use core::future::poll_fn; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||||
| use embassy_hal_common::drop::OnDrop; | ||||
| use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| @@ -17,7 +18,6 @@ use saadc::oversample::OVERSAMPLE_A; | ||||
| use saadc::resolution::VAL_A; | ||||
|  | ||||
| use self::sealed::Input as _; | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; | ||||
| use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | ||||
| use crate::{interrupt, pac, peripherals, Peripheral}; | ||||
| @@ -28,9 +28,30 @@ use crate::{interrupt, pac, peripherals, Peripheral}; | ||||
| #[non_exhaustive] | ||||
| pub enum Error {} | ||||
|  | ||||
| /// One-shot and continuous SAADC. | ||||
| pub struct Saadc<'d, const N: usize> { | ||||
|     _p: PeripheralRef<'d, peripherals::SAADC>, | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler { | ||||
|     _private: (), | ||||
| } | ||||
|  | ||||
| impl interrupt::Handler<interrupt::SAADC> for InterruptHandler { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = unsafe { &*SAADC::ptr() }; | ||||
|  | ||||
|         if r.events_calibratedone.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.calibratedone().clear()); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|         if r.events_started.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.started().clear()); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static WAKER: AtomicWaker = AtomicWaker::new(); | ||||
| @@ -114,15 +135,20 @@ pub enum CallbackResult { | ||||
|     Stop, | ||||
| } | ||||
|  | ||||
| /// One-shot and continuous SAADC. | ||||
| pub struct Saadc<'d, const N: usize> { | ||||
|     _p: PeripheralRef<'d, peripherals::SAADC>, | ||||
| } | ||||
|  | ||||
| impl<'d, const N: usize> Saadc<'d, N> { | ||||
|     /// Create a new SAADC driver. | ||||
|     pub fn new( | ||||
|         saadc: impl Peripheral<P = peripherals::SAADC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::SAADC> + 'd, | ||||
|         _irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd, | ||||
|         config: Config, | ||||
|         channel_configs: [ChannelConfig; N], | ||||
|     ) -> Self { | ||||
|         into_ref!(saadc, irq); | ||||
|         into_ref!(saadc); | ||||
|  | ||||
|         let r = unsafe { &*SAADC::ptr() }; | ||||
|  | ||||
| @@ -163,32 +189,12 @@ impl<'d, const N: usize> Saadc<'d, N> { | ||||
|         // Disable all events interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { interrupt::SAADC::steal() }.unpend(); | ||||
|         unsafe { interrupt::SAADC::steal() }.enable(); | ||||
|  | ||||
|         Self { _p: saadc } | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_ctx: *mut ()) { | ||||
|         let r = Self::regs(); | ||||
|  | ||||
|         if r.events_calibratedone.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.calibratedone().clear()); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|         if r.events_started.read().bits() != 0 { | ||||
|             r.intenclr.write(|w| w.started().clear()); | ||||
|             WAKER.wake(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn regs() -> &'static saadc::RegisterBlock { | ||||
|         unsafe { &*SAADC::ptr() } | ||||
|     } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| @@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | ||||
| use crate::chip::FORCE_COPY_BUFFER_SIZE; | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | ||||
| use crate::{pac, Peripheral}; | ||||
|  | ||||
| @@ -31,11 +32,6 @@ pub enum Error { | ||||
|     BufferNotInRAM, | ||||
| } | ||||
|  | ||||
| /// SPIM driver. | ||||
| pub struct Spim<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| /// SPIM configuration. | ||||
| #[non_exhaustive] | ||||
| pub struct Config { | ||||
| @@ -62,11 +58,33 @@ impl Default for Config { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// SPIM driver. | ||||
| pub struct Spim<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Spim<'d, T> { | ||||
|     /// Create a new SPIM driver. | ||||
|     pub fn new( | ||||
|         spim: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         miso: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         mosi: impl Peripheral<P = impl GpioPin> + 'd, | ||||
| @@ -75,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         into_ref!(sck, miso, mosi); | ||||
|         Self::new_inner( | ||||
|             spim, | ||||
|             irq, | ||||
|             sck.map_into(), | ||||
|             Some(miso.map_into()), | ||||
|             Some(mosi.map_into()), | ||||
| @@ -86,36 +103,35 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|     /// Create a new SPIM driver, capable of TX only (MOSI only). | ||||
|     pub fn new_txonly( | ||||
|         spim: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         mosi: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(sck, mosi); | ||||
|         Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config) | ||||
|         Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config) | ||||
|     } | ||||
|  | ||||
|     /// Create a new SPIM driver, capable of RX only (MISO only). | ||||
|     pub fn new_rxonly( | ||||
|         spim: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         miso: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(sck, miso); | ||||
|         Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config) | ||||
|         Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         spim: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         sck: PeripheralRef<'d, AnyPin>, | ||||
|         miso: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         mosi: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(spim, irq); | ||||
|         into_ref!(spim); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> { | ||||
|         // Disable all events interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         Self { _p: spim } | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { | ||||
|         slice_in_ram_or(tx, Error::BufferNotInRAM)?; | ||||
|         // NOTE: RAM slice check for rx is not necessary, as a mutable | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| #![macro_use] | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| @@ -12,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO | ||||
| use crate::chip::FORCE_COPY_BUFFER_SIZE; | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin}; | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | ||||
| use crate::{pac, Peripheral}; | ||||
|  | ||||
| @@ -29,11 +30,6 @@ pub enum Error { | ||||
|     BufferNotInRAM, | ||||
| } | ||||
|  | ||||
| /// SPIS driver. | ||||
| pub struct Spis<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| /// SPIS configuration. | ||||
| #[non_exhaustive] | ||||
| pub struct Config { | ||||
| @@ -67,11 +63,38 @@ impl Default for Config { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|         } | ||||
|  | ||||
|         if r.events_acquired.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.acquired().clear()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// SPIS driver. | ||||
| pub struct Spis<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Spis<'d, T> { | ||||
|     /// Create a new SPIS driver. | ||||
|     pub fn new( | ||||
|         spis: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         cs: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         miso: impl Peripheral<P = impl GpioPin> + 'd, | ||||
| @@ -81,7 +104,6 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         into_ref!(cs, sck, miso, mosi); | ||||
|         Self::new_inner( | ||||
|             spis, | ||||
|             irq, | ||||
|             cs.map_into(), | ||||
|             sck.map_into(), | ||||
|             Some(miso.map_into()), | ||||
| @@ -93,48 +115,31 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|     /// Create a new SPIS driver, capable of TX only (MISO only). | ||||
|     pub fn new_txonly( | ||||
|         spis: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         cs: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         miso: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(cs, sck, miso); | ||||
|         Self::new_inner( | ||||
|             spis, | ||||
|             irq, | ||||
|             cs.map_into(), | ||||
|             sck.map_into(), | ||||
|             Some(miso.map_into()), | ||||
|             None, | ||||
|             config, | ||||
|         ) | ||||
|         Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config) | ||||
|     } | ||||
|  | ||||
|     /// Create a new SPIS driver, capable of RX only (MOSI only). | ||||
|     pub fn new_rxonly( | ||||
|         spis: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         cs: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         sck: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         mosi: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(cs, sck, mosi); | ||||
|         Self::new_inner( | ||||
|             spis, | ||||
|             irq, | ||||
|             cs.map_into(), | ||||
|             sck.map_into(), | ||||
|             None, | ||||
|             Some(mosi.map_into()), | ||||
|             config, | ||||
|         ) | ||||
|         Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         spis: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         cs: PeripheralRef<'d, AnyPin>, | ||||
|         sck: PeripheralRef<'d, AnyPin>, | ||||
|         miso: Option<PeripheralRef<'d, AnyPin>>, | ||||
| @@ -143,7 +148,7 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|     ) -> Self { | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|         into_ref!(spis, irq, cs, sck); | ||||
|         into_ref!(spis, cs, sck); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -209,28 +214,12 @@ impl<'d, T: Instance> Spis<'d, T> { | ||||
|         // Disable all events interrupts. | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         Self { _p: spis } | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_end.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.end().clear()); | ||||
|         } | ||||
|  | ||||
|         if r.events_acquired.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.write(|w| w.acquired().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { | ||||
|         slice_in_ram_or(tx, Error::BufferNotInRAM)?; | ||||
|         // NOTE: RAM slice check for rx is not necessary, as a mutable | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| use core::future::poll_fn; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_cortex_m::interrupt::Interrupt; | ||||
| use embassy_hal_common::drop::OnDrop; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| @@ -12,27 +13,39 @@ use crate::interrupt::InterruptExt; | ||||
| use crate::peripherals::TEMP; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler { | ||||
|     _private: (), | ||||
| } | ||||
|  | ||||
| impl interrupt::Handler<interrupt::TEMP> for InterruptHandler { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = unsafe { &*pac::TEMP::PTR }; | ||||
|         r.intenclr.write(|w| w.datardy().clear()); | ||||
|         WAKER.wake(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Builtin temperature sensor driver. | ||||
| pub struct Temp<'d> { | ||||
|     _irq: PeripheralRef<'d, interrupt::TEMP>, | ||||
|     _peri: PeripheralRef<'d, TEMP>, | ||||
| } | ||||
|  | ||||
| static WAKER: AtomicWaker = AtomicWaker::new(); | ||||
|  | ||||
| impl<'d> Temp<'d> { | ||||
|     /// Create a new temperature sensor driver. | ||||
|     pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self { | ||||
|         into_ref!(_t, irq); | ||||
|     pub fn new( | ||||
|         _peri: impl Peripheral<P = TEMP> + 'd, | ||||
|         _irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd, | ||||
|     ) -> Self { | ||||
|         into_ref!(_peri); | ||||
|  | ||||
|         // Enable interrupt that signals temperature values | ||||
|         irq.disable(); | ||||
|         irq.set_handler(|_| { | ||||
|             let t = Self::regs(); | ||||
|             t.intenclr.write(|w| w.datardy().clear()); | ||||
|             WAKER.wake(); | ||||
|         }); | ||||
|         irq.enable(); | ||||
|         Self { _irq: irq } | ||||
|         unsafe { interrupt::TEMP::steal() }.unpend(); | ||||
|         unsafe { interrupt::TEMP::steal() }.enable(); | ||||
|  | ||||
|         Self { _peri } | ||||
|     } | ||||
|  | ||||
|     /// Perform an asynchronous temperature measurement. The returned future | ||||
|   | ||||
| @@ -6,15 +6,9 @@ | ||||
|  | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_hal_common::drop::OnDrop; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::Interrupt; | ||||
| use crate::ppi::{Event, Task}; | ||||
| use crate::{pac, Peripheral}; | ||||
|  | ||||
| @@ -26,8 +20,6 @@ pub(crate) mod sealed { | ||||
|         /// The number of CC registers this instance has. | ||||
|         const CCS: usize; | ||||
|         fn regs() -> &'static pac::timer0::RegisterBlock; | ||||
|         /// Storage for the waker for CC register `n`. | ||||
|         fn waker(n: usize) -> &'static AtomicWaker; | ||||
|     } | ||||
|     pub trait ExtendedInstance {} | ||||
|  | ||||
| @@ -50,12 +42,6 @@ macro_rules! impl_timer { | ||||
|             fn regs() -> &'static pac::timer0::RegisterBlock { | ||||
|                 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } | ||||
|             } | ||||
|             fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker { | ||||
|                 use ::embassy_sync::waitqueue::AtomicWaker; | ||||
|                 const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||||
|                 static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs]; | ||||
|                 &WAKERS[n] | ||||
|             } | ||||
|         } | ||||
|         impl crate::timer::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
| @@ -99,59 +85,18 @@ pub enum Frequency { | ||||
| /// nRF Timer driver. | ||||
| /// | ||||
| /// The timer has an internal counter, which is incremented for every tick of the timer. | ||||
| /// The counter is 32-bit, so it wraps back to 0 at 4294967296. | ||||
| /// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32. | ||||
| /// | ||||
| /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter | ||||
| /// or trigger an event when the counter reaches a certain value. | ||||
|  | ||||
| pub trait TimerType: sealed::TimerType {} | ||||
|  | ||||
| /// Marker type indicating the timer driver can await expiration (it owns the timer interrupt). | ||||
| pub enum Awaitable {} | ||||
|  | ||||
| /// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt). | ||||
| pub enum NotAwaitable {} | ||||
|  | ||||
| impl sealed::TimerType for Awaitable {} | ||||
| impl sealed::TimerType for NotAwaitable {} | ||||
| impl TimerType for Awaitable {} | ||||
| impl TimerType for NotAwaitable {} | ||||
|  | ||||
| /// Timer driver. | ||||
| pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { | ||||
| pub struct Timer<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
|     _i: PhantomData<I>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Timer<'d, T, Awaitable> { | ||||
|     /// Create a new async-capable timer driver. | ||||
|     pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self { | ||||
|         into_ref!(irq); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|  | ||||
|         Self::new_inner(timer, false) | ||||
|     } | ||||
|  | ||||
|     /// Create a new async-capable timer driver in counter mode. | ||||
|     pub fn new_awaitable_counter( | ||||
|         timer: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|     ) -> Self { | ||||
|         into_ref!(irq); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|  | ||||
|         Self::new_inner(timer, true) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { | ||||
|     /// Create a `Timer` driver without an interrupt, meaning `Cc::wait` won't work. | ||||
| impl<'d, T: Instance> Timer<'d, T> { | ||||
|     /// Create a new `Timer` driver. | ||||
|     /// | ||||
|     /// This can be useful for triggering tasks via PPI | ||||
|     /// `Uarte` uses this internally. | ||||
| @@ -159,28 +104,20 @@ impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { | ||||
|         Self::new_inner(timer, false) | ||||
|     } | ||||
|  | ||||
|     /// Create a `Timer` driver in counter mode without an interrupt, meaning `Cc::wait` won't work. | ||||
|     /// Create a new `Timer` driver in counter mode. | ||||
|     /// | ||||
|     /// This can be useful for triggering tasks via PPI | ||||
|     /// `Uarte` uses this internally. | ||||
|     pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self { | ||||
|         Self::new_inner(timer, true) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | ||||
|     /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. | ||||
|     /// | ||||
|     /// This is used by the public constructors. | ||||
|     fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { | ||||
|         into_ref!(timer); | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         let mut this = Self { | ||||
|             _p: timer, | ||||
|             _i: PhantomData, | ||||
|         }; | ||||
|         let mut this = Self { _p: timer }; | ||||
|  | ||||
|         // Stop the timer before doing anything else, | ||||
|         // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. | ||||
| @@ -272,31 +209,17 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | ||||
|             .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let regs = T::regs(); | ||||
|         for n in 0..T::CCS { | ||||
|             if regs.events_compare[n].read().bits() != 0 { | ||||
|                 // Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits. | ||||
|                 // We can't clear the event, because it's used to poll whether the future is done or still pending. | ||||
|                 regs.intenclr | ||||
|                     .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) }); | ||||
|                 T::waker(n).wake(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Returns this timer's `n`th CC register. | ||||
|     /// | ||||
|     /// # Panics | ||||
|     /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). | ||||
|     pub fn cc(&mut self, n: usize) -> Cc<T, I> { | ||||
|     pub fn cc(&mut self, n: usize) -> Cc<T> { | ||||
|         if n >= T::CCS { | ||||
|             panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); | ||||
|         } | ||||
|         Cc { | ||||
|             n, | ||||
|             _p: self._p.reborrow(), | ||||
|             _i: PhantomData, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -308,49 +231,12 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | ||||
| /// | ||||
| /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. | ||||
| /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register | ||||
| pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { | ||||
| pub struct Cc<'d, T: Instance> { | ||||
|     n: usize, | ||||
|     _p: PeripheralRef<'d, T>, | ||||
|     _i: PhantomData<I>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Cc<'d, T, Awaitable> { | ||||
|     /// Wait until the timer's counter reaches the value stored in this register. | ||||
|     /// | ||||
|     /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`. | ||||
|     pub async fn wait(&mut self) { | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         // Enable the interrupt for this CC's COMPARE event. | ||||
|         regs.intenset | ||||
|             .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||||
|  | ||||
|         // Disable the interrupt if the future is dropped. | ||||
|         let on_drop = OnDrop::new(|| { | ||||
|             regs.intenclr | ||||
|                 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||||
|         }); | ||||
|  | ||||
|         poll_fn(|cx| { | ||||
|             T::waker(self.n).register(cx.waker()); | ||||
|  | ||||
|             if regs.events_compare[self.n].read().bits() != 0 { | ||||
|                 // Reset the register for next time | ||||
|                 regs.events_compare[self.n].reset(); | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }) | ||||
|         .await; | ||||
|  | ||||
|         // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again. | ||||
|         on_drop.defuse(); | ||||
|     } | ||||
| } | ||||
| impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {} | ||||
|  | ||||
| impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { | ||||
| impl<'d, T: Instance> Cc<'d, T> { | ||||
|     /// Get the current value stored in the register. | ||||
|     pub fn read(&self) -> u32 { | ||||
|         T::regs().cc[self.n].read().cc().bits() | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::{poll_fn, Future}; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::compiler_fence; | ||||
| use core::sync::atomic::Ordering::SeqCst; | ||||
| use core::task::Poll; | ||||
| @@ -15,7 +16,7 @@ use embassy_time::{Duration, Instant}; | ||||
|  | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::Pin as GpioPin; | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::util::{slice_in_ram, slice_in_ram_or}; | ||||
| use crate::{gpio, pac, Peripheral}; | ||||
|  | ||||
| @@ -92,6 +93,27 @@ pub enum Error { | ||||
|     Timeout, | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.stopped().clear()); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.error().clear()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// TWI driver. | ||||
| pub struct Twim<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| @@ -101,12 +123,12 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|     /// Create a new TWI driver. | ||||
|     pub fn new( | ||||
|         twim: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sda: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         scl: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(twim, irq, sda, scl); | ||||
|         into_ref!(twim, sda, scl); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -152,27 +174,12 @@ impl<'d, T: Instance> Twim<'d, T> { | ||||
|         // Disable all events interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         Self { _p: twim } | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.stopped().clear()); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.error().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Set TX buffer, checking that it is in RAM and has suitable length. | ||||
|     unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||||
|         slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::{poll_fn, Future}; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::compiler_fence; | ||||
| use core::sync::atomic::Ordering::SeqCst; | ||||
| use core::task::Poll; | ||||
| @@ -14,7 +15,7 @@ use embassy_time::{Duration, Instant}; | ||||
|  | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::Pin as GpioPin; | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::util::slice_in_ram_or; | ||||
| use crate::{gpio, pac, Peripheral}; | ||||
|  | ||||
| @@ -108,6 +109,31 @@ pub enum Command { | ||||
|     Write(usize), | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.read().clear().write().clear()); | ||||
|         } | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.stopped().clear()); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.error().clear()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// TWIS driver. | ||||
| pub struct Twis<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| @@ -117,12 +143,12 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|     /// Create a new TWIS driver. | ||||
|     pub fn new( | ||||
|         twis: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         sda: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         scl: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(twis, irq, sda, scl); | ||||
|         into_ref!(twis, sda, scl); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -178,31 +204,12 @@ impl<'d, T: Instance> Twis<'d, T> { | ||||
|         // Generate suspend on read event | ||||
|         r.shorts.write(|w| w.read_suspend().enabled()); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         Self { _p: twis } | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.read().clear().write().clear()); | ||||
|         } | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.stopped().clear()); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|             s.waker.wake(); | ||||
|             r.intenclr.modify(|_r, w| w.error().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Set TX buffer, checking that it is in RAM and has suitable length. | ||||
|     unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||||
|         slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| @@ -26,7 +27,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | ||||
| use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | ||||
| use crate::util::slice_in_ram_or; | ||||
| @@ -62,6 +63,27 @@ pub enum Error { | ||||
|     BufferNotInRAM, | ||||
| } | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_endrx.read().bits() != 0 { | ||||
|             s.endrx_waker.wake(); | ||||
|             r.intenclr.write(|w| w.endrx().clear()); | ||||
|         } | ||||
|         if r.events_endtx.read().bits() != 0 { | ||||
|             s.endtx_waker.wake(); | ||||
|             r.intenclr.write(|w| w.endtx().clear()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// UARTE driver. | ||||
| pub struct Uarte<'d, T: Instance> { | ||||
|     tx: UarteTx<'d, T>, | ||||
| @@ -86,19 +108,19 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|     /// Create a new UARTE without hardware flow control | ||||
|     pub fn new( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd, txd); | ||||
|         Self::new_inner(uarte, irq, rxd.map_into(), txd.map_into(), None, None, config) | ||||
|         Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config) | ||||
|     } | ||||
|  | ||||
|     /// Create a new UARTE with hardware flow control (RTS/CTS) | ||||
|     pub fn new_with_rtscts( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         cts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
| @@ -108,7 +130,6 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|         into_ref!(rxd, txd, cts, rts); | ||||
|         Self::new_inner( | ||||
|             uarte, | ||||
|             irq, | ||||
|             rxd.map_into(), | ||||
|             txd.map_into(), | ||||
|             Some(cts.map_into()), | ||||
| @@ -119,14 +140,13 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|  | ||||
|     fn new_inner( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         rxd: PeripheralRef<'d, AnyPin>, | ||||
|         txd: PeripheralRef<'d, AnyPin>, | ||||
|         cts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         rts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(uarte, irq); | ||||
|         into_ref!(uarte); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -148,9 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|         } | ||||
|         r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         let hardware_flow_control = match (rts.is_some(), cts.is_some()) { | ||||
|             (false, false) => false, | ||||
| @@ -238,20 +257,6 @@ impl<'d, T: Instance> Uarte<'d, T> { | ||||
|         Event::from_reg(&r.events_endtx) | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_endrx.read().bits() != 0 { | ||||
|             s.endrx_waker.wake(); | ||||
|             r.intenclr.write(|w| w.endrx().clear()); | ||||
|         } | ||||
|         if r.events_endtx.read().bits() != 0 { | ||||
|             s.endtx_waker.wake(); | ||||
|             r.intenclr.write(|w| w.endtx().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Read bytes until the buffer is filled. | ||||
|     pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||||
|         self.rx.read(buffer).await | ||||
| @@ -308,34 +313,33 @@ impl<'d, T: Instance> UarteTx<'d, T> { | ||||
|     /// Create a new tx-only UARTE without hardware flow control | ||||
|     pub fn new( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(txd); | ||||
|         Self::new_inner(uarte, irq, txd.map_into(), None, config) | ||||
|         Self::new_inner(uarte, txd.map_into(), None, config) | ||||
|     } | ||||
|  | ||||
|     /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) | ||||
|     pub fn new_with_rtscts( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         txd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         cts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(txd, cts); | ||||
|         Self::new_inner(uarte, irq, txd.map_into(), Some(cts.map_into()), config) | ||||
|         Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         txd: PeripheralRef<'d, AnyPin>, | ||||
|         cts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(uarte, irq); | ||||
|         into_ref!(uarte); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -354,9 +358,8 @@ impl<'d, T: Instance> UarteTx<'d, T> { | ||||
|         let hardware_flow_control = cts.is_some(); | ||||
|         configure(r, config, hardware_flow_control); | ||||
|  | ||||
|         irq.set_handler(Uarte::<T>::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         let s = T::state(); | ||||
|         s.tx_rx_refcount.store(1, Ordering::Relaxed); | ||||
| @@ -506,34 +509,33 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|     /// Create a new rx-only UARTE without hardware flow control | ||||
|     pub fn new( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd); | ||||
|         Self::new_inner(uarte, irq, rxd.map_into(), None, config) | ||||
|         Self::new_inner(uarte, rxd.map_into(), None, config) | ||||
|     } | ||||
|  | ||||
|     /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) | ||||
|     pub fn new_with_rtscts( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         rts: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(rxd, rts); | ||||
|         Self::new_inner(uarte, irq, rxd.map_into(), Some(rts.map_into()), config) | ||||
|         Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) | ||||
|     } | ||||
|  | ||||
|     fn new_inner( | ||||
|         uarte: impl Peripheral<P = T> + 'd, | ||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||
|         rxd: PeripheralRef<'d, AnyPin>, | ||||
|         rts: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(uarte, irq); | ||||
|         into_ref!(uarte); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
| @@ -549,9 +551,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { | ||||
|         r.psel.txd.write(|w| w.connect().disconnected()); | ||||
|         r.psel.cts.write(|w| w.connect().disconnected()); | ||||
|  | ||||
|         irq.set_handler(Uarte::<T>::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
|  | ||||
|         let hardware_flow_control = rts.is_some(); | ||||
|         configure(r, config, hardware_flow_control); | ||||
|   | ||||
| @@ -2,10 +2,12 @@ | ||||
| 
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| pub mod vbus_detect; | ||||
| 
 | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::mem::MaybeUninit; | ||||
| use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | ||||
| use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; | ||||
| use core::task::Poll; | ||||
| 
 | ||||
| use cortex_m::peripheral::NVIC; | ||||
| @@ -15,7 +17,8 @@ use embassy_usb_driver as driver; | ||||
| use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; | ||||
| use pac::usbd::RegisterBlock; | ||||
| 
 | ||||
| use crate::interrupt::{Interrupt, InterruptExt}; | ||||
| use self::vbus_detect::VbusDetect; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::util::slice_in_ram; | ||||
| use crate::{pac, Peripheral}; | ||||
| 
 | ||||
| @@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | ||||
| static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | ||||
| static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); | ||||
| 
 | ||||
| /// Trait for detecting USB VBUS power.
 | ||||
| ///
 | ||||
| /// There are multiple ways to detect USB power. The behavior
 | ||||
| /// here provides a hook into determining whether it is.
 | ||||
| pub trait VbusDetect { | ||||
|     /// Report whether power is detected.
 | ||||
|     ///
 | ||||
|     /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
 | ||||
|     /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
 | ||||
|     fn is_usb_detected(&self) -> bool; | ||||
| 
 | ||||
|     /// Wait until USB power is ready.
 | ||||
|     ///
 | ||||
|     /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
 | ||||
|     /// `USBPWRRDY` event from the `POWER` peripheral.
 | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()>; | ||||
| /// Interrupt handler.
 | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
| 
 | ||||
| /// [`VbusDetect`] implementation using the native hardware POWER peripheral.
 | ||||
| ///
 | ||||
| /// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
 | ||||
| /// to POWER. In that case, use [`VbusDetectSignal`].
 | ||||
| #[cfg(not(feature = "_nrf5340-app"))] | ||||
| pub struct HardwareVbusDetect { | ||||
|     _private: (), | ||||
| } | ||||
| 
 | ||||
| static POWER_WAKER: AtomicWaker = NEW_AW; | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf5340-app"))] | ||||
| impl HardwareVbusDetect { | ||||
|     /// Create a new `VbusDetectNative`.
 | ||||
|     pub fn new(power_irq: impl Interrupt) -> Self { | ||||
|         let regs = unsafe { &*pac::POWER::ptr() }; | ||||
| 
 | ||||
|         power_irq.set_handler(Self::on_interrupt); | ||||
|         power_irq.unpend(); | ||||
|         power_irq.enable(); | ||||
| 
 | ||||
|         regs.intenset | ||||
|             .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||||
| 
 | ||||
|         Self { _private: () } | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(not(feature = "_nrf5340-app"))] | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let regs = unsafe { &*pac::POWER::ptr() }; | ||||
| 
 | ||||
|         if regs.events_usbdetected.read().bits() != 0 { | ||||
|             regs.events_usbdetected.reset(); | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_usbremoved.read().bits() != 0 { | ||||
|             regs.events_usbremoved.reset(); | ||||
|             BUS_WAKER.wake(); | ||||
|             POWER_WAKER.wake(); | ||||
|         } | ||||
| 
 | ||||
|         if regs.events_usbpwrrdy.read().bits() != 0 { | ||||
|             regs.events_usbpwrrdy.reset(); | ||||
|             POWER_WAKER.wake(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "_nrf5340-app"))] | ||||
| impl VbusDetect for HardwareVbusDetect { | ||||
|     fn is_usb_detected(&self) -> bool { | ||||
|         let regs = unsafe { &*pac::POWER::ptr() }; | ||||
|         regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||||
|     } | ||||
| 
 | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||||
|         poll_fn(move |cx| { | ||||
|             POWER_WAKER.register(cx.waker()); | ||||
|             let regs = unsafe { &*pac::POWER::ptr() }; | ||||
| 
 | ||||
|             if regs.usbregstatus.read().outputrdy().is_ready() { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if !self.is_usb_detected() { | ||||
|                 Poll::Ready(Err(())) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }) | ||||
|         .await | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Software-backed [`VbusDetect`] implementation.
 | ||||
| ///
 | ||||
| /// This implementation does not interact with the hardware, it allows user code
 | ||||
| /// to notify the power events by calling functions instead.
 | ||||
| ///
 | ||||
| /// This is suitable for use with the nRF softdevice, by calling the functions
 | ||||
| /// when the softdevice reports power-related events.
 | ||||
| pub struct SoftwareVbusDetect { | ||||
|     usb_detected: AtomicBool, | ||||
|     power_ready: AtomicBool, | ||||
| } | ||||
| 
 | ||||
| impl SoftwareVbusDetect { | ||||
|     /// Create a new `SoftwareVbusDetect`.
 | ||||
|     pub fn new(usb_detected: bool, power_ready: bool) -> Self { | ||||
|         BUS_WAKER.wake(); | ||||
| 
 | ||||
|         Self { | ||||
|             usb_detected: AtomicBool::new(usb_detected), | ||||
|             power_ready: AtomicBool::new(power_ready), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Report whether power was detected.
 | ||||
|     ///
 | ||||
|     /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
 | ||||
|     pub fn detected(&self, detected: bool) { | ||||
|         self.usb_detected.store(detected, Ordering::Relaxed); | ||||
|         self.power_ready.store(false, Ordering::Relaxed); | ||||
|         BUS_WAKER.wake(); | ||||
|         POWER_WAKER.wake(); | ||||
|     } | ||||
| 
 | ||||
|     /// Report when USB power is ready.
 | ||||
|     ///
 | ||||
|     /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
 | ||||
|     pub fn ready(&self) { | ||||
|         self.power_ready.store(true, Ordering::Relaxed); | ||||
|         POWER_WAKER.wake(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VbusDetect for &SoftwareVbusDetect { | ||||
|     fn is_usb_detected(&self) -> bool { | ||||
|         self.usb_detected.load(Ordering::Relaxed) | ||||
|     } | ||||
| 
 | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||||
|         poll_fn(move |cx| { | ||||
|             POWER_WAKER.register(cx.waker()); | ||||
| 
 | ||||
|             if self.power_ready.load(Ordering::Relaxed) { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if !self.usb_detected.load(Ordering::Relaxed) { | ||||
|                 Poll::Ready(Err(())) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }) | ||||
|         .await | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// USB driver.
 | ||||
| pub struct Driver<'d, T: Instance, P: VbusDetect> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
|     alloc_in: Allocator, | ||||
|     alloc_out: Allocator, | ||||
|     usb_supply: P, | ||||
| } | ||||
| 
 | ||||
| impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> { | ||||
|     /// Create a new USB driver.
 | ||||
|     pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self { | ||||
|         into_ref!(usb, irq); | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
| 
 | ||||
|         Self { | ||||
|             _p: usb, | ||||
|             alloc_in: Allocator::new(), | ||||
|             alloc_out: Allocator::new(), | ||||
|             usb_supply, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let regs = T::regs(); | ||||
| 
 | ||||
|         if regs.events_usbreset.read().bits() != 0 { | ||||
| @@ -255,11 +86,40 @@ impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> { | ||||
| /// USB driver.
 | ||||
| pub struct Driver<'d, T: Instance, V: VbusDetect> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
|     alloc_in: Allocator, | ||||
|     alloc_out: Allocator, | ||||
|     vbus_detect: V, | ||||
| } | ||||
| 
 | ||||
| impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { | ||||
|     /// Create a new USB driver.
 | ||||
|     pub fn new( | ||||
|         usb: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         vbus_detect: V, | ||||
|     ) -> Self { | ||||
|         into_ref!(usb); | ||||
| 
 | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
| 
 | ||||
|         Self { | ||||
|             _p: usb, | ||||
|             alloc_in: Allocator::new(), | ||||
|             alloc_out: Allocator::new(), | ||||
|             vbus_detect, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> { | ||||
|     type EndpointOut = Endpoint<'d, T, Out>; | ||||
|     type EndpointIn = Endpoint<'d, T, In>; | ||||
|     type ControlPipe = ControlPipe<'d, T>; | ||||
|     type Bus = Bus<'d, T, P>; | ||||
|     type Bus = Bus<'d, T, V>; | ||||
| 
 | ||||
|     fn alloc_endpoint_in( | ||||
|         &mut self, | ||||
| @@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P | ||||
|             Bus { | ||||
|                 _p: unsafe { self._p.clone_unchecked() }, | ||||
|                 power_available: false, | ||||
|                 usb_supply: self.usb_supply, | ||||
|                 vbus_detect: self.vbus_detect, | ||||
|             }, | ||||
|             ControlPipe { | ||||
|                 _p: self._p, | ||||
| @@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P | ||||
| } | ||||
| 
 | ||||
| /// USB bus.
 | ||||
| pub struct Bus<'d, T: Instance, P: VbusDetect> { | ||||
| pub struct Bus<'d, T: Instance, V: VbusDetect> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
|     power_available: bool, | ||||
|     usb_supply: P, | ||||
|     vbus_detect: V, | ||||
| } | ||||
| 
 | ||||
| impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | ||||
| impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { | ||||
|     async fn enable(&mut self) { | ||||
|         let regs = T::regs(); | ||||
| 
 | ||||
| @@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | ||||
|             w | ||||
|         }); | ||||
| 
 | ||||
|         if self.usb_supply.wait_power_ready().await.is_ok() { | ||||
|         if self.vbus_detect.wait_power_ready().await.is_ok() { | ||||
|             // Enable the USB pullup, allowing enumeration.
 | ||||
|             regs.usbpullup.write(|w| w.connect().enabled()); | ||||
|             trace!("enabled"); | ||||
| @@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | ||||
|                 trace!("USB event: ready"); | ||||
|             } | ||||
| 
 | ||||
|             if self.usb_supply.is_usb_detected() != self.power_available { | ||||
|             if self.vbus_detect.is_usb_detected() != self.power_available { | ||||
|                 self.power_available = !self.power_available; | ||||
|                 if self.power_available { | ||||
|                     trace!("Power event: available"); | ||||
							
								
								
									
										177
									
								
								embassy-nrf/src/usb/vbus_detect.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								embassy-nrf/src/usb/vbus_detect.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| //! Trait and implementations for performing VBUS detection. | ||||
|  | ||||
| use core::future::poll_fn; | ||||
| use core::sync::atomic::{AtomicBool, Ordering}; | ||||
| use core::task::Poll; | ||||
|  | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
|  | ||||
| use super::BUS_WAKER; | ||||
| use crate::interrupt::{self, Interrupt, InterruptExt}; | ||||
| use crate::pac; | ||||
|  | ||||
| /// Trait for detecting USB VBUS power. | ||||
| /// | ||||
| /// There are multiple ways to detect USB power. The behavior | ||||
| /// here provides a hook into determining whether it is. | ||||
| pub trait VbusDetect { | ||||
|     /// Report whether power is detected. | ||||
|     /// | ||||
|     /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the | ||||
|     /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||||
|     fn is_usb_detected(&self) -> bool; | ||||
|  | ||||
|     /// Wait until USB power is ready. | ||||
|     /// | ||||
|     /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the | ||||
|     /// `USBPWRRDY` event from the `POWER` peripheral. | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()>; | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "_nrf5340"))] | ||||
| type UsbRegIrq = interrupt::POWER_CLOCK; | ||||
| #[cfg(feature = "_nrf5340")] | ||||
| type UsbRegIrq = interrupt::USBREGULATOR; | ||||
|  | ||||
| #[cfg(not(feature = "_nrf5340"))] | ||||
| type UsbRegPeri = pac::POWER; | ||||
| #[cfg(feature = "_nrf5340")] | ||||
| type UsbRegPeri = pac::USBREGULATOR; | ||||
|  | ||||
| /// Interrupt handler. | ||||
| pub struct InterruptHandler { | ||||
|     _private: (), | ||||
| } | ||||
|  | ||||
| impl interrupt::Handler<UsbRegIrq> for InterruptHandler { | ||||
|     unsafe fn on_interrupt() { | ||||
|         let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|  | ||||
|         if regs.events_usbdetected.read().bits() != 0 { | ||||
|             regs.events_usbdetected.reset(); | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|         if regs.events_usbremoved.read().bits() != 0 { | ||||
|             regs.events_usbremoved.reset(); | ||||
|             BUS_WAKER.wake(); | ||||
|             POWER_WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|         if regs.events_usbpwrrdy.read().bits() != 0 { | ||||
|             regs.events_usbpwrrdy.reset(); | ||||
|             POWER_WAKER.wake(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// [`VbusDetect`] implementation using the native hardware POWER peripheral. | ||||
| /// | ||||
| /// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces | ||||
| /// to POWER. In that case, use [`VbusDetectSignal`]. | ||||
| pub struct HardwareVbusDetect { | ||||
|     _private: (), | ||||
| } | ||||
|  | ||||
| static POWER_WAKER: AtomicWaker = AtomicWaker::new(); | ||||
|  | ||||
| impl HardwareVbusDetect { | ||||
|     /// Create a new `VbusDetectNative`. | ||||
|     pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { | ||||
|         let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|  | ||||
|         unsafe { UsbRegIrq::steal() }.unpend(); | ||||
|         unsafe { UsbRegIrq::steal() }.enable(); | ||||
|  | ||||
|         regs.intenset | ||||
|             .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||||
|  | ||||
|         Self { _private: () } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl VbusDetect for HardwareVbusDetect { | ||||
|     fn is_usb_detected(&self) -> bool { | ||||
|         let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|         regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||||
|     } | ||||
|  | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||||
|         poll_fn(move |cx| { | ||||
|             POWER_WAKER.register(cx.waker()); | ||||
|             let regs = unsafe { &*UsbRegPeri::ptr() }; | ||||
|  | ||||
|             if regs.usbregstatus.read().outputrdy().is_ready() { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if !self.is_usb_detected() { | ||||
|                 Poll::Ready(Err(())) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }) | ||||
|         .await | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Software-backed [`VbusDetect`] implementation. | ||||
| /// | ||||
| /// This implementation does not interact with the hardware, it allows user code | ||||
| /// to notify the power events by calling functions instead. | ||||
| /// | ||||
| /// This is suitable for use with the nRF softdevice, by calling the functions | ||||
| /// when the softdevice reports power-related events. | ||||
| pub struct SoftwareVbusDetect { | ||||
|     usb_detected: AtomicBool, | ||||
|     power_ready: AtomicBool, | ||||
| } | ||||
|  | ||||
| impl SoftwareVbusDetect { | ||||
|     /// Create a new `SoftwareVbusDetect`. | ||||
|     pub fn new(usb_detected: bool, power_ready: bool) -> Self { | ||||
|         BUS_WAKER.wake(); | ||||
|  | ||||
|         Self { | ||||
|             usb_detected: AtomicBool::new(usb_detected), | ||||
|             power_ready: AtomicBool::new(power_ready), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Report whether power was detected. | ||||
|     /// | ||||
|     /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||||
|     pub fn detected(&self, detected: bool) { | ||||
|         self.usb_detected.store(detected, Ordering::Relaxed); | ||||
|         self.power_ready.store(false, Ordering::Relaxed); | ||||
|         BUS_WAKER.wake(); | ||||
|         POWER_WAKER.wake(); | ||||
|     } | ||||
|  | ||||
|     /// Report when USB power is ready. | ||||
|     /// | ||||
|     /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral. | ||||
|     pub fn ready(&self) { | ||||
|         self.power_ready.store(true, Ordering::Relaxed); | ||||
|         POWER_WAKER.wake(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl VbusDetect for &SoftwareVbusDetect { | ||||
|     fn is_usb_detected(&self) -> bool { | ||||
|         self.usb_detected.load(Ordering::Relaxed) | ||||
|     } | ||||
|  | ||||
|     async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||||
|         poll_fn(move |cx| { | ||||
|             POWER_WAKER.register(cx.waker()); | ||||
|  | ||||
|             if self.power_ready.load(Ordering::Relaxed) { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else if !self.usb_detected.load(Ordering::Relaxed) { | ||||
|                 Poll::Ready(Err(())) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }) | ||||
|         .await | ||||
|     } | ||||
| } | ||||
| @@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0" | ||||
|  | ||||
| [features] | ||||
| default = ["nightly"] | ||||
| msos-descriptor = ["embassy-usb/msos-descriptor"] | ||||
| nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net", | ||||
|            "embassy-lora", "lorawan-device", "lorawan"] | ||||
|  | ||||
| @@ -17,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | ||||
| embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||||
| embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | ||||
| embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } | ||||
| embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | ||||
| embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } | ||||
| embedded-io = "0.4.0" | ||||
| embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } | ||||
|  | ||||
| @@ -36,7 +35,3 @@ rand = { version = "0.8.4", default-features = false } | ||||
| embedded-storage = "0.3.0" | ||||
| usbd-hid = "0.6.0" | ||||
| serde = { version = "1.0.136", default-features = false } | ||||
|  | ||||
| [[bin]] | ||||
| name = "usb_serial_winusb" | ||||
| required-features = ["msos-descriptor"] | ||||
|   | ||||
| @@ -1,26 +0,0 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(type_alias_impl_trait)] | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::timer::Timer; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0)); | ||||
|     // default frequency is 1MHz, so this triggers every second | ||||
|     t.cc(0).write(1_000_000); | ||||
|     // clear the timer value on cc[0] compare match | ||||
|     t.cc(0).short_compare_clear(); | ||||
|     t.start(); | ||||
|  | ||||
|     loop { | ||||
|         // wait for compare match | ||||
|         t.cc(0).wait().await; | ||||
|         info!("hardware timer tick"); | ||||
|     } | ||||
| } | ||||
| @@ -4,11 +4,15 @@ | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::buffered_uarte::BufferedUarte; | ||||
| use embassy_nrf::{interrupt, uarte}; | ||||
| use embassy_nrf::buffered_uarte::{self, BufferedUarte}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, uarte}; | ||||
| use embedded_io::asynch::Write; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -19,14 +23,13 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut tx_buffer = [0u8; 4096]; | ||||
|     let mut rx_buffer = [0u8; 4096]; | ||||
|  | ||||
|     let irq = interrupt::take!(UARTE0_UART0); | ||||
|     let mut u = BufferedUarte::new( | ||||
|         p.UARTE0, | ||||
|         p.TIMER0, | ||||
|         p.PPI_CH0, | ||||
|         p.PPI_CH1, | ||||
|         p.PPI_GROUP0, | ||||
|         irq, | ||||
|         Irqs, | ||||
|         p.P0_08, | ||||
|         p.P0_06, | ||||
|         config, | ||||
|   | ||||
| @@ -7,7 +7,7 @@ use core::f32::consts::PI; | ||||
| use defmt::{error, info}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| type Sample = i16; | ||||
| @@ -15,6 +15,10 @@ type Sample = i16; | ||||
| const NUM_BUFFERS: usize = 2; | ||||
| const NUM_SAMPLES: usize = 4; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     I2S => i2s::InterruptHandler<peripherals::I2S>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) { | ||||
|     config.sample_width = SampleWidth::_16bit; | ||||
|     config.channels = Channels::MonoLeft; | ||||
|  | ||||
|     let irq = interrupt::take!(I2S); | ||||
|     let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); | ||||
|     let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); | ||||
|     let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex( | ||||
|         p.P0_29, | ||||
|         p.P0_28, | ||||
|         buffers_out, | ||||
|         buffers_in, | ||||
|     ); | ||||
|     let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config) | ||||
|         .full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in); | ||||
|  | ||||
|     let mut modulator = SineOsc::new(); | ||||
|     modulator.set_frequency(8.0, 1.0 / sample_rate as f32); | ||||
|   | ||||
| @@ -5,14 +5,18 @@ | ||||
| use defmt::{debug, error, info}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::pwm::{Prescaler, SimplePwm}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| type Sample = i16; | ||||
|  | ||||
| const NUM_SAMPLES: usize = 500; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     I2S => i2s::InterruptHandler<peripherals::I2S>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) { | ||||
|     config.sample_width = SampleWidth::_16bit; | ||||
|     config.channels = Channels::MonoLeft; | ||||
|  | ||||
|     let irq = interrupt::take!(I2S); | ||||
|     let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); | ||||
|     let mut input_stream = | ||||
|         I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); | ||||
|         I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); | ||||
|  | ||||
|     // Configure the PWM to use the pins corresponding to the RGB leds | ||||
|     let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); | ||||
|   | ||||
| @@ -7,13 +7,17 @@ use core::f32::consts::PI; | ||||
| use defmt::{error, info}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| type Sample = i16; | ||||
|  | ||||
| const NUM_SAMPLES: usize = 50; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     I2S => i2s::InterruptHandler<peripherals::I2S>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) { | ||||
|     config.sample_width = SampleWidth::_16bit; | ||||
|     config.channels = Channels::MonoLeft; | ||||
|  | ||||
|     let irq = interrupt::take!(I2S); | ||||
|     let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); | ||||
|     let mut output_stream = | ||||
|         I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers); | ||||
|         I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers); | ||||
|  | ||||
|     let mut waveform = Waveform::new(1.0 / sample_rate as f32); | ||||
|  | ||||
|   | ||||
| @@ -11,11 +11,15 @@ use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_lora::sx126x::*; | ||||
| use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; | ||||
| use embassy_nrf::{interrupt, spim}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, spim}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) { | ||||
|     spi_config.frequency = spim::Frequency::M16; | ||||
|  | ||||
|     let mut radio = { | ||||
|         let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|         let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config); | ||||
|         let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); | ||||
|  | ||||
|         let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); | ||||
|         let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); | ||||
|   | ||||
| @@ -12,13 +12,17 @@ use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_lora::sx126x::*; | ||||
| use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; | ||||
| use embassy_nrf::{interrupt, spim}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, spim}; | ||||
| use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||||
| use embassy_sync::pubsub::{PubSubChannel, Publisher}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig}; | ||||
| use {defmt_rtt as _, panic_probe as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>; | ||||
| }); | ||||
|  | ||||
| // Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection) | ||||
| static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new(); | ||||
|  | ||||
| @@ -58,8 +62,7 @@ async fn main(spawner: Spawner) { | ||||
|     spi_config.frequency = spim::Frequency::M16; | ||||
|  | ||||
|     let mut radio = { | ||||
|         let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|         let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config); | ||||
|         let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); | ||||
|  | ||||
|         let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); | ||||
|         let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); | ||||
|   | ||||
| @@ -4,16 +4,20 @@ | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::pdm::{Config, Pdm}; | ||||
| use embassy_nrf::pdm::{self, Config, Pdm}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     PDM => pdm::InterruptHandler<peripherals::PDM>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_p: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let config = Config::default(); | ||||
|     let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), p.P0_01, p.P0_00, config); | ||||
|     let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config); | ||||
|  | ||||
|     loop { | ||||
|         pdm.start().await; | ||||
|   | ||||
| @@ -4,16 +4,19 @@ | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::qdec::{self, Qdec}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     QDEC => qdec::InterruptHandler<peripherals::QDEC>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let irq = interrupt::take!(QDEC); | ||||
|     let config = qdec::Config::default(); | ||||
|     let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config); | ||||
|     let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config); | ||||
|  | ||||
|     info!("Turn rotary encoder!"); | ||||
|     let mut value = 0; | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| use defmt::{assert_eq, info, unwrap}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::qspi::Frequency; | ||||
| use embassy_nrf::{interrupt, qspi}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, qspi}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| const PAGE_SIZE: usize = 4096; | ||||
| @@ -15,6 +15,10 @@ const PAGE_SIZE: usize = 4096; | ||||
| #[repr(C, align(4))] | ||||
| struct AlignedBuf([u8; 4096]); | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     QSPI => qspi::InterruptHandler<peripherals::QSPI>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -26,9 +30,8 @@ async fn main(_spawner: Spawner) { | ||||
|     config.write_opcode = qspi::WriteOpcode::PP4IO; | ||||
|     config.write_page_size = qspi::WritePageSize::_256BYTES; | ||||
|  | ||||
|     let irq = interrupt::take!(QSPI); | ||||
|     let mut q = qspi::Qspi::new( | ||||
|         p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, | ||||
|         p.QSPI, Irqs, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, | ||||
|     ); | ||||
|  | ||||
|     let mut id = [1; 3]; | ||||
|   | ||||
| @@ -7,7 +7,7 @@ use core::mem; | ||||
| use defmt::{info, unwrap}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::qspi::Frequency; | ||||
| use embassy_nrf::{interrupt, qspi}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, qspi}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| @@ -16,10 +16,13 @@ use {defmt_rtt as _, panic_probe as _}; | ||||
| #[repr(C, align(4))] | ||||
| struct AlignedBuf([u8; 64]); | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     QSPI => qspi::InterruptHandler<peripherals::QSPI>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_p: Spawner) { | ||||
|     let mut p = embassy_nrf::init(Default::default()); | ||||
|     let mut irq = interrupt::take!(QSPI); | ||||
|  | ||||
|     loop { | ||||
|         // Config for the MX25R64 present in the nRF52840 DK | ||||
| @@ -36,7 +39,7 @@ async fn main(_p: Spawner) { | ||||
|  | ||||
|         let mut q = qspi::Qspi::new( | ||||
|             &mut p.QSPI, | ||||
|             &mut irq, | ||||
|             Irqs, | ||||
|             &mut p.P0_19, | ||||
|             &mut p.P0_17, | ||||
|             &mut p.P0_20, | ||||
|   | ||||
| @@ -3,15 +3,19 @@ | ||||
| #![feature(type_alias_impl_trait)] | ||||
|  | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::rng::Rng; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, rng}; | ||||
| use rand::Rng as _; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     RNG => rng::InterruptHandler<peripherals::RNG>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let mut rng = Rng::new(p.RNG, interrupt::take!(RNG)); | ||||
|     let mut rng = Rng::new(p.RNG, Irqs); | ||||
|  | ||||
|     // Async API | ||||
|     let mut bytes = [0; 4]; | ||||
|   | ||||
| @@ -4,17 +4,21 @@ | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::saadc::{ChannelConfig, Config, Saadc}; | ||||
| use embassy_nrf::{bind_interrupts, saadc}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SAADC => saadc::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_p: Spawner) { | ||||
|     let mut p = embassy_nrf::init(Default::default()); | ||||
|     let config = Config::default(); | ||||
|     let channel_config = ChannelConfig::single_ended(&mut p.P0_02); | ||||
|     let mut saadc = Saadc::new(p.SAADC, interrupt::take!(SAADC), config, [channel_config]); | ||||
|     let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]); | ||||
|  | ||||
|     loop { | ||||
|         let mut buf = [0; 1]; | ||||
|   | ||||
| @@ -4,14 +4,18 @@ | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc}; | ||||
| use embassy_nrf::timer::Frequency; | ||||
| use embassy_nrf::{bind_interrupts, saadc}; | ||||
| use embassy_time::Duration; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| // Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SAADC => saadc::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_p: Spawner) { | ||||
|     let mut p = embassy_nrf::init(Default::default()); | ||||
| @@ -21,7 +25,7 @@ async fn main(_p: Spawner) { | ||||
|     let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04); | ||||
|     let mut saadc = Saadc::new( | ||||
|         p.SAADC, | ||||
|         interrupt::take!(SAADC), | ||||
|         Irqs, | ||||
|         config, | ||||
|         [channel_1_config, channel_2_config, channel_3_config], | ||||
|     ); | ||||
|   | ||||
| @@ -5,9 +5,13 @@ | ||||
| use defmt::{info, unwrap}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||||
| use embassy_nrf::{interrupt, spim}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, spim}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut config = spim::Config::default(); | ||||
|     config.frequency = spim::Frequency::M16; | ||||
|  | ||||
|     let irq = interrupt::take!(SPIM3); | ||||
|     let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config); | ||||
|     let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config); | ||||
|  | ||||
|     let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); | ||||
|  | ||||
|   | ||||
| @@ -4,17 +4,20 @@ | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::spis::{Config, Spis}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, spis}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     info!("Running!"); | ||||
|  | ||||
|     let irq = interrupt::take!(SPIM2_SPIS2_SPI2); | ||||
|     let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default()); | ||||
|     let mut spis = Spis::new(p.SPI2, Irqs, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default()); | ||||
|  | ||||
|     loop { | ||||
|         let mut rx_buf = [0_u8; 64]; | ||||
|   | ||||
| @@ -4,16 +4,19 @@ | ||||
|  | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::temp::Temp; | ||||
| use embassy_nrf::{bind_interrupts, temp}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     TEMP => temp::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let irq = interrupt::take!(TEMP); | ||||
|     let mut temp = Temp::new(p.TEMP, irq); | ||||
|     let mut temp = Temp::new(p.TEMP, Irqs); | ||||
|  | ||||
|     loop { | ||||
|         let value = temp.read().await; | ||||
|   | ||||
| @@ -8,19 +8,22 @@ | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::twim::{self, Twim}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| const ADDRESS: u8 = 0x50; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     info!("Initializing TWI..."); | ||||
|     let config = twim::Config::default(); | ||||
|     let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); | ||||
|     let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); | ||||
|  | ||||
|     info!("Reading..."); | ||||
|  | ||||
|   | ||||
| @@ -12,25 +12,28 @@ use core::mem; | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::twim::{self, Twim}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| const ADDRESS: u8 = 0x50; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_p: Spawner) { | ||||
|     let mut p = embassy_nrf::init(Default::default()); | ||||
|     info!("Started!"); | ||||
|     let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|  | ||||
|     loop { | ||||
|         info!("Initializing TWI..."); | ||||
|         let config = twim::Config::default(); | ||||
|  | ||||
|         // Create the TWIM instance with borrowed singletons, so they're not consumed. | ||||
|         let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); | ||||
|         let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config); | ||||
|  | ||||
|         info!("Reading..."); | ||||
|  | ||||
|   | ||||
| @@ -6,19 +6,21 @@ | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::twis::{self, Command, Twis}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|  | ||||
|     let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     let mut config = twis::Config::default(); | ||||
|     // Set i2c address | ||||
|     config.address0 = 0x55; | ||||
|     let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); | ||||
|     config.address0 = 0x55; // Set i2c address | ||||
|     let mut i2c = Twis::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); | ||||
|  | ||||
|     info!("Listening..."); | ||||
|     loop { | ||||
|   | ||||
| @@ -4,9 +4,13 @@ | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::{interrupt, uarte}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, uarte}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -14,8 +18,7 @@ async fn main(_spawner: Spawner) { | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
|  | ||||
|     let irq = interrupt::take!(UARTE0_UART0); | ||||
|     let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config); | ||||
|     let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); | ||||
|  | ||||
|     info!("uarte initialized!"); | ||||
|  | ||||
|   | ||||
| @@ -4,9 +4,14 @@ | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::{interrupt, uarte}; | ||||
| use embassy_nrf::peripherals::UARTE0; | ||||
| use embassy_nrf::{bind_interrupts, uarte}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) { | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
|  | ||||
|     let irq = interrupt::take!(UARTE0_UART0); | ||||
|     let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config); | ||||
|     let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); | ||||
|     let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1); | ||||
|  | ||||
|     info!("uarte initialized!"); | ||||
|   | ||||
| @@ -6,13 +6,17 @@ use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::peripherals::UARTE0; | ||||
| use embassy_nrf::uarte::UarteRx; | ||||
| use embassy_nrf::{interrupt, uarte}; | ||||
| use embassy_nrf::{bind_interrupts, uarte}; | ||||
| use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||||
| use embassy_sync::channel::Channel; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -20,8 +24,7 @@ async fn main(spawner: Spawner) { | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
|  | ||||
|     let irq = interrupt::take!(UARTE0_UART0); | ||||
|     let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config); | ||||
|     let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); | ||||
|     let (mut tx, rx) = uart.split(); | ||||
|  | ||||
|     info!("uarte initialized!"); | ||||
|   | ||||
| @@ -9,8 +9,9 @@ use embassy_executor::Spawner; | ||||
| use embassy_net::tcp::TcpSocket; | ||||
| use embassy_net::{Stack, StackResources}; | ||||
| use embassy_nrf::rng::Rng; | ||||
| use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | ||||
| use embassy_nrf::{interrupt, pac, peripherals}; | ||||
| use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||||
| use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; | ||||
| use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | ||||
| use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | ||||
| use embassy_usb::{Builder, Config, UsbDevice}; | ||||
| @@ -18,6 +19,12 @@ use embedded_io::asynch::Write; | ||||
| use static_cell::StaticCell; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     USBD => usb::InterruptHandler<peripherals::USBD>; | ||||
|     POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||||
|     RNG => rng::InterruptHandler<peripherals::RNG>; | ||||
| }); | ||||
|  | ||||
| type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | ||||
|  | ||||
| macro_rules! singleton { | ||||
| @@ -56,9 +63,7 @@ async fn main(spawner: Spawner) { | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let irq = interrupt::take!(USBD); | ||||
|     let power_irq = interrupt::take!(POWER_CLOCK); | ||||
|     let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
|     // Create embassy-usb Config | ||||
|     let mut config = Config::new(0xc0de, 0xcafe); | ||||
| @@ -82,6 +87,7 @@ async fn main(spawner: Spawner) { | ||||
|         &mut singleton!([0; 256])[..], | ||||
|         &mut singleton!([0; 256])[..], | ||||
|         &mut singleton!([0; 128])[..], | ||||
|         &mut singleton!([0; 128])[..], | ||||
|     ); | ||||
|  | ||||
|     // Our MAC addr. | ||||
| @@ -108,7 +114,7 @@ async fn main(spawner: Spawner) { | ||||
|     //}); | ||||
|  | ||||
|     // Generate random seed | ||||
|     let mut rng = Rng::new(p.RNG, interrupt::take!(RNG)); | ||||
|     let mut rng = Rng::new(p.RNG, Irqs); | ||||
|     let mut seed = [0; 8]; | ||||
|     rng.blocking_fill_bytes(&mut seed); | ||||
|     let seed = u64::from_le_bytes(seed); | ||||
|   | ||||
| @@ -10,8 +10,9 @@ use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| use embassy_futures::select::{select, Either}; | ||||
| use embassy_nrf::gpio::{Input, Pin, Pull}; | ||||
| use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | ||||
| use embassy_nrf::{interrupt, pac}; | ||||
| use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||||
| use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||||
| use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||||
| use embassy_sync::signal::Signal; | ||||
| use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||||
| @@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler}; | ||||
| use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     USBD => usb::InterruptHandler<peripherals::USBD>; | ||||
|     POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| static SUSPENDED: AtomicBool = AtomicBool::new(false); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| @@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) { | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let irq = interrupt::take!(USBD); | ||||
|     let power_irq = interrupt::take!(POWER_CLOCK); | ||||
|     let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
|     // Create embassy-usb Config | ||||
|     let mut config = Config::new(0xc0de, 0xcafe); | ||||
| @@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut device_descriptor = [0; 256]; | ||||
|     let mut config_descriptor = [0; 256]; | ||||
|     let mut bos_descriptor = [0; 256]; | ||||
|     let mut msos_descriptor = [0; 256]; | ||||
|     let mut control_buf = [0; 64]; | ||||
|     let request_handler = MyRequestHandler {}; | ||||
|     let mut device_handler = MyDeviceHandler::new(); | ||||
| @@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) { | ||||
|         &mut device_descriptor, | ||||
|         &mut config_descriptor, | ||||
|         &mut bos_descriptor, | ||||
|         &mut msos_descriptor, | ||||
|         &mut control_buf, | ||||
|     ); | ||||
|  | ||||
|   | ||||
| @@ -7,8 +7,9 @@ use core::mem; | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | ||||
| use embassy_nrf::{interrupt, pac}; | ||||
| use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||||
| use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | ||||
| use embassy_usb::control::OutResponse; | ||||
| @@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config}; | ||||
| use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     USBD => usb::InterruptHandler<peripherals::USBD>; | ||||
|     POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) { | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let irq = interrupt::take!(USBD); | ||||
|     let power_irq = interrupt::take!(POWER_CLOCK); | ||||
|     let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
|     // Create embassy-usb Config | ||||
|     let mut config = Config::new(0xc0de, 0xcafe); | ||||
| @@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut device_descriptor = [0; 256]; | ||||
|     let mut config_descriptor = [0; 256]; | ||||
|     let mut bos_descriptor = [0; 256]; | ||||
|     let mut msos_descriptor = [0; 256]; | ||||
|     let mut control_buf = [0; 64]; | ||||
|     let request_handler = MyRequestHandler {}; | ||||
|  | ||||
| @@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) { | ||||
|         &mut device_descriptor, | ||||
|         &mut config_descriptor, | ||||
|         &mut bos_descriptor, | ||||
|         &mut msos_descriptor, | ||||
|         &mut control_buf, | ||||
|     ); | ||||
|  | ||||
|   | ||||
| @@ -7,13 +7,19 @@ use core::mem; | ||||
| use defmt::{info, panic}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; | ||||
| use embassy_nrf::{interrupt, pac}; | ||||
| use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; | ||||
| use embassy_nrf::usb::{Driver, Instance}; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||||
| use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||||
| use embassy_usb::driver::EndpointError; | ||||
| use embassy_usb::{Builder, Config}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     USBD => usb::InterruptHandler<peripherals::USBD>; | ||||
|     POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) { | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let irq = interrupt::take!(USBD); | ||||
|     let power_irq = interrupt::take!(POWER_CLOCK); | ||||
|     let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
|     // Create embassy-usb Config | ||||
|     let mut config = Config::new(0xc0de, 0xcafe); | ||||
| @@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut device_descriptor = [0; 256]; | ||||
|     let mut config_descriptor = [0; 256]; | ||||
|     let mut bos_descriptor = [0; 256]; | ||||
|     let mut msos_descriptor = [0; 256]; | ||||
|     let mut control_buf = [0; 64]; | ||||
|  | ||||
|     let mut state = State::new(); | ||||
| @@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) { | ||||
|         &mut device_descriptor, | ||||
|         &mut config_descriptor, | ||||
|         &mut bos_descriptor, | ||||
|         &mut msos_descriptor, | ||||
|         &mut control_buf, | ||||
|     ); | ||||
|  | ||||
|   | ||||
| @@ -6,14 +6,29 @@ use core::mem; | ||||
|  | ||||
| use defmt::{info, panic, unwrap}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | ||||
| use embassy_nrf::{interrupt, pac, peripherals}; | ||||
| use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||||
| use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||||
| use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||||
| use embassy_usb::driver::EndpointError; | ||||
| use embassy_usb::{Builder, Config, UsbDevice}; | ||||
| use static_cell::StaticCell; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     USBD => usb::InterruptHandler<peripherals::USBD>; | ||||
|     POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| macro_rules! singleton { | ||||
|     ($val:expr) => {{ | ||||
|         type T = impl Sized; | ||||
|         static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||||
|         let (x,) = STATIC_CELL.init(($val,)); | ||||
|         x | ||||
|     }}; | ||||
| } | ||||
|  | ||||
| type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | ||||
|  | ||||
| #[embassy_executor::task] | ||||
| @@ -39,10 +54,9 @@ async fn main(spawner: Spawner) { | ||||
|     info!("Enabling ext hfosc..."); | ||||
|     clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let irq = interrupt::take!(USBD); | ||||
|     let power_irq = interrupt::take!(POWER_CLOCK); | ||||
|     let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
|     // Create embassy-usb Config | ||||
|     let mut config = Config::new(0xc0de, 0xcafe); | ||||
| @@ -59,34 +73,21 @@ async fn main(spawner: Spawner) { | ||||
|     config.device_protocol = 0x01; | ||||
|     config.composite_with_iads = true; | ||||
|  | ||||
|     struct Resources { | ||||
|         device_descriptor: [u8; 256], | ||||
|         config_descriptor: [u8; 256], | ||||
|         bos_descriptor: [u8; 256], | ||||
|         control_buf: [u8; 64], | ||||
|         serial_state: State<'static>, | ||||
|     } | ||||
|     static RESOURCES: StaticCell<Resources> = StaticCell::new(); | ||||
|     let res = RESOURCES.init(Resources { | ||||
|         device_descriptor: [0; 256], | ||||
|         config_descriptor: [0; 256], | ||||
|         bos_descriptor: [0; 256], | ||||
|         control_buf: [0; 64], | ||||
|         serial_state: State::new(), | ||||
|     }); | ||||
|     let state = singleton!(State::new()); | ||||
|  | ||||
|     // Create embassy-usb DeviceBuilder using the driver and config. | ||||
|     let mut builder = Builder::new( | ||||
|         driver, | ||||
|         config, | ||||
|         &mut res.device_descriptor, | ||||
|         &mut res.config_descriptor, | ||||
|         &mut res.bos_descriptor, | ||||
|         &mut res.control_buf, | ||||
|         &mut singleton!([0; 256])[..], | ||||
|         &mut singleton!([0; 256])[..], | ||||
|         &mut singleton!([0; 256])[..], | ||||
|         &mut singleton!([0; 128])[..], | ||||
|         &mut singleton!([0; 128])[..], | ||||
|     ); | ||||
|  | ||||
|     // Create classes on the builder. | ||||
|     let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); | ||||
|     let class = CdcAcmClass::new(&mut builder, state, 64); | ||||
|  | ||||
|     // Build the builder. | ||||
|     let usb = builder.build(); | ||||
|   | ||||
| @@ -7,8 +7,9 @@ use core::mem; | ||||
| use defmt::{info, panic}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; | ||||
| use embassy_nrf::{interrupt, pac}; | ||||
| use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; | ||||
| use embassy_nrf::usb::{Driver, Instance}; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||||
| use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||||
| use embassy_usb::driver::EndpointError; | ||||
| use embassy_usb::msos::{self, windows_version}; | ||||
| @@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber; | ||||
| use embassy_usb::{Builder, Config}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     USBD => usb::InterruptHandler<peripherals::USBD>; | ||||
|     POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||||
| }); | ||||
|  | ||||
| // This is a randomly generated GUID to allow clients on Windows to find our device | ||||
| const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; | ||||
|  | ||||
| @@ -29,9 +35,7 @@ async fn main(_spawner: Spawner) { | ||||
|     while clock.events_hfclkstarted.read().bits() != 1 {} | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let irq = interrupt::take!(USBD); | ||||
|     let power_irq = interrupt::take!(POWER_CLOCK); | ||||
|     let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||||
|     let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); | ||||
|  | ||||
|     // Create embassy-usb Config | ||||
|     let mut config = Config::new(0xc0de, 0xcafe); | ||||
|   | ||||
| @@ -4,9 +4,14 @@ | ||||
|  | ||||
| use defmt::*; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::{interrupt, uarte}; | ||||
| use embassy_nrf::peripherals::SERIAL0; | ||||
| use embassy_nrf::{bind_interrupts, uarte}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     SERIAL0 => uarte::InterruptHandler<SERIAL0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) { | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
|  | ||||
|     let irq = interrupt::take!(SERIAL0); | ||||
|     let mut uart = uarte::Uarte::new(p.SERIAL0, irq, p.P1_00, p.P1_01, config); | ||||
|     let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config); | ||||
|  | ||||
|     info!("uarte initialized!"); | ||||
|  | ||||
|   | ||||
| @@ -5,10 +5,14 @@ | ||||
| use defmt::{assert_eq, *}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| use embassy_nrf::buffered_uarte::BufferedUarte; | ||||
| use embassy_nrf::{interrupt, uarte}; | ||||
| use embassy_nrf::buffered_uarte::{self, BufferedUarte}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals, uarte}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
| @@ -25,7 +29,7 @@ async fn main(_spawner: Spawner) { | ||||
|         p.PPI_CH0, | ||||
|         p.PPI_CH1, | ||||
|         p.PPI_GROUP0, | ||||
|         interrupt::take!(UARTE0_UART0), | ||||
|         Irqs, | ||||
|         p.P1_03, | ||||
|         p.P1_02, | ||||
|         config.clone(), | ||||
|   | ||||
| @@ -7,14 +7,19 @@ use core::ptr::NonNull; | ||||
|  | ||||
| use defmt::{assert_eq, *}; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::buffered_uarte::BufferedUarte; | ||||
| use embassy_nrf::buffered_uarte::{self, BufferedUarte}; | ||||
| use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||||
| use embassy_nrf::ppi::{Event, Ppi, Task}; | ||||
| use embassy_nrf::uarte::Uarte; | ||||
| use embassy_nrf::{interrupt, pac, uarte}; | ||||
| use embassy_nrf::{bind_interrupts, pac, peripherals, uarte}; | ||||
| use embassy_time::{Duration, Timer}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| bind_interrupts!(struct Irqs { | ||||
|     UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; | ||||
|     UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>; | ||||
| }); | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let mut p = embassy_nrf::init(Default::default()); | ||||
| @@ -33,7 +38,7 @@ async fn main(_spawner: Spawner) { | ||||
|         p.PPI_CH0, | ||||
|         p.PPI_CH1, | ||||
|         p.PPI_GROUP0, | ||||
|         interrupt::take!(UARTE0_UART0), | ||||
|         Irqs, | ||||
|         p.P1_03, | ||||
|         p.P1_04, | ||||
|         config.clone(), | ||||
| @@ -49,7 +54,7 @@ async fn main(_spawner: Spawner) { | ||||
|     // Tx spam in a loop. | ||||
|     const NSPAM: usize = 17; | ||||
|     static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; | ||||
|     let _spam = Uarte::new(p.UARTE1, interrupt::take!(UARTE1), p.P1_01, p.P1_02, config.clone()); | ||||
|     let _spam = Uarte::new(p.UARTE1, Irqs, p.P1_01, p.P1_02, config.clone()); | ||||
|     let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) }; | ||||
|     let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) }; | ||||
|     let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user