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

+ 'd, - irq: impl Peripheral

+ 'd, + qspi: impl Peripheral

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

+ 'd, csn: impl Peripheral

+ 'd, io0: impl Peripheral

+ 'd, @@ -134,7 +152,7 @@ impl<'d, T: Instance> Qspi<'d, T> { io3: impl Peripheral

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

+ sealed::Instance + 'static { +pub trait Instance: Peripheral

+ sealed::Instance + 'static + Send { /// Interrupt for this peripheral. type Interrupt: Interrupt; } @@ -652,7 +657,7 @@ pub trait Instance: Peripheral

+ 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 { diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs index 21a10940..9e8a01f4 100644 --- a/examples/nrf52840/src/bin/qspi.rs +++ b/examples/nrf52840/src/bin/qspi.rs @@ -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; +}); + #[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]; diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs index 20c90391..22a5c0c6 100644 --- a/examples/nrf52840/src/bin/qspi_lowpower.rs +++ b/examples/nrf52840/src/bin/qspi_lowpower.rs @@ -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; +}); + #[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,