diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 1b7436477..55b5e060e 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -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 { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + 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

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, cs: impl Peripheral

+ 'd, sck: impl Peripheral

+ 'd, miso: impl Peripheral

+ '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

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, cs: impl Peripheral

+ 'd, sck: impl Peripheral

+ 'd, miso: impl Peripheral

+ '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

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, cs: impl Peripheral

+ 'd, sck: impl Peripheral

+ 'd, mosi: impl Peripheral

+ '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

+ 'd, - irq: impl Peripheral

+ 'd, cs: PeripheralRef<'d, AnyPin>, sck: PeripheralRef<'d, AnyPin>, miso: Option>, @@ -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 diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs index fe3b0c53d..77b6e8b64 100644 --- a/examples/nrf52840/src/bin/spis.rs +++ b/examples/nrf52840/src/bin/spis.rs @@ -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; +}); + #[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];