forked from esp-rs/esp-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into make-rmt-channel-creator-public
- Loading branch information
Showing
23 changed files
with
1,535 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
[package] | ||
name = "esp-storage" | ||
version = "0.3.0" | ||
edition = "2021" | ||
authors = [ | ||
"The ESP-RS team", | ||
"Björn Quentin <bjoern.quentin@mobile-j.de>", | ||
] | ||
description = "Implementation of embedded-storage traits to access unencrypted ESP32 flash" | ||
repository = "https://github.com/esp-rs/esp-storage" | ||
license = "MIT OR Apache-2.0" | ||
|
||
keywords = [ | ||
"embedded-storage", | ||
"esp", | ||
"no-std", | ||
] | ||
categories = [ | ||
"embedded", | ||
"hardware-support", | ||
"no-std", | ||
] | ||
|
||
[dependencies] | ||
embedded-storage = "0.3.0" | ||
critical-section = { version = "1.1.1", optional = true } | ||
|
||
[build-dependencies] | ||
esp-build = { version = "0.1.0", path = "../esp-build" } | ||
|
||
[features] | ||
default = ["critical-section", "storage"] | ||
critical-section = ["dep:critical-section"] | ||
# ReadStorage/Storage traits | ||
storage = [] | ||
# ReadNorFlash/NorFlash traits | ||
nor-flash = [] | ||
# Bytewise read emulation | ||
bytewise-read = [] | ||
esp32c2 = [] | ||
esp32c3 = [] | ||
esp32c6 = [] | ||
esp32h2 = [] | ||
esp32 = [] | ||
esp32s2 = [] | ||
esp32s3 = [] | ||
# Enable flash emulation to run tests | ||
emulation = [] | ||
|
||
# this feature is reserved for very specific use-cases - usually you don't want to use this! | ||
low-level = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# esp-storage | ||
|
||
This implements [`embedded-storage`](https://github.com/rust-embedded-community/embedded-storage) traits to access unencrypted ESP32 flash. | ||
|
||
## Current support | ||
|
||
ESP32, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-H2, ESP32-S2 and ESP32-S3 are supported in `esp-storage` | ||
|
||
## Important | ||
|
||
For ESP32 it is necessary to build with [optimization level](https://doc.rust-lang.org/cargo/reference/profiles.html#opt-level) 2 or 3. | ||
|
||
To make it work also for `debug` builds add this to your `Cargo.toml` | ||
|
||
```toml | ||
[profile.dev.package.esp-storage] | ||
opt-level = 3 | ||
``` | ||
|
||
## License | ||
|
||
Licensed under either of | ||
|
||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or | ||
http://www.apache.org/licenses/LICENSE-2.0) | ||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
|
||
at your option. | ||
|
||
### Contribution | ||
|
||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the | ||
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any | ||
additional terms or conditions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
fn main() -> Result<(), String> { | ||
// Ensure that only a single chip is specified | ||
esp_build::assert_unique_used_features!( | ||
"esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4", "esp32s2", "esp32s3" | ||
); | ||
|
||
if cfg!(feature = "esp32") { | ||
match std::env::var("OPT_LEVEL") { | ||
Ok(level) => { | ||
if level != "2" && level != "3" { | ||
Err(format!("Building esp-storage for ESP32 needs optimization level 2 or 3 - yours is {}. See https://github.com/esp-rs/esp-storage", level)) | ||
} else { | ||
Ok(()) | ||
} | ||
} | ||
Err(_err) => Ok(()), | ||
} | ||
} else { | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
use core::ops::{Deref, DerefMut}; | ||
|
||
use crate::chip_specific; | ||
|
||
#[repr(C, align(4))] | ||
pub struct FlashSectorBuffer { | ||
// NOTE: Ensure that no unaligned fields are added above `data` to maintain its required | ||
// alignment | ||
data: [u8; FlashStorage::SECTOR_SIZE as usize], | ||
} | ||
|
||
impl Deref for FlashSectorBuffer { | ||
type Target = [u8; FlashStorage::SECTOR_SIZE as usize]; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.data | ||
} | ||
} | ||
|
||
impl DerefMut for FlashSectorBuffer { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.data | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
#[non_exhaustive] | ||
pub enum FlashStorageError { | ||
IoError, | ||
IoTimeout, | ||
CantUnlock, | ||
NotAligned, | ||
OutOfBounds, | ||
Other(i32), | ||
} | ||
|
||
#[inline(always)] | ||
pub fn check_rc(rc: i32) -> Result<(), FlashStorageError> { | ||
match rc { | ||
0 => Ok(()), | ||
1 => Err(FlashStorageError::IoError), | ||
2 => Err(FlashStorageError::IoTimeout), | ||
_ => Err(FlashStorageError::Other(rc)), | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct FlashStorage { | ||
pub(crate) capacity: usize, | ||
unlocked: bool, | ||
} | ||
|
||
impl Default for FlashStorage { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl FlashStorage { | ||
pub const WORD_SIZE: u32 = 4; | ||
pub const SECTOR_SIZE: u32 = 4096; | ||
|
||
pub fn new() -> FlashStorage { | ||
let mut storage = FlashStorage { | ||
capacity: 0, | ||
unlocked: false, | ||
}; | ||
|
||
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))] | ||
const ADDR: u32 = 0x0000; | ||
#[cfg(any(feature = "esp32", feature = "esp32s2"))] | ||
const ADDR: u32 = 0x1000; | ||
|
||
let mut buffer = [0u8; 8]; | ||
storage.internal_read(ADDR, &mut buffer).ok(); | ||
let mb = match buffer[3] & 0xf0 { | ||
0x00 => 1, | ||
0x10 => 2, | ||
0x20 => 4, | ||
0x30 => 8, | ||
0x40 => 16, | ||
_ => 0, | ||
}; | ||
storage.capacity = mb * 1024 * 1024; | ||
|
||
storage | ||
} | ||
|
||
#[cfg(feature = "nor-flash")] | ||
#[inline(always)] | ||
pub(crate) fn check_alignment<const ALIGN: u32>( | ||
&self, | ||
offset: u32, | ||
length: usize, | ||
) -> Result<(), FlashStorageError> { | ||
let offset = offset as usize; | ||
if offset % ALIGN as usize != 0 || length % ALIGN as usize != 0 { | ||
return Err(FlashStorageError::NotAligned); | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[inline(always)] | ||
pub(crate) fn check_bounds(&self, offset: u32, length: usize) -> Result<(), FlashStorageError> { | ||
let offset = offset as usize; | ||
if length > self.capacity || offset > self.capacity - length { | ||
return Err(FlashStorageError::OutOfBounds); | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[allow(clippy::all)] | ||
#[inline(never)] | ||
#[link_section = ".rwtext"] | ||
pub(crate) fn internal_read( | ||
&mut self, | ||
offset: u32, | ||
bytes: &mut [u8], | ||
) -> Result<(), FlashStorageError> { | ||
check_rc(chip_specific::esp_rom_spiflash_read( | ||
offset, | ||
bytes.as_ptr() as *mut u32, | ||
bytes.len() as u32, | ||
)) | ||
} | ||
|
||
#[inline(always)] | ||
fn unlock_once(&mut self) -> Result<(), FlashStorageError> { | ||
if !self.unlocked { | ||
if chip_specific::esp_rom_spiflash_unlock() != 0 { | ||
return Err(FlashStorageError::CantUnlock); | ||
} | ||
self.unlocked = true; | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[inline(never)] | ||
#[link_section = ".rwtext"] | ||
pub(crate) fn internal_erase(&mut self, sector: u32) -> Result<(), FlashStorageError> { | ||
self.unlock_once()?; | ||
|
||
check_rc(chip_specific::esp_rom_spiflash_erase_sector(sector)) | ||
} | ||
|
||
#[inline(never)] | ||
#[link_section = ".rwtext"] | ||
pub(crate) fn internal_write( | ||
&mut self, | ||
offset: u32, | ||
bytes: &[u8], | ||
) -> Result<(), FlashStorageError> { | ||
self.unlock_once()?; | ||
|
||
check_rc(chip_specific::esp_rom_spiflash_write( | ||
offset, | ||
bytes.as_ptr() as *const u32, | ||
bytes.len() as u32, | ||
)) | ||
} | ||
} |
Oops, something went wrong.