diff options
| -rw-r--r-- | embassy-nrf-examples/src/bin/qspi.rs | 25 | ||||
| -rw-r--r-- | embassy-nrf/src/qspi.rs | 99 | ||||
| -rw-r--r-- | embassy-traits/src/flash.rs | 7 |
3 files changed, 66 insertions, 65 deletions
diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index 27dd28d72..28cde6e51 100644 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs | |||
| @@ -14,7 +14,6 @@ use embassy::traits::flash::Flash; | |||
| 14 | use embassy_nrf::Peripherals; | 14 | use embassy_nrf::Peripherals; |
| 15 | use embassy_nrf::{interrupt, qspi}; | 15 | use embassy_nrf::{interrupt, qspi}; |
| 16 | use example_common::*; | 16 | use example_common::*; |
| 17 | use futures::pin_mut; | ||
| 18 | 17 | ||
| 19 | const PAGE_SIZE: usize = 4096; | 18 | const PAGE_SIZE: usize = 4096; |
| 20 | 19 | ||
| @@ -36,32 +35,22 @@ async fn main(spawner: Spawner) { | |||
| 36 | 35 | ||
| 37 | let config = qspi::Config::default(); | 36 | let config = qspi::Config::default(); |
| 38 | let irq = interrupt::take!(QSPI); | 37 | let irq = interrupt::take!(QSPI); |
| 39 | let q = qspi::Qspi::new(p.QSPI, irq, sck, csn, io0, io1, io2, io3, config); | 38 | let mut q = qspi::Qspi::new(p.QSPI, irq, sck, csn, io0, io1, io2, io3, config); |
| 40 | pin_mut!(q); | ||
| 41 | 39 | ||
| 42 | let mut id = [1; 3]; | 40 | let mut id = [1; 3]; |
| 43 | q.as_mut() | 41 | q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); |
| 44 | .custom_instruction(0x9F, &[], &mut id) | ||
| 45 | .await | ||
| 46 | .unwrap(); | ||
| 47 | info!("id: {}", id); | 42 | info!("id: {}", id); |
| 48 | 43 | ||
| 49 | // Read status register | 44 | // Read status register |
| 50 | let mut status = [4; 1]; | 45 | let mut status = [4; 1]; |
| 51 | q.as_mut() | 46 | q.custom_instruction(0x05, &[], &mut status).await.unwrap(); |
| 52 | .custom_instruction(0x05, &[], &mut status) | ||
| 53 | .await | ||
| 54 | .unwrap(); | ||
| 55 | 47 | ||
| 56 | info!("status: {:?}", status[0]); | 48 | info!("status: {:?}", status[0]); |
| 57 | 49 | ||
| 58 | if status[0] & 0x40 == 0 { | 50 | if status[0] & 0x40 == 0 { |
| 59 | status[0] |= 0x40; | 51 | status[0] |= 0x40; |
| 60 | 52 | ||
| 61 | q.as_mut() | 53 | q.custom_instruction(0x01, &status, &mut []).await.unwrap(); |
| 62 | .custom_instruction(0x01, &status, &mut []) | ||
| 63 | .await | ||
| 64 | .unwrap(); | ||
| 65 | 54 | ||
| 66 | info!("enabled quad in status"); | 55 | info!("enabled quad in status"); |
| 67 | } | 56 | } |
| @@ -72,19 +61,19 @@ async fn main(spawner: Spawner) { | |||
| 72 | 61 | ||
| 73 | for i in 0..8 { | 62 | for i in 0..8 { |
| 74 | info!("page {:?}: erasing... ", i); | 63 | info!("page {:?}: erasing... ", i); |
| 75 | q.as_mut().erase(i * PAGE_SIZE).await.unwrap(); | 64 | q.erase(i * PAGE_SIZE).await.unwrap(); |
| 76 | 65 | ||
| 77 | for j in 0..PAGE_SIZE { | 66 | for j in 0..PAGE_SIZE { |
| 78 | buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); | 67 | buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); |
| 79 | } | 68 | } |
| 80 | 69 | ||
| 81 | info!("programming..."); | 70 | info!("programming..."); |
| 82 | q.as_mut().write(i * PAGE_SIZE, &buf.0).await.unwrap(); | 71 | q.write(i * PAGE_SIZE, &buf.0).await.unwrap(); |
| 83 | } | 72 | } |
| 84 | 73 | ||
| 85 | for i in 0..8 { | 74 | for i in 0..8 { |
| 86 | info!("page {:?}: reading... ", i); | 75 | info!("page {:?}: reading... ", i); |
| 87 | q.as_mut().read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); | 76 | q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); |
| 88 | 77 | ||
| 89 | info!("verifying..."); | 78 | info!("verifying..."); |
| 90 | for j in 0..PAGE_SIZE { | 79 | for j in 0..PAGE_SIZE { |
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 033c9e012..d682c1b8c 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | use core::future::Future; | 1 | use core::future::Future; |
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::pin::Pin; | ||
| 4 | use core::task::Poll; | 3 | use core::task::Poll; |
| 5 | 4 | use embassy::interrupt::{Interrupt, InterruptExt}; | |
| 6 | use embassy::interrupt::Interrupt; | 5 | use embassy::traits::flash::{Error, Flash}; |
| 7 | use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; | 6 | use embassy::util::{AtomicWaker, DropBomb, PeripheralBorrow}; |
| 8 | use embassy_extras::unborrow; | 7 | use embassy_extras::unborrow; |
| 8 | use futures::future::poll_fn; | ||
| 9 | 9 | ||
| 10 | use crate::fmt::{assert, assert_eq, *}; | 10 | use crate::fmt::{assert, assert_eq, *}; |
| 11 | use crate::gpio::Pin as GpioPin; | 11 | use crate::gpio::Pin as GpioPin; |
| @@ -27,10 +27,6 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode; | |||
| 27 | // - activate/deactivate | 27 | // - activate/deactivate |
| 28 | // - set gpio in high drive | 28 | // - set gpio in high drive |
| 29 | 29 | ||
| 30 | use embassy::traits::flash::{Error, Flash}; | ||
| 31 | use embassy::util::{wake_on_interrupt, DropBomb, PeripheralBorrow, WakerRegistration}; | ||
| 32 | use futures::future::poll_fn; | ||
| 33 | |||
| 34 | pub struct DeepPowerDownConfig { | 30 | pub struct DeepPowerDownConfig { |
| 35 | pub enter_time: u16, | 31 | pub enter_time: u16, |
| 36 | pub exit_time: u16, | 32 | pub exit_time: u16, |
| @@ -77,7 +73,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 77 | ) -> Self { | 73 | ) -> Self { |
| 78 | unborrow!(qspi, irq, sck, csn, io0, io1, io2, io3); | 74 | unborrow!(qspi, irq, sck, csn, io0, io1, io2, io3); |
| 79 | 75 | ||
| 80 | let r = qspi.regs(); | 76 | let r = T::regs(); |
| 81 | 77 | ||
| 82 | for cnf in &[ | 78 | for cnf in &[ |
| 83 | sck.conf(), | 79 | sck.conf(), |
| @@ -137,6 +133,10 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 137 | while r.events_ready.read().bits() == 0 {} | 133 | while r.events_ready.read().bits() == 0 {} |
| 138 | r.events_ready.reset(); | 134 | r.events_ready.reset(); |
| 139 | 135 | ||
| 136 | irq.set_handler(Self::on_interrupt); | ||
| 137 | irq.unpend(); | ||
| 138 | irq.enable(); | ||
| 139 | |||
| 140 | Self { | 140 | Self { |
| 141 | peri: qspi, | 141 | peri: qspi, |
| 142 | irq, | 142 | irq, |
| @@ -144,8 +144,18 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 144 | } | 144 | } |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | pub fn sleep(mut self: Pin<&mut Self>) { | 147 | fn on_interrupt(_: *mut ()) { |
| 148 | let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); | 148 | let r = T::regs(); |
| 149 | let s = T::state(); | ||
| 150 | |||
| 151 | if r.events_ready.read().bits() != 0 { | ||
| 152 | s.ready_waker.wake(); | ||
| 153 | r.intenclr.write(|w| w.ready().clear()); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | pub fn sleep(&mut self) { | ||
| 158 | let r = T::regs(); | ||
| 149 | 159 | ||
| 150 | info!("flash: sleeping"); | 160 | info!("flash: sleeping"); |
| 151 | info!("flash: state = {:?}", r.status.read().bits()); | 161 | info!("flash: state = {:?}", r.status.read().bits()); |
| @@ -158,7 +168,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 158 | } | 168 | } |
| 159 | 169 | ||
| 160 | pub async fn custom_instruction( | 170 | pub async fn custom_instruction( |
| 161 | mut self: Pin<&mut Self>, | 171 | &mut self, |
| 162 | opcode: u8, | 172 | opcode: u8, |
| 163 | req: &[u8], | 173 | req: &[u8], |
| 164 | resp: &mut [u8], | 174 | resp: &mut [u8], |
| @@ -184,7 +194,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 184 | 194 | ||
| 185 | let len = core::cmp::max(req.len(), resp.len()) as u8; | 195 | let len = core::cmp::max(req.len(), resp.len()) as u8; |
| 186 | 196 | ||
| 187 | let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); | 197 | let r = T::regs(); |
| 188 | r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); | 198 | r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); |
| 189 | r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); | 199 | r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); |
| 190 | 200 | ||
| @@ -203,9 +213,9 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 203 | w | 213 | w |
| 204 | }); | 214 | }); |
| 205 | 215 | ||
| 206 | self.as_mut().wait_ready().await; | 216 | self.wait_ready().await; |
| 207 | 217 | ||
| 208 | let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); | 218 | let r = T::regs(); |
| 209 | 219 | ||
| 210 | let dat0 = r.cinstrdat0.read().bits(); | 220 | let dat0 = r.cinstrdat0.read().bits(); |
| 211 | let dat1 = r.cinstrdat1.read().bits(); | 221 | let dat1 = r.cinstrdat1.read().bits(); |
| @@ -225,19 +235,14 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 225 | Ok(()) | 235 | Ok(()) |
| 226 | } | 236 | } |
| 227 | 237 | ||
| 228 | async fn wait_ready(self: Pin<&mut Self>) { | 238 | async fn wait_ready(&mut self) { |
| 229 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 230 | |||
| 231 | poll_fn(move |cx| { | 239 | poll_fn(move |cx| { |
| 232 | let r = this.peri.regs(); | 240 | let r = T::regs(); |
| 233 | 241 | let s = T::state(); | |
| 242 | s.ready_waker.register(cx.waker()); | ||
| 234 | if r.events_ready.read().bits() != 0 { | 243 | if r.events_ready.read().bits() != 0 { |
| 235 | r.events_ready.reset(); | ||
| 236 | return Poll::Ready(()); | 244 | return Poll::Ready(()); |
| 237 | } | 245 | } |
| 238 | |||
| 239 | wake_on_interrupt(&mut this.irq, cx.waker()); | ||
| 240 | |||
| 241 | Poll::Pending | 246 | Poll::Pending |
| 242 | }) | 247 | }) |
| 243 | .await | 248 | .await |
| @@ -252,11 +257,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 252 | #[rustfmt::skip] | 257 | #[rustfmt::skip] |
| 253 | type ErasePageFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; | 258 | type ErasePageFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; |
| 254 | 259 | ||
| 255 | fn read<'a>( | 260 | fn read<'a>(&'a mut self, address: usize, data: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 256 | mut self: Pin<&'a mut Self>, | ||
| 257 | address: usize, | ||
| 258 | data: &'a mut [u8], | ||
| 259 | ) -> Self::ReadFuture<'a> { | ||
| 260 | async move { | 261 | async move { |
| 261 | let bomb = DropBomb::new(); | 262 | let bomb = DropBomb::new(); |
| 262 | 263 | ||
| @@ -264,7 +265,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 264 | assert_eq!(data.len() as u32 % 4, 0); | 265 | assert_eq!(data.len() as u32 % 4, 0); |
| 265 | assert_eq!(address as u32 % 4, 0); | 266 | assert_eq!(address as u32 % 4, 0); |
| 266 | 267 | ||
| 267 | let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); | 268 | let r = T::regs(); |
| 268 | 269 | ||
| 269 | r.read | 270 | r.read |
| 270 | .src | 271 | .src |
| @@ -280,7 +281,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 280 | r.intenset.write(|w| w.ready().set()); | 281 | r.intenset.write(|w| w.ready().set()); |
| 281 | r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); | 282 | r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); |
| 282 | 283 | ||
| 283 | self.as_mut().wait_ready().await; | 284 | self.wait_ready().await; |
| 284 | 285 | ||
| 285 | bomb.defuse(); | 286 | bomb.defuse(); |
| 286 | 287 | ||
| @@ -288,11 +289,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 288 | } | 289 | } |
| 289 | } | 290 | } |
| 290 | 291 | ||
| 291 | fn write<'a>( | 292 | fn write<'a>(&'a mut self, address: usize, data: &'a [u8]) -> Self::WriteFuture<'a> { |
| 292 | mut self: Pin<&'a mut Self>, | ||
| 293 | address: usize, | ||
| 294 | data: &'a [u8], | ||
| 295 | ) -> Self::WriteFuture<'a> { | ||
| 296 | async move { | 293 | async move { |
| 297 | let bomb = DropBomb::new(); | 294 | let bomb = DropBomb::new(); |
| 298 | 295 | ||
| @@ -300,7 +297,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 300 | assert_eq!(data.len() as u32 % 4, 0); | 297 | assert_eq!(data.len() as u32 % 4, 0); |
| 301 | assert_eq!(address as u32 % 4, 0); | 298 | assert_eq!(address as u32 % 4, 0); |
| 302 | 299 | ||
| 303 | let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); | 300 | let r = T::regs(); |
| 304 | r.write | 301 | r.write |
| 305 | .src | 302 | .src |
| 306 | .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); | 303 | .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); |
| @@ -315,7 +312,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 315 | r.intenset.write(|w| w.ready().set()); | 312 | r.intenset.write(|w| w.ready().set()); |
| 316 | r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); | 313 | r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); |
| 317 | 314 | ||
| 318 | self.as_mut().wait_ready().await; | 315 | self.wait_ready().await; |
| 319 | 316 | ||
| 320 | bomb.defuse(); | 317 | bomb.defuse(); |
| 321 | 318 | ||
| @@ -323,13 +320,13 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 323 | } | 320 | } |
| 324 | } | 321 | } |
| 325 | 322 | ||
| 326 | fn erase<'a>(mut self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a> { | 323 | fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a> { |
| 327 | async move { | 324 | async move { |
| 328 | let bomb = DropBomb::new(); | 325 | let bomb = DropBomb::new(); |
| 329 | 326 | ||
| 330 | assert_eq!(address as u32 % 4096, 0); | 327 | assert_eq!(address as u32 % 4096, 0); |
| 331 | 328 | ||
| 332 | let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); | 329 | let r = T::regs(); |
| 333 | r.erase | 330 | r.erase |
| 334 | .ptr | 331 | .ptr |
| 335 | .write(|w| unsafe { w.ptr().bits(address as u32) }); | 332 | .write(|w| unsafe { w.ptr().bits(address as u32) }); |
| @@ -339,7 +336,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 339 | r.intenset.write(|w| w.ready().set()); | 336 | r.intenset.write(|w| w.ready().set()); |
| 340 | r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); | 337 | r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); |
| 341 | 338 | ||
| 342 | self.as_mut().wait_ready().await; | 339 | self.wait_ready().await; |
| 343 | 340 | ||
| 344 | bomb.defuse(); | 341 | bomb.defuse(); |
| 345 | 342 | ||
| @@ -367,8 +364,20 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | |||
| 367 | mod sealed { | 364 | mod sealed { |
| 368 | use super::*; | 365 | use super::*; |
| 369 | 366 | ||
| 367 | pub struct State { | ||
| 368 | pub ready_waker: AtomicWaker, | ||
| 369 | } | ||
| 370 | impl State { | ||
| 371 | pub const fn new() -> Self { | ||
| 372 | Self { | ||
| 373 | ready_waker: AtomicWaker::new(), | ||
| 374 | } | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 370 | pub trait Instance { | 378 | pub trait Instance { |
| 371 | fn regs(&self) -> &pac::qspi::RegisterBlock; | 379 | fn regs() -> &'static pac::qspi::RegisterBlock; |
| 380 | fn state() -> &'static State; | ||
| 372 | } | 381 | } |
| 373 | } | 382 | } |
| 374 | 383 | ||
| @@ -379,9 +388,13 @@ pub trait Instance: sealed::Instance + 'static { | |||
| 379 | macro_rules! impl_instance { | 388 | macro_rules! impl_instance { |
| 380 | ($type:ident, $irq:ident) => { | 389 | ($type:ident, $irq:ident) => { |
| 381 | impl sealed::Instance for peripherals::$type { | 390 | impl sealed::Instance for peripherals::$type { |
| 382 | fn regs(&self) -> &pac::qspi::RegisterBlock { | 391 | fn regs() -> &'static pac::qspi::RegisterBlock { |
| 383 | unsafe { &*pac::$type::ptr() } | 392 | unsafe { &*pac::$type::ptr() } |
| 384 | } | 393 | } |
| 394 | fn state() -> &'static sealed::State { | ||
| 395 | static STATE: sealed::State = sealed::State::new(); | ||
| 396 | &STATE | ||
| 397 | } | ||
| 385 | } | 398 | } |
| 386 | impl Instance for peripherals::$type { | 399 | impl Instance for peripherals::$type { |
| 387 | type Interrupt = interrupt::$irq; | 400 | type Interrupt = interrupt::$irq; |
diff --git a/embassy-traits/src/flash.rs b/embassy-traits/src/flash.rs index 3adaa3a0a..c9b14a390 100644 --- a/embassy-traits/src/flash.rs +++ b/embassy-traits/src/flash.rs | |||
| @@ -27,19 +27,18 @@ pub trait Flash { | |||
| 27 | /// | 27 | /// |
| 28 | /// address must be a multiple of self.read_size(). | 28 | /// address must be a multiple of self.read_size(). |
| 29 | /// buf.len() must be a multiple of self.read_size(). | 29 | /// buf.len() must be a multiple of self.read_size(). |
| 30 | fn read<'a>(self: Pin<&'a mut Self>, address: usize, buf: &'a mut [u8]) | 30 | fn read<'a>(&'a mut self, address: usize, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; |
| 31 | -> Self::ReadFuture<'a>; | ||
| 32 | 31 | ||
| 33 | /// Writes data to the flash device. | 32 | /// Writes data to the flash device. |
| 34 | /// | 33 | /// |
| 35 | /// address must be a multiple of self.write_size(). | 34 | /// address must be a multiple of self.write_size(). |
| 36 | /// buf.len() must be a multiple of self.write_size(). | 35 | /// buf.len() must be a multiple of self.write_size(). |
| 37 | fn write<'a>(self: Pin<&'a mut Self>, address: usize, buf: &'a [u8]) -> Self::WriteFuture<'a>; | 36 | fn write<'a>(&'a mut self, address: usize, buf: &'a [u8]) -> Self::WriteFuture<'a>; |
| 38 | 37 | ||
| 39 | /// Erases a single page from the flash device. | 38 | /// Erases a single page from the flash device. |
| 40 | /// | 39 | /// |
| 41 | /// address must be a multiple of self.erase_size(). | 40 | /// address must be a multiple of self.erase_size(). |
| 42 | fn erase<'a>(self: Pin<&'a mut Self>, address: usize) -> Self::ErasePageFuture<'a>; | 41 | fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a>; |
| 43 | 42 | ||
| 44 | /// Returns the total size, in bytes. | 43 | /// Returns the total size, in bytes. |
| 45 | /// This is not guaranteed to be a power of 2. | 44 | /// This is not guaranteed to be a power of 2. |
