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]
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 {

View File

@ -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];

View File

@ -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,