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.
This commit is contained in:
Dario Nieuwenhuis 2023-03-05 02:55:00 +01:00
parent 8eb8ea6174
commit f7dfc49c5c
3 changed files with 76 additions and 20 deletions

View file

@ -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> {

View file

@ -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;

View file

@ -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;