embassy/embassy-nrf/src/qspi.rs

386 lines
11 KiB
Rust
Raw Normal View History

2020-09-22 18:03:43 +02:00
use core::future::Future;
2021-03-21 20:54:09 +01:00
use core::marker::PhantomData;
2021-02-28 22:05:37 +01:00
use core::pin::Pin;
use core::task::Poll;
2020-10-31 23:03:09 +01:00
2021-03-21 20:54:09 +01:00
use embassy::interrupt::Interrupt;
2021-03-08 00:15:40 +01:00
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
2021-02-28 22:05:37 +01:00
use crate::fmt::{assert, assert_eq, *};
2021-03-21 20:54:09 +01:00
use crate::gpio::Pin as GpioPin;
2021-03-01 00:23:54 +01:00
use crate::interrupt::{self};
2021-03-21 20:54:09 +01:00
use crate::{pac, peripherals};
2020-09-22 18:03:43 +02:00
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::READOC_A as ReadOpcode;
pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
// 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
2021-03-02 00:32:23 +01:00
use embassy::traits::flash::{Error, Flash};
2021-03-21 20:54:09 +01:00
use embassy::util::{wake_on_interrupt, DropBomb, PeripheralBorrow, WakerRegistration};
2021-02-28 22:05:37 +01:00
use futures::future::poll_fn;
2020-09-22 18:03:43 +02:00
2020-11-27 18:42:59 +01:00
pub struct DeepPowerDownConfig {
pub enter_time: u16,
pub exit_time: u16,
}
2020-09-22 18:03:43 +02:00
pub struct Config {
pub xip_offset: u32,
pub read_opcode: ReadOpcode,
pub write_opcode: WriteOpcode,
pub write_page_size: WritePageSize,
2020-11-27 18:42:59 +01:00
pub deep_power_down: Option<DeepPowerDownConfig>,
2020-09-22 18:03:43 +02:00
}
2021-03-21 20:54:09 +01:00
pub struct Qspi<'d, T: Instance> {
peri: T,
2021-03-21 20:54:09 +01:00
irq: T::Interrupt,
phantom: PhantomData<&'d mut T>,
2021-02-28 22:05:37 +01:00
}
2021-03-21 20:54:09 +01:00
impl<'d, T: Instance> Qspi<'d, T> {
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() };
let r = qspi.regs();
for cnf in &[
sck.conf(),
csn.conf(),
io0.conf(),
io1.conf(),
io2.conf(),
io3.conf(),
] {
cnf.write(|w| w.dir().output().drive().h0h1());
}
2020-09-22 18:03:43 +02:00
2021-03-21 20:54:09 +01: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 18:03:43 +02:00
2021-03-21 20:54:09 +01:00
r.ifconfig0.write(|mut w| {
2020-11-27 18:42:59 +01:00
w = w.addrmode().variant(AddressMode::_24BIT);
if config.deep_power_down.is_some() {
w = w.dpmenable().enable();
} else {
w = w.dpmenable().disable();
}
w = w.ppsize().variant(config.write_page_size);
w = w.readoc().variant(config.read_opcode);
w = w.writeoc().variant(config.write_opcode);
2020-09-22 18:03:43 +02:00
w
});
2020-11-27 18:42:59 +01:00
if let Some(dpd) = &config.deep_power_down {
2021-03-21 20:54:09 +01:00
r.dpmdur.write(|mut w| unsafe {
2020-11-27 18:42:59 +01:00
w = w.enter().bits(dpd.enter_time);
w = w.exit().bits(dpd.exit_time);
w
})
}
2021-03-21 20:54:09 +01:00
r.ifconfig1.write(|w| {
2020-09-22 18:03:43 +02:00
let w = unsafe { w.sckdelay().bits(80) };
let w = w.dpmen().exit();
let w = w.spimode().mode0();
let w = unsafe { w.sckfreq().bits(3) };
w
});
2021-03-21 20:54:09 +01:00
r.xipoffset
2020-09-22 18:03:43 +02:00
.write(|w| unsafe { w.xipoffset().bits(config.xip_offset) });
// Enable it
2021-03-21 20:54:09 +01:00
r.enable.write(|w| w.enable().enabled());
2020-09-22 18:03:43 +02:00
2021-03-21 20:54:09 +01:00
r.events_ready.reset();
r.tasks_activate.write(|w| w.tasks_activate().bit(true));
while r.events_ready.read().bits() == 0 {}
r.events_ready.reset();
2020-09-22 18:03:43 +02:00
2021-02-28 22:05:37 +01:00
Self {
peri: qspi,
2021-03-21 20:54:09 +01:00
irq,
phantom: PhantomData,
2021-02-28 22:05:37 +01:00
}
2020-09-22 18:03:43 +02:00
}
2021-03-21 20:54:09 +01:00
pub fn sleep(mut self: Pin<&mut Self>) {
let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
2021-03-21 20:54:09 +01:00
info!("flash: sleeping");
info!("flash: state = {:?}", r.status.read().bits());
r.ifconfig1.modify(|_, w| w.dpmen().enter());
info!("flash: state = {:?}", r.status.read().bits());
cortex_m::asm::delay(1000000);
info!("flash: state = {:?}", r.status.read().bits());
r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
2020-11-27 18:42:59 +01:00
}
2021-03-21 20:54:09 +01:00
pub async fn custom_instruction(
mut self: Pin<&mut Self>,
2020-09-22 18:03:43 +02:00
opcode: u8,
2021-03-21 20:54:09 +01:00
req: &[u8],
resp: &mut [u8],
2021-02-14 01:41:36 +01:00
) -> Result<(), Error> {
let bomb = DropBomb::new();
2020-09-22 18:03:43 +02:00
2021-02-14 01:41:36 +01:00
assert!(req.len() <= 8);
assert!(resp.len() <= 8);
2020-09-22 18:03:43 +02:00
2021-02-14 01:41:36 +01:00
let mut dat0: u32 = 0;
let mut dat1: u32 = 0;
2020-09-22 18:03:43 +02:00
2021-02-14 01:41:36 +01:00
for i in 0..4 {
if i < req.len() {
dat0 |= (req[i] as u32) << (i * 8);
2020-09-22 18:03:43 +02:00
}
2021-02-14 01:41:36 +01:00
}
for i in 0..4 {
if i + 4 < req.len() {
dat1 |= (req[i + 4] as u32) << (i * 8);
2020-09-22 18:03:43 +02:00
}
2021-02-14 01:41:36 +01:00
}
2020-09-22 18:03:43 +02:00
2021-02-14 01:41:36 +01:00
let len = core::cmp::max(req.len(), resp.len()) as u8;
let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
2021-03-21 20:54:09 +01: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 01:41:36 +01:00
});
2020-09-22 18:03:43 +02:00
2021-02-28 22:05:37 +01:00
self.as_mut().wait_ready().await;
2020-09-22 18:03:43 +02:00
let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
2021-03-21 20:54:09 +01: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 18:03:43 +02:00
}
2021-03-21 20:54:09 +01:00
}
for i in 0..4 {
if i + 4 < resp.len() {
resp[i] = (dat1 >> (i * 8)) as u8;
2020-09-22 18:03:43 +02:00
}
2021-03-21 20:54:09 +01:00
}
2020-09-22 18:03:43 +02:00
2021-02-14 01:41:36 +01:00
bomb.defuse();
2020-09-22 18:03:43 +02:00
2021-02-14 01:41:36 +01:00
Ok(())
2020-09-22 18:03:43 +02:00
}
2021-02-28 22:05:37 +01:00
2021-03-21 20:54:09 +01:00
async fn wait_ready(self: Pin<&mut Self>) {
let this = unsafe { self.get_unchecked_mut() };
2021-02-28 22:05:37 +01:00
poll_fn(move |cx| {
let r = this.peri.regs();
2021-03-21 20:54:09 +01:00
if r.events_ready.read().bits() != 0 {
r.events_ready.reset();
return Poll::Ready(());
}
wake_on_interrupt(&mut this.irq, cx.waker());
Poll::Pending
2021-02-28 22:05:37 +01:00
})
2021-03-21 20:54:09 +01:00
.await
2021-02-28 22:05:37 +01:00
}
2020-09-22 18:03:43 +02:00
}
2021-03-21 20:54:09 +01:00
impl<'d, T: Instance> Flash for Qspi<'d, T> {
#[rustfmt::skip]
type ReadFuture<'a> where Self: '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;
2020-09-22 18:03:43 +02:00
2021-02-28 22:05:37 +01:00
fn read<'a>(
mut self: Pin<&'a mut Self>,
address: usize,
data: &'a mut [u8],
) -> Self::ReadFuture<'a> {
2020-09-22 18:03:43 +02:00
async move {
let bomb = DropBomb::new();
assert_eq!(data.as_ptr() as u32 % 4, 0);
assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0);
let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
2021-03-21 20:54:09 +01: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) });
r.events_ready.reset();
r.intenset.write(|w| w.ready().set());
r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
2021-02-28 22:05:37 +01:00
self.as_mut().wait_ready().await;
2020-09-22 18:03:43 +02:00
bomb.defuse();
Ok(())
}
}
2021-02-28 22:05:37 +01:00
fn write<'a>(
mut self: Pin<&'a mut Self>,
address: usize,
data: &'a [u8],
) -> Self::WriteFuture<'a> {
2020-09-22 18:03:43 +02:00
async move {
let bomb = DropBomb::new();
assert_eq!(data.as_ptr() as u32 % 4, 0);
assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0);
let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
2021-03-21 20:54:09 +01: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) });
r.events_ready.reset();
r.intenset.write(|w| w.ready().set());
r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
2021-02-28 22:05:37 +01:00
self.as_mut().wait_ready().await;
2020-09-22 18:03:43 +02:00
bomb.defuse();
Ok(())
}
}
2021-02-28 22:05:37 +01:00
fn erase<'a>(mut self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a> {
2020-09-22 18:03:43 +02:00
async move {
let bomb = DropBomb::new();
assert_eq!(address as u32 % 4096, 0);
let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
2021-03-21 20:54:09 +01:00
r.erase
.ptr
.write(|w| unsafe { w.ptr().bits(address as u32) });
r.erase.len.write(|w| w.len()._4kb());
2021-02-28 22:05:37 +01:00
2021-03-21 20:54:09 +01:00
r.events_ready.reset();
r.intenset.write(|w| w.ready().set());
r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
2020-09-22 18:03:43 +02:00
2021-02-28 22:05:37 +01:00
self.as_mut().wait_ready().await;
2020-09-22 18:03:43 +02:00
bomb.defuse();
Ok(())
}
}
fn size(&self) -> usize {
256 * 4096 // TODO
}
fn read_size(&self) -> usize {
4 // TODO
}
fn write_size(&self) -> usize {
4 // TODO
}
fn erase_size(&self) -> usize {
4096 // TODO
}
}
2021-03-21 20:54:09 +01:00
mod sealed {
use super::*;
2020-09-22 18:03:43 +02:00
2021-03-21 20:54:09 +01:00
pub trait Instance {
fn regs(&mut self) -> &pac::qspi::RegisterBlock;
2020-09-22 18:03:43 +02:00
}
}
2021-03-21 20:54:09 +01:00
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);