Write state to flash

This commit is contained in:
Mona Mayrhofer 2025-06-27 22:39:25 +02:00
parent 700bc71bf6
commit b828cc4bde
No known key found for this signature in database
GPG key ID: 3E2BDA732A957188
5 changed files with 239 additions and 53 deletions

View file

@ -1,14 +1,15 @@
[target.riscv32imc-unknown-none-elf]
runner = "espflash flash --monitor --chip esp32c3"
runner = "espflash flash --monitor --chip esp32c3 --partition-table ./partitions.csv"
[env]
ESP_LOG="info"
ESP_LOG = "info"
[build]
rustflags = [
# Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.)
# NOTE: May negatively impact performance of produced code
"-C", "force-frame-pointers",
"-C",
"force-frame-pointers",
]
target = "riscv32imc-unknown-none-elf"

168
Cargo.lock generated
View file

@ -8,6 +8,15 @@ version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]]
name = "autocfg"
version = "1.5.0"
@ -111,7 +120,7 @@ dependencies = [
"embedded-io",
"embedded-io-async",
"futures-intrusive",
"heapless",
"heapless 0.8.0",
]
[[package]]
@ -147,6 +156,15 @@ dependencies = [
"num-traits",
]
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "critical-section"
version = "1.2.0"
@ -266,7 +284,7 @@ dependencies = [
"embassy-time",
"embedded-io-async",
"embedded-nal-async",
"heapless",
"heapless 0.8.0",
"managed",
"smoltcp",
]
@ -288,7 +306,7 @@ dependencies = [
"embedded-io-async",
"futures-sink",
"futures-util",
"heapless",
"heapless 0.8.0",
]
[[package]]
@ -302,7 +320,7 @@ dependencies = [
"embedded-io-async",
"futures-sink",
"futures-util",
"heapless",
"heapless 0.8.0",
]
[[package]]
@ -338,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83"
dependencies = [
"embassy-executor",
"heapless",
"heapless 0.8.0",
]
[[package]]
@ -487,6 +505,17 @@ dependencies = [
"termcolor",
]
[[package]]
name = "esp-build"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "837020ff95fbf4c15c206541dda7994f1bbe6e1505e36a6a5ecb51fdb61656d7"
dependencies = [
"quote",
"syn 2.0.104",
"termcolor",
]
[[package]]
name = "esp-config"
version = "0.3.1"
@ -520,10 +549,10 @@ dependencies = [
"embedded-io",
"embedded-io-async",
"enumset",
"esp-build",
"esp-build 0.2.0",
"esp-config",
"esp-hal-procmacros",
"esp-metadata",
"esp-metadata 0.6.0",
"esp-riscv-rt",
"esp32c3",
"fugit",
@ -555,11 +584,11 @@ dependencies = [
"embassy-time",
"embassy-time-driver",
"embassy-time-queue-utils",
"esp-build",
"esp-build 0.2.0",
"esp-config",
"esp-hal",
"esp-hal-procmacros",
"esp-metadata",
"esp-metadata 0.6.0",
"portable-atomic",
"static_cell",
]
@ -592,6 +621,18 @@ dependencies = [
"strum 0.26.3",
]
[[package]]
name = "esp-metadata"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0154d59933c2419ef25a01938517cc6969f47b6af53ebb34c279393aa20d9654"
dependencies = [
"anyhow",
"basic-toml",
"serde",
"strum 0.27.1",
]
[[package]]
name = "esp-println"
version = "0.13.1"
@ -599,7 +640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960703930f9f3c899ddedd122ea27a09d6a612c22323157e524af5b18876448e"
dependencies = [
"critical-section",
"esp-build",
"esp-build 0.2.0",
"log",
"portable-atomic",
]
@ -615,6 +656,19 @@ dependencies = [
"riscv-rt-macros",
]
[[package]]
name = "esp-storage"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b6502654e5750e8162e66512d7e8d84f7eb51d17ec6aa7e0da95cd102769425"
dependencies = [
"critical-section",
"document-features",
"embedded-storage",
"esp-build 0.3.0",
"esp-metadata 0.7.0",
]
[[package]]
name = "esp-wifi"
version = "0.13.0"
@ -631,12 +685,12 @@ dependencies = [
"embedded-io-async",
"enumset",
"esp-alloc",
"esp-build",
"esp-build 0.2.0",
"esp-config",
"esp-hal",
"esp-metadata",
"esp-metadata 0.6.0",
"esp-wifi-sys",
"heapless",
"heapless 0.8.0",
"libm",
"log",
"num-derive",
@ -758,6 +812,15 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
[[package]]
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"byteorder",
]
[[package]]
name = "hash32"
version = "0.3.1"
@ -773,13 +836,27 @@ version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heapless"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
dependencies = [
"atomic-polyfill",
"hash32 0.2.1",
"rustc_version",
"serde",
"spin",
"stable_deref_trait",
]
[[package]]
name = "heapless"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"hash32 0.3.1",
"portable-atomic",
"stable_deref_trait",
]
@ -894,14 +971,18 @@ dependencies = [
"embassy-time",
"embedded-io",
"embedded-io-async",
"embedded-storage",
"esp-alloc",
"esp-hal",
"esp-hal-embassy",
"esp-println",
"esp-storage",
"esp-wifi",
"heapless",
"heapless 0.8.0",
"libm",
"log",
"postcard",
"serde",
"smart-leds",
"smoltcp",
"static_cell",
@ -1015,6 +1096,17 @@ dependencies = [
"syn 2.0.104",
]
[[package]]
name = "postcard"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c1de96e20f51df24ca73cafcc4690e044854d803259db27a00a461cb3b9d17a"
dependencies = [
"cobs",
"heapless 0.7.17",
"serde",
]
[[package]]
name = "proc-macro-crate"
version = "3.3.0"
@ -1150,6 +1242,15 @@ dependencies = [
"syn 2.0.104",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.21"
@ -1162,6 +1263,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "serde"
version = "1.0.219"
@ -1218,10 +1325,19 @@ dependencies = [
"bitflags 1.3.2",
"byteorder",
"cfg-if",
"heapless",
"heapless 0.8.0",
"managed",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
@ -1318,6 +1434,26 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]]
name = "toml"
version = "0.8.23"

View file

@ -67,6 +67,10 @@ ws2812-spi = "0.5.0"
embassy-futures = "0.1.1"
embassy-sync = "0.7.0"
libm = "0.2.15"
esp-storage = { version = "0.6.0", features = ["esp32c3"] }
embedded-storage = "0.3.1"
postcard = { version = "1.1.2", features = [] }
serde = { version = "1.0.219", features = ["derive"], default-features = false }
[profile.dev]
# Rust debug is too slow.

8
partitions.csv Normal file
View file

@ -0,0 +1,8 @@
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
# TODO Keep in sync with main.rs APP_DATA_OFFSET
app_store,0x40, 0x01, 0x10000, 0x10000,
factory, app, factory, 0x20000, 1M,
1 # ESP-IDF Partition Table
2 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 # TODO Keep in sync with main.rs APP_DATA_OFFSET
6 app_store,0x40, 0x01, 0x10000, 0x10000,
7 factory, app, factory, 0x20000, 1M,

View file

@ -1,29 +1,28 @@
#![no_std]
#![no_main]
use alloc::boxed::Box;
use core::ops::BitXor;
use core::ops::Rem;
use core::pin::Pin;
use embassy_executor::Spawner;
use embassy_futures::select::{Either, select};
use embassy_futures::select::select;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::channel::{Channel, Sender};
use embassy_sync::mutex::Mutex;
use embassy_sync::watch::{self, Watch};
use embassy_time::{Duration, Instant, Timer, WithTimeout};
use embassy_time::Timer;
use embedded_storage::nor_flash::NorFlash;
use embedded_storage::nor_flash::ReadNorFlash;
use esp_hal::Blocking;
use esp_hal::clock::CpuClock;
use esp_hal::gpio::{DriveMode, Input, InputConfig, Pull};
use esp_hal::peripherals::GPIO;
use esp_hal::rng;
use esp_hal::gpio::{Input, InputConfig, Pull};
use esp_hal::spi::master::{Config, Spi};
use esp_hal::time::Rate;
use esp_hal::timer::systimer::SystemTimer;
use esp_hal::timer::timg::TimerGroup;
use esp_hal::{Async, Blocking, DriverMode};
use libm::sin;
use esp_storage::FlashStorage;
use log::info;
use postcard::from_bytes;
use postcard::to_vec;
use serde::Deserialize;
use serde::Serialize;
use smart_leds::RGB8;
use smart_leds::SmartLedsWrite;
use static_cell::StaticCell;
@ -36,17 +35,14 @@ fn panic(_: &core::panic::PanicInfo) -> ! {
extern crate alloc;
#[derive(Clone, Debug, PartialEq, Eq)]
struct TargetState {
enabled: [bool; 12],
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
struct State {
pub count: u8,
}
impl Default for TargetState {
fn default() -> Self {
TargetState {
enabled: [false; 12],
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
struct TargetState {
enabled: [bool; 12],
}
static CHANNEL: StaticCell<Channel<NoopRawMutex, i32, 2>> = StaticCell::new();
@ -56,11 +52,12 @@ static STATE: Mutex<CriticalSectionRawMutex, TargetState> = Mutex::new(TargetSta
const ORDER: [usize; 12] = [5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11];
//Keep in syn with partitions.csv
const APP_DATA_OFFSET: u32 = 0x10_000;
#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
let channel = CHANNEL.init(Channel::new());
//let state_watch = STATE.init(Arc::new(Mutex::new(TargetState::default())));
// generator version: 0.3.1
esp_println::logger::init_logger_from_env();
@ -74,6 +71,21 @@ async fn main(spawner: Spawner) {
info!("Embassy initialized!");
let mut flash = FlashStorage::new();
info!("Flash: {flash:?}");
let mut state = {
let mut bytes = [0; 128];
flash.read(APP_DATA_OFFSET, &mut bytes[..]).unwrap();
info!("{bytes:x?}");
if let Ok(data) = from_bytes::<State>(&bytes[..]) {
info!("Successfully restored data.");
data
} else {
State { count: 0 }
}
};
let timer1 = TimerGroup::new(peripherals.TIMG0);
let _init = esp_wifi::init(
timer1.timer0,
@ -107,19 +119,36 @@ async fn main(spawner: Spawner) {
.unwrap();
spawner.spawn(render_gems(led_strip)).unwrap();
let mut state = TargetState::default();
let mut cnt = 0;
loop {
let delta = channel.receive().await;
cnt = (cnt + delta).clamp(0, 12);
state.enabled = [false; 12];
for i in (0..12) {
state.enabled[ORDER[i]] = (cnt > i as i32);
// Process State
let mut target_state = TargetState {
enabled: [false; 12],
};
for i in 0..12 {
target_state.enabled[ORDER[i]] = (state.count > i as u8);
}
{
let mut state_lock = STATE.lock().await;
*state_lock = state.clone();
*state_lock = target_state.clone();
}
//Wait for updates
let delta = channel.receive().await;
state.count = state.count.saturating_add_signed(delta as i8).clamp(0, 12);
//Write Updated state
let mut d = [10u8; 128];
postcard::to_slice(&state, d.as_mut_slice()).unwrap();
info!("{d:x?}");
let r = flash.erase(APP_DATA_OFFSET, APP_DATA_OFFSET + (4 << 10));
info!("{r:?}");
let r = flash.write(APP_DATA_OFFSET, d.as_slice());
info!("{r:?}");
{
let mut bytes = [0; 128];
flash.read(APP_DATA_OFFSET, &mut bytes[..]).unwrap();
info!("Write -> Reaa: {bytes:x?}");
}
}
@ -161,6 +190,8 @@ async fn render_gems(
for i in (0..12) {
if target.enabled[i] && !last_state.enabled[i] {
temp[i] = 3.0;
} else if !target.enabled[i] && last_state.enabled[i] {
temp[i] = -1.0;
} else {
let trg = if target.enabled[i] { 1.0 } else { 0.0 };
let speed = ((temp[i] - trg).abs() * 0.2).clamp(0.1, 0.5);
@ -196,6 +227,12 @@ async fn render_gems(
g: (50.0 + (255.0 - 50.0) * (temp - 1.0)) as u8,
b: (255.0 * (temp - 1.0)) as u8,
}
} else if temp < 0.0 {
RGB8 {
r: 0u8,
g: (green_tint * temp.abs()) as u8,
b: (20.0 + (255.0 - 20.0) * (temp.abs())) as u8,
}
} else {
RGB8 {
r: (255.0 * temp) as u8,