nrf/qspi: switch to new interrupt binding.
This commit is contained in:
parent
c66b28e759
commit
96788ac93a
@ -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 {
|
||||||
|
@ -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];
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user