diff options
| author | Mathias <[email protected]> | 2022-09-16 12:40:39 +0200 |
|---|---|---|
| committer | Mathias <[email protected]> | 2022-09-16 13:20:22 +0200 |
| commit | feb840c503a7110db5d12c0f49eea10ac92aa1c1 (patch) | |
| tree | b8d46c0d6b813925fca6ed125e2549dfa2ca2601 | |
| parent | 9794bc59cc74598f5131f502153d4288c3261274 (diff) | |
First iteration attempt on implementing generic flash mutation access for RP2040
| -rw-r--r-- | embassy-rp/Cargo.toml | 2 | ||||
| -rw-r--r-- | embassy-rp/src/flash.rs | 100 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 1 |
3 files changed, 103 insertions, 0 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index ccb2f6525..51cdda7b1 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -44,6 +44,8 @@ cortex-m-rt = ">=0.6.15,<0.8" | |||
| 44 | cortex-m = "0.7.6" | 44 | cortex-m = "0.7.6" |
| 45 | critical-section = "1.1" | 45 | critical-section = "1.1" |
| 46 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 46 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 47 | rp2040-flash = { version = "0.1" } | ||
| 48 | embedded-storage = { version = "0.3" } | ||
| 47 | 49 | ||
| 48 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } | 50 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } |
| 49 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } | 51 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } |
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs new file mode 100644 index 000000000..3b6405090 --- /dev/null +++ b/embassy-rp/src/flash.rs | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | use embedded_storage::nor_flash::{ | ||
| 2 | ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, | ||
| 3 | }; | ||
| 4 | |||
| 5 | /// Error type for NVMC operations. | ||
| 6 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 7 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 8 | pub enum Error { | ||
| 9 | /// Opration using a location not in flash. | ||
| 10 | OutOfBounds, | ||
| 11 | /// Unaligned operation or using unaligned buffers. | ||
| 12 | Unaligned, | ||
| 13 | } | ||
| 14 | |||
| 15 | impl NorFlashError for Error { | ||
| 16 | fn kind(&self) -> NorFlashErrorKind { | ||
| 17 | match self { | ||
| 18 | Self::OutOfBounds => NorFlashErrorKind::OutOfBounds, | ||
| 19 | Self::Unaligned => NorFlashErrorKind::NotAligned, | ||
| 20 | } | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | pub struct Flash<const FLASH_SIZE: usize>; | ||
| 25 | |||
| 26 | impl<const FLASH_SIZE: usize> ErrorType for Flash<FLASH_SIZE> { | ||
| 27 | type Error = Error; | ||
| 28 | } | ||
| 29 | |||
| 30 | impl<const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<FLASH_SIZE> {} | ||
| 31 | |||
| 32 | impl<const FLASH_SIZE: usize> ReadNorFlash for Flash<FLASH_SIZE> { | ||
| 33 | const READ_SIZE: usize = 1; | ||
| 34 | |||
| 35 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 36 | if offset as usize >= FLASH_SIZE || offset as usize + bytes.len() > FLASH_SIZE { | ||
| 37 | return Err(Error::OutOfBounds); | ||
| 38 | } | ||
| 39 | |||
| 40 | let flash_data = unsafe { core::slice::from_raw_parts(offset as *const u8, bytes.len()) }; | ||
| 41 | bytes.copy_from_slice(flash_data); | ||
| 42 | Ok(()) | ||
| 43 | } | ||
| 44 | |||
| 45 | fn capacity(&self) -> usize { | ||
| 46 | FLASH_SIZE | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> { | ||
| 51 | const WRITE_SIZE: usize = 4; | ||
| 52 | |||
| 53 | const ERASE_SIZE: usize = 4096; | ||
| 54 | |||
| 55 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 56 | if to < from || to as usize > FLASH_SIZE { | ||
| 57 | return Err(Error::OutOfBounds); | ||
| 58 | } | ||
| 59 | if from as usize % Self::ERASE_SIZE != 0 || to as usize % Self::ERASE_SIZE != 0 { | ||
| 60 | return Err(Error::Unaligned); | ||
| 61 | } | ||
| 62 | |||
| 63 | let len = to - from; | ||
| 64 | |||
| 65 | // Make sure to uphold the contract point with rp2040-flash. | ||
| 66 | // - interrupts must be disabled | ||
| 67 | // - DMA must not access flash memory | ||
| 68 | // FIXME: Pause all DMA channels for the duration of the flash_write? | ||
| 69 | |||
| 70 | critical_section::with(|_| { | ||
| 71 | unsafe { rp2040_flash::flash::flash_range_erase(from, len, true) }; | ||
| 72 | }); | ||
| 73 | |||
| 74 | // Re-enable DMA channels | ||
| 75 | |||
| 76 | Ok(()) | ||
| 77 | } | ||
| 78 | |||
| 79 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 80 | if offset as usize + bytes.len() > FLASH_SIZE { | ||
| 81 | return Err(Error::OutOfBounds); | ||
| 82 | } | ||
| 83 | if offset as usize % 4 != 0 || bytes.len() as usize % 4 != 0 { | ||
| 84 | return Err(Error::Unaligned); | ||
| 85 | } | ||
| 86 | |||
| 87 | // Make sure to uphold the contract point with rp2040-flash. | ||
| 88 | // - interrupts must be disabled | ||
| 89 | // - DMA must not access flash memory | ||
| 90 | // FIXME: Pause all DMA channels for the duration of the flash_write? | ||
| 91 | |||
| 92 | critical_section::with(|_| { | ||
| 93 | unsafe { rp2040_flash::flash::flash_range_program(offset, bytes, true) }; | ||
| 94 | }); | ||
| 95 | |||
| 96 | // Re-enable DMA channels | ||
| 97 | |||
| 98 | Ok(()) | ||
| 99 | } | ||
| 100 | } | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index aebbbf567..d86162fb2 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -14,6 +14,7 @@ pub mod uart; | |||
| 14 | pub mod usb; | 14 | pub mod usb; |
| 15 | 15 | ||
| 16 | mod clocks; | 16 | mod clocks; |
| 17 | pub mod flash; | ||
| 17 | mod reset; | 18 | mod reset; |
| 18 | 19 | ||
| 19 | // Reexports | 20 | // Reexports |
