Merge upstream
This commit is contained in:
@ -3,19 +3,21 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
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};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
pub use crate::pac::qspi::ifconfig0::{
|
||||
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
||||
};
|
||||
pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
|
||||
use crate::{pac, Peripheral};
|
||||
use crate::Peripheral;
|
||||
|
||||
/// Deep power-down config.
|
||||
pub struct DeepPowerDownConfig {
|
||||
@ -82,6 +84,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 +100,7 @@ impl Default for Config {
|
||||
sck_delay: 80,
|
||||
spi_mode: SpiMode::MODE0,
|
||||
address_mode: AddressMode::_24BIT,
|
||||
capacity: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,17 +115,35 @@ pub enum Error {
|
||||
// TODO add "not in data memory" error and check for it
|
||||
}
|
||||
|
||||
/// QSPI flash driver.
|
||||
pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
|
||||
irq: PeripheralRef<'d, T::Interrupt>,
|
||||
dpm_enabled: bool,
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.ready().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// QSPI flash driver.
|
||||
pub struct Qspi<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
dpm_enabled: bool,
|
||||
capacity: u32,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Qspi<'d, T> {
|
||||
/// Create a new QSPI driver.
|
||||
pub fn new(
|
||||
_qspi: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
qspi: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
csn: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
io0: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -128,30 +151,31 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
io2: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
io3: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Qspi<'d, T, FLASH_SIZE> {
|
||||
into_ref!(irq, sck, csn, io0, io1, io2, io3);
|
||||
) -> Self {
|
||||
into_ref!(qspi, sck, csn, io0, io1, io2, io3);
|
||||
|
||||
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);
|
||||
@ -183,16 +207,16 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
w
|
||||
});
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
// Enable it
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
|
||||
let res = Self {
|
||||
_peri: qspi,
|
||||
dpm_enabled: config.deep_power_down.is_some(),
|
||||
irq,
|
||||
capacity: config.capacity,
|
||||
};
|
||||
|
||||
r.events_ready.reset();
|
||||
@ -205,16 +229,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
res
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
s.ready_waker.wake();
|
||||
r.intenclr.write(|w| w.ready().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Do a custom QSPI instruction.
|
||||
pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
|
||||
let ondrop = OnDrop::new(Self::blocking_wait_ready);
|
||||
@ -303,7 +317,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
poll_fn(move |cx| {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
s.ready_waker.register(cx.waker());
|
||||
s.waker.register(cx.waker());
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
@ -321,17 +335,15 @@ 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> {
|
||||
// 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 as u32 % 4, 0);
|
||||
if address > FLASH_SIZE {
|
||||
return Err(Error::OutOfBounds);
|
||||
}
|
||||
assert_eq!(address % 4, 0);
|
||||
|
||||
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) });
|
||||
|
||||
@ -342,18 +354,15 @@ 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> {
|
||||
// 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 as u32 % 4, 0);
|
||||
|
||||
if address > FLASH_SIZE {
|
||||
return Err(Error::OutOfBounds);
|
||||
}
|
||||
assert_eq!(address % 4, 0);
|
||||
|
||||
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();
|
||||
@ -363,14 +372,12 @@ 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);
|
||||
if address > FLASH_SIZE {
|
||||
return Err(Error::OutOfBounds);
|
||||
}
|
||||
fn start_erase(&mut self, address: u32) -> Result<(), Error> {
|
||||
// TODO: Return these as errors instead.
|
||||
assert_eq!(address % 4096, 0);
|
||||
|
||||
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();
|
||||
@ -380,8 +387,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read data from the flash memory.
|
||||
pub async fn read(&mut self, address: usize, 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)?;
|
||||
@ -392,8 +403,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write data to the flash memory.
|
||||
pub async fn write(&mut self, address: usize, 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)?;
|
||||
@ -404,8 +419,46 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
||||
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: usize) -> Result<(), Error> {
|
||||
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)?;
|
||||
@ -417,28 +470,39 @@ 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> {
|
||||
self.start_read(address, data)?;
|
||||
Self::blocking_wait_ready();
|
||||
Ok(())
|
||||
pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
|
||||
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: usize, data: &[u8]) -> Result<(), Error> {
|
||||
self.start_write(address, data)?;
|
||||
Self::blocking_wait_ready();
|
||||
Ok(())
|
||||
pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
|
||||
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: usize) -> Result<(), Error> {
|
||||
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, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> {
|
||||
impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
let r = T::regs();
|
||||
|
||||
@ -468,8 +532,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE>
|
||||
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
|
||||
self.irq.disable();
|
||||
|
||||
// Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
|
||||
// leaving it floating, the flash chip might read it as zero which would cause it to
|
||||
// spuriously exit DPM.
|
||||
@ -483,9 +545,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> ErrorType for Qspi<'d, T> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
@ -495,66 +555,66 @@ impl NorFlashError for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> 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> {
|
||||
self.blocking_read(offset as usize, bytes)?;
|
||||
self.blocking_read(offset, bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn capacity(&self) -> usize {
|
||||
FLASH_SIZE
|
||||
self.capacity as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> 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;
|
||||
|
||||
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||
for address in (from as usize..to as usize).step_by(<Self as NorFlash>::ERASE_SIZE) {
|
||||
for address in (from..to).step_by(<Self as NorFlash>::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(())
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "nightly")]
|
||||
{
|
||||
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
|
||||
#[cfg(feature = "nightly")]
|
||||
mod _eh1 {
|
||||
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
||||
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
|
||||
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
|
||||
use super::*;
|
||||
|
||||
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(offset as usize, data).await
|
||||
}
|
||||
impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> {
|
||||
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
|
||||
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
|
||||
|
||||
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||
for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
|
||||
self.erase(address).await?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(offset, data).await
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
||||
const READ_SIZE: usize = 4;
|
||||
async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(address as usize, data).await
|
||||
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||
for address in (from..to).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
|
||||
self.erase(address).await?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn capacity(&self) -> usize {
|
||||
FLASH_SIZE
|
||||
}
|
||||
impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> {
|
||||
const READ_SIZE: usize = 4;
|
||||
async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(address, data).await
|
||||
}
|
||||
|
||||
fn capacity(&self) -> usize {
|
||||
self.capacity as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -562,27 +622,27 @@ cfg_if::cfg_if! {
|
||||
pub(crate) mod sealed {
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub ready_waker: AtomicWaker,
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ready_waker: AtomicWaker::new(),
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static pac::qspi::RegisterBlock;
|
||||
fn regs() -> &'static crate::pac::qspi::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// QSPI peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
@ -590,7 +650,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||
macro_rules! impl_qspi {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::qspi::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static pac::qspi::RegisterBlock {
|
||||
fn regs() -> &'static crate::pac::qspi::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::qspi::sealed::State {
|
||||
|
Reference in New Issue
Block a user