Port qspi to PeripheralMutex

This commit is contained in:
Dario Nieuwenhuis 2021-02-28 22:05:37 +01:00
parent 962fb95ff0
commit 7433dc1039
6 changed files with 187 additions and 114 deletions

View file

@ -6,6 +6,7 @@
"rust-analyzer.checkOnSave.allTargets": false, "rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.procMacro.enable": true, "rust-analyzer.procMacro.enable": true,
"rust-analyzer.cargo.loadOutDirsFromCheck": true, "rust-analyzer.cargo.loadOutDirsFromCheck": true,
"rust-analyzer.cargo.target": "thumbv7em-none-eabi",
"files.watcherExclude": { "files.watcherExclude": {
"**/.git/objects/**": true, "**/.git/objects/**": true,
"**/.git/subtree-cache/**": true, "**/.git/subtree-cache/**": true,

View file

@ -17,13 +17,13 @@ defmt-error = []
[dependencies] [dependencies]
embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } embassy = { version = "0.1.0", path = "../embassy", features = ["defmt"] }
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] } embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "52840"] }
defmt = "0.2.0" defmt = "0.2.0"
defmt-rtt = "0.2.0" defmt-rtt = "0.2.0"
cortex-m = "0.7.1" cortex-m = { version = "0.7.1", features = ["inline-asm"] }
cortex-m-rt = "0.6.13" cortex-m-rt = "0.6.13"
embedded-hal = { version = "0.2.4" } embedded-hal = { version = "0.2.4" }
panic-probe = "0.1.0" panic-probe = "0.1.0"

View file

@ -8,6 +8,7 @@ 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 nrf52840_hal::gpio; use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
@ -69,22 +70,32 @@ async fn run() {
}; };
let irq = interrupt::take!(QSPI); let irq = interrupt::take!(QSPI);
let mut q = qspi::Qspi::new(p.QSPI, irq, config); let q = qspi::Qspi::new(p.QSPI, irq, config);
pin_mut!(q);
let mut id = [1; 3]; let mut id = [1; 3];
q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); q.as_mut()
.custom_instruction(0x9F, &[], &mut id)
.await
.unwrap();
info!("id: {}", id); info!("id: {}", id);
// Read status register // Read status register
let mut status = [0; 1]; let mut status = [0; 1];
q.custom_instruction(0x05, &[], &mut status).await.unwrap(); q.as_mut()
.custom_instruction(0x05, &[], &mut status)
.await
.unwrap();
info!("status: {:?}", status[0]); info!("status: {:?}", status[0]);
if status[0] & 0x40 == 0 { if status[0] & 0x40 == 0 {
status[0] |= 0x40; status[0] |= 0x40;
q.custom_instruction(0x01, &status, &mut []).await.unwrap(); q.as_mut()
.custom_instruction(0x01, &status, &mut [])
.await
.unwrap();
info!("enabled quad in status"); info!("enabled quad in status");
} }
@ -95,19 +106,19 @@ async fn run() {
for i in 0..8 { for i in 0..8 {
info!("page {:?}: erasing... ", i); info!("page {:?}: erasing... ", i);
q.erase(i * PAGE_SIZE).await.unwrap(); q.as_mut().erase(i * PAGE_SIZE).await.unwrap();
for j in 0..PAGE_SIZE { for j in 0..PAGE_SIZE {
buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); buf.0[j] = pattern((j + i * PAGE_SIZE) as u32);
} }
info!("programming..."); info!("programming...");
q.write(i * PAGE_SIZE, &buf.0).await.unwrap(); q.as_mut().write(i * PAGE_SIZE, &buf.0).await.unwrap();
} }
for i in 0..8 { for i in 0..8 {
info!("page {:?}: reading... ", i); info!("page {:?}: reading... ", i);
q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); q.as_mut().read(i * PAGE_SIZE, &mut buf.0).await.unwrap();
info!("verifying..."); info!("verifying...");
for j in 0..PAGE_SIZE { for j in 0..PAGE_SIZE {

View file

@ -27,6 +27,7 @@ cortex-m-rt = "0.6.13"
cortex-m = "0.7.1" cortex-m = "0.7.1"
embedded-hal = { version = "0.2.4" } embedded-hal = { version = "0.2.4" }
embedded-dma = { version = "0.1.2" } embedded-dma = { version = "0.1.2" }
futures = { version = "0.3.5", default-features = false }
nrf52810-pac = { version = "0.9.0", optional = true } nrf52810-pac = { version = "0.9.0", optional = true }
nrf52811-pac = { version = "0.9.1", optional = true } nrf52811-pac = { version = "0.9.1", optional = true }

View file

@ -1,6 +1,9 @@
use crate::fmt::{assert, assert_eq, *};
use core::future::Future; use core::future::Future;
use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use crate::fmt::{assert, assert_eq, *};
use crate::hal::gpio::{Output, Pin as GpioPin, Port as GpioPort, PushPull}; use crate::hal::gpio::{Output, Pin as GpioPin, Port as GpioPort, PushPull};
use crate::interrupt::{self, Interrupt}; use crate::interrupt::{self, Interrupt};
use crate::pac::QSPI; use crate::pac::QSPI;
@ -9,6 +12,7 @@ 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;
pub use crate::pac::qspi::ifconfig0::READOC_A as ReadOpcode; pub use crate::pac::qspi::ifconfig0::READOC_A as ReadOpcode;
pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode; pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
use crate::util::peripheral::{PeripheralMutex, PeripheralState};
// TODO // TODO
// - config: // - config:
@ -21,7 +25,8 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
// - set gpio in high drive // - set gpio in high drive
use embassy::flash::{Error, Flash}; use embassy::flash::{Error, Flash};
use embassy::util::{DropBomb, Signal}; use embassy::util::{DropBomb, WakerRegistration};
use futures::future::poll_fn;
pub struct Pins { pub struct Pins {
pub sck: GpioPin<Output<PushPull>>, pub sck: GpioPin<Output<PushPull>>,
@ -46,8 +51,13 @@ pub struct Config {
pub deep_power_down: Option<DeepPowerDownConfig>, pub deep_power_down: Option<DeepPowerDownConfig>,
} }
pub struct Qspi { struct State {
inner: QSPI, inner: QSPI,
waker: WakerRegistration,
}
pub struct Qspi {
inner: PeripheralMutex<State>,
} }
fn port_bit(port: GpioPort) -> bool { fn port_bit(port: GpioPort) -> bool {
@ -142,32 +152,34 @@ impl Qspi {
while qspi.events_ready.read().bits() == 0 {} while qspi.events_ready.read().bits() == 0 {}
qspi.events_ready.reset(); qspi.events_ready.reset();
// Enable READY interrupt Self {
SIGNAL.reset(); inner: PeripheralMutex::new(
qspi.intenset.write(|w| w.ready().set()); State {
inner: qspi,
irq.set_handler(irq_handler); waker: WakerRegistration::new(),
irq.unpend(); },
irq.enable(); irq,
),
Self { inner: qspi } }
} }
pub fn sleep(&mut self) { pub fn sleep(self: Pin<&mut Self>) {
info!("flash: sleeping"); self.inner().with(|s, _| {
info!("flash: state = {:?}", self.inner.status.read().bits()); info!("flash: sleeping");
self.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); info!("flash: state = {:?}", s.inner.status.read().bits());
info!("flash: state = {:?}", self.inner.status.read().bits()); s.inner.ifconfig1.modify(|_, w| w.dpmen().enter());
cortex_m::asm::delay(1000000); info!("flash: state = {:?}", s.inner.status.read().bits());
info!("flash: state = {:?}", self.inner.status.read().bits()); cortex_m::asm::delay(1000000);
info!("flash: state = {:?}", s.inner.status.read().bits());
self.inner s.inner
.tasks_deactivate .tasks_deactivate
.write(|w| w.tasks_deactivate().set_bit()); .write(|w| w.tasks_deactivate().set_bit());
});
} }
pub async fn custom_instruction<'a>( pub async fn custom_instruction<'a>(
&'a mut self, mut self: Pin<&'a mut Self>,
opcode: u8, opcode: u8,
req: &'a [u8], req: &'a [u8],
resp: &'a mut [u8], resp: &'a mut [u8],
@ -193,40 +205,68 @@ 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.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); self.as_mut().inner().with(|s, _| {
self.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); s.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
self.inner.events_ready.reset(); s.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
self.inner.cinstrconf.write(|w| {
let w = unsafe { w.opcode().bits(opcode) }; s.inner.events_ready.reset();
let w = unsafe { w.length().bits(len + 1) }; s.inner.intenset.write(|w| w.ready().set());
let w = w.lio2().bit(true);
let w = w.lio3().bit(true); s.inner.cinstrconf.write(|w| {
let w = w.wipwait().bit(true); let w = unsafe { w.opcode().bits(opcode) };
let w = w.wren().bit(true); let w = unsafe { w.length().bits(len + 1) };
let w = w.lfen().bit(false); let w = w.lio2().bit(true);
let w = w.lfstop().bit(false); let w = w.lio3().bit(true);
w 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
});
}); });
SIGNAL.wait().await; self.as_mut().wait_ready().await;
let dat0 = self.inner.cinstrdat0.read().bits(); self.as_mut().inner().with(|s, _| {
let dat1 = self.inner.cinstrdat1.read().bits(); let dat0 = s.inner.cinstrdat0.read().bits();
for i in 0..4 { let dat1 = s.inner.cinstrdat1.read().bits();
if i < resp.len() { for i in 0..4 {
resp[i] = (dat0 >> (i * 8)) as u8; if i < resp.len() {
resp[i] = (dat0 >> (i * 8)) as u8;
}
} }
} for i in 0..4 {
for i in 0..4 { if i + 4 < resp.len() {
if i + 4 < resp.len() { 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>> {
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
}
pub fn free(self: Pin<&mut Self>) -> (QSPI, interrupt::QSPI) {
let (state, irq) = self.inner().free();
(state.inner, irq)
}
fn wait_ready<'a>(mut self: Pin<&'a mut Self>) -> impl Future<Output = ()> + 'a {
poll_fn(move |cx| {
self.as_mut().inner().with(|s, irq| {
if s.inner.events_ready.read().bits() != 0 {
return Poll::Ready(());
}
s.waker.register(cx.waker());
Poll::Pending
})
})
}
} }
impl Flash for Qspi { impl Flash for Qspi {
@ -234,7 +274,11 @@ impl Flash for Qspi {
type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
type ErasePageFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type ErasePageFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
fn read<'a>(&'a mut self, address: usize, data: &'a mut [u8]) -> Self::ReadFuture<'a> { fn read<'a>(
mut self: Pin<&'a mut Self>,
address: usize,
data: &'a mut [u8],
) -> Self::ReadFuture<'a> {
async move { async move {
let bomb = DropBomb::new(); let bomb = DropBomb::new();
@ -242,25 +286,28 @@ 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.inner self.as_mut().inner().with(|s, _| {
.read s.inner
.src .read
.write(|w| unsafe { w.src().bits(address as u32) }); .src
self.inner .write(|w| unsafe { w.src().bits(address as u32) });
.read s.inner
.dst .read
.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); .dst
self.inner .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
.read s.inner
.cnt .read
.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); .cnt
.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
self.inner.events_ready.reset(); s.inner.events_ready.reset();
self.inner s.inner.intenset.write(|w| w.ready().set());
.tasks_readstart s.inner
.write(|w| w.tasks_readstart().bit(true)); .tasks_readstart
.write(|w| w.tasks_readstart().bit(true));
});
SIGNAL.wait().await; self.as_mut().wait_ready().await;
bomb.defuse(); bomb.defuse();
@ -268,7 +315,11 @@ impl Flash for Qspi {
} }
} }
fn write<'a>(&'a mut self, address: usize, data: &'a [u8]) -> Self::WriteFuture<'a> { fn write<'a>(
mut self: Pin<&'a mut Self>,
address: usize,
data: &'a [u8],
) -> Self::WriteFuture<'a> {
async move { async move {
let bomb = DropBomb::new(); let bomb = DropBomb::new();
@ -276,25 +327,28 @@ 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.inner self.as_mut().inner().with(|s, _| {
.write s.inner
.src .write
.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); .src
self.inner .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
.write s.inner
.dst .write
.write(|w| unsafe { w.dst().bits(address as u32) }); .dst
self.inner .write(|w| unsafe { w.dst().bits(address as u32) });
.write s.inner
.cnt .write
.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); .cnt
.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
self.inner.events_ready.reset(); s.inner.events_ready.reset();
self.inner s.inner.intenset.write(|w| w.ready().set());
.tasks_writestart s.inner
.write(|w| w.tasks_writestart().bit(true)); .tasks_writestart
.write(|w| w.tasks_writestart().bit(true));
});
SIGNAL.wait().await; self.as_mut().wait_ready().await;
bomb.defuse(); bomb.defuse();
@ -302,23 +356,27 @@ impl Flash for Qspi {
} }
} }
fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a> { fn erase<'a>(mut self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a> {
async move { async move {
let bomb = DropBomb::new(); let bomb = DropBomb::new();
assert_eq!(address as u32 % 4096, 0); assert_eq!(address as u32 % 4096, 0);
self.inner self.as_mut().inner().with(|s, _| {
.erase s.inner
.ptr .erase
.write(|w| unsafe { w.ptr().bits(address as u32) }); .ptr
self.inner.erase.len.write(|w| w.len()._4kb()); .write(|w| unsafe { w.ptr().bits(address as u32) });
self.inner.events_ready.reset(); s.inner.erase.len.write(|w| w.len()._4kb());
self.inner
.tasks_erasestart
.write(|w| w.tasks_erasestart().bit(true));
SIGNAL.wait().await; s.inner.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set());
s.inner
.tasks_erasestart
.write(|w| w.tasks_erasestart().bit(true));
});
self.as_mut().wait_ready().await;
bomb.defuse(); bomb.defuse();
@ -343,13 +401,13 @@ impl Flash for Qspi {
} }
} }
static SIGNAL: Signal<()> = Signal::new(); impl PeripheralState for State {
type Interrupt = interrupt::QSPI;
unsafe fn irq_handler(_ctx: *mut ()) { fn on_interrupt(&mut self) {
let p = crate::pac::Peripherals::steal().QSPI; if self.inner.events_ready.read().bits() != 0 {
if p.events_ready.read().events_ready().bit_is_set() { self.inner.intenclr.write(|w| w.ready().clear());
p.events_ready.reset(); self.waker.wake()
info!("qspi ready"); }
SIGNAL.signal(());
} }
} }

View file

@ -1,4 +1,5 @@
use core::future::Future; use core::future::Future;
use core::pin::Pin;
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -18,18 +19,19 @@ pub trait Flash {
/// ///
/// address must be a multiple of self.read_size(). /// address must be a multiple of self.read_size().
/// buf.len() must be a multiple of self.read_size(). /// buf.len() must be a multiple of self.read_size().
fn read<'a>(&'a mut self, address: usize, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; fn read<'a>(self: Pin<&'a mut Self>, address: usize, buf: &'a mut [u8])
-> Self::ReadFuture<'a>;
/// Writes data to the flash device. /// Writes data to the flash device.
/// ///
/// address must be a multiple of self.write_size(). /// address must be a multiple of self.write_size().
/// buf.len() must be a multiple of self.write_size(). /// buf.len() must be a multiple of self.write_size().
fn write<'a>(&'a mut self, address: usize, buf: &'a [u8]) -> Self::WriteFuture<'a>; fn write<'a>(self: Pin<&'a mut Self>, address: usize, buf: &'a [u8]) -> Self::WriteFuture<'a>;
/// Erases a single page from the flash device. /// Erases a single page from the flash device.
/// ///
/// address must be a multiple of self.erase_size(). /// address must be a multiple of self.erase_size().
fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a>; fn erase<'a>(self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a>;
/// Returns the total size, in bytes. /// Returns the total size, in bytes.
/// This is not guaranteed to be a power of 2. /// This is not guaranteed to be a power of 2.