aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/qspi.rs65
-rw-r--r--examples/nrf52840/src/bin/qspi.rs9
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs9
3 files changed, 47 insertions, 36 deletions
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index d514e0274..7f004b9fc 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -3,6 +3,7 @@
3#![macro_use] 3#![macro_use]
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData;
6use core::ptr; 7use core::ptr;
7use core::task::Poll; 8use core::task::Poll;
8 9
@@ -11,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef};
11use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
12 13
13use crate::gpio::{self, Pin as GpioPin}; 14use crate::gpio::{self, Pin as GpioPin};
14use crate::interrupt::{Interrupt, InterruptExt}; 15use crate::interrupt::{self, Interrupt, InterruptExt};
15pub use crate::pac::qspi::ifconfig0::{ 16pub use crate::pac::qspi::ifconfig0::{
16 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, 17 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
17}; 18};
18pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; 19pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
19use crate::{pac, Peripheral}; 20use crate::Peripheral;
20 21
21/// Deep power-down config. 22/// Deep power-down config.
22pub struct DeepPowerDownConfig { 23pub struct DeepPowerDownConfig {
@@ -114,9 +115,26 @@ pub enum Error {
114 // TODO add "not in data memory" error and check for it 115 // TODO add "not in data memory" error and check for it
115} 116}
116 117
118/// Interrupt handler.
119pub struct InterruptHandler<T: Instance> {
120 _phantom: PhantomData<T>,
121}
122
123impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
124 unsafe fn on_interrupt() {
125 let r = T::regs();
126 let s = T::state();
127
128 if r.events_ready.read().bits() != 0 {
129 s.waker.wake();
130 r.intenclr.write(|w| w.ready().clear());
131 }
132 }
133}
134
117/// QSPI flash driver. 135/// QSPI flash driver.
118pub struct Qspi<'d, T: Instance> { 136pub struct Qspi<'d, T: Instance> {
119 irq: PeripheralRef<'d, T::Interrupt>, 137 _peri: PeripheralRef<'d, T>,
120 dpm_enabled: bool, 138 dpm_enabled: bool,
121 capacity: u32, 139 capacity: u32,
122} 140}
@@ -124,8 +142,8 @@ pub struct Qspi<'d, T: Instance> {
124impl<'d, T: Instance> Qspi<'d, T> { 142impl<'d, T: Instance> Qspi<'d, T> {
125 /// Create a new QSPI driver. 143 /// Create a new QSPI driver.
126 pub fn new( 144 pub fn new(
127 _qspi: impl Peripheral<P = T> + 'd, 145 qspi: impl Peripheral<P = T> + 'd,
128 irq: impl Peripheral<P = T::Interrupt> + 'd, 146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
129 sck: impl Peripheral<P = impl GpioPin> + 'd, 147 sck: impl Peripheral<P = impl GpioPin> + 'd,
130 csn: impl Peripheral<P = impl GpioPin> + 'd, 148 csn: impl Peripheral<P = impl GpioPin> + 'd,
131 io0: impl Peripheral<P = impl GpioPin> + 'd, 149 io0: impl Peripheral<P = impl GpioPin> + 'd,
@@ -134,7 +152,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
134 io3: impl Peripheral<P = impl GpioPin> + 'd, 152 io3: impl Peripheral<P = impl GpioPin> + 'd,
135 config: Config, 153 config: Config,
136 ) -> Self { 154 ) -> Self {
137 into_ref!(irq, sck, csn, io0, io1, io2, io3); 155 into_ref!(qspi, sck, csn, io0, io1, io2, io3);
138 156
139 let r = T::regs(); 157 let r = T::regs();
140 158
@@ -189,16 +207,15 @@ impl<'d, T: Instance> Qspi<'d, T> {
189 w 207 w
190 }); 208 });
191 209
192 irq.set_handler(Self::on_interrupt); 210 unsafe { T::Interrupt::steal() }.unpend();
193 irq.unpend(); 211 unsafe { T::Interrupt::steal() }.enable();
194 irq.enable();
195 212
196 // Enable it 213 // Enable it
197 r.enable.write(|w| w.enable().enabled()); 214 r.enable.write(|w| w.enable().enabled());
198 215
199 let res = Self { 216 let res = Self {
217 _peri: qspi,
200 dpm_enabled: config.deep_power_down.is_some(), 218 dpm_enabled: config.deep_power_down.is_some(),
201 irq,
202 capacity: config.capacity, 219 capacity: config.capacity,
203 }; 220 };
204 221
@@ -212,16 +229,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
212 res 229 res
213 } 230 }
214 231
215 fn on_interrupt(_: *mut ()) {
216 let r = T::regs();
217 let s = T::state();
218
219 if r.events_ready.read().bits() != 0 {
220 s.ready_waker.wake();
221 r.intenclr.write(|w| w.ready().clear());
222 }
223 }
224
225 /// Do a custom QSPI instruction. 232 /// Do a custom QSPI instruction.
226 pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { 233 pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
227 let ondrop = OnDrop::new(Self::blocking_wait_ready); 234 let ondrop = OnDrop::new(Self::blocking_wait_ready);
@@ -310,7 +317,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
310 poll_fn(move |cx| { 317 poll_fn(move |cx| {
311 let r = T::regs(); 318 let r = T::regs();
312 let s = T::state(); 319 let s = T::state();
313 s.ready_waker.register(cx.waker()); 320 s.waker.register(cx.waker());
314 if r.events_ready.read().bits() != 0 { 321 if r.events_ready.read().bits() != 0 {
315 return Poll::Ready(()); 322 return Poll::Ready(());
316 } 323 }
@@ -525,8 +532,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
525 532
526 r.enable.write(|w| w.enable().disabled()); 533 r.enable.write(|w| w.enable().disabled());
527 534
528 self.irq.disable();
529
530 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, 535 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
531 // leaving it floating, the flash chip might read it as zero which would cause it to 536 // leaving it floating, the flash chip might read it as zero which would cause it to
532 // spuriously exit DPM. 537 // spuriously exit DPM.
@@ -624,27 +629,27 @@ mod _eh1 {
624pub(crate) mod sealed { 629pub(crate) mod sealed {
625 use embassy_sync::waitqueue::AtomicWaker; 630 use embassy_sync::waitqueue::AtomicWaker;
626 631
627 use super::*; 632 /// Peripheral static state
628
629 pub struct State { 633 pub struct State {
630 pub ready_waker: AtomicWaker, 634 pub waker: AtomicWaker,
631 } 635 }
636
632 impl State { 637 impl State {
633 pub const fn new() -> Self { 638 pub const fn new() -> Self {
634 Self { 639 Self {
635 ready_waker: AtomicWaker::new(), 640 waker: AtomicWaker::new(),
636 } 641 }
637 } 642 }
638 } 643 }
639 644
640 pub trait Instance { 645 pub trait Instance {
641 fn regs() -> &'static pac::qspi::RegisterBlock; 646 fn regs() -> &'static crate::pac::qspi::RegisterBlock;
642 fn state() -> &'static State; 647 fn state() -> &'static State;
643 } 648 }
644} 649}
645 650
646/// QSPI peripheral instance. 651/// QSPI peripheral instance.
647pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 652pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
648 /// Interrupt for this peripheral. 653 /// Interrupt for this peripheral.
649 type Interrupt: Interrupt; 654 type Interrupt: Interrupt;
650} 655}
@@ -652,7 +657,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
652macro_rules! impl_qspi { 657macro_rules! impl_qspi {
653 ($type:ident, $pac_type:ident, $irq:ident) => { 658 ($type:ident, $pac_type:ident, $irq:ident) => {
654 impl crate::qspi::sealed::Instance for peripherals::$type { 659 impl crate::qspi::sealed::Instance for peripherals::$type {
655 fn regs() -> &'static pac::qspi::RegisterBlock { 660 fn regs() -> &'static crate::pac::qspi::RegisterBlock {
656 unsafe { &*pac::$pac_type::ptr() } 661 unsafe { &*pac::$pac_type::ptr() }
657 } 662 }
658 fn state() -> &'static crate::qspi::sealed::State { 663 fn state() -> &'static crate::qspi::sealed::State {
diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
index 21a10940d..9e8a01f4e 100644
--- a/examples/nrf52840/src/bin/qspi.rs
+++ b/examples/nrf52840/src/bin/qspi.rs
@@ -5,7 +5,7 @@
5use defmt::{assert_eq, info, unwrap}; 5use defmt::{assert_eq, info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::qspi::Frequency; 7use embassy_nrf::qspi::Frequency;
8use embassy_nrf::{interrupt, qspi}; 8use embassy_nrf::{bind_interrupts, peripherals, qspi};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11const PAGE_SIZE: usize = 4096; 11const PAGE_SIZE: usize = 4096;
@@ -15,6 +15,10 @@ const PAGE_SIZE: usize = 4096;
15#[repr(C, align(4))] 15#[repr(C, align(4))]
16struct AlignedBuf([u8; 4096]); 16struct AlignedBuf([u8; 4096]);
17 17
18bind_interrupts!(struct Irqs {
19 QSPI => qspi::InterruptHandler<peripherals::QSPI>;
20});
21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default()); 24 let p = embassy_nrf::init(Default::default());
@@ -26,9 +30,8 @@ async fn main(_spawner: Spawner) {
26 config.write_opcode = qspi::WriteOpcode::PP4IO; 30 config.write_opcode = qspi::WriteOpcode::PP4IO;
27 config.write_page_size = qspi::WritePageSize::_256BYTES; 31 config.write_page_size = qspi::WritePageSize::_256BYTES;
28 32
29 let irq = interrupt::take!(QSPI);
30 let mut q = qspi::Qspi::new( 33 let mut q = qspi::Qspi::new(
31 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, 34 p.QSPI, Irqs, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
32 ); 35 );
33 36
34 let mut id = [1; 3]; 37 let mut id = [1; 3];
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 20c903914..22a5c0c6d 100644
--- a/examples/nrf52840/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -7,7 +7,7 @@ use core::mem;
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::qspi::Frequency; 9use embassy_nrf::qspi::Frequency;
10use embassy_nrf::{interrupt, qspi}; 10use embassy_nrf::{bind_interrupts, peripherals, qspi};
11use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -16,10 +16,13 @@ use {defmt_rtt as _, panic_probe as _};
16#[repr(C, align(4))] 16#[repr(C, align(4))]
17struct AlignedBuf([u8; 64]); 17struct AlignedBuf([u8; 64]);
18 18
19bind_interrupts!(struct Irqs {
20 QSPI => qspi::InterruptHandler<peripherals::QSPI>;
21});
22
19#[embassy_executor::main] 23#[embassy_executor::main]
20async fn main(_p: Spawner) { 24async fn main(_p: Spawner) {
21 let mut p = embassy_nrf::init(Default::default()); 25 let mut p = embassy_nrf::init(Default::default());
22 let mut irq = interrupt::take!(QSPI);
23 26
24 loop { 27 loop {
25 // Config for the MX25R64 present in the nRF52840 DK 28 // Config for the MX25R64 present in the nRF52840 DK
@@ -36,7 +39,7 @@ async fn main(_p: Spawner) {
36 39
37 let mut q = qspi::Qspi::new( 40 let mut q = qspi::Qspi::new(
38 &mut p.QSPI, 41 &mut p.QSPI,
39 &mut irq, 42 Irqs,
40 &mut p.P0_19, 43 &mut p.P0_19,
41 &mut p.P0_17, 44 &mut p.P0_17,
42 &mut p.P0_20, 45 &mut p.P0_20,