nrf/qspi: update to new api

This commit is contained in:
Dario Nieuwenhuis 2021-03-21 20:54:09 +01:00
parent 16bb6fd6ac
commit ec7309962a
3 changed files with 200 additions and 229 deletions

View File

@ -6,12 +6,12 @@
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use embassy_nrf::peripherals::Peripherals;
use example_common::*; use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::{assert_eq, panic}; use defmt::{assert_eq, panic};
use futures::pin_mut; use futures::pin_mut;
use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::traits::flash::Flash; use embassy::traits::flash::Flash;
@ -27,43 +27,16 @@ struct AlignedBuf([u8; 4096]);
#[task] #[task]
async fn run() { async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unsafe { Peripherals::steal() };
let port0 = gpio::p0::Parts::new(p.P0); let csn = p.p0_17;
let sck = p.p0_19;
let pins = qspi::Pins { let io0 = p.p0_20;
csn: port0 let io1 = p.p0_21;
.p0_17 let io2 = p.p0_22;
.into_push_pull_output(gpio::Level::High) let io3 = p.p0_23;
.degrade(),
sck: port0
.p0_19
.into_push_pull_output(gpio::Level::High)
.degrade(),
io0: port0
.p0_20
.into_push_pull_output(gpio::Level::High)
.degrade(),
io1: port0
.p0_21
.into_push_pull_output(gpio::Level::High)
.degrade(),
io2: Some(
port0
.p0_22
.into_push_pull_output(gpio::Level::High)
.degrade(),
),
io3: Some(
port0
.p0_23
.into_push_pull_output(gpio::Level::High)
.degrade(),
),
};
let config = qspi::Config { let config = qspi::Config {
pins,
read_opcode: qspi::ReadOpcode::READ4IO, read_opcode: qspi::ReadOpcode::READ4IO,
write_opcode: qspi::WriteOpcode::PP4IO, write_opcode: qspi::WriteOpcode::PP4IO,
xip_offset: 0, xip_offset: 0,
@ -72,7 +45,7 @@ async fn run() {
}; };
let irq = interrupt::take!(QSPI); let irq = interrupt::take!(QSPI);
let q = qspi::Qspi::new(p.QSPI, irq, config); let q = qspi::Qspi::new(p.qspi, irq, sck, csn, io0, io1, io2, io3, config);
pin_mut!(q); pin_mut!(q);
let mut id = [1; 3]; let mut id = [1; 3];
@ -83,7 +56,7 @@ async fn run() {
info!("id: {}", id); info!("id: {}", id);
// Read status register // Read status register
let mut status = [0; 1]; let mut status = [4; 1];
q.as_mut() q.as_mut()
.custom_instruction(0x05, &[], &mut status) .custom_instruction(0x05, &[], &mut status)
.await .await

View File

@ -1,13 +1,15 @@
use core::future::Future; use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin; use core::pin::Pin;
use core::task::Poll; use core::task::Poll;
use embassy::interrupt::Interrupt;
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
use crate::fmt::{assert, assert_eq, *}; use crate::fmt::{assert, assert_eq, *};
use crate::hal::gpio::{Output, Pin as GpioPin, PushPull}; use crate::gpio::Pin as GpioPin;
use crate::interrupt::{self}; use crate::interrupt::{self};
use crate::pac::QSPI; use crate::{pac, peripherals};
pub use crate::pac::qspi::ifconfig0::ADDRMODE_A as AddressMode; pub use crate::pac::qspi::ifconfig0::ADDRMODE_A as AddressMode;
pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize; pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize;
@ -25,25 +27,15 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
// - set gpio in high drive // - set gpio in high drive
use embassy::traits::flash::{Error, Flash}; use embassy::traits::flash::{Error, Flash};
use embassy::util::{DropBomb, WakerRegistration}; use embassy::util::{wake_on_interrupt, DropBomb, PeripheralBorrow, WakerRegistration};
use futures::future::poll_fn; use futures::future::poll_fn;
pub struct Pins {
pub sck: GpioPin<Output<PushPull>>,
pub csn: GpioPin<Output<PushPull>>,
pub io0: GpioPin<Output<PushPull>>,
pub io1: GpioPin<Output<PushPull>>,
pub io2: Option<GpioPin<Output<PushPull>>>,
pub io3: Option<GpioPin<Output<PushPull>>>,
}
pub struct DeepPowerDownConfig { pub struct DeepPowerDownConfig {
pub enter_time: u16, pub enter_time: u16,
pub exit_time: u16, pub exit_time: u16,
} }
pub struct Config { pub struct Config {
pub pins: Pins,
pub xip_offset: u32, pub xip_offset: u32,
pub read_opcode: ReadOpcode, pub read_opcode: ReadOpcode,
pub write_opcode: WriteOpcode, pub write_opcode: WriteOpcode,
@ -51,55 +43,54 @@ pub struct Config {
pub deep_power_down: Option<DeepPowerDownConfig>, pub deep_power_down: Option<DeepPowerDownConfig>,
} }
struct State { pub struct Qspi<'d, T: Instance> {
inner: QSPI, qspi: T,
waker: WakerRegistration, irq: T::Interrupt,
phantom: PhantomData<&'d mut T>,
} }
pub struct Qspi { impl<'d, T: Instance> Qspi<'d, T> {
inner: PeripheralMutex<State>, pub fn new(
} qspi: impl PeripheralBorrow<Target = T> + 'd,
irq: impl PeripheralBorrow<Target = T::Interrupt> + 'd,
sck: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
csn: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
io0: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
io1: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
io2: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
io3: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
config: Config,
) -> Self {
let mut qspi = unsafe { qspi.unborrow() };
let irq = unsafe { irq.unborrow() };
let sck = unsafe { sck.unborrow() };
let csn = unsafe { csn.unborrow() };
let io0 = unsafe { io0.unborrow() };
let io1 = unsafe { io1.unborrow() };
let io2 = unsafe { io2.unborrow() };
let io3 = unsafe { io3.unborrow() };
impl Qspi { let r = qspi.regs();
pub fn new(qspi: QSPI, irq: interrupt::QSPI, config: Config) -> Self {
qspi.psel.sck.write(|w| {
let pin = &config.pins.sck;
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
});
qspi.psel.csn.write(|w| {
let pin = &config.pins.csn;
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
});
qspi.psel.io0.write(|w| {
let pin = &config.pins.io0;
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
});
qspi.psel.io1.write(|w| {
let pin = &config.pins.io1;
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
});
qspi.psel.io2.write(|w| {
if let Some(ref pin) = config.pins.io2 {
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
} else {
w.connect().disconnected()
}
});
qspi.psel.io3.write(|w| {
if let Some(ref pin) = config.pins.io3 {
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
} else {
w.connect().disconnected()
}
});
qspi.ifconfig0.write(|mut w| { for cnf in &[
sck.conf(),
csn.conf(),
io0.conf(),
io1.conf(),
io2.conf(),
io3.conf(),
] {
cnf.write(|w| w.dir().output().drive().h0h1());
}
r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) });
r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) });
r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) });
r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) });
r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) });
r.ifconfig0.write(|mut w| {
w = w.addrmode().variant(AddressMode::_24BIT); w = w.addrmode().variant(AddressMode::_24BIT);
if config.deep_power_down.is_some() { if config.deep_power_down.is_some() {
w = w.dpmenable().enable(); w = w.dpmenable().enable();
@ -113,14 +104,14 @@ impl Qspi {
}); });
if let Some(dpd) = &config.deep_power_down { if let Some(dpd) = &config.deep_power_down {
qspi.dpmdur.write(|mut w| unsafe { r.dpmdur.write(|mut w| unsafe {
w = w.enter().bits(dpd.enter_time); w = w.enter().bits(dpd.enter_time);
w = w.exit().bits(dpd.exit_time); w = w.exit().bits(dpd.exit_time);
w w
}) })
} }
qspi.ifconfig1.write(|w| { r.ifconfig1.write(|w| {
let w = unsafe { w.sckdelay().bits(80) }; let w = unsafe { w.sckdelay().bits(80) };
let w = w.dpmen().exit(); let w = w.dpmen().exit();
let w = w.spimode().mode0(); let w = w.spimode().mode0();
@ -128,48 +119,42 @@ impl Qspi {
w w
}); });
qspi.xipoffset r.xipoffset
.write(|w| unsafe { w.xipoffset().bits(config.xip_offset) }); .write(|w| unsafe { w.xipoffset().bits(config.xip_offset) });
// Enable it // Enable it
qspi.enable.write(|w| w.enable().enabled()); r.enable.write(|w| w.enable().enabled());
qspi.events_ready.reset(); r.events_ready.reset();
qspi.tasks_activate.write(|w| w.tasks_activate().bit(true)); r.tasks_activate.write(|w| w.tasks_activate().bit(true));
while qspi.events_ready.read().bits() == 0 {} while r.events_ready.read().bits() == 0 {}
qspi.events_ready.reset(); r.events_ready.reset();
Self { Self {
inner: PeripheralMutex::new( qspi,
State {
inner: qspi,
waker: WakerRegistration::new(),
},
irq, irq,
), phantom: PhantomData,
} }
} }
pub fn sleep(self: Pin<&mut Self>) { pub fn sleep(mut self: Pin<&mut Self>) {
self.inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs();
info!("flash: sleeping"); info!("flash: sleeping");
info!("flash: state = {:?}", s.inner.status.read().bits()); info!("flash: state = {:?}", r.status.read().bits());
s.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); r.ifconfig1.modify(|_, w| w.dpmen().enter());
info!("flash: state = {:?}", s.inner.status.read().bits()); info!("flash: state = {:?}", r.status.read().bits());
cortex_m::asm::delay(1000000); cortex_m::asm::delay(1000000);
info!("flash: state = {:?}", s.inner.status.read().bits()); info!("flash: state = {:?}", r.status.read().bits());
s.inner r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
.tasks_deactivate
.write(|w| w.tasks_deactivate().set_bit());
});
} }
pub async fn custom_instruction<'a>( pub async fn custom_instruction(
mut self: Pin<&'a mut Self>, mut self: Pin<&mut Self>,
opcode: u8, opcode: u8,
req: &'a [u8], req: &[u8],
resp: &'a mut [u8], resp: &mut [u8],
) -> Result<(), Error> { ) -> Result<(), Error> {
let bomb = DropBomb::new(); let bomb = DropBomb::new();
@ -192,14 +177,14 @@ impl Qspi {
let len = core::cmp::max(req.len(), resp.len()) as u8; let len = core::cmp::max(req.len(), resp.len()) as u8;
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs();
s.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); r.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
s.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); r.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner.cinstrconf.write(|w| { r.cinstrconf.write(|w| {
let w = unsafe { w.opcode().bits(opcode) }; let w = unsafe { w.opcode().bits(opcode) };
let w = unsafe { w.length().bits(len + 1) }; let w = unsafe { w.length().bits(len + 1) };
let w = w.lio2().bit(true); let w = w.lio2().bit(true);
@ -210,13 +195,13 @@ impl Qspi {
let w = w.lfstop().bit(false); let w = w.lfstop().bit(false);
w w
}); });
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs();
let dat0 = s.inner.cinstrdat0.read().bits();
let dat1 = s.inner.cinstrdat1.read().bits(); let dat0 = r.cinstrdat0.read().bits();
let dat1 = r.cinstrdat1.read().bits();
for i in 0..4 { for i in 0..4 {
if i < resp.len() { if i < resp.len() {
resp[i] = (dat0 >> (i * 8)) as u8; resp[i] = (dat0 >> (i * 8)) as u8;
@ -227,34 +212,38 @@ impl Qspi {
resp[i] = (dat1 >> (i * 8)) as u8; resp[i] = (dat1 >> (i * 8)) as u8;
} }
} }
});
bomb.defuse(); bomb.defuse();
Ok(()) Ok(())
} }
fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State>> { async fn wait_ready(self: Pin<&mut Self>) {
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } let this = unsafe { self.get_unchecked_mut() };
}
fn wait_ready<'a>(mut self: Pin<&'a mut Self>) -> impl Future<Output = ()> + 'a {
poll_fn(move |cx| { poll_fn(move |cx| {
self.as_mut().inner().with(|s, _irq| { let r = this.qspi.regs();
if s.inner.events_ready.read().bits() != 0 {
if r.events_ready.read().bits() != 0 {
r.events_ready.reset();
return Poll::Ready(()); return Poll::Ready(());
} }
s.waker.register(cx.waker());
wake_on_interrupt(&mut this.irq, cx.waker());
Poll::Pending Poll::Pending
}) })
}) .await
} }
} }
impl Flash for Qspi { impl<'d, T: Instance> Flash for Qspi<'d, T> {
type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; #[rustfmt::skip]
type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
type ErasePageFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; #[rustfmt::skip]
type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
#[rustfmt::skip]
type ErasePageFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
fn read<'a>( fn read<'a>(
mut self: Pin<&'a mut Self>, mut self: Pin<&'a mut Self>,
@ -268,26 +257,21 @@ impl Flash for Qspi {
assert_eq!(data.len() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0); assert_eq!(address as u32 % 4, 0);
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs();
s.inner
.read r.read
.src .src
.write(|w| unsafe { w.src().bits(address as u32) }); .write(|w| unsafe { w.src().bits(address as u32) });
s.inner r.read
.read
.dst .dst
.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
s.inner r.read
.read
.cnt .cnt
.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); .write(|w| unsafe { w.cnt().bits(data.len() as u32) });
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
.tasks_readstart
.write(|w| w.tasks_readstart().bit(true));
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
@ -309,26 +293,20 @@ impl Flash for Qspi {
assert_eq!(data.len() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0); assert_eq!(address as u32 % 4, 0);
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs();
s.inner r.write
.write
.src .src
.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
s.inner r.write
.write
.dst .dst
.write(|w| unsafe { w.dst().bits(address as u32) }); .write(|w| unsafe { w.dst().bits(address as u32) });
s.inner r.write
.write
.cnt .cnt
.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); .write(|w| unsafe { w.cnt().bits(data.len() as u32) });
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
.tasks_writestart
.write(|w| w.tasks_writestart().bit(true));
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
@ -344,19 +322,15 @@ impl Flash for Qspi {
assert_eq!(address as u32 % 4096, 0); assert_eq!(address as u32 % 4096, 0);
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs();
s.inner r.erase
.erase
.ptr .ptr
.write(|w| unsafe { w.ptr().bits(address as u32) }); .write(|w| unsafe { w.ptr().bits(address as u32) });
s.inner.erase.len.write(|w| w.len()._4kb()); r.erase.len.write(|w| w.len()._4kb());
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
.tasks_erasestart
.write(|w| w.tasks_erasestart().bit(true));
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
@ -383,13 +357,29 @@ impl Flash for Qspi {
} }
} }
impl PeripheralState for State { mod sealed {
type Interrupt = interrupt::QSPI; use super::*;
fn on_interrupt(&mut self) { pub trait Instance {
if self.inner.events_ready.read().bits() != 0 { fn regs(&mut self) -> &pac::qspi::RegisterBlock;
self.inner.intenclr.write(|w| w.ready().clear());
self.waker.wake()
}
} }
} }
pub trait Instance: sealed::Instance + 'static {
type Interrupt: Interrupt;
}
macro_rules! make_impl {
($type:ident, $irq:ident) => {
impl sealed::Instance for peripherals::$type {
fn regs(&mut self) -> &pac::qspi::RegisterBlock {
unsafe { &*pac::$type::ptr() }
}
}
impl Instance for peripherals::$type {
type Interrupt = interrupt::$irq;
}
};
}
make_impl!(QSPI, QSPI);

View File

@ -11,9 +11,17 @@ pub enum Error {
} }
pub trait Flash { pub trait Flash {
type ReadFuture<'a>: Future<Output = Result<(), Error>>; type ReadFuture<'a>: Future<Output = Result<(), Error>>
type WriteFuture<'a>: Future<Output = Result<(), Error>>; where
type ErasePageFuture<'a>: Future<Output = Result<(), Error>>; Self: 'a;
type WriteFuture<'a>: Future<Output = Result<(), Error>>
where
Self: 'a;
type ErasePageFuture<'a>: Future<Output = Result<(), Error>>
where
Self: 'a;
/// Reads data from the flash device. /// Reads data from the flash device.
/// ///