aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2022-04-19 14:39:59 +0200
committerUlf Lilleengen <[email protected]>2022-04-19 19:06:36 +0200
commite966125d62db32ba4ca7136d96a31d2cb7e7775d (patch)
tree903f63818316556770ed4f13ab2d2978d38ce9ba
parent00c51c8fd57603a4c0336abda023060671f96f55 (diff)
Add embedded-storage trait impls for QSPI
* Adds implementations of embedded-storage and embedded-storage-async for QSPI * Add blocking implementations of QSPI * Use blocking implementation in new() and embedded-storage impls * Use async implementation in embedded-storage-async impls * Add FLASH_SIZE const generic parameter * Own IRQ in Qspi to disable it on drop
-rw-r--r--embassy-nrf/Cargo.toml3
-rw-r--r--embassy-nrf/src/qspi.rs231
-rw-r--r--examples/nrf/src/bin/qspi.rs5
-rw-r--r--examples/nrf/src/bin/qspi_lowpower.rs5
4 files changed, 207 insertions, 37 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 858ff1f6e..5299c04a8 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -18,7 +18,7 @@ flavors = [
18[features] 18[features]
19 19
20# Enable nightly-only features 20# Enable nightly-only features
21nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb"] 21nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async"]
22 22
23# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. 23# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`.
24# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. 24# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version.
@@ -80,6 +80,7 @@ critical-section = "0.2.5"
80rand_core = "0.6.3" 80rand_core = "0.6.3"
81fixed = "1.10.0" 81fixed = "1.10.0"
82embedded-storage = "0.3.0" 82embedded-storage = "0.3.0"
83embedded-storage-async = { version = "0.3.0", optional = true }
83cfg-if = "1.0.0" 84cfg-if = "1.0.0"
84 85
85nrf52805-pac = { version = "0.11.0", optional = true, features = [ "rt" ] } 86nrf52805-pac = { version = "0.11.0", optional = true, features = [ "rt" ] }
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 89262ac05..8902879f8 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -60,16 +60,18 @@ impl Default for Config {
60#[cfg_attr(feature = "defmt", derive(defmt::Format))] 60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61#[non_exhaustive] 61#[non_exhaustive]
62pub enum Error { 62pub enum Error {
63 OutOfBounds,
63 // TODO add "not in data memory" error and check for it 64 // TODO add "not in data memory" error and check for it
64} 65}
65 66
66pub struct Qspi<'d, T: Instance> { 67pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
68 irq: T::Interrupt,
67 dpm_enabled: bool, 69 dpm_enabled: bool,
68 phantom: PhantomData<&'d mut T>, 70 phantom: PhantomData<&'d mut T>,
69} 71}
70 72
71impl<'d, T: Instance> Qspi<'d, T> { 73impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
72 pub async fn new( 74 pub fn new(
73 _qspi: impl Unborrow<Target = T> + 'd, 75 _qspi: impl Unborrow<Target = T> + 'd,
74 irq: impl Unborrow<Target = T::Interrupt> + 'd, 76 irq: impl Unborrow<Target = T::Interrupt> + 'd,
75 sck: impl Unborrow<Target = impl GpioPin> + 'd, 77 sck: impl Unborrow<Target = impl GpioPin> + 'd,
@@ -79,7 +81,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
79 io2: impl Unborrow<Target = impl GpioPin> + 'd, 81 io2: impl Unborrow<Target = impl GpioPin> + 'd,
80 io3: impl Unborrow<Target = impl GpioPin> + 'd, 82 io3: impl Unborrow<Target = impl GpioPin> + 'd,
81 config: Config, 83 config: Config,
82 ) -> Qspi<'d, T> { 84 ) -> Qspi<'d, T, FLASH_SIZE> {
83 unborrow!(irq, sck, csn, io0, io1, io2, io3); 85 unborrow!(irq, sck, csn, io0, io1, io2, io3);
84 86
85 let r = T::regs(); 87 let r = T::regs();
@@ -142,6 +144,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
142 144
143 let mut res = Self { 145 let mut res = Self {
144 dpm_enabled: config.deep_power_down.is_some(), 146 dpm_enabled: config.deep_power_down.is_some(),
147 irq,
145 phantom: PhantomData, 148 phantom: PhantomData,
146 }; 149 };
147 150
@@ -150,7 +153,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
150 153
151 r.tasks_activate.write(|w| w.tasks_activate().bit(true)); 154 r.tasks_activate.write(|w| w.tasks_activate().bit(true));
152 155
153 res.wait_ready().await; 156 res.blocking_wait_ready();
154 157
155 res 158 res
156 } 159 }
@@ -173,8 +176,36 @@ impl<'d, T: Instance> Qspi<'d, T> {
173 ) -> Result<(), Error> { 176 ) -> Result<(), Error> {
174 let bomb = DropBomb::new(); 177 let bomb = DropBomb::new();
175 178
179 let len = core::cmp::max(req.len(), resp.len()) as u8;
180 self.custom_instruction_start(opcode, req, len)?;
181
182 self.wait_ready().await;
183
184 self.custom_instruction_finish(resp)?;
185
186 bomb.defuse();
187
188 Ok(())
189 }
190
191 pub fn blocking_custom_instruction(
192 &mut self,
193 opcode: u8,
194 req: &[u8],
195 resp: &mut [u8],
196 ) -> Result<(), Error> {
197 let len = core::cmp::max(req.len(), resp.len()) as u8;
198 self.custom_instruction_start(opcode, req, len)?;
199
200 self.blocking_wait_ready();
201
202 self.custom_instruction_finish(resp)?;
203
204 Ok(())
205 }
206
207 fn custom_instruction_start(&mut self, opcode: u8, req: &[u8], len: u8) -> Result<(), Error> {
176 assert!(req.len() <= 8); 208 assert!(req.len() <= 8);
177 assert!(resp.len() <= 8);
178 209
179 let mut dat0: u32 = 0; 210 let mut dat0: u32 = 0;
180 let mut dat1: u32 = 0; 211 let mut dat1: u32 = 0;
@@ -190,8 +221,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
190 } 221 }
191 } 222 }
192 223
193 let len = core::cmp::max(req.len(), resp.len()) as u8;
194
195 let r = T::regs(); 224 let r = T::regs();
196 r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); 225 r.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
197 r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); 226 r.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
@@ -210,9 +239,10 @@ impl<'d, T: Instance> Qspi<'d, T> {
210 let w = w.lfstop().bit(false); 239 let w = w.lfstop().bit(false);
211 w 240 w
212 }); 241 });
242 Ok(())
243 }
213 244
214 self.wait_ready().await; 245 fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> {
215
216 let r = T::regs(); 246 let r = T::regs();
217 247
218 let dat0 = r.cinstrdat0.read().bits(); 248 let dat0 = r.cinstrdat0.read().bits();
@@ -227,9 +257,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
227 resp[i] = (dat1 >> (i * 8)) as u8; 257 resp[i] = (dat1 >> (i * 8)) as u8;
228 } 258 }
229 } 259 }
230
231 bomb.defuse();
232
233 Ok(()) 260 Ok(())
234 } 261 }
235 262
@@ -246,12 +273,22 @@ impl<'d, T: Instance> Qspi<'d, T> {
246 .await 273 .await
247 } 274 }
248 275
249 pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { 276 fn blocking_wait_ready(&mut self) {
250 let bomb = DropBomb::new(); 277 loop {
278 let r = T::regs();
279 if r.events_ready.read().bits() != 0 {
280 break;
281 }
282 }
283 }
251 284
285 fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
252 assert_eq!(data.as_ptr() as u32 % 4, 0); 286 assert_eq!(data.as_ptr() as u32 % 4, 0);
253 assert_eq!(data.len() as u32 % 4, 0); 287 assert_eq!(data.len() as u32 % 4, 0);
254 assert_eq!(address as u32 % 4, 0); 288 assert_eq!(address as u32 % 4, 0);
289 if address > FLASH_SIZE {
290 return Err(Error::OutOfBounds);
291 }
255 292
256 let r = T::regs(); 293 let r = T::regs();
257 294
@@ -269,19 +306,20 @@ impl<'d, T: Instance> Qspi<'d, T> {
269 r.intenset.write(|w| w.ready().set()); 306 r.intenset.write(|w| w.ready().set());
270 r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); 307 r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
271 308
272 self.wait_ready().await;
273
274 bomb.defuse();
275
276 Ok(()) 309 Ok(())
277 } 310 }
278 311
279 pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { 312 fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
280 let bomb = DropBomb::new(); 313 //info!("start_write ptr {}", data.as_ptr() as u32);
281
282 assert_eq!(data.as_ptr() as u32 % 4, 0); 314 assert_eq!(data.as_ptr() as u32 % 4, 0);
315 //info!("start_write OK ptr");
283 assert_eq!(data.len() as u32 % 4, 0); 316 assert_eq!(data.len() as u32 % 4, 0);
317 //info!("start_write OK len");
284 assert_eq!(address as u32 % 4, 0); 318 assert_eq!(address as u32 % 4, 0);
319 //info!("start_write OK addr");
320 if address > FLASH_SIZE {
321 return Err(Error::OutOfBounds);
322 }
285 323
286 let r = T::regs(); 324 let r = T::regs();
287 r.write 325 r.write
@@ -298,17 +336,14 @@ impl<'d, T: Instance> Qspi<'d, T> {
298 r.intenset.write(|w| w.ready().set()); 336 r.intenset.write(|w| w.ready().set());
299 r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); 337 r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
300 338
301 self.wait_ready().await;
302
303 bomb.defuse();
304
305 Ok(()) 339 Ok(())
306 } 340 }
307 341
308 pub async fn erase(&mut self, address: usize) -> Result<(), Error> { 342 fn start_erase(&mut self, address: usize) -> Result<(), Error> {
309 let bomb = DropBomb::new();
310
311 assert_eq!(address as u32 % 4096, 0); 343 assert_eq!(address as u32 % 4096, 0);
344 if address > FLASH_SIZE {
345 return Err(Error::OutOfBounds);
346 }
312 347
313 let r = T::regs(); 348 let r = T::regs();
314 r.erase 349 r.erase
@@ -320,15 +355,65 @@ impl<'d, T: Instance> Qspi<'d, T> {
320 r.intenset.write(|w| w.ready().set()); 355 r.intenset.write(|w| w.ready().set());
321 r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); 356 r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
322 357
358 Ok(())
359 }
360
361 pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
362 let bomb = DropBomb::new();
363
364 self.start_read(address, data)?;
323 self.wait_ready().await; 365 self.wait_ready().await;
324 366
325 bomb.defuse(); 367 bomb.defuse();
326 368
327 Ok(()) 369 Ok(())
328 } 370 }
371
372 pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
373 let bomb = DropBomb::new();
374
375 //info!("WRITE {} bytes at {}", data.len(), address);
376 self.start_write(address, data)?;
377 //info!("STARTED");
378 self.wait_ready().await;
379 //info!("WRITE DONE");
380
381 bomb.defuse();
382
383 Ok(())
384 }
385
386 pub async fn erase(&mut self, address: usize) -> Result<(), Error> {
387 let bomb = DropBomb::new();
388
389 self.start_erase(address)?;
390 self.wait_ready().await;
391
392 bomb.defuse();
393
394 Ok(())
395 }
396
397 pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
398 self.start_read(address, data)?;
399 self.blocking_wait_ready();
400 Ok(())
401 }
402
403 pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
404 self.start_write(address, data)?;
405 self.blocking_wait_ready();
406 Ok(())
407 }
408
409 pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> {
410 self.start_erase(address)?;
411 self.blocking_wait_ready();
412 Ok(())
413 }
329} 414}
330 415
331impl<'d, T: Instance> Drop for Qspi<'d, T> { 416impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> {
332 fn drop(&mut self) { 417 fn drop(&mut self) {
333 let r = T::regs(); 418 let r = T::regs();
334 419
@@ -358,6 +443,8 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
358 443
359 r.enable.write(|w| w.enable().disabled()); 444 r.enable.write(|w| w.enable().disabled());
360 445
446 self.irq.disable();
447
361 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, 448 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
362 // leaving it floating, the flash chip might read it as zero which would cause it to 449 // leaving it floating, the flash chip might read it as zero which would cause it to
363 // spuriously exit DPM. 450 // spuriously exit DPM.
@@ -371,6 +458,90 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
371 } 458 }
372} 459}
373 460
461use embedded_storage::nor_flash::{
462 ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
463};
464
465impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> {
466 type Error = Error;
467}
468
469impl NorFlashError for Error {
470 fn kind(&self) -> NorFlashErrorKind {
471 NorFlashErrorKind::Other
472 }
473}
474
475impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
476 const READ_SIZE: usize = 4;
477
478 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
479 self.blocking_read(offset as usize, bytes)?;
480 Ok(())
481 }
482
483 fn capacity(&self) -> usize {
484 FLASH_SIZE
485 }
486}
487
488impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> {
489 const WRITE_SIZE: usize = 4;
490 const ERASE_SIZE: usize = 4096;
491
492 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
493 for address in (from as usize..to as usize).step_by(<Self as NorFlash>::ERASE_SIZE) {
494 self.blocking_erase(address)?;
495 }
496 Ok(())
497 }
498
499 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
500 self.blocking_write(offset as usize, bytes)?;
501 Ok(())
502 }
503}
504
505cfg_if::cfg_if! {
506 if #[cfg(feature = "nightly")]
507 {
508 use embedded_storage_async::nor_flash::{AsyncNorFlash, AsyncReadNorFlash};
509 use core::future::Future;
510
511 impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> {
512 const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
513 const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
514
515 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
516 fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> {
517 async move { self.write(offset as usize, data).await }
518 }
519
520 type EraseFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
521 fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> {
522 async move {
523 for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
524 self.erase(address).await?
525 }
526 Ok(())
527 }
528 }
529 }
530
531 impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
532 const READ_SIZE: usize = 4;
533 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
534 fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
535 async move { self.read(address as usize, data).await }
536 }
537
538 fn capacity(&self) -> usize {
539 FLASH_SIZE
540 }
541 }
542 }
543}
544
374pub(crate) mod sealed { 545pub(crate) mod sealed {
375 use embassy::waitqueue::AtomicWaker; 546 use embassy::waitqueue::AtomicWaker;
376 547
diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf/src/bin/qspi.rs
index ba60716c8..8673b7961 100644
--- a/examples/nrf/src/bin/qspi.rs
+++ b/examples/nrf/src/bin/qspi.rs
@@ -26,10 +26,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
26 config.write_page_size = qspi::WritePageSize::_256BYTES; 26 config.write_page_size = qspi::WritePageSize::_256BYTES;
27 27
28 let irq = interrupt::take!(QSPI); 28 let irq = interrupt::take!(QSPI);
29 let mut q = qspi::Qspi::new( 29 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
30 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, 30 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
31 ) 31 );
32 .await;
33 32
34 let mut id = [1; 3]; 33 let mut id = [1; 3];
35 unwrap!(q.custom_instruction(0x9F, &[], &mut id).await); 34 unwrap!(q.custom_instruction(0x9F, &[], &mut id).await);
diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf/src/bin/qspi_lowpower.rs
index a8184cd63..255ce5d5e 100644
--- a/examples/nrf/src/bin/qspi_lowpower.rs
+++ b/examples/nrf/src/bin/qspi_lowpower.rs
@@ -32,7 +32,7 @@ async fn main(_spawner: Spawner, mut p: Peripherals) {
32 exit_time: 3, // tRDP = 35uS 32 exit_time: 3, // tRDP = 35uS
33 }); 33 });
34 34
35 let mut q = qspi::Qspi::new( 35 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
36 &mut p.QSPI, 36 &mut p.QSPI,
37 &mut irq, 37 &mut irq,
38 &mut p.P0_19, 38 &mut p.P0_19,
@@ -42,8 +42,7 @@ async fn main(_spawner: Spawner, mut p: Peripherals) {
42 &mut p.P0_22, 42 &mut p.P0_22,
43 &mut p.P0_23, 43 &mut p.P0_23,
44 config, 44 config,
45 ) 45 );
46 .await;
47 46
48 let mut id = [1; 3]; 47 let mut id = [1; 3];
49 unwrap!(q.custom_instruction(0x9F, &[], &mut id).await); 48 unwrap!(q.custom_instruction(0x9F, &[], &mut id).await);