First iteration attempt on implementing generic flash mutation access for RP2040
This commit is contained in:
parent
816778e3fa
commit
9d674f0212
3 changed files with 102 additions and 0 deletions
|
@ -52,6 +52,7 @@ cortex-m = "0.7.6"
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||||
chrono = { version = "0.4", default-features = false, optional = true }
|
chrono = { version = "0.4", default-features = false, optional = true }
|
||||||
|
embedded-storage = { version = "0.3" }
|
||||||
|
|
||||||
rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
|
rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
|
||||||
#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
|
#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
|
||||||
|
|
100
embassy-rp/src/flash.rs
Normal file
100
embassy-rp/src/flash.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use embedded_storage::nor_flash::{
|
||||||
|
ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Error type for NVMC operations.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Error {
|
||||||
|
/// Opration using a location not in flash.
|
||||||
|
OutOfBounds,
|
||||||
|
/// Unaligned operation or using unaligned buffers.
|
||||||
|
Unaligned,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NorFlashError for Error {
|
||||||
|
fn kind(&self) -> NorFlashErrorKind {
|
||||||
|
match self {
|
||||||
|
Self::OutOfBounds => NorFlashErrorKind::OutOfBounds,
|
||||||
|
Self::Unaligned => NorFlashErrorKind::NotAligned,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Flash<const FLASH_SIZE: usize>;
|
||||||
|
|
||||||
|
impl<const FLASH_SIZE: usize> ErrorType for Flash<FLASH_SIZE> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<FLASH_SIZE> {}
|
||||||
|
|
||||||
|
impl<const FLASH_SIZE: usize> ReadNorFlash for Flash<FLASH_SIZE> {
|
||||||
|
const READ_SIZE: usize = 1;
|
||||||
|
|
||||||
|
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
if offset as usize >= FLASH_SIZE || offset as usize + bytes.len() > FLASH_SIZE {
|
||||||
|
return Err(Error::OutOfBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
let flash_data = unsafe { core::slice::from_raw_parts(offset as *const u8, bytes.len()) };
|
||||||
|
bytes.copy_from_slice(flash_data);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capacity(&self) -> usize {
|
||||||
|
FLASH_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> {
|
||||||
|
const WRITE_SIZE: usize = 4;
|
||||||
|
|
||||||
|
const ERASE_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||||
|
if to < from || to as usize > FLASH_SIZE {
|
||||||
|
return Err(Error::OutOfBounds);
|
||||||
|
}
|
||||||
|
if from as usize % Self::ERASE_SIZE != 0 || to as usize % Self::ERASE_SIZE != 0 {
|
||||||
|
return Err(Error::Unaligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = to - from;
|
||||||
|
|
||||||
|
// Make sure to uphold the contract point with rp2040-flash.
|
||||||
|
// - interrupts must be disabled
|
||||||
|
// - DMA must not access flash memory
|
||||||
|
// FIXME: Pause all DMA channels for the duration of the flash_write?
|
||||||
|
|
||||||
|
critical_section::with(|_| {
|
||||||
|
unsafe { rp2040_flash::flash::flash_range_erase(from, len, true) };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-enable DMA channels
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
if offset as usize + bytes.len() > FLASH_SIZE {
|
||||||
|
return Err(Error::OutOfBounds);
|
||||||
|
}
|
||||||
|
if offset as usize % 4 != 0 || bytes.len() as usize % 4 != 0 {
|
||||||
|
return Err(Error::Unaligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure to uphold the contract point with rp2040-flash.
|
||||||
|
// - interrupts must be disabled
|
||||||
|
// - DMA must not access flash memory
|
||||||
|
// FIXME: Pause all DMA channels for the duration of the flash_write?
|
||||||
|
|
||||||
|
critical_section::with(|_| {
|
||||||
|
unsafe { rp2040_flash::flash::flash_range_program(offset, bytes, true) };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-enable DMA channels
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ pub mod uart;
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
|
|
||||||
mod clocks;
|
mod clocks;
|
||||||
|
pub mod flash;
|
||||||
mod reset;
|
mod reset;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
|
|
Loading…
Reference in a new issue