From 9eb65b11cb29ec85224c129660d8ae2e01e06119 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 23 Feb 2023 22:23:01 +0100 Subject: [PATCH 1/5] nrf/qspi: remove cfg_if hack --- embassy-nrf/src/qspi.rs | 59 +++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index d434327f..5b68aa4d 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -525,42 +525,43 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SI } } -cfg_if::cfg_if! { - if #[cfg(feature = "nightly")] - { - use embedded_storage_async::nor_flash::{AsyncNorFlash, AsyncReadNorFlash}; - use core::future::Future; +#[cfg(feature = "nightly")] +mod _eh1 { + use core::future::Future; - impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { - const WRITE_SIZE: usize = ::WRITE_SIZE; - const ERASE_SIZE: usize = ::ERASE_SIZE; + use embedded_storage_async::nor_flash::{AsyncNorFlash, AsyncReadNorFlash}; - type WriteFuture<'a> = impl Future> + 'a where Self: 'a; - fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> { - async move { self.write(offset as usize, data).await } - } + use super::*; - type EraseFuture<'a> = impl Future> + 'a where Self: 'a; - fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> { - async move { - for address in (from as usize..to as usize).step_by(::ERASE_SIZE) { - self.erase(address).await? - } - Ok(()) - } - } + impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { + const WRITE_SIZE: usize = ::WRITE_SIZE; + const ERASE_SIZE: usize = ::ERASE_SIZE; + + type WriteFuture<'a> = impl Future> + 'a where Self: 'a; + fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> { + async move { self.write(offset as usize, data).await } } - impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { - const READ_SIZE: usize = 4; - type ReadFuture<'a> = impl Future> + 'a where Self: 'a; - fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { self.read(address as usize, data).await } + type EraseFuture<'a> = impl Future> + 'a where Self: 'a; + fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> { + async move { + for address in (from as usize..to as usize).step_by(::ERASE_SIZE) { + self.erase(address).await? + } + Ok(()) } + } + } - fn capacity(&self) -> usize { - FLASH_SIZE - } + impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { + const READ_SIZE: usize = 4; + type ReadFuture<'a> = impl Future> + 'a where Self: 'a; + fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> { + async move { self.read(address as usize, data).await } + } + + fn capacity(&self) -> usize { + FLASH_SIZE } } } From 1955a225e86d358d39f00620c770631c2186576f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 23 Feb 2023 22:36:10 +0100 Subject: [PATCH 2/5] nrf/qspi: add nrf53 support. --- embassy-nrf/src/chips/nrf5340_app.rs | 5 ++++ embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/qspi.rs | 37 ++++++++++++++-------------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 2e1c7f38..9c7b738e 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -250,6 +250,9 @@ embassy_hal_common::peripherals! { TIMER1, TIMER2, + // QSPI + QSPI, + // GPIOTE GPIOTE_CH0, GPIOTE_CH1, @@ -393,6 +396,8 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_qspi!(QSPI, QSPI, QSPI); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); #[cfg(feature = "nfc-pins-as-gpio")] diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index a9683df4..26f22b61 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -58,7 +58,7 @@ pub mod ppi; pub mod pwm; #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] pub mod qdec; -#[cfg(feature = "nrf52840")] +#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] pub mod qspi; #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] pub mod rng; diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 5b68aa4d..9a4e614f 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -133,25 +133,26 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { let r = T::regs(); - sck.set_high(); - csn.set_high(); - io0.set_high(); - io1.set_high(); - io2.set_high(); - io3.set_high(); - sck.conf().write(|w| w.dir().output().drive().h0h1()); - csn.conf().write(|w| w.dir().output().drive().h0h1()); - io0.conf().write(|w| w.dir().output().drive().h0h1()); - io1.conf().write(|w| w.dir().output().drive().h0h1()); - io2.conf().write(|w| w.dir().output().drive().h0h1()); - io3.conf().write(|w| w.dir().output().drive().h0h1()); + macro_rules! config_pin { + ($pin:ident) => { + $pin.set_high(); + $pin.conf().write(|w| { + w.dir().output(); + w.drive().h0h1(); + #[cfg(feature = "_nrf5340-s")] + w.mcusel().peripheral(); + w + }); + r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) }); + }; + } - r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); - r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) }); - r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) }); - r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) }); - r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) }); - r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) }); + config_pin!(sck); + config_pin!(csn); + config_pin!(io0); + config_pin!(io1); + config_pin!(io2); + config_pin!(io3); r.ifconfig0.write(|w| { w.addrmode().variant(config.address_mode); From 75f69803af244329ba6dd9093599be357f12ae60 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 5 Mar 2023 02:24:52 +0100 Subject: [PATCH 3/5] nrf/qspi: always use u32 for addresses. --- embassy-nrf/src/qspi.rs | 62 +++++++++++++++---------------- examples/nrf52840/src/bin/qspi.rs | 10 ++--- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 9a4e614f..404438ea 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -111,12 +111,12 @@ pub enum Error { } /// QSPI flash driver. -pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> { +pub struct Qspi<'d, T: Instance, const FLASH_SIZE: u32> { irq: PeripheralRef<'d, T::Interrupt>, dpm_enabled: bool, } -impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { /// Create a new QSPI driver. pub fn new( _qspi: impl Peripheral

+ 'd, @@ -322,17 +322,17 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { } } - fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { + fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { assert_eq!(data.as_ptr() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0); - assert_eq!(address as u32 % 4, 0); + assert_eq!(address % 4, 0); if address > FLASH_SIZE { return Err(Error::OutOfBounds); } let r = T::regs(); - r.read.src.write(|w| unsafe { w.src().bits(address as u32) }); + r.read.src.write(|w| unsafe { w.src().bits(address) }); r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); @@ -343,10 +343,10 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { Ok(()) } - fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { + fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { assert_eq!(data.as_ptr() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0); - assert_eq!(address as u32 % 4, 0); + assert_eq!(address % 4, 0); if address > FLASH_SIZE { return Err(Error::OutOfBounds); @@ -354,7 +354,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { let r = T::regs(); r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); - r.write.dst.write(|w| unsafe { w.dst().bits(address as u32) }); + r.write.dst.write(|w| unsafe { w.dst().bits(address) }); r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); r.events_ready.reset(); @@ -364,14 +364,14 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { Ok(()) } - fn start_erase(&mut self, address: usize) -> Result<(), Error> { - assert_eq!(address as u32 % 4096, 0); + fn start_erase(&mut self, address: u32) -> Result<(), Error> { + assert_eq!(address % 4096, 0); if address > FLASH_SIZE { return Err(Error::OutOfBounds); } let r = T::regs(); - r.erase.ptr.write(|w| unsafe { w.ptr().bits(address as u32) }); + r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) }); r.erase.len.write(|w| w.len()._4kb()); r.events_ready.reset(); @@ -382,7 +382,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { } /// Read data from the flash memory. - pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { + pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { let ondrop = OnDrop::new(Self::blocking_wait_ready); self.start_read(address, data)?; @@ -394,7 +394,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { } /// Write data to the flash memory. - pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { + pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { let ondrop = OnDrop::new(Self::blocking_wait_ready); self.start_write(address, data)?; @@ -406,7 +406,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { } /// Erase a sector on the flash memory. - pub async fn erase(&mut self, address: usize) -> Result<(), Error> { + pub async fn erase(&mut self, address: u32) -> Result<(), Error> { let ondrop = OnDrop::new(Self::blocking_wait_ready); self.start_erase(address)?; @@ -418,28 +418,28 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { } /// Read data from the flash memory, blocking version. - pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { + pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { self.start_read(address, data)?; Self::blocking_wait_ready(); Ok(()) } /// Write data to the flash memory, blocking version. - pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { + pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { self.start_write(address, data)?; Self::blocking_wait_ready(); Ok(()) } /// Erase a sector on the flash memory, blocking version. - pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> { + pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> { self.start_erase(address)?; Self::blocking_wait_ready(); Ok(()) } } -impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance, const FLASH_SIZE: u32> Drop for Qspi<'d, T, FLASH_SIZE> { fn drop(&mut self) { let r = T::regs(); @@ -486,7 +486,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; -impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance, const FLASH_SIZE: u32> ErrorType for Qspi<'d, T, FLASH_SIZE> { type Error = Error; } @@ -496,32 +496,32 @@ impl NorFlashError for Error { } } -impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance, const FLASH_SIZE: u32> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> { const READ_SIZE: usize = 4; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset as usize, bytes)?; + self.blocking_read(offset, bytes)?; Ok(()) } fn capacity(&self) -> usize { - FLASH_SIZE + FLASH_SIZE as usize } } -impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance, const FLASH_SIZE: u32> NorFlash for Qspi<'d, T, FLASH_SIZE> { const WRITE_SIZE: usize = 4; const ERASE_SIZE: usize = 4096; fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - for address in (from as usize..to as usize).step_by(::ERASE_SIZE) { + for address in (from..to).step_by(::ERASE_SIZE) { self.blocking_erase(address)?; } Ok(()) } fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(offset as usize, bytes)?; + self.blocking_write(offset, bytes)?; Ok(()) } } @@ -534,19 +534,19 @@ mod _eh1 { use super::*; - impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { + impl<'d, T: Instance, const FLASH_SIZE: u32> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { const WRITE_SIZE: usize = ::WRITE_SIZE; const ERASE_SIZE: usize = ::ERASE_SIZE; type WriteFuture<'a> = impl Future> + 'a where Self: 'a; fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> { - async move { self.write(offset as usize, data).await } + async move { self.write(offset, data).await } } type EraseFuture<'a> = impl Future> + 'a where Self: 'a; fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> { async move { - for address in (from as usize..to as usize).step_by(::ERASE_SIZE) { + for address in (from..to).step_by(::ERASE_SIZE) { self.erase(address).await? } Ok(()) @@ -554,15 +554,15 @@ mod _eh1 { } } - impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { + impl<'d, T: Instance, const FLASH_SIZE: u32> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { const READ_SIZE: usize = 4; type ReadFuture<'a> = impl Future> + 'a where Self: 'a; fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { self.read(address as usize, data).await } + async move { self.read(address, data).await } } fn capacity(&self) -> usize { - FLASH_SIZE + FLASH_SIZE as usize } } } diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs index bdcf710b..bc55f846 100644 --- a/examples/nrf52840/src/bin/qspi.rs +++ b/examples/nrf52840/src/bin/qspi.rs @@ -52,23 +52,23 @@ async fn main(_spawner: Spawner) { for i in 0..8 { info!("page {:?}: erasing... ", i); - unwrap!(q.erase(i * PAGE_SIZE).await); + unwrap!(q.erase(i * PAGE_SIZE as u32).await); for j in 0..PAGE_SIZE { - buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); + buf.0[j] = pattern((j as u32 + i * PAGE_SIZE as u32) as u32); } info!("programming..."); - unwrap!(q.write(i * PAGE_SIZE, &buf.0).await); + unwrap!(q.write(i * PAGE_SIZE as u32, &buf.0).await); } for i in 0..8 { info!("page {:?}: reading... ", i); - unwrap!(q.read(i * PAGE_SIZE, &mut buf.0).await); + unwrap!(q.read(i * PAGE_SIZE as u32, &mut buf.0).await); info!("verifying..."); for j in 0..PAGE_SIZE { - assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32)); + assert_eq!(buf.0[j], pattern((j as u32 + i * PAGE_SIZE as u32) as u32)); } } From 8eb8ea617419726915834555266e37568b8504e0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 5 Mar 2023 02:33:02 +0100 Subject: [PATCH 4/5] nrf/qspi: remove FLASH_SIZE const generic param. --- embassy-nrf/src/qspi.rs | 36 ++++++++++++---------- examples/nrf52840/src/bin/qspi.rs | 2 +- examples/nrf52840/src/bin/qspi_lowpower.rs | 2 +- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 404438ea..3f7f464d 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -8,6 +8,7 @@ use core::task::Poll; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; +use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; use crate::gpio::{self, Pin as GpioPin}; use crate::interrupt::{Interrupt, InterruptExt}; @@ -82,6 +83,8 @@ pub struct Config { pub spi_mode: SpiMode, /// Addressing mode (24-bit or 32-bit) pub address_mode: AddressMode, + /// Flash memory capacity in bytes. This is the value reported by the `embedded-storage` traits. + pub capacity: u32, } impl Default for Config { @@ -96,6 +99,7 @@ impl Default for Config { sck_delay: 80, spi_mode: SpiMode::MODE0, address_mode: AddressMode::_24BIT, + capacity: 0, } } } @@ -111,12 +115,13 @@ pub enum Error { } /// QSPI flash driver. -pub struct Qspi<'d, T: Instance, const FLASH_SIZE: u32> { +pub struct Qspi<'d, T: Instance> { irq: PeripheralRef<'d, T::Interrupt>, dpm_enabled: bool, + capacity: u32, } -impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance> Qspi<'d, T> { /// Create a new QSPI driver. pub fn new( _qspi: impl Peripheral

+ 'd, @@ -128,7 +133,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { io2: impl Peripheral

+ 'd, io3: impl Peripheral

+ 'd, config: Config, - ) -> Qspi<'d, T, FLASH_SIZE> { + ) -> Self { into_ref!(irq, sck, csn, io0, io1, io2, io3); let r = T::regs(); @@ -194,6 +199,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { let res = Self { dpm_enabled: config.deep_power_down.is_some(), irq, + capacity: config.capacity, }; r.events_ready.reset(); @@ -326,7 +332,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { assert_eq!(data.as_ptr() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address % 4, 0); - if address > FLASH_SIZE { + if address > self.capacity { return Err(Error::OutOfBounds); } @@ -348,7 +354,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address % 4, 0); - if address > FLASH_SIZE { + if address > self.capacity { return Err(Error::OutOfBounds); } @@ -366,7 +372,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { fn start_erase(&mut self, address: u32) -> Result<(), Error> { assert_eq!(address % 4096, 0); - if address > FLASH_SIZE { + if address > self.capacity { return Err(Error::OutOfBounds); } @@ -439,7 +445,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Qspi<'d, T, FLASH_SIZE> { } } -impl<'d, T: Instance, const FLASH_SIZE: u32> Drop for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance> Drop for Qspi<'d, T> { fn drop(&mut self) { let r = T::regs(); @@ -484,9 +490,7 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> Drop for Qspi<'d, T, FLASH_SIZE> { } } -use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; - -impl<'d, T: Instance, const FLASH_SIZE: u32> ErrorType for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance> ErrorType for Qspi<'d, T> { type Error = Error; } @@ -496,7 +500,7 @@ impl NorFlashError for Error { } } -impl<'d, T: Instance, const FLASH_SIZE: u32> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { const READ_SIZE: usize = 4; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { @@ -505,11 +509,11 @@ impl<'d, T: Instance, const FLASH_SIZE: u32> ReadNorFlash for Qspi<'d, T, FLASH_ } fn capacity(&self) -> usize { - FLASH_SIZE as usize + self.capacity as usize } } -impl<'d, T: Instance, const FLASH_SIZE: u32> NorFlash for Qspi<'d, T, FLASH_SIZE> { +impl<'d, T: Instance> NorFlash for Qspi<'d, T> { const WRITE_SIZE: usize = 4; const ERASE_SIZE: usize = 4096; @@ -534,7 +538,7 @@ mod _eh1 { use super::*; - impl<'d, T: Instance, const FLASH_SIZE: u32> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { + impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> { const WRITE_SIZE: usize = ::WRITE_SIZE; const ERASE_SIZE: usize = ::ERASE_SIZE; @@ -554,7 +558,7 @@ mod _eh1 { } } - impl<'d, T: Instance, const FLASH_SIZE: u32> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { + impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> { const READ_SIZE: usize = 4; type ReadFuture<'a> = impl Future> + 'a where Self: 'a; fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> { @@ -562,7 +566,7 @@ mod _eh1 { } fn capacity(&self) -> usize { - FLASH_SIZE as usize + self.capacity as usize } } } diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs index bc55f846..be665149 100644 --- a/examples/nrf52840/src/bin/qspi.rs +++ b/examples/nrf52840/src/bin/qspi.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { config.write_page_size = qspi::WritePageSize::_256BYTES; let irq = interrupt::take!(QSPI); - let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new( + let mut q = qspi::Qspi::new( p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, ); diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs index 9341a237..5008481c 100644 --- a/examples/nrf52840/src/bin/qspi_lowpower.rs +++ b/examples/nrf52840/src/bin/qspi_lowpower.rs @@ -31,7 +31,7 @@ async fn main(_p: Spawner) { exit_time: 3, // tRDP = 35uS }); - let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new( + let mut q = qspi::Qspi::new( &mut p.QSPI, &mut irq, &mut p.P0_19, From f7dfc49c5c40d70852d6d3c7313973adf97e4716 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 5 Mar 2023 02:55:00 +0100 Subject: [PATCH 5/5] nrf/qspi: add _raw variants of methods that don't do bounds checks. Useful for the nRF7002, which presents as a "fake" QSPI flash, and the "capacity" concept doesn't really apply to it. --- embassy-nrf/src/qspi.rs | 90 +++++++++++++++++----- examples/nrf52840/src/bin/qspi.rs | 3 + examples/nrf52840/src/bin/qspi_lowpower.rs | 3 + 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 3f7f464d..d514e027 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -329,12 +329,10 @@ impl<'d, T: Instance> Qspi<'d, T> { } fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { + // TODO: Return these as errors instead. assert_eq!(data.as_ptr() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address % 4, 0); - if address > self.capacity { - return Err(Error::OutOfBounds); - } let r = T::regs(); @@ -350,14 +348,11 @@ impl<'d, T: Instance> Qspi<'d, T> { } fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { + // TODO: Return these as errors instead. assert_eq!(data.as_ptr() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address % 4, 0); - if address > self.capacity { - return Err(Error::OutOfBounds); - } - let r = T::regs(); r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); r.write.dst.write(|w| unsafe { w.dst().bits(address) }); @@ -371,10 +366,8 @@ impl<'d, T: Instance> Qspi<'d, T> { } fn start_erase(&mut self, address: u32) -> Result<(), Error> { + // TODO: Return these as errors instead. assert_eq!(address % 4096, 0); - if address > self.capacity { - return Err(Error::OutOfBounds); - } let r = T::regs(); r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) }); @@ -387,8 +380,12 @@ impl<'d, T: Instance> Qspi<'d, T> { Ok(()) } - /// Read data from the flash memory. - pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { + /// Raw QSPI read. + /// + /// The difference with `read` is that this does not do bounds checks + /// against the flash capacity. It is intended for use when QSPI is used as + /// a raw bus, not with flash memory. + pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { let ondrop = OnDrop::new(Self::blocking_wait_ready); self.start_read(address, data)?; @@ -399,8 +396,12 @@ impl<'d, T: Instance> Qspi<'d, T> { Ok(()) } - /// Write data to the flash memory. - pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { + /// Raw QSPI write. + /// + /// The difference with `write` is that this does not do bounds checks + /// against the flash capacity. It is intended for use when QSPI is used as + /// a raw bus, not with flash memory. + pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { let ondrop = OnDrop::new(Self::blocking_wait_ready); self.start_write(address, data)?; @@ -411,8 +412,46 @@ impl<'d, T: Instance> Qspi<'d, T> { Ok(()) } + /// Raw QSPI read, blocking version. + /// + /// The difference with `blocking_read` is that this does not do bounds checks + /// against the flash capacity. It is intended for use when QSPI is used as + /// a raw bus, not with flash memory. + pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { + self.start_read(address, data)?; + Self::blocking_wait_ready(); + Ok(()) + } + + /// Raw QSPI write, blocking version. + /// + /// The difference with `blocking_write` is that this does not do bounds checks + /// against the flash capacity. It is intended for use when QSPI is used as + /// a raw bus, not with flash memory. + pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { + self.start_write(address, data)?; + Self::blocking_wait_ready(); + Ok(()) + } + + /// Read data from the flash memory. + pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { + self.bounds_check(address, data.len())?; + self.read_raw(address, data).await + } + + /// Write data to the flash memory. + pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { + self.bounds_check(address, data.len())?; + self.write_raw(address, data).await + } + /// Erase a sector on the flash memory. pub async fn erase(&mut self, address: u32) -> Result<(), Error> { + if address >= self.capacity { + return Err(Error::OutOfBounds); + } + let ondrop = OnDrop::new(Self::blocking_wait_ready); self.start_erase(address)?; @@ -425,24 +464,35 @@ impl<'d, T: Instance> Qspi<'d, T> { /// Read data from the flash memory, blocking version. pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { - self.start_read(address, data)?; - Self::blocking_wait_ready(); - Ok(()) + self.bounds_check(address, data.len())?; + self.blocking_read_raw(address, data) } /// Write data to the flash memory, blocking version. pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { - self.start_write(address, data)?; - Self::blocking_wait_ready(); - Ok(()) + self.bounds_check(address, data.len())?; + self.blocking_write_raw(address, data) } /// Erase a sector on the flash memory, blocking version. pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> { + if address >= self.capacity { + return Err(Error::OutOfBounds); + } + self.start_erase(address)?; Self::blocking_wait_ready(); Ok(()) } + + fn bounds_check(&self, address: u32, len: usize) -> Result<(), Error> { + let len_u32: u32 = len.try_into().map_err(|_| Error::OutOfBounds)?; + let end_address = address.checked_add(len_u32).ok_or(Error::OutOfBounds)?; + if end_address > self.capacity { + return Err(Error::OutOfBounds); + } + Ok(()) + } } impl<'d, T: Instance> Drop for Qspi<'d, T> { diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs index be665149..21a10940 100644 --- a/examples/nrf52840/src/bin/qspi.rs +++ b/examples/nrf52840/src/bin/qspi.rs @@ -4,6 +4,7 @@ use defmt::{assert_eq, info, unwrap}; use embassy_executor::Spawner; +use embassy_nrf::qspi::Frequency; use embassy_nrf::{interrupt, qspi}; use {defmt_rtt as _, panic_probe as _}; @@ -19,6 +20,8 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); // Config for the MX25R64 present in the nRF52840 DK let mut config = qspi::Config::default(); + config.capacity = 8 * 1024 * 1024; // 8 MB + config.frequency = Frequency::M32; config.read_opcode = qspi::ReadOpcode::READ4IO; config.write_opcode = qspi::WriteOpcode::PP4IO; config.write_page_size = qspi::WritePageSize::_256BYTES; diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs index 5008481c..20c90391 100644 --- a/examples/nrf52840/src/bin/qspi_lowpower.rs +++ b/examples/nrf52840/src/bin/qspi_lowpower.rs @@ -6,6 +6,7 @@ use core::mem; use defmt::{info, unwrap}; use embassy_executor::Spawner; +use embassy_nrf::qspi::Frequency; use embassy_nrf::{interrupt, qspi}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -23,6 +24,8 @@ async fn main(_p: Spawner) { loop { // Config for the MX25R64 present in the nRF52840 DK let mut config = qspi::Config::default(); + config.capacity = 8 * 1024 * 1024; // 8 MB + config.frequency = Frequency::M32; config.read_opcode = qspi::ReadOpcode::READ4IO; config.write_opcode = qspi::WriteOpcode::PP4IO; config.write_page_size = qspi::WritePageSize::_256BYTES;