Skip to content

Commit e2ed41b

Browse files
bors[bot]lulf
andauthored
Merge #723
723: Add embedded-storage trait impls for QSPI r=Dirbaio a=lulf * 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 instance to disable it on drop. Co-authored-by: Ulf Lilleengen <ulf.lilleengen@gmail.com>
2 parents 00c51c8 + e966125 commit e2ed41b

File tree

4 files changed

+207
-37
lines changed

4 files changed

+207
-37
lines changed

embassy-nrf/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ flavors = [
1818
[features]
1919

2020
# Enable nightly-only features
21-
nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb"]
21+
nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async"]
2222

2323
# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`.
2424
# 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"
8080
rand_core = "0.6.3"
8181
fixed = "1.10.0"
8282
embedded-storage = "0.3.0"
83+
embedded-storage-async = { version = "0.3.0", optional = true }
8384
cfg-if = "1.0.0"
8485

8586
nrf52805-pac = { version = "0.11.0", optional = true, features = [ "rt" ] }

embassy-nrf/src/qspi.rs

Lines changed: 201 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,18 @@ impl Default for Config {
6060
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6161
#[non_exhaustive]
6262
pub enum Error {
63+
OutOfBounds,
6364
// TODO add "not in data memory" error and check for it
6465
}
6566

66-
pub struct Qspi<'d, T: Instance> {
67+
pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
68+
irq: T::Interrupt,
6769
dpm_enabled: bool,
6870
phantom: PhantomData<&'d mut T>,
6971
}
7072

71-
impl<'d, T: Instance> Qspi<'d, T> {
72-
pub async fn new(
73+
impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
74+
pub fn new(
7375
_qspi: impl Unborrow<Target = T> + 'd,
7476
irq: impl Unborrow<Target = T::Interrupt> + 'd,
7577
sck: impl Unborrow<Target = impl GpioPin> + 'd,
@@ -79,7 +81,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
7981
io2: impl Unborrow<Target = impl GpioPin> + 'd,
8082
io3: impl Unborrow<Target = impl GpioPin> + 'd,
8183
config: Config,
82-
) -> Qspi<'d, T> {
84+
) -> Qspi<'d, T, FLASH_SIZE> {
8385
unborrow!(irq, sck, csn, io0, io1, io2, io3);
8486

8587
let r = T::regs();
@@ -142,6 +144,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
142144

143145
let mut res = Self {
144146
dpm_enabled: config.deep_power_down.is_some(),
147+
irq,
145148
phantom: PhantomData,
146149
};
147150

@@ -150,7 +153,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
150153

151154
r.tasks_activate.write(|w| w.tasks_activate().bit(true));
152155

153-
res.wait_ready().await;
156+
res.blocking_wait_ready();
154157

155158
res
156159
}
@@ -173,8 +176,36 @@ impl<'d, T: Instance> Qspi<'d, T> {
173176
) -> Result<(), Error> {
174177
let bomb = DropBomb::new();
175178

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> {
176208
assert!(req.len() <= 8);
177-
assert!(resp.len() <= 8);
178209

179210
let mut dat0: u32 = 0;
180211
let mut dat1: u32 = 0;
@@ -190,8 +221,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
190221
}
191222
}
192223

193-
let len = core::cmp::max(req.len(), resp.len()) as u8;
194-
195224
let r = T::regs();
196225
r.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
197226
r.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
@@ -210,9 +239,10 @@ impl<'d, T: Instance> Qspi<'d, T> {
210239
let w = w.lfstop().bit(false);
211240
w
212241
});
242+
Ok(())
243+
}
213244

214-
self.wait_ready().await;
215-
245+
fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> {
216246
let r = T::regs();
217247

218248
let dat0 = r.cinstrdat0.read().bits();
@@ -227,9 +257,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
227257
resp[i] = (dat1 >> (i * 8)) as u8;
228258
}
229259
}
230-
231-
bomb.defuse();
232-
233260
Ok(())
234261
}
235262

@@ -246,12 +273,22 @@ impl<'d, T: Instance> Qspi<'d, T> {
246273
.await
247274
}
248275

249-
pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
250-
let bomb = DropBomb::new();
276+
fn blocking_wait_ready(&mut self) {
277+
loop {
278+
let r = T::regs();
279+
if r.events_ready.read().bits() != 0 {
280+
break;
281+
}
282+
}
283+
}
251284

285+
fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
252286
assert_eq!(data.as_ptr() as u32 % 4, 0);
253287
assert_eq!(data.len() as u32 % 4, 0);
254288
assert_eq!(address as u32 % 4, 0);
289+
if address > FLASH_SIZE {
290+
return Err(Error::OutOfBounds);
291+
}
255292

256293
let r = T::regs();
257294

@@ -269,19 +306,20 @@ impl<'d, T: Instance> Qspi<'d, T> {
269306
r.intenset.write(|w| w.ready().set());
270307
r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
271308

272-
self.wait_ready().await;
273-
274-
bomb.defuse();
275-
276309
Ok(())
277310
}
278311

279-
pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
280-
let bomb = DropBomb::new();
281-
312+
fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
313+
//info!("start_write ptr {}", data.as_ptr() as u32);
282314
assert_eq!(data.as_ptr() as u32 % 4, 0);
315+
//info!("start_write OK ptr");
283316
assert_eq!(data.len() as u32 % 4, 0);
317+
//info!("start_write OK len");
284318
assert_eq!(address as u32 % 4, 0);
319+
//info!("start_write OK addr");
320+
if address > FLASH_SIZE {
321+
return Err(Error::OutOfBounds);
322+
}
285323

286324
let r = T::regs();
287325
r.write
@@ -298,17 +336,14 @@ impl<'d, T: Instance> Qspi<'d, T> {
298336
r.intenset.write(|w| w.ready().set());
299337
r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
300338

301-
self.wait_ready().await;
302-
303-
bomb.defuse();
304-
305339
Ok(())
306340
}
307341

308-
pub async fn erase(&mut self, address: usize) -> Result<(), Error> {
309-
let bomb = DropBomb::new();
310-
342+
fn start_erase(&mut self, address: usize) -> Result<(), Error> {
311343
assert_eq!(address as u32 % 4096, 0);
344+
if address > FLASH_SIZE {
345+
return Err(Error::OutOfBounds);
346+
}
312347

313348
let r = T::regs();
314349
r.erase
@@ -320,15 +355,65 @@ impl<'d, T: Instance> Qspi<'d, T> {
320355
r.intenset.write(|w| w.ready().set());
321356
r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
322357

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)?;
323365
self.wait_ready().await;
324366

325367
bomb.defuse();
326368

327369
Ok(())
328370
}
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+
}
329414
}
330415

331-
impl<'d, T: Instance> Drop for Qspi<'d, T> {
416+
impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> {
332417
fn drop(&mut self) {
333418
let r = T::regs();
334419

@@ -358,6 +443,8 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
358443

359444
r.enable.write(|w| w.enable().disabled());
360445

446+
self.irq.disable();
447+
361448
// Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
362449
// leaving it floating, the flash chip might read it as zero which would cause it to
363450
// spuriously exit DPM.
@@ -371,6 +458,90 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
371458
}
372459
}
373460

461+
use embedded_storage::nor_flash::{
462+
ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
463+
};
464+
465+
impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> {
466+
type Error = Error;
467+
}
468+
469+
impl NorFlashError for Error {
470+
fn kind(&self) -> NorFlashErrorKind {
471+
NorFlashErrorKind::Other
472+
}
473+
}
474+
475+
impl<'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+
488+
impl<'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+
505+
cfg_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+
374545
pub(crate) mod sealed {
375546
use embassy::waitqueue::AtomicWaker;
376547

examples/nrf/src/bin/qspi.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
2626
config.write_page_size = qspi::WritePageSize::_256BYTES;
2727

2828
let irq = interrupt::take!(QSPI);
29-
let mut q = qspi::Qspi::new(
29+
let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
3030
p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
31-
)
32-
.await;
31+
);
3332

3433
let mut id = [1; 3];
3534
unwrap!(q.custom_instruction(0x9F, &[], &mut id).await);

0 commit comments

Comments
 (0)