2021-05-11 01:04:59 +00:00
|
|
|
#![macro_use]
|
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
use core::ptr;
|
2021-02-28 21:05:37 +00:00
|
|
|
use core::task::Poll;
|
2022-06-12 20:15:44 +00:00
|
|
|
|
2021-09-10 23:53:53 +00:00
|
|
|
use embassy_hal_common::drop::DropBomb;
|
2022-07-03 21:16:10 +00:00
|
|
|
use embassy_hal_common::{unborrow, Unborrowed};
|
2021-04-14 15:00:28 +00:00
|
|
|
use futures::future::poll_fn;
|
2021-03-07 23:15:40 +00:00
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
use crate::gpio::sealed::Pin as _;
|
|
|
|
use crate::gpio::{self, Pin as GpioPin};
|
2022-06-12 20:15:44 +00:00
|
|
|
use crate::interrupt::{Interrupt, InterruptExt};
|
|
|
|
pub use crate::pac::qspi::ifconfig0::{
|
|
|
|
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
|
|
|
};
|
|
|
|
use crate::{pac, Unborrow};
|
2020-09-22 16:03:43 +00:00
|
|
|
|
|
|
|
// TODO
|
|
|
|
// - config:
|
|
|
|
// - 32bit address mode
|
|
|
|
// - SPI freq
|
|
|
|
// - SPI sck delay
|
|
|
|
// - Deep power down mode (DPM)
|
|
|
|
// - SPI mode 3
|
|
|
|
// - activate/deactivate
|
|
|
|
// - set gpio in high drive
|
|
|
|
|
2020-11-27 17:42:59 +00:00
|
|
|
pub struct DeepPowerDownConfig {
|
2021-05-26 21:26:07 +00:00
|
|
|
/// Time required for entering DPM, in units of 16us
|
2020-11-27 17:42:59 +00:00
|
|
|
pub enter_time: u16,
|
2021-05-26 21:26:07 +00:00
|
|
|
/// Time required for exiting DPM, in units of 16us
|
2020-11-27 17:42:59 +00:00
|
|
|
pub exit_time: u16,
|
|
|
|
}
|
|
|
|
|
2021-03-28 22:55:05 +00:00
|
|
|
#[non_exhaustive]
|
2020-09-22 16:03:43 +00:00
|
|
|
pub struct Config {
|
|
|
|
pub xip_offset: u32,
|
|
|
|
pub read_opcode: ReadOpcode,
|
|
|
|
pub write_opcode: WriteOpcode,
|
|
|
|
pub write_page_size: WritePageSize,
|
2020-11-27 17:42:59 +00:00
|
|
|
pub deep_power_down: Option<DeepPowerDownConfig>,
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
|
|
|
|
2021-03-28 22:55:05 +00:00
|
|
|
impl Default for Config {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
read_opcode: ReadOpcode::READ4IO,
|
|
|
|
write_opcode: WriteOpcode::PP4IO,
|
|
|
|
xip_offset: 0,
|
|
|
|
write_page_size: WritePageSize::_256BYTES,
|
|
|
|
deep_power_down: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 22:05:31 +00:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum Error {
|
2022-04-19 12:39:59 +00:00
|
|
|
OutOfBounds,
|
2022-01-13 22:05:31 +00:00
|
|
|
// TODO add "not in data memory" error and check for it
|
|
|
|
}
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
|
2022-07-03 21:16:10 +00:00
|
|
|
irq: Unborrowed<'d, T::Interrupt>,
|
2021-05-26 21:26:07 +00:00
|
|
|
dpm_enabled: bool,
|
2021-02-28 21:05:37 +00:00
|
|
|
}
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|
|
|
pub fn new(
|
2021-05-17 10:23:04 +00:00
|
|
|
_qspi: impl Unborrow<Target = T> + 'd,
|
2021-04-14 17:59:52 +00:00
|
|
|
irq: impl Unborrow<Target = T::Interrupt> + 'd,
|
|
|
|
sck: impl Unborrow<Target = impl GpioPin> + 'd,
|
|
|
|
csn: impl Unborrow<Target = impl GpioPin> + 'd,
|
|
|
|
io0: impl Unborrow<Target = impl GpioPin> + 'd,
|
|
|
|
io1: impl Unborrow<Target = impl GpioPin> + 'd,
|
|
|
|
io2: impl Unborrow<Target = impl GpioPin> + 'd,
|
|
|
|
io3: impl Unborrow<Target = impl GpioPin> + 'd,
|
2021-03-21 19:54:09 +00:00
|
|
|
config: Config,
|
2022-04-19 12:39:59 +00:00
|
|
|
) -> Qspi<'d, T, FLASH_SIZE> {
|
2021-05-17 10:23:04 +00:00
|
|
|
unborrow!(irq, sck, csn, io0, io1, io2, io3);
|
2021-03-21 19:54:09 +00:00
|
|
|
|
2021-04-14 15:00:28 +00:00
|
|
|
let r = T::regs();
|
2021-03-21 19:54:09 +00:00
|
|
|
|
2022-07-03 21:16:10 +00:00
|
|
|
unborrow_and_degrade!(sck, csn, io0, io1, io2, io3);
|
2021-05-26 21:26:07 +00:00
|
|
|
|
|
|
|
for pin in [&sck, &csn, &io0, &io1, &io2, &io3] {
|
|
|
|
pin.set_high();
|
|
|
|
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
2021-03-21 19:54:09 +00:00
|
|
|
}
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-03-21 19:54:09 +00:00
|
|
|
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()) });
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
r.ifconfig0.write(|w| {
|
|
|
|
w.addrmode().variant(AddressMode::_24BIT);
|
|
|
|
w.dpmenable().bit(config.deep_power_down.is_some());
|
|
|
|
w.ppsize().variant(config.write_page_size);
|
|
|
|
w.readoc().variant(config.read_opcode);
|
|
|
|
w.writeoc().variant(config.write_opcode);
|
2020-09-22 16:03:43 +00:00
|
|
|
w
|
|
|
|
});
|
|
|
|
|
2020-11-27 17:42:59 +00:00
|
|
|
if let Some(dpd) = &config.deep_power_down {
|
2021-05-26 21:26:07 +00:00
|
|
|
r.dpmdur.write(|w| unsafe {
|
|
|
|
w.enter().bits(dpd.enter_time);
|
|
|
|
w.exit().bits(dpd.exit_time);
|
2020-11-27 17:42:59 +00:00
|
|
|
w
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
r.ifconfig1.write(|w| unsafe {
|
|
|
|
w.sckdelay().bits(80);
|
|
|
|
w.dpmen().exit();
|
|
|
|
w.spimode().mode0();
|
|
|
|
w.sckfreq().bits(3);
|
|
|
|
w
|
|
|
|
});
|
|
|
|
|
|
|
|
r.xipoffset.write(|w| unsafe {
|
|
|
|
w.xipoffset().bits(config.xip_offset);
|
2020-09-22 16:03:43 +00:00
|
|
|
w
|
|
|
|
});
|
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
irq.set_handler(Self::on_interrupt);
|
|
|
|
irq.unpend();
|
|
|
|
irq.enable();
|
2020-09-22 16:03:43 +00:00
|
|
|
|
|
|
|
// Enable it
|
2021-03-21 19:54:09 +00:00
|
|
|
r.enable.write(|w| w.enable().enabled());
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
let mut res = Self {
|
|
|
|
dpm_enabled: config.deep_power_down.is_some(),
|
2022-04-19 12:39:59 +00:00
|
|
|
irq,
|
2021-05-26 21:26:07 +00:00
|
|
|
};
|
|
|
|
|
2021-03-21 19:54:09 +00:00
|
|
|
r.events_ready.reset();
|
2021-05-26 21:26:07 +00:00
|
|
|
r.intenset.write(|w| w.ready().set());
|
|
|
|
|
2021-03-21 19:54:09 +00:00
|
|
|
r.tasks_activate.write(|w| w.tasks_activate().bit(true));
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
res.blocking_wait_ready();
|
2021-04-14 15:00:28 +00:00
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
res
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
|
|
|
|
2021-04-14 15:00:28 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-12 20:15:44 +00:00
|
|
|
pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
|
2021-02-14 00:41:36 +00:00
|
|
|
let bomb = DropBomb::new();
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
let len = core::cmp::max(req.len(), resp.len()) as u8;
|
|
|
|
self.custom_instruction_start(opcode, req, len)?;
|
|
|
|
|
|
|
|
self.wait_ready().await;
|
|
|
|
|
|
|
|
self.custom_instruction_finish(resp)?;
|
|
|
|
|
|
|
|
bomb.defuse();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-06-12 20:15:44 +00:00
|
|
|
pub fn blocking_custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
|
2022-04-19 12:39:59 +00:00
|
|
|
let len = core::cmp::max(req.len(), resp.len()) as u8;
|
|
|
|
self.custom_instruction_start(opcode, req, len)?;
|
|
|
|
|
|
|
|
self.blocking_wait_ready();
|
|
|
|
|
|
|
|
self.custom_instruction_finish(resp)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn custom_instruction_start(&mut self, opcode: u8, req: &[u8], len: u8) -> Result<(), Error> {
|
2021-02-14 00:41:36 +00:00
|
|
|
assert!(req.len() <= 8);
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-02-14 00:41:36 +00:00
|
|
|
let mut dat0: u32 = 0;
|
|
|
|
let mut dat1: u32 = 0;
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-02-14 00:41:36 +00:00
|
|
|
for i in 0..4 {
|
|
|
|
if i < req.len() {
|
|
|
|
dat0 |= (req[i] as u32) << (i * 8);
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
2021-02-14 00:41:36 +00:00
|
|
|
}
|
|
|
|
for i in 0..4 {
|
|
|
|
if i + 4 < req.len() {
|
|
|
|
dat1 |= (req[i + 4] as u32) << (i * 8);
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
2021-02-14 00:41:36 +00:00
|
|
|
}
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-04-14 15:00:28 +00:00
|
|
|
let r = T::regs();
|
2021-03-21 19:54:09 +00:00
|
|
|
r.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
|
|
|
|
r.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
|
|
|
|
|
|
|
|
r.events_ready.reset();
|
|
|
|
r.intenset.write(|w| w.ready().set());
|
|
|
|
|
|
|
|
r.cinstrconf.write(|w| {
|
|
|
|
let w = unsafe { w.opcode().bits(opcode) };
|
|
|
|
let w = unsafe { w.length().bits(len + 1) };
|
|
|
|
let w = w.lio2().bit(true);
|
|
|
|
let w = w.lio3().bit(true);
|
|
|
|
let w = w.wipwait().bit(true);
|
|
|
|
let w = w.wren().bit(true);
|
|
|
|
let w = w.lfen().bit(false);
|
|
|
|
let w = w.lfstop().bit(false);
|
|
|
|
w
|
2021-02-14 00:41:36 +00:00
|
|
|
});
|
2022-04-19 12:39:59 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> {
|
2021-04-14 15:00:28 +00:00
|
|
|
let r = T::regs();
|
2021-03-21 19:54:09 +00:00
|
|
|
|
|
|
|
let dat0 = r.cinstrdat0.read().bits();
|
|
|
|
let dat1 = r.cinstrdat1.read().bits();
|
|
|
|
for i in 0..4 {
|
|
|
|
if i < resp.len() {
|
|
|
|
resp[i] = (dat0 >> (i * 8)) as u8;
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
2021-03-21 19:54:09 +00:00
|
|
|
}
|
|
|
|
for i in 0..4 {
|
|
|
|
if i + 4 < resp.len() {
|
|
|
|
resp[i] = (dat1 >> (i * 8)) as u8;
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
2021-03-21 19:54:09 +00:00
|
|
|
}
|
2021-02-14 00:41:36 +00:00
|
|
|
Ok(())
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
2021-02-28 21:05:37 +00:00
|
|
|
|
2021-04-14 15:00:28 +00:00
|
|
|
async fn wait_ready(&mut self) {
|
2021-02-28 21:05:37 +00:00
|
|
|
poll_fn(move |cx| {
|
2021-04-14 15:00:28 +00:00
|
|
|
let r = T::regs();
|
|
|
|
let s = T::state();
|
|
|
|
s.ready_waker.register(cx.waker());
|
2021-03-21 19:54:09 +00:00
|
|
|
if r.events_ready.read().bits() != 0 {
|
|
|
|
return Poll::Ready(());
|
|
|
|
}
|
|
|
|
Poll::Pending
|
2021-02-28 21:05:37 +00:00
|
|
|
})
|
2021-03-21 19:54:09 +00:00
|
|
|
.await
|
2021-02-28 21:05:37 +00:00
|
|
|
}
|
2022-01-13 22:05:31 +00:00
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
fn blocking_wait_ready(&mut self) {
|
|
|
|
loop {
|
|
|
|
let r = T::regs();
|
|
|
|
if r.events_ready.read().bits() != 0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-13 22:05:31 +00:00
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
|
2022-01-13 22:05:31 +00:00
|
|
|
assert_eq!(data.as_ptr() as u32 % 4, 0);
|
|
|
|
assert_eq!(data.len() as u32 % 4, 0);
|
|
|
|
assert_eq!(address as u32 % 4, 0);
|
2022-04-19 12:39:59 +00:00
|
|
|
if address > FLASH_SIZE {
|
|
|
|
return Err(Error::OutOfBounds);
|
|
|
|
}
|
2022-01-13 22:05:31 +00:00
|
|
|
|
|
|
|
let r = T::regs();
|
|
|
|
|
2022-06-12 20:15:44 +00:00
|
|
|
r.read.src.write(|w| unsafe { w.src().bits(address as u32) });
|
|
|
|
r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
|
|
|
|
r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
2022-01-13 22:05:31 +00:00
|
|
|
|
|
|
|
r.events_ready.reset();
|
|
|
|
r.intenset.write(|w| w.ready().set());
|
|
|
|
r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
|
|
|
|
//info!("start_write ptr {}", data.as_ptr() as u32);
|
2022-01-13 22:05:31 +00:00
|
|
|
assert_eq!(data.as_ptr() as u32 % 4, 0);
|
2022-04-19 12:39:59 +00:00
|
|
|
//info!("start_write OK ptr");
|
2022-01-13 22:05:31 +00:00
|
|
|
assert_eq!(data.len() as u32 % 4, 0);
|
2022-04-19 12:39:59 +00:00
|
|
|
//info!("start_write OK len");
|
2022-01-13 22:05:31 +00:00
|
|
|
assert_eq!(address as u32 % 4, 0);
|
2022-04-19 12:39:59 +00:00
|
|
|
//info!("start_write OK addr");
|
|
|
|
if address > FLASH_SIZE {
|
|
|
|
return Err(Error::OutOfBounds);
|
|
|
|
}
|
2022-01-13 22:05:31 +00:00
|
|
|
|
|
|
|
let r = T::regs();
|
2022-06-12 20:15:44 +00:00
|
|
|
r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
|
|
|
|
r.write.dst.write(|w| unsafe { w.dst().bits(address as u32) });
|
|
|
|
r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
2022-01-13 22:05:31 +00:00
|
|
|
|
|
|
|
r.events_ready.reset();
|
|
|
|
r.intenset.write(|w| w.ready().set());
|
|
|
|
r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
fn start_erase(&mut self, address: usize) -> Result<(), Error> {
|
2022-01-13 22:05:31 +00:00
|
|
|
assert_eq!(address as u32 % 4096, 0);
|
2022-04-19 12:39:59 +00:00
|
|
|
if address > FLASH_SIZE {
|
|
|
|
return Err(Error::OutOfBounds);
|
|
|
|
}
|
2022-01-13 22:05:31 +00:00
|
|
|
|
|
|
|
let r = T::regs();
|
2022-06-12 20:15:44 +00:00
|
|
|
r.erase.ptr.write(|w| unsafe { w.ptr().bits(address as u32) });
|
2022-01-13 22:05:31 +00:00
|
|
|
r.erase.len.write(|w| w.len()._4kb());
|
|
|
|
|
|
|
|
r.events_ready.reset();
|
|
|
|
r.intenset.write(|w| w.ready().set());
|
|
|
|
r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
|
|
|
|
let bomb = DropBomb::new();
|
|
|
|
|
|
|
|
self.start_read(address, data)?;
|
2022-01-13 22:05:31 +00:00
|
|
|
self.wait_ready().await;
|
|
|
|
|
|
|
|
bomb.defuse();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-04-19 12:39:59 +00:00
|
|
|
|
|
|
|
pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
|
|
|
|
let bomb = DropBomb::new();
|
|
|
|
|
|
|
|
//info!("WRITE {} bytes at {}", data.len(), address);
|
|
|
|
self.start_write(address, data)?;
|
|
|
|
//info!("STARTED");
|
|
|
|
self.wait_ready().await;
|
|
|
|
//info!("WRITE DONE");
|
|
|
|
|
|
|
|
bomb.defuse();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn erase(&mut self, address: usize) -> Result<(), Error> {
|
|
|
|
let bomb = DropBomb::new();
|
|
|
|
|
|
|
|
self.start_erase(address)?;
|
|
|
|
self.wait_ready().await;
|
|
|
|
|
|
|
|
bomb.defuse();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
|
|
|
|
self.start_read(address, data)?;
|
|
|
|
self.blocking_wait_ready();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
|
|
|
|
self.start_write(address, data)?;
|
|
|
|
self.blocking_wait_ready();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> {
|
|
|
|
self.start_erase(address)?;
|
|
|
|
self.blocking_wait_ready();
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> {
|
2021-05-26 21:26:07 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
let r = T::regs();
|
|
|
|
|
|
|
|
if self.dpm_enabled {
|
2021-12-23 12:43:14 +00:00
|
|
|
trace!("qspi: doing deep powerdown...");
|
2021-05-26 21:26:07 +00:00
|
|
|
|
|
|
|
r.ifconfig1.modify(|_, w| w.dpmen().enter());
|
|
|
|
|
|
|
|
// Wait for DPM enter.
|
|
|
|
// Unfortunately we must spin. There's no way to do this interrupt-driven.
|
|
|
|
// The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:)
|
|
|
|
while r.status.read().dpm().is_disabled() {}
|
2021-05-26 22:42:29 +00:00
|
|
|
|
|
|
|
// Wait MORE for DPM enter.
|
|
|
|
// I have absolutely no idea why, but the wait above is not enough :'(
|
|
|
|
// Tested with mx25r64 in nrf52840-dk, and with mx25r16 in custom board
|
|
|
|
cortex_m::asm::delay(4096);
|
2021-05-26 21:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it.
|
|
|
|
r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
|
|
|
|
|
|
|
|
// Workaround https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev1/ERR/nRF52840/Rev1/latest/anomaly_840_122.html?cp=4_0_1_2_1_7
|
|
|
|
// Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate,
|
|
|
|
// so we only do the second one here.
|
|
|
|
unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) }
|
|
|
|
|
|
|
|
r.enable.write(|w| w.enable().disabled());
|
|
|
|
|
2022-04-19 12:39:59 +00:00
|
|
|
self.irq.disable();
|
|
|
|
|
2021-05-26 21:26:07 +00:00
|
|
|
// 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.
|
|
|
|
gpio::deconfigure_pin(r.psel.sck.read().bits());
|
|
|
|
gpio::deconfigure_pin(r.psel.io0.read().bits());
|
|
|
|
gpio::deconfigure_pin(r.psel.io1.read().bits());
|
|
|
|
gpio::deconfigure_pin(r.psel.io2.read().bits());
|
|
|
|
gpio::deconfigure_pin(r.psel.io3.read().bits());
|
|
|
|
|
2021-12-23 12:43:14 +00:00
|
|
|
trace!("qspi: dropped");
|
2021-05-26 21:26:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-12 20:15:44 +00:00
|
|
|
use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
|
2022-04-19 12:39:59 +00:00
|
|
|
|
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> {
|
|
|
|
type Error = Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NorFlashError for Error {
|
|
|
|
fn kind(&self) -> NorFlashErrorKind {
|
|
|
|
NorFlashErrorKind::Other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
|
|
|
const READ_SIZE: usize = 4;
|
|
|
|
|
|
|
|
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
|
|
|
self.blocking_read(offset as usize, bytes)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn capacity(&self) -> usize {
|
|
|
|
FLASH_SIZE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> {
|
|
|
|
const WRITE_SIZE: usize = 4;
|
|
|
|
const ERASE_SIZE: usize = 4096;
|
|
|
|
|
|
|
|
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
|
|
|
for address in (from as usize..to as usize).step_by(<Self as NorFlash>::ERASE_SIZE) {
|
|
|
|
self.blocking_erase(address)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
|
|
|
self.blocking_write(offset as usize, bytes)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
if #[cfg(feature = "nightly")]
|
|
|
|
{
|
|
|
|
use embedded_storage_async::nor_flash::{AsyncNorFlash, AsyncReadNorFlash};
|
|
|
|
use core::future::Future;
|
|
|
|
|
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
|
|
|
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
|
|
|
|
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
|
|
|
|
|
|
|
|
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
|
|
|
fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> {
|
|
|
|
async move { self.write(offset as usize, data).await }
|
|
|
|
}
|
|
|
|
|
|
|
|
type EraseFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
|
|
|
fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> {
|
|
|
|
async move {
|
|
|
|
for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
|
|
|
|
self.erase(address).await?
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
|
|
|
const READ_SIZE: usize = 4;
|
|
|
|
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
|
|
|
fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
|
|
async move { self.read(address as usize, data).await }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn capacity(&self) -> usize {
|
|
|
|
FLASH_SIZE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-11 01:04:59 +00:00
|
|
|
pub(crate) mod sealed {
|
2021-09-10 23:53:53 +00:00
|
|
|
use embassy::waitqueue::AtomicWaker;
|
|
|
|
|
2021-03-21 19:54:09 +00:00
|
|
|
use super::*;
|
2020-09-22 16:03:43 +00:00
|
|
|
|
2021-04-14 15:00:28 +00:00
|
|
|
pub struct State {
|
|
|
|
pub ready_waker: AtomicWaker,
|
|
|
|
}
|
|
|
|
impl State {
|
|
|
|
pub const fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
ready_waker: AtomicWaker::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-21 19:54:09 +00:00
|
|
|
pub trait Instance {
|
2021-04-14 15:00:28 +00:00
|
|
|
fn regs() -> &'static pac::qspi::RegisterBlock;
|
|
|
|
fn state() -> &'static State;
|
2020-09-22 16:03:43 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-21 19:54:09 +00:00
|
|
|
|
2021-05-14 22:05:32 +00:00
|
|
|
pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static {
|
2021-03-21 19:54:09 +00:00
|
|
|
type Interrupt: Interrupt;
|
|
|
|
}
|
|
|
|
|
2021-05-11 01:04:59 +00:00
|
|
|
macro_rules! impl_qspi {
|
|
|
|
($type:ident, $pac_type:ident, $irq:ident) => {
|
|
|
|
impl crate::qspi::sealed::Instance for peripherals::$type {
|
2021-04-14 15:00:28 +00:00
|
|
|
fn regs() -> &'static pac::qspi::RegisterBlock {
|
2021-05-11 01:04:59 +00:00
|
|
|
unsafe { &*pac::$pac_type::ptr() }
|
2021-03-21 19:54:09 +00:00
|
|
|
}
|
2021-05-11 01:04:59 +00:00
|
|
|
fn state() -> &'static crate::qspi::sealed::State {
|
|
|
|
static STATE: crate::qspi::sealed::State = crate::qspi::sealed::State::new();
|
2021-04-14 15:00:28 +00:00
|
|
|
&STATE
|
|
|
|
}
|
2021-03-21 19:54:09 +00:00
|
|
|
}
|
2021-05-11 01:04:59 +00:00
|
|
|
impl crate::qspi::Instance for peripherals::$type {
|
|
|
|
type Interrupt = crate::interrupt::$irq;
|
2021-03-21 19:54:09 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|