diff --git a/.vscode/settings.json b/.vscode/settings.json index 8915126a4..19efb1373 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "rust-analyzer.checkOnSave.allTargets": false, "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.loadOutDirsFromCheck": true, + "rust-analyzer.cargo.target": "thumbv7em-none-eabi", "files.watcherExclude": { "**/.git/objects/**": true, "**/.git/subtree-cache/**": true, diff --git a/embassy-nrf-examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml index 364fd8a51..b7e4c340c 100644 --- a/embassy-nrf-examples/Cargo.toml +++ b/embassy-nrf-examples/Cargo.toml @@ -17,13 +17,13 @@ defmt-error = [] [dependencies] -embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } -embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] } +embassy = { version = "0.1.0", path = "../embassy", features = ["defmt"] } +embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "52840"] } defmt = "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" embedded-hal = { version = "0.2.4" } panic-probe = "0.1.0" diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index 850681d7c..790dedc91 100644 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs @@ -8,6 +8,7 @@ use example_common::*; use cortex_m_rt::entry; use defmt::{assert_eq, panic}; +use futures::pin_mut; use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; @@ -69,22 +70,32 @@ async fn run() { }; 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]; - q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); + q.as_mut() + .custom_instruction(0x9F, &[], &mut id) + .await + .unwrap(); info!("id: {}", id); // Read status register 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]); if status[0] & 0x40 == 0 { 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"); } @@ -95,19 +106,19 @@ async fn run() { for i in 0..8 { 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 { buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); } 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 { 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..."); for j in 0..PAGE_SIZE { diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index ddd2dc31a..6324792fc 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -27,6 +27,7 @@ cortex-m-rt = "0.6.13" cortex-m = "0.7.1" embedded-hal = { version = "0.2.4" } embedded-dma = { version = "0.1.2" } +futures = { version = "0.3.5", default-features = false } nrf52810-pac = { version = "0.9.0", optional = true } nrf52811-pac = { version = "0.9.1", optional = true } diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 300b32ad5..c238a6c82 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -1,6 +1,9 @@ -use crate::fmt::{assert, assert_eq, *}; 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::interrupt::{self, Interrupt}; 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::READOC_A as ReadOpcode; pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode; +use crate::util::peripheral::{PeripheralMutex, PeripheralState}; // TODO // - config: @@ -21,7 +25,8 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode; // - set gpio in high drive use embassy::flash::{Error, Flash}; -use embassy::util::{DropBomb, Signal}; +use embassy::util::{DropBomb, WakerRegistration}; +use futures::future::poll_fn; pub struct Pins { pub sck: GpioPin>, @@ -46,8 +51,13 @@ pub struct Config { pub deep_power_down: Option, } -pub struct Qspi { +struct State { inner: QSPI, + waker: WakerRegistration, +} + +pub struct Qspi { + inner: PeripheralMutex, } fn port_bit(port: GpioPort) -> bool { @@ -142,32 +152,34 @@ impl Qspi { while qspi.events_ready.read().bits() == 0 {} qspi.events_ready.reset(); - // Enable READY interrupt - SIGNAL.reset(); - qspi.intenset.write(|w| w.ready().set()); - - irq.set_handler(irq_handler); - irq.unpend(); - irq.enable(); - - Self { inner: qspi } + Self { + inner: PeripheralMutex::new( + State { + inner: qspi, + waker: WakerRegistration::new(), + }, + irq, + ), + } } - pub fn sleep(&mut self) { - info!("flash: sleeping"); - info!("flash: state = {:?}", self.inner.status.read().bits()); - self.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); - info!("flash: state = {:?}", self.inner.status.read().bits()); - cortex_m::asm::delay(1000000); - info!("flash: state = {:?}", self.inner.status.read().bits()); + pub fn sleep(self: Pin<&mut Self>) { + self.inner().with(|s, _| { + info!("flash: sleeping"); + info!("flash: state = {:?}", s.inner.status.read().bits()); + s.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); + info!("flash: state = {:?}", s.inner.status.read().bits()); + cortex_m::asm::delay(1000000); + info!("flash: state = {:?}", s.inner.status.read().bits()); - self.inner - .tasks_deactivate - .write(|w| w.tasks_deactivate().set_bit()); + s.inner + .tasks_deactivate + .write(|w| w.tasks_deactivate().set_bit()); + }); } pub async fn custom_instruction<'a>( - &'a mut self, + mut self: Pin<&'a mut Self>, opcode: u8, req: &'a [u8], resp: &'a mut [u8], @@ -193,40 +205,68 @@ impl Qspi { let len = core::cmp::max(req.len(), resp.len()) as u8; - self.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); - self.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); - self.inner.events_ready.reset(); - self.inner.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 + self.as_mut().inner().with(|s, _| { + s.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); + s.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); + + s.inner.events_ready.reset(); + s.inner.intenset.write(|w| w.ready().set()); + + s.inner.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 + }); }); - SIGNAL.wait().await; + self.as_mut().wait_ready().await; - let dat0 = self.inner.cinstrdat0.read().bits(); - let dat1 = self.inner.cinstrdat1.read().bits(); - for i in 0..4 { - if i < resp.len() { - resp[i] = (dat0 >> (i * 8)) as u8; + self.as_mut().inner().with(|s, _| { + let dat0 = s.inner.cinstrdat0.read().bits(); + let dat1 = s.inner.cinstrdat1.read().bits(); + for i in 0..4 { + if i < resp.len() { + resp[i] = (dat0 >> (i * 8)) as u8; + } } - } - for i in 0..4 { - if i + 4 < resp.len() { - resp[i] = (dat1 >> (i * 8)) as u8; + for i in 0..4 { + if i + 4 < resp.len() { + resp[i] = (dat1 >> (i * 8)) as u8; + } } - } + }); bomb.defuse(); Ok(()) } + + fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex> { + 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 + '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 { @@ -234,7 +274,11 @@ impl Flash for Qspi { type WriteFuture<'a> = impl Future> + 'a; type ErasePageFuture<'a> = impl Future> + '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 { let bomb = DropBomb::new(); @@ -242,25 +286,28 @@ impl Flash for Qspi { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address as u32 % 4, 0); - self.inner - .read - .src - .write(|w| unsafe { w.src().bits(address as u32) }); - self.inner - .read - .dst - .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); - self.inner - .read - .cnt - .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + self.as_mut().inner().with(|s, _| { + s.inner + .read + .src + .write(|w| unsafe { w.src().bits(address as u32) }); + s.inner + .read + .dst + .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); + s.inner + .read + .cnt + .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); - self.inner.events_ready.reset(); - self.inner - .tasks_readstart - .write(|w| w.tasks_readstart().bit(true)); + s.inner.events_ready.reset(); + s.inner.intenset.write(|w| w.ready().set()); + s.inner + .tasks_readstart + .write(|w| w.tasks_readstart().bit(true)); + }); - SIGNAL.wait().await; + self.as_mut().wait_ready().await; 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 { let bomb = DropBomb::new(); @@ -276,25 +327,28 @@ impl Flash for Qspi { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address as u32 % 4, 0); - self.inner - .write - .src - .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); - self.inner - .write - .dst - .write(|w| unsafe { w.dst().bits(address as u32) }); - self.inner - .write - .cnt - .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + self.as_mut().inner().with(|s, _| { + s.inner + .write + .src + .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); + s.inner + .write + .dst + .write(|w| unsafe { w.dst().bits(address as u32) }); + s.inner + .write + .cnt + .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); - self.inner.events_ready.reset(); - self.inner - .tasks_writestart - .write(|w| w.tasks_writestart().bit(true)); + s.inner.events_ready.reset(); + s.inner.intenset.write(|w| w.ready().set()); + s.inner + .tasks_writestart + .write(|w| w.tasks_writestart().bit(true)); + }); - SIGNAL.wait().await; + self.as_mut().wait_ready().await; 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 { let bomb = DropBomb::new(); assert_eq!(address as u32 % 4096, 0); - self.inner - .erase - .ptr - .write(|w| unsafe { w.ptr().bits(address as u32) }); - self.inner.erase.len.write(|w| w.len()._4kb()); - self.inner.events_ready.reset(); - self.inner - .tasks_erasestart - .write(|w| w.tasks_erasestart().bit(true)); + self.as_mut().inner().with(|s, _| { + s.inner + .erase + .ptr + .write(|w| unsafe { w.ptr().bits(address as u32) }); + s.inner.erase.len.write(|w| w.len()._4kb()); - 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(); @@ -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 ()) { - let p = crate::pac::Peripherals::steal().QSPI; - if p.events_ready.read().events_ready().bit_is_set() { - p.events_ready.reset(); - info!("qspi ready"); - SIGNAL.signal(()); + fn on_interrupt(&mut self) { + if self.inner.events_ready.read().bits() != 0 { + self.inner.intenclr.write(|w| w.ready().clear()); + self.waker.wake() + } } } diff --git a/embassy/src/flash.rs b/embassy/src/flash.rs index 5866fdf05..145cc7684 100644 --- a/embassy/src/flash.rs +++ b/embassy/src/flash.rs @@ -1,4 +1,5 @@ use core::future::Future; +use core::pin::Pin; #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -18,18 +19,19 @@ pub trait Flash { /// /// address 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. /// /// address 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. /// /// 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. /// This is not guaranteed to be a power of 2.