nrf/qspi: switch to new interrupt binding.

This commit is contained in:
Dario Nieuwenhuis 2023-03-05 21:37:21 +01:00
parent c66b28e759
commit 96788ac93a
3 changed files with 47 additions and 36 deletions

View File

@ -3,6 +3,7 @@
#![macro_use] #![macro_use]
use core::future::poll_fn; use core::future::poll_fn;
use core::marker::PhantomData;
use core::ptr; use core::ptr;
use core::task::Poll; 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 embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
use crate::gpio::{self, Pin as GpioPin}; use crate::gpio::{self, Pin as GpioPin};
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{self, Interrupt, InterruptExt};
pub use crate::pac::qspi::ifconfig0::{ pub use crate::pac::qspi::ifconfig0::{
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, 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; pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
use crate::{pac, Peripheral}; use crate::Peripheral;
/// Deep power-down config. /// Deep power-down config.
pub struct DeepPowerDownConfig { pub struct DeepPowerDownConfig {
@ -114,9 +115,26 @@ pub enum Error {
// TODO add "not in data memory" error and check for it // 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. /// QSPI flash driver.
pub struct Qspi<'d, T: Instance> { pub struct Qspi<'d, T: Instance> {
irq: PeripheralRef<'d, T::Interrupt>, _peri: PeripheralRef<'d, T>,
dpm_enabled: bool, dpm_enabled: bool,
capacity: u32, capacity: u32,
} }
@ -124,8 +142,8 @@ pub struct Qspi<'d, T: Instance> {
impl<'d, T: Instance> Qspi<'d, T> { impl<'d, T: Instance> Qspi<'d, T> {
/// Create a new QSPI driver. /// Create a new QSPI driver.
pub fn new( pub fn new(
_qspi: impl Peripheral<P = T> + 'd, qspi: 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, sck: impl Peripheral<P = impl GpioPin> + 'd,
csn: impl Peripheral<P = impl GpioPin> + 'd, csn: impl Peripheral<P = impl GpioPin> + 'd,
io0: 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, io3: impl Peripheral<P = impl GpioPin> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(irq, sck, csn, io0, io1, io2, io3); into_ref!(qspi, sck, csn, io0, io1, io2, io3);
let r = T::regs(); let r = T::regs();
@ -189,16 +207,15 @@ impl<'d, T: Instance> Qspi<'d, T> {
w w
}); });
irq.set_handler(Self::on_interrupt); unsafe { T::Interrupt::steal() }.unpend();
irq.unpend(); unsafe { T::Interrupt::steal() }.enable();
irq.enable();
// Enable it // Enable it
r.enable.write(|w| w.enable().enabled()); r.enable.write(|w| w.enable().enabled());
let res = Self { let res = Self {
_peri: qspi,
dpm_enabled: config.deep_power_down.is_some(), dpm_enabled: config.deep_power_down.is_some(),
irq,
capacity: config.capacity, capacity: config.capacity,
}; };
@ -212,16 +229,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
res 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. /// Do a custom QSPI instruction.
pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
let ondrop = OnDrop::new(Self::blocking_wait_ready); let ondrop = OnDrop::new(Self::blocking_wait_ready);
@ -310,7 +317,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
poll_fn(move |cx| { poll_fn(move |cx| {
let r = T::regs(); let r = T::regs();
let s = T::state(); let s = T::state();
s.ready_waker.register(cx.waker()); s.waker.register(cx.waker());
if r.events_ready.read().bits() != 0 { if r.events_ready.read().bits() != 0 {
return Poll::Ready(()); return Poll::Ready(());
} }
@ -525,8 +532,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
r.enable.write(|w| w.enable().disabled()); 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, // 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 // leaving it floating, the flash chip might read it as zero which would cause it to
// spuriously exit DPM. // spuriously exit DPM.
@ -624,27 +629,27 @@ mod _eh1 {
pub(crate) mod sealed { pub(crate) mod sealed {
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use super::*; /// Peripheral static state
pub struct State { pub struct State {
pub ready_waker: AtomicWaker, pub waker: AtomicWaker,
} }
impl State { impl State {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
ready_waker: AtomicWaker::new(), waker: AtomicWaker::new(),
} }
} }
} }
pub trait Instance { pub trait Instance {
fn regs() -> &'static pac::qspi::RegisterBlock; fn regs() -> &'static crate::pac::qspi::RegisterBlock;
fn state() -> &'static State; fn state() -> &'static State;
} }
} }
/// QSPI peripheral instance. /// 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. /// Interrupt for this peripheral.
type Interrupt: Interrupt; type Interrupt: Interrupt;
} }
@ -652,7 +657,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
macro_rules! impl_qspi { macro_rules! impl_qspi {
($type:ident, $pac_type:ident, $irq:ident) => { ($type:ident, $pac_type:ident, $irq:ident) => {
impl crate::qspi::sealed::Instance for peripherals::$type { 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() } unsafe { &*pac::$pac_type::ptr() }
} }
fn state() -> &'static crate::qspi::sealed::State { fn state() -> &'static crate::qspi::sealed::State {

View File

@ -5,7 +5,7 @@
use defmt::{assert_eq, info, unwrap}; use defmt::{assert_eq, info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::qspi::Frequency; use embassy_nrf::qspi::Frequency;
use embassy_nrf::{interrupt, qspi}; use embassy_nrf::{bind_interrupts, peripherals, qspi};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
const PAGE_SIZE: usize = 4096; const PAGE_SIZE: usize = 4096;
@ -15,6 +15,10 @@ const PAGE_SIZE: usize = 4096;
#[repr(C, align(4))] #[repr(C, align(4))]
struct AlignedBuf([u8; 4096]); struct AlignedBuf([u8; 4096]);
bind_interrupts!(struct Irqs {
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
});
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default()); let p = embassy_nrf::init(Default::default());
@ -26,9 +30,8 @@ async fn main(_spawner: Spawner) {
config.write_opcode = qspi::WriteOpcode::PP4IO; config.write_opcode = qspi::WriteOpcode::PP4IO;
config.write_page_size = qspi::WritePageSize::_256BYTES; config.write_page_size = qspi::WritePageSize::_256BYTES;
let irq = interrupt::take!(QSPI);
let mut q = qspi::Qspi::new( 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]; let mut id = [1; 3];

View File

@ -7,7 +7,7 @@ use core::mem;
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::qspi::Frequency; use embassy_nrf::qspi::Frequency;
use embassy_nrf::{interrupt, qspi}; use embassy_nrf::{bind_interrupts, peripherals, qspi};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -16,10 +16,13 @@ use {defmt_rtt as _, panic_probe as _};
#[repr(C, align(4))] #[repr(C, align(4))]
struct AlignedBuf([u8; 64]); struct AlignedBuf([u8; 64]);
bind_interrupts!(struct Irqs {
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
});
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_p: Spawner) { async fn main(_p: Spawner) {
let mut p = embassy_nrf::init(Default::default()); let mut p = embassy_nrf::init(Default::default());
let mut irq = interrupt::take!(QSPI);
loop { loop {
// Config for the MX25R64 present in the nRF52840 DK // Config for the MX25R64 present in the nRF52840 DK
@ -36,7 +39,7 @@ async fn main(_p: Spawner) {
let mut q = qspi::Qspi::new( let mut q = qspi::Qspi::new(
&mut p.QSPI, &mut p.QSPI,
&mut irq, Irqs,
&mut p.P0_19, &mut p.P0_19,
&mut p.P0_17, &mut p.P0_17,
&mut p.P0_20, &mut p.P0_20,