pub struct FlashArray<const N: usize>;target_os=none only.Expand description
A device abstraction for type-safe persistent storage in flash memory.
This struct provides a generic flash-block storage system for Raspberry Pi Pico,
allowing you to store any serde-compatible type in the device’s internal flash.
You choose the number of storage blocks at compile time. Each block holds up to 3900 bytes of postcard-serialized data (a hardware-determined 4 KB flash block minus metadata space).
§Features
- Type safety: Hash-based type checking prevents reading data written under a
different Rust type name. The hash is derived from the full type path
(for example,
app1::BootCounter). Trying to read a different types returnsOk(None). Structural changes (adding or removing fields) do not change the hash, but may cause deserialization to fail and return an error. - Postcard serialization: A compact,
no_std-friendly binary format.
§Block allocation
Conceptually, flash is treated as an array of fixed-size erase blocks counted from the end of memory backward. Your code can split that array using destructuring assignment and hand individual blocks to subsystems that need persistent storage.
⚠️ Warning: Pico 1 and Pico 2 store firmware, vector tables, and user data in the same flash device. Allocating too many blocks can overwrite your firmware.
§Example
use device_envoy::flash_array::FlashArray;
/// Boot counter (newtype) that wraps at 10.
/// Stored with `postcard` (Serde).
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy)]
struct BootCounter(u8);
impl BootCounter {
const fn new(value: u8) -> Self {
Self(value)
}
fn increment(self) -> Self {
Self((self.0 + 1) % 10)
}
}
async fn example() -> device_envoy::Result<Infallible> {
let p = embassy_rp::init(Default::default());
// Create a flash array. You can destructure it however you like.
let [mut boot_counter_flash_block] = FlashArray::<1>::new(p.FLASH)?;
// Read boot counter from flash then increment.
// FlashArray includes a runtime type hash so values are only loaded
// if the stored type matches the requested type; mismatches yield `None`.
let boot_counter = boot_counter_flash_block
.load()?
.unwrap_or(BootCounter::new(0)) // Default to 0 type not present
.increment();
// Write incremented counter back to flash.
// This example writes once per power-up (fine for a demo; don't write in a tight loop).
// Flash is typically good for ~100K erase cycles per block.
boot_counter_flash_block.save(&boot_counter)?;
info!("Boot counter: {}", boot_counter.0);
future::pending().await // Keep running
}Implementations§
Source§impl<const N: usize> FlashArray<N>
impl<const N: usize> FlashArray<N>
Sourcepub fn new(peripheral: Peri<'static, FLASH>) -> Result<[FlashBlock; N]>
pub fn new(peripheral: Peri<'static, FLASH>) -> Result<[FlashBlock; N]>
Reserve N contiguous blocks and return them as an array that you can destructure however you like.
See FlashArray for usage examples.
Auto Trait Implementations§
impl<const N: usize> Freeze for FlashArray<N>
impl<const N: usize> RefUnwindSafe for FlashArray<N>
impl<const N: usize> Send for FlashArray<N>
impl<const N: usize> Sync for FlashArray<N>
impl<const N: usize> Unpin for FlashArray<N>
impl<const N: usize> UnwindSafe for FlashArray<N>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
Source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
Source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
Source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more