Skip to content

Commit

Permalink
Merge branch 'main' into make-rmt-channel-creator-public
Browse files Browse the repository at this point in the history
  • Loading branch information
jessebraham authored May 27, 2024
2 parents 3d79e47 + 60e4b88 commit af790f0
Show file tree
Hide file tree
Showing 23 changed files with 1,535 additions and 14 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exclude = [
"esp-println",
"esp-riscv-rt",
"esp-wifi",
"esp-storage",
"examples",
"extras/bench-server",
"extras/esp-wifishark",
Expand Down
14 changes: 7 additions & 7 deletions esp-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ xtensa-lx = { version = "0.9.0", optional = true }
# IMPORTANT:
# Each supported device MUST have its PAC included below along with a
# corresponding feature.
esp32 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs/", rev = "9a36a93", features = ["critical-section", "rt"], optional = true }
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9a36a9375a1dfd1b51a559ee76f144935a7e8ed8", features = ["critical-section", "rt"], optional = true }

[target.'cfg(target_arch = "riscv32")'.dependencies]
esp-riscv-rt = { version = "0.8.0", path = "../esp-riscv-rt" }
Expand Down
51 changes: 51 additions & 0 deletions esp-storage/Cargo.toml
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 = []
34 changes: 34 additions & 0 deletions esp-storage/README.md
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.
21 changes: 21 additions & 0 deletions esp-storage/build.rs
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(())
}
}
161 changes: 161 additions & 0 deletions esp-storage/src/common.rs
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,
))
}
}
Loading

0 comments on commit af790f0

Please sign in to comment.