diff --git a/esp-hal-procmacros/Cargo.toml b/esp-hal-procmacros/Cargo.toml
index 53eab3aa737..4193040a424 100644
--- a/esp-hal-procmacros/Cargo.toml
+++ b/esp-hal-procmacros/Cargo.toml
@@ -33,7 +33,7 @@ enum-dispatch = []
interrupt = []
## Provide a `#[ram]` procmacro to place functions in RAM instead of flash.
ram = []
-## Indicates the target devices has RTC slow memory available.
+## Indicates the target device has RTC slow memory available.
rtc_slow = []
#! ### Low-power Core Feature Flags
diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs
index e108fcfb0b3..6bec2d198f1 100644
--- a/esp-hal-procmacros/src/lib.rs
+++ b/esp-hal-procmacros/src/lib.rs
@@ -16,25 +16,22 @@
//! optimized memory usage and precise handling of hardware interrupts.
//!
//! Key Components:
-//! - [interrupt](attr.interrupt.html) - Attribute macro for marking interrupt
-//! handlers. Interrupt handlers are used to handle specific hardware
-//! interrupts generated by peripherals.
The macro allows users to
-//! specify the interrupt name explicitly or use the function name to match
-//! the interrupt.
-//! - [main](attr.main.html) - Creates a new `executor`` instance and declares
+//! - [`interrupt`](attr.interrupt.html) - Attribute macro for marking
+//! interrupt handlers. Interrupt handlers are used to handle specific
+//! hardware interrupts generated by peripherals.
+//!
+//! The macro allows users to specify the interrupt name explicitly or use
+//! the function name to match the interrupt.
+//! - [`main`](attr.main.html) - Creates a new `executor` instance and declares
//! an application entry point spawning the corresponding function body as an
//! async task.
-//! - [ram](attr.ram.html) - Attribute macro for placing statics and functions
-//! into specific memory sections, such as SRAM or RTC RAM (slow or fast)
-//! with different initialization options. Supported options are:
-//! - `rtc_fast` - Use RTC fast RAM
-//! - `rtc_slow` - Use RTC slow RAM (not all targets support slow RTC RAM)
-//! - `uninitialized` - Skip initialization of the memory
-//! - `zeroed` - Initialize the memory to zero
+//! - [`ram`](attr.ram.html) - Attribute macro for placing statics and
+//! functions into specific memory sections, such as SRAM or RTC RAM (slow or
+//! fast) with different initialization options. See its documentation for
+//! details.
//!
//! ## Examples
//!
-//!
//! #### `main` macro
//!
//! Requires the `embassy` feature to be enabled.
@@ -46,21 +43,6 @@
//! }
//! ```
//!
-//! #### `ram` macro
-//!
-//! Requires the `ram` feature to be enabled.
-//!
-//! ```rust, no_run
-//! #[ram(rtc_fast)]
-//! static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
-//!
-//! #[ram(rtc_fast, uninitialized)]
-//! static mut SOME_UNINITED_DATA: [u8; 2] = [0; 2];
-//!
-//! #[ram(rtc_fast, zeroed)]
-//! static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
-//! ```
-//!
//! ## Feature Flags
#![doc = document_features::document_features!()]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
@@ -88,19 +70,64 @@ mod lp_core;
struct RamArgs {
rtc_fast: bool,
rtc_slow: bool,
- uninitialized: bool,
+ persistent: bool,
zeroed: bool,
}
-/// This attribute allows placing statics and functions into ram.
+/// Sets which segment of RAM to use for a function or static and how it should
+/// be initialized.
+///
+/// Requires the `ram` feature.
+///
+/// # Options
+///
+/// - `rtc_fast`: Use RTC fast RAM.
+/// - `rtc_slow`: Use RTC slow RAM. **Note**: not available on all targets
+/// - `persistent`: Persist the contents of the `static` across resets. See [the
+/// section below](#persistent) for details.
+/// - `zeroed`: Initialize the memory of the `static` to zero. The initializer
+/// expression will be discarded. Types used must implement
+/// [`bytemuck::Zeroable`].
+///
+/// Using both `rtc_fast` and `rtc_slow` or `persistent` and `zeroed` together
+/// is an error.
+///
+/// ## `persistent`
+///
+/// Initialize the memory to zero after the initial boot. Thereafter,
+/// initialization is skipped to allow communication across `software_reset()`,
+/// deep sleep, watchdog timeouts, etc.
+///
+/// Types used must implement [`bytemuck::AnyBitPattern`].
///
-/// Options that can be specified are rtc_slow or rtc_fast to use the
-/// RTC slow or RTC fast ram instead of the normal SRAM.
+/// ### Warnings
///
-/// The uninitialized option will skip initialization of the memory
-/// (e.g. to persist it across resets or deep sleep mode for the RTC RAM)
+/// - A system-level or lesser reset occurring before the ram has been zeroed
+/// *could* skip initialization and start the application with the static
+/// filled with random bytes.
+/// - There is no way to keep some kinds of resets from happening while updating
+/// a persistent static—not even a critical section.
///
-/// Not all targets support RTC slow ram.
+/// If these are issues for your application, consider adding a checksum
+/// alongside the data.
+///
+/// # Examples
+///
+/// ```rust, no_run
+/// #[ram(rtc_fast)]
+/// static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
+///
+/// #[ram(rtc_fast, persistent)]
+/// static mut SOME_PERSISTENT_DATA: [u8; 2] = [0; 2];
+///
+/// #[ram(rtc_fast, zeroed)]
+/// static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
+/// ```
+///
+/// See the `ram` example in the esp-hal repository for a full usage example.
+///
+/// [`bytemuck::AnyBitPattern`]: https://docs.rs/bytemuck/1.9.0/bytemuck/trait.AnyBitPattern.html
+/// [`bytemuck::Zeroable`]: https://docs.rs/bytemuck/1.9.0/bytemuck/trait.Zeroable.html
#[cfg(feature = "ram")]
#[proc_macro_attribute]
#[proc_macro_error::proc_macro_error]
@@ -120,7 +147,7 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
let RamArgs {
rtc_fast,
rtc_slow,
- uninitialized,
+ persistent,
zeroed,
} = match FromMeta::from_list(&attr_args) {
Ok(v) => v,
@@ -140,7 +167,7 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
}
let is_fn = matches!(item, Item::Fn(_));
- let section_name = match (is_fn, rtc_fast, rtc_slow, uninitialized, zeroed) {
+ let section_name = match (is_fn, rtc_fast, rtc_slow, persistent, zeroed) {
(true, false, false, false, false) => Ok(".rwtext"),
(true, true, false, false, false) => Ok(".rtc_fast.text"),
(true, false, true, false, false) => Ok(".rtc_slow.text"),
@@ -148,11 +175,11 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
(false, false, false, false, false) => Ok(".data"),
(false, true, false, false, false) => Ok(".rtc_fast.data"),
- (false, true, false, true, false) => Ok(".rtc_fast.noinit"),
+ (false, true, false, true, false) => Ok(".rtc_fast.persistent"),
(false, true, false, false, true) => Ok(".rtc_fast.bss"),
(false, false, true, false, false) => Ok(".rtc_slow.data"),
- (false, false, true, true, false) => Ok(".rtc_slow.noinit"),
+ (false, false, true, true, false) => Ok(".rtc_slow.persistent"),
(false, false, true, false, true) => Ok(".rtc_slow.bss"),
_ => Err(()),
@@ -171,9 +198,39 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
}
};
+ let trait_check = if zeroed {
+ Some("zeroable")
+ } else if persistent {
+ Some("persistable")
+ } else {
+ None
+ };
+ let trait_check = trait_check.map(|name| {
+ use proc_macro_crate::{crate_name, FoundCrate};
+
+ let hal = proc_macro2::Ident::new(
+ if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
+ &name
+ } else {
+ "crate"
+ },
+ Span::call_site().into(),
+ );
+
+ let assertion = quote::format_ident!("assert_is_{name}");
+ let Item::Static(ref item) = item else {
+ abort!(item, "Expected a `static`");
+ };
+ let ty = &item.ty;
+ quote::quote! {
+ const _: () = #hal::__macro_implementation::#assertion::<#ty>();
+ }
+ });
+
let output = quote::quote! {
#section
#item
+ #trait_check
};
output.into()
diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md
index f3af559724c..fd6d4d960bb 100644
--- a/esp-hal/CHANGELOG.md
+++ b/esp-hal/CHANGELOG.md
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add support for GPIO wake-up source (#1724)
- dma: add Mem2Mem to support memory to memory transfer (#1738)
- Add `uart` wake source (#1727)
+- `#[ram(persistent)]` option to replace the unsound `uninitialized` option (#1677)
- uart: Make `rx_timeout` optional in Config struct (#1759)
- Add interrupt related functions to `PeriodicTimer`/`OneShotTimer`, added `ErasedTimer` (#1753)
@@ -31,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix `sleep_light` for ESP32-C6 (#1720)
- ROM Functions: Fix address of `ets_update_cpu_frequency_rom` (#1722)
- Fix `regi2c_*` functions for `esp32h2` (#1737)
+- Improved `#[ram(zeroed)]` soundness by adding a `bytemuck::Zeroable` type bound (#1677)
- EESP32-S2 / ESP32-S3: Fix UsbDm and UsbDp for Gpio19 and Gpio20
### Changed
@@ -45,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Removed
- uart: Removed `configure_pins` methods (#1592)
- Removed `DmaError::Exhausted` error by improving the implementation of the `pop` function (#1664)
+- Unsound `#[ram(uninitialized)]` option in favor of the new `persistent` option (#1677)
## [0.18.0] - 2024-06-04
diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml
index 0187dac56c5..8c70ad3b690 100644
--- a/esp-hal/Cargo.toml
+++ b/esp-hal/Cargo.toml
@@ -16,6 +16,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
bitflags = "2.5.0"
+bytemuck = "1.0.0"
bitfield = "0.15.0"
cfg-if = "1.0.0"
critical-section = "1.1.2"
@@ -77,7 +78,7 @@ serde = { version = "1.0.203", features = ["derive"] }
[features]
default = ["embedded-hal"]
-riscv = ["dep:riscv", "critical-section/restore-state-u8", "esp-riscv-rt/zero-bss"]
+riscv = ["dep:riscv", "critical-section/restore-state-u8"]
xtensa = ["dep:xtensa-lx", "critical-section/restore-state-u32"]
bluetooth = []
@@ -105,11 +106,11 @@ esp32 = ["dep:esp32", "xtensa", "xtensa-lx/spin", "xtensa-lx-rt/esp32"]
# Target the ESP32-C2.
esp32c2 = ["dep:esp32c2", "riscv", "portable-atomic/unsafe-assume-single-core"]
# Target the ESP32-C3.
-esp32c3 = ["dep:esp32c3", "riscv", "portable-atomic/unsafe-assume-single-core", "rv-zero-rtc-bss"]
+esp32c3 = ["dep:esp32c3", "riscv", "portable-atomic/unsafe-assume-single-core", "esp-riscv-rt/rtc-ram"]
# Target the ESP32-C6.
-esp32c6 = ["dep:esp32c6", "riscv", "procmacros/has-lp-core", "rv-zero-rtc-bss"]
+esp32c6 = ["dep:esp32c6", "riscv", "procmacros/has-lp-core", "esp-riscv-rt/rtc-ram"]
# Target the ESP32-H2.
-esp32h2 = ["dep:esp32h2", "riscv", "rv-zero-rtc-bss"]
+esp32h2 = ["dep:esp32h2", "riscv", "esp-riscv-rt/rtc-ram"]
# Target the ESP32-S2.
esp32s2 = ["dep:esp32s2", "xtensa", "portable-atomic/critical-section", "procmacros/has-ulp-core", "xtensa-lx-rt/esp32s2", "usb-otg"]
# Target the ESP32-S3.
@@ -119,12 +120,6 @@ esp32s3 = ["dep:esp32s3", "xtensa", "procmacros/has-ulp-core", "xtensa-lx/spin",
## Move the stack to start of RAM to get zero-cost stack overflow protection
## (ESP32-C6 and ESPS32-H2 only!).
flip-link = ["esp-riscv-rt/fix-sp"]
-## Initialize the `.data` section of memory.
-rv-init-data = ["esp-riscv-rt/init-data", "esp-riscv-rt/init-rw-text"]
-## Zero the `.bss` section of low-power memory.
-rv-zero-rtc-bss = ["esp-riscv-rt/zero-rtc-fast-bss"]
-## Initialize the `.data` section of low-power memory.
-rv-init-rtc-data = ["esp-riscv-rt/init-rtc-fast-data", "esp-riscv-rt/init-rtc-fast-text"]
#! ### Trait Implementation Feature Flags
## Enable support for asynchronous operation, with interfaces provided by
diff --git a/esp-hal/ld/sections/rtc_fast.x b/esp-hal/ld/sections/rtc_fast.x
index 3bf5e1dd2f7..ea2ffb76d64 100644
--- a/esp-hal/ld/sections/rtc_fast.x
+++ b/esp-hal/ld/sections/rtc_fast.x
@@ -25,10 +25,12 @@ SECTIONS {
. = ALIGN(4);
} > RTC_FAST_RWDATA
- .rtc_fast.noinit (NOLOAD) :
+ .rtc_fast.persistent (NOLOAD) :
{
. = ALIGN(4);
- *(.rtc_fast.noinit .rtc_fast.noinit.*)
+ _rtc_fast_persistent_start = ABSOLUTE(.);
+ *(.rtc_fast.persistent .rtc_fast.persistent.*)
+ _rtc_fast_persistent_end = ABSOLUTE(.);
. = ALIGN(4);
} > RTC_FAST_RWDATA
}
\ No newline at end of file
diff --git a/esp-hal/ld/sections/rtc_slow.x b/esp-hal/ld/sections/rtc_slow.x
index 035e95ca9a5..fe864dfc8bd 100644
--- a/esp-hal/ld/sections/rtc_slow.x
+++ b/esp-hal/ld/sections/rtc_slow.x
@@ -25,10 +25,12 @@ SECTIONS {
. = ALIGN(4);
} > rtc_slow_seg
- .rtc_slow.noinit (NOLOAD) :
+ .rtc_slow.persistent (NOLOAD) :
{
. = ALIGN(4);
- *(.rtc_slow.noinit .rtc_slow.noinit.*)
+ _rtc_slow_persistent_start = ABSOLUTE(.);
+ *(.rtc_slow.persistent .rtc_slow.persistent.*)
+ _rtc_slow_persistent_end = ABSOLUTE(.);
. = ALIGN(4);
} > rtc_slow_seg
}
\ No newline at end of file
diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs
index f853f6741d2..a3fbed98576 100644
--- a/esp-hal/src/lib.rs
+++ b/esp-hal/src/lib.rs
@@ -288,6 +288,39 @@ pub(crate) mod private {
pub struct Internal;
}
+/// Marker trait for types that can be safely used in `#[ram(persistent)]`.
+///
+/// # Safety
+///
+/// - The type must be inhabited
+/// - The type must be valid for any bit pattern of its backing memory in case a
+/// reset occurs during a write or a reset interrupts the zero initialization
+/// on first boot.
+/// - Structs must contain only `Persistable` fields and padding
+pub unsafe trait Persistable: Sized {}
+
+macro_rules! impl_persistable {
+ ($($t:ty),+) => {$(
+ unsafe impl Persistable for $t {}
+ )+};
+ (atomic $($t:ident),+) => {$(
+ unsafe impl Persistable for portable_atomic::$t {}
+ )+};
+}
+
+impl_persistable!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64);
+impl_persistable!(atomic AtomicU8, AtomicI8, AtomicU16, AtomicI16, AtomicU32, AtomicI32, AtomicUsize, AtomicIsize);
+
+unsafe impl Persistable for [T; N] {}
+
+#[doc(hidden)]
+pub mod __macro_implementation {
+ //! Unstable private implementation details of esp-hal-procmacros.
+
+ pub const fn assert_is_zeroable() {}
+ pub const fn assert_is_persistable() {}
+}
+
/// Available CPU cores
///
/// The actual number of available cores depends on the target.
diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs
index 4d10c0be1be..bff898dfd5a 100644
--- a/esp-hal/src/soc/esp32/mod.rs
+++ b/esp-hal/src/soc/esp32/mod.rs
@@ -8,7 +8,10 @@
use core::ptr::addr_of_mut;
use self::peripherals::{LPWR, TIMG0, TIMG1};
-use crate::{rtc_cntl::Rtc, timer::timg::Wdt};
+use crate::{
+ rtc_cntl::{Rtc, SocResetReason},
+ timer::timg::Wdt,
+};
pub mod cpu_control;
pub mod efuse;
@@ -55,9 +58,13 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
extern "C" {
static mut _rtc_fast_bss_start: u32;
static mut _rtc_fast_bss_end: u32;
+ static mut _rtc_fast_persistent_start: u32;
+ static mut _rtc_fast_persistent_end: u32;
static mut _rtc_slow_bss_start: u32;
static mut _rtc_slow_bss_end: u32;
+ static mut _rtc_slow_persistent_start: u32;
+ static mut _rtc_slow_persistent_end: u32;
static mut _stack_start_cpu0: u32;
@@ -79,6 +86,19 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
addr_of_mut!(_rtc_slow_bss_start),
addr_of_mut!(_rtc_slow_bss_end),
);
+ if matches!(
+ crate::reset::get_reset_reason(),
+ None | Some(SocResetReason::ChipPowerOn)
+ ) {
+ xtensa_lx_rt::zero_bss(
+ addr_of_mut!(_rtc_fast_persistent_start),
+ addr_of_mut!(_rtc_fast_persistent_end),
+ );
+ xtensa_lx_rt::zero_bss(
+ addr_of_mut!(_rtc_slow_persistent_start),
+ addr_of_mut!(_rtc_slow_persistent_end),
+ );
+ }
unsafe {
let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard);
diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs
index 8fbf4a6390d..5a7b61ded07 100644
--- a/esp-hal/src/soc/esp32s2/mod.rs
+++ b/esp-hal/src/soc/esp32s2/mod.rs
@@ -12,7 +12,10 @@
use core::ptr::addr_of_mut;
use self::peripherals::{LPWR, TIMG0, TIMG1};
-use crate::{rtc_cntl::Rtc, timer::timg::Wdt};
+use crate::{
+ rtc_cntl::{Rtc, SocResetReason},
+ timer::timg::Wdt,
+};
pub mod efuse;
pub mod gpio;
@@ -60,9 +63,13 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
extern "C" {
static mut _rtc_fast_bss_start: u32;
static mut _rtc_fast_bss_end: u32;
+ static mut _rtc_fast_persistent_start: u32;
+ static mut _rtc_fast_persistent_end: u32;
static mut _rtc_slow_bss_start: u32;
static mut _rtc_slow_bss_end: u32;
+ static mut _rtc_slow_persistent_start: u32;
+ static mut _rtc_slow_persistent_end: u32;
static mut _stack_start_cpu0: u32;
@@ -84,6 +91,19 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
addr_of_mut!(_rtc_slow_bss_start),
addr_of_mut!(_rtc_slow_bss_end),
);
+ if matches!(
+ crate::reset::get_reset_reason(),
+ None | Some(SocResetReason::ChipPowerOn)
+ ) {
+ xtensa_lx_rt::zero_bss(
+ addr_of_mut!(_rtc_fast_persistent_start),
+ addr_of_mut!(_rtc_fast_persistent_end),
+ );
+ xtensa_lx_rt::zero_bss(
+ addr_of_mut!(_rtc_slow_persistent_start),
+ addr_of_mut!(_rtc_slow_persistent_end),
+ );
+ }
unsafe {
let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard);
diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs
index 5a76765f722..fdda6395f5b 100644
--- a/esp-hal/src/soc/esp32s3/mod.rs
+++ b/esp-hal/src/soc/esp32s3/mod.rs
@@ -12,7 +12,10 @@
use core::ptr::addr_of_mut;
use self::peripherals::{LPWR, TIMG0, TIMG1};
-use crate::{rtc_cntl::Rtc, timer::timg::Wdt};
+use crate::{
+ rtc_cntl::{Rtc, SocResetReason},
+ timer::timg::Wdt,
+};
pub mod cpu_control;
pub mod efuse;
@@ -94,9 +97,13 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
extern "C" {
static mut _rtc_fast_bss_start: u32;
static mut _rtc_fast_bss_end: u32;
+ static mut _rtc_fast_persistent_start: u32;
+ static mut _rtc_fast_persistent_end: u32;
static mut _rtc_slow_bss_start: u32;
static mut _rtc_slow_bss_end: u32;
+ static mut _rtc_slow_persistent_start: u32;
+ static mut _rtc_slow_persistent_end: u32;
static mut _stack_start_cpu0: u32;
@@ -118,6 +125,19 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
addr_of_mut!(_rtc_slow_bss_start),
addr_of_mut!(_rtc_slow_bss_end),
);
+ if matches!(
+ crate::reset::get_reset_reason(),
+ None | Some(SocResetReason::ChipPowerOn)
+ ) {
+ xtensa_lx_rt::zero_bss(
+ addr_of_mut!(_rtc_fast_persistent_start),
+ addr_of_mut!(_rtc_fast_persistent_end),
+ );
+ xtensa_lx_rt::zero_bss(
+ addr_of_mut!(_rtc_slow_persistent_start),
+ addr_of_mut!(_rtc_slow_persistent_end),
+ );
+ }
unsafe {
let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard);
diff --git a/esp-riscv-rt/CHANGELOG.md b/esp-riscv-rt/CHANGELOG.md
index 324b2a2c89d..9383611740d 100644
--- a/esp-riscv-rt/CHANGELOG.md
+++ b/esp-riscv-rt/CHANGELOG.md
@@ -9,12 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- `rtc-ram` feature used by `esp-hal` to control rtc ram initialization (#1677)
+
### Fixed
### Changed
### Removed
+- All existing features controlling ram initialization. Most (`init-data`, `init-rw-text`,
+ `init-rtc-fast-data`, and `init-rtc-fast-text`) were only used for the (already removed) direct
+ boot support. `zero-bss` is now enabled unconditionally. `zero-rtc-fast-bss` was merged into the
+ new `rtc-ram` feature. (#1677)
+
## 0.8.0 - 2024-04-18
### Fixed
diff --git a/esp-riscv-rt/Cargo.toml b/esp-riscv-rt/Cargo.toml
index ae45b80ca12..9198eb98694 100644
--- a/esp-riscv-rt/Cargo.toml
+++ b/esp-riscv-rt/Cargo.toml
@@ -20,29 +20,12 @@ riscv-rt-macros = "0.2.1"
fix-sp = []
## Indicate that the device supports `mie` and `mip` instructions.
has-mie-mip = []
-
-#! ### Memory Initialization Feature Flags
-## Initialize the `data` section.
-init-data = []
-## Initialize the `.rtc_fast.data` section.
-init-rtc-fast-data = []
-## Initialize the `.rtc_fast.text` section.
-init-rtc-fast-text = []
-## Initialize the `.rwtext` section.
-init-rw-text = []
-## Zero the `.bss` section.
-zero-bss = []
-## Zero the `.rtc_fast.bss` section.
-zero-rtc-fast-bss = []
+## Indicate that the device has RTC RAM.
+rtc-ram = []
# This feature is intended for testing; you probably don't want to enable it:
ci = [
"fix-sp",
"has-mie-mip",
- "init-data",
- "init-rtc-fast-data",
- "init-rtc-fast-text",
- "init-rw-text",
- "zero-bss",
- "zero-rtc-fast-bss",
+ "rtc-ram",
]
diff --git a/esp-riscv-rt/src/lib.rs b/esp-riscv-rt/src/lib.rs
index 3ff1f837a06..2283280c96d 100644
--- a/esp-riscv-rt/src/lib.rs
+++ b/esp-riscv-rt/src/lib.rs
@@ -298,7 +298,6 @@ _abs_start:
csrw mie, 0
csrw mip, 0
"#,
-#[cfg(feature = "zero-bss")]
r#"
la a0, _bss_start
la a1, _bss_end
@@ -310,7 +309,7 @@ _abs_start:
blt a0, a1, 1b
2:
"#,
-#[cfg(feature = "zero-rtc-fast-bss")]
+#[cfg(feature = "rtc-ram")]
r#"
la a0, _rtc_fast_bss_start
la a1, _rtc_fast_bss_end
@@ -322,59 +321,20 @@ _abs_start:
blt a0, a1, 1b
2:
"#,
-#[cfg(feature = "init-data")]
+ // Zero .rtc_fast.persistent iff the chip just powered on
+#[cfg(feature = "rtc-ram")]
r#"
- la a0, _data_start
- la a1, _data_end
+ mv a0, zero
+ call rtc_get_reset_reason
+ addi a1, zero, 1
+ bne a0, a1, 2f
+ la a0, _rtc_fast_persistent_start
+ la a1, _rtc_fast_persistent_end
bge a0, a1, 2f
- la a2, _sidata
- 1:
- lw a3, 0(a2)
- sw a3, 0(a0)
- addi a0, a0, 4
- addi a2, a2, 4
- blt a0, a1, 1b
- 2:
-"#,
-#[cfg(feature = "init-rw-text")]
- r#"
- la a0, _srwtext
- la a1, _erwtext
- bge a0, a1, 2f
- la a2, _irwtext
- 1:
- lw a3, 0(a2)
- sw a3, 0(a0)
- addi a0, a0, 4
- addi a2, a2, 4
- blt a0, a1, 1b
- 2:
-"#,
-#[cfg(feature = "init-rtc-fast-data")]
- r#"
- la a0, _rtc_fast_data_start
- la a1, _rtc_fast_data_end
- bge a0, a1, 2f
- la a2, _irtc_fast_data
- 1:
- lw a3, 0(a2)
- sw a3, 0(a0)
- addi a0, a0, 4
- addi a2, a2, 4
- blt a0, a1, 1b
- 2:
-"#,
-#[cfg(feature = "init-rtc-fast-text")]
- r#"
- la a0, _srtc_fast_text
- la a1, _ertc_fast_text
- bge a0, a1, 2f
- la a2, _irtc_fast_text
+ mv a3, x0
1:
- lw a3, 0(a2)
sw a3, 0(a0)
addi a0, a0, 4
- addi a2, a2, 4
blt a0, a1, 1b
2:
"#,
diff --git a/examples/src/bin/ram.rs b/examples/src/bin/ram.rs
index db406ae5a85..7e71ba5972f 100644
--- a/examples/src/bin/ram.rs
+++ b/examples/src/bin/ram.rs
@@ -4,8 +4,8 @@
//!
//! Initialized memory is always re-initialized on startup.
//!
-//! Uninitialzed memory isn't initialized on startup and can be used to keep
-//! data during resets.
+//! Persistent memory is not zeroed after resets that preserve RTC ram. See the
+//! documentation for `esp-hal-procmacros` for the full list.
//!
//! Zeroed memory is initialized to zero on startup.
//!
@@ -31,8 +31,8 @@ use esp_println::println;
#[ram(rtc_fast)]
static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
-#[ram(rtc_fast, uninitialized)]
-static mut SOME_UNINITED_DATA: [u8; 2] = [0; 2];
+#[ram(rtc_fast, persistent)]
+static mut SOME_PERSISTENT_DATA: [u8; 2] = [0; 2];
#[ram(rtc_fast, zeroed)]
static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
@@ -56,27 +56,22 @@ fn main() -> ! {
);
unsafe {
println!("SOME_INITED_DATA {:x?}", SOME_INITED_DATA);
- println!("SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA);
+ println!("SOME_PERSISTENT_DATA {:x?}", SOME_PERSISTENT_DATA);
println!("SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA);
SOME_INITED_DATA[0] = 0xff;
SOME_ZEROED_DATA[0] = 0xff;
println!("SOME_INITED_DATA {:x?}", SOME_INITED_DATA);
- println!("SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA);
+ println!("SOME_PERSISTENT_DATA {:x?}", SOME_PERSISTENT_DATA);
println!("SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA);
- if SOME_UNINITED_DATA[0] != 0 {
- SOME_UNINITED_DATA[0] = 0;
- SOME_UNINITED_DATA[1] = 0;
+ if SOME_PERSISTENT_DATA[1] == 0xff {
+ SOME_PERSISTENT_DATA[1] = 0;
}
- if SOME_UNINITED_DATA[1] == 0xff {
- SOME_UNINITED_DATA[1] = 0;
- }
-
- println!("Counter {}", SOME_UNINITED_DATA[1]);
- SOME_UNINITED_DATA[1] += 1;
+ println!("Counter {}", SOME_PERSISTENT_DATA[1]);
+ SOME_PERSISTENT_DATA[1] += 1;
}
println!(