我目前尝试将基于 esp-idf (c) 的 esp 应用程序移植到 rust esp
no_std
。
我有一个问题,我尝试解决了很长一段时间,但找不到合适的解决方案。
//! Stores measurements and sends once `x` measurements are collected
#![no_std]
#![no_main]
use core::time::Duration;
use esp_backtrace as _;
use esp_hal::prelude::ram;
use esp_hal::{entry, peripherals::Peripherals};
use esp_println::println;
mod sleep;
use self::sleep::enter_deep as enter_deep_sleep;
#[derive(Clone, Copy, Debug)]
pub struct FloatMeasurement {
/// The measured temperature in degree Celsius (°C).
pub temperature: f32,
/// The measured relative humidity in percent (%).
pub humidity: f32,
}
use heapless::Vec;
#[ram(rtc_fast)]
static MEASUREMENTS: &'static Vec<FloatMeasurement, 10> = &Vec::new();
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
loop {
println!("{}", MEASUREMENTS.len());
// not working below
let _ = MEASUREMENTS.push(FloatMeasurement {
temperature: 1.0,
humidity: 2.0,
});
println!("{}", MEASUREMENTS.len());
// if e.g. 10 then send and reset vec
enter_deep_sleep(peripherals.LPWR, Duration::from_secs(4).into());
}
}
以上是我的应用程序中提取的不起作用的部分。
我发现 heapless Vector 是一个很好的东西,可以满足我的需求。
然后我找到了 Once_cell 作为解决方案,但经过几次尝试后我无法使其工作。 如果它被全局声明为静态,我将无法获得可变引用。 如果我将其声明为:
static MEASUREMENTS: &'static mut Vec<FloatMeasurement, 10> = &mut Vec::new();
我失败了
mutable references are not allowed in the final value of statics
我会非常高兴获得帮助,如何正确地拥有像全局可访问的数据列表之类的东西,我可以在其中写入和读取,只有1线程访问它进行读/写,所以实际上不需要互斥体存在。
lazy_static 似乎也能做到我想要的,但它似乎已被弃用,并且我发现的替代品仅适用于 std 环境。
---- 编辑 ----
摘录如下答案。
我没有使用once_cell或其他任何东西,因为我将其保持在最低限度。 请注意,如果需要线程或其他并发访问该数据结构,则需要某种锁定。
#![no_std]
#![no_main]
use core::time::Duration;
use esp_backtrace as _;
use esp_hal::prelude::ram;
use esp_hal::{
clock::ClockControl,
delay::Delay,
entry,
peripherals::Peripherals,
prelude::*,
rtc_cntl::sleep::{RtcSleepConfig, TimerWakeupSource},
system::SystemControl,
};
use esp_println::println;
use esp_hal::rtc_cntl::Rtc;
#[derive(Clone, Copy, Debug)]
pub struct FloatMeasurement {
/// The measurred temperature in degree Celsius (°C).
pub temperature: f32,
/// The measured relative humidity in percent (%).
pub humidity: f32,
}
use heapless::Vec;
#[ram(rtc_fast)]
static mut MEASUREMENTS: Vec<FloatMeasurement, 10> = Vec::<FloatMeasurement, 10>::new();
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut cfg = RtcSleepConfig::deep();
cfg.set_rtc_fastmem_pd_en(false);
let wakeup_source = TimerWakeupSource::new(Duration::from_secs(2));
let mut rtc = Rtc::new(peripherals.LPWR);
rtc.rwdt.enable();
unsafe {
// safe here because only 1 thread exists and we can be sure only we access it.
println!("length {}", MEASUREMENTS.len());
let _ = MEASUREMENTS.push(FloatMeasurement {
temperature: 1.0,
humidity: 2.0,
});
for x in MEASUREMENTS.iter() {
println!("{}", x.humidity);
}
println!("--------------");
}
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let delay = Delay::new(&clocks);
delay.delay(500.millis());
rtc.sleep(&cfg, &[&wakeup_source]);
loop {}
}
这段代码工作完美..在尝试让它工作的过程中,我使问题变得过于复杂:)实际上,当进入深度睡眠时,RTC内存被关闭..所以解决方案是..保持它打开(参见下面的代码片段) )
`cfg.set_rtc_fastmem_pd_en(false);`
我得到了 esp-rs 团队的提示。 https://github.com/esp-rs/esp-hal/issues/2516
(从编辑的问题中提取,问题编辑回来。)