From 3d0a1998fad79b7494b721a5e8b6d4d74aad682c Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Fri, 20 Sep 2024 15:51:35 +0200 Subject: [PATCH] Allow configuring the watchdogs in the init config (#2180) * feat: Allow configuring the watchdogs in the init config * docs: Update changelog * refactor: Remove unnecesary unsafe * feat: Add a config module * test: Add some init tests * style: Rename all ocurrences to esp_hal::config::Config::default() * style: Fix format * fix: Doc errors * revert: Move Config struct to lib.rs * tests: Add default config test * test: Add a test with CpuClock::max() * test: Add timg1 test * feat: Move Config struct to config module and reexport it in lib.rs * fix: Fix init compilation for C2 * revert: Move Config struct to config module and reexport it in lib.rs * fix: Use proper timergroup --- esp-hal-embassy/MIGRATING-0.3.md | 2 +- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.20.md | 2 +- esp-hal/src/config.rs | 59 +++++++++++++++++ esp-hal/src/lib.rs | 54 ++++++++++++--- esp-hal/src/rtc_cntl/mod.rs | 5 ++ esp-wifi/MIGRATING-0.9.md | 4 +- hil-test/Cargo.toml | 4 ++ hil-test/tests/init.rs | 110 +++++++++++++++++++++++++++++++ 9 files changed, 229 insertions(+), 12 deletions(-) create mode 100644 esp-hal/src/config.rs create mode 100644 hil-test/tests/init.rs diff --git a/esp-hal-embassy/MIGRATING-0.3.md b/esp-hal-embassy/MIGRATING-0.3.md index be65c5db9..80b7cdeb8 100644 --- a/esp-hal-embassy/MIGRATING-0.3.md +++ b/esp-hal-embassy/MIGRATING-0.3.md @@ -13,7 +13,7 @@ You no longer have to set up clocks and pass them to `esp_hal_embassy::init`. prelude::*, - system::SystemControl, }; - + #[esp_hal_embassy::main] async fn main(_spawner: Spawner) -> ! { - let peripherals = Peripherals::take(); diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index e35e202fa..c9bfc1aad 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implement `TryFrom` for `ledc::timer::config::Duty` (#1984) - Expose `RtcClock::get_xtal_freq` and `RtcClock::get_slow_freq` publically for all chips (#2183) - TWAI support for ESP32-H2 (#2199) +- Added a way to configure watchdogs in `esp_hal::init` (#2180) ### Changed diff --git a/esp-hal/MIGRATING-0.20.md b/esp-hal/MIGRATING-0.20.md index 4f19c3f48..08f4f10ad 100644 --- a/esp-hal/MIGRATING-0.20.md +++ b/esp-hal/MIGRATING-0.20.md @@ -158,7 +158,7 @@ configure an input pin, and pass it to `set_edge_signal` or `set_ctrl_signal`. - PcntInputConfig { pull: Pull::Up }, - )); + ch0.set_ctrl_signal(Input::new(io.pins.gpio4, Pull::Up)); - + - let mut pin_b = io.pins.gpio5; - ch0.set_edge_signal(PcntSource::from_pin( - &mut pin_b, diff --git a/esp-hal/src/config.rs b/esp-hal/src/config.rs new file mode 100644 index 000000000..0e3295ed9 --- /dev/null +++ b/esp-hal/src/config.rs @@ -0,0 +1,59 @@ +//! # Configuration +//! +//! ## Overview +//! This module contains the initial configuation for the system. +//! +//! ## Configuration +//! In the esp_hal::init method, we can configure different parameters for the +//! system: +//! - CPU clock configuration. +//! - Watchdog configuration. +//! +//! ## Example +//! +//! ### Default initialization +//! +//! ```rust, no_run +#![doc = crate::before_snippet!()] +//! let peripherals = esp_hal::init(esp_hal::Config::default()); +//! # } +//! ``` +//! +//! ### Custom initialization +//! ```rust, no_run +#![doc = crate::before_snippet!()] +//! let mut config = esp_hal::Config::default(); +//! config.cpu_clock = CpuClock::max(); +//! config.watchdog.rwdt = +//! esp_hal::config::WatchdogStatus::Enabled(fugit::MicrosDurationU64::millis(1000 as u64)); +//! let peripherals = esp_hal::init(config); +//! # } +//! ``` + +/// Watchdog status. +#[derive(Default, PartialEq)] +pub enum WatchdogStatus { + /// Enables a watchdog timer with the specified timeout. + Enabled(fugit::MicrosDurationU64), + /// Disables the watchdog timer. + #[default] + Disabled, +} + +/// Watchdogs configuration. +#[non_exhaustive] +#[derive(Default)] +pub struct WatchdogConfig { + #[cfg(not(any(esp32, esp32s2)))] + /// Enable the super watchdog timer, which is slightly less than one second. + pub swd: bool, + /// Configures the reset watchdog timer. + pub rwdt: WatchdogStatus, + /// Configures the timg0 watchdog timer. + pub timg0: WatchdogStatus, + #[cfg(timg1)] + /// Configures the timg1 watchdog timer. + /// + /// By default, the bootloader does not enables this watchdog timer. + pub timg1: WatchdogStatus, +} diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index cf86a3b47..a18baa94a 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -168,6 +168,9 @@ pub mod analog; pub mod assist_debug; #[cfg(any(dport, hp_sys, pcr, system))] pub mod clock; + +pub mod config; + #[cfg(any(xtensa, all(riscv, systimer)))] pub mod delay; #[cfg(any(gdma, pdma))] @@ -466,6 +469,7 @@ macro_rules! before_snippet { use crate::{ clock::{Clocks, CpuClock}, + config::{WatchdogConfig, WatchdogStatus}, peripherals::Peripherals, }; @@ -475,24 +479,58 @@ use crate::{ pub struct Config { /// The CPU clock configuration. pub cpu_clock: CpuClock, + /// Enable watchdog timer(s). + pub watchdog: WatchdogConfig, } /// Initialize the system. /// -/// This function sets up the CPU clock and returns the peripherals and clocks. +/// This function sets up the CPU clock and watchdog, then, returns the +/// peripherals and clocks. pub fn init(config: Config) -> Peripherals { let mut peripherals = Peripherals::take(); // RTC domain must be enabled before we try to disable let mut rtc = crate::rtc_cntl::Rtc::new(&mut peripherals.LPWR); - #[cfg(not(any(esp32, esp32s2)))] - rtc.swd.disable(); - rtc.rwdt.disable(); - unsafe { - crate::timer::timg::Wdt::::set_wdt_enabled(false); - #[cfg(timg1)] - crate::timer::timg::Wdt::::set_wdt_enabled(false); + #[cfg(not(any(esp32, esp32s2)))] + if config.watchdog.swd { + rtc.swd.enable(); + } else { + rtc.swd.disable(); + } + + match config.watchdog.rwdt { + WatchdogStatus::Enabled(duration) => { + rtc.rwdt.enable(); + rtc.rwdt.set_timeout(duration); + } + WatchdogStatus::Disabled => { + rtc.rwdt.disable(); + } + } + + match config.watchdog.timg0 { + WatchdogStatus::Enabled(duration) => { + let mut timg0_wd = crate::timer::timg::Wdt::::new(); + timg0_wd.enable(); + timg0_wd.set_timeout(duration); + } + WatchdogStatus::Disabled => { + crate::timer::timg::Wdt::::new().disable(); + } + } + + #[cfg(timg1)] + match config.watchdog.timg1 { + WatchdogStatus::Enabled(duration) => { + let mut timg1_wd = crate::timer::timg::Wdt::::new(); + timg1_wd.enable(); + timg1_wd.set_timeout(duration); + } + WatchdogStatus::Disabled => { + crate::timer::timg::Wdt::::new().disable(); + } } Clocks::init(config.cpu_clock); diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 11a2c7a01..dd835eee2 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -988,6 +988,11 @@ impl Swd { Self } + /// Enable the watchdog timer instance + pub fn enable(&mut self) { + self.set_enabled(true); + } + /// Disable the watchdog timer instance pub fn disable(&mut self) { self.set_enabled(false); diff --git a/esp-wifi/MIGRATING-0.9.md b/esp-wifi/MIGRATING-0.9.md index 1647fb2a0..40142b4fa 100644 --- a/esp-wifi/MIGRATING-0.9.md +++ b/esp-wifi/MIGRATING-0.9.md @@ -15,7 +15,7 @@ You no longer have to set up clocks and pass them to `esp_wifi::initialize`. initialize, // ... }; - + #[entry] fn main() -> ! { - let peripherals = Peripherals::take(); @@ -65,7 +65,7 @@ The size of the heap depends on what you are going to use esp-wifi for and if yo E.g. when using `coex` you need around 92k. If not using `coex`, going lower than 72k you will observe some failed allocations but it might still work. Going even lower will make things fail. -If you see linker errors regarding undefined symbols for `esp_wifi_free_internal_heap` and `esp_wifi_allocate_from_internal_ram` you either want to opt-in to use the `esp-alloc` feature +If you see linker errors regarding undefined symbols for `esp_wifi_free_internal_heap` and `esp_wifi_allocate_from_internal_ram` you either want to opt-in to use the `esp-alloc` feature or provide your own allocator (see below) ### Using your own allocator diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index f14169959..bef22fea4 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -55,6 +55,10 @@ harness = false name = "i2c" harness = false +[[test]] +name = "init" +harness = false + [[test]] name = "i2s" harness = false diff --git a/hil-test/tests/init.rs b/hil-test/tests/init.rs new file mode 100644 index 000000000..cec885c73 --- /dev/null +++ b/hil-test/tests/init.rs @@ -0,0 +1,110 @@ +//! Initialization tests + +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 + +#![no_std] +#![no_main] + +use esp_hal::{ + config::WatchdogStatus, + delay::Delay, + prelude::*, + rtc_cntl::Rtc, + timer::timg::TimerGroup, + Config, +}; +use hil_test as _; + +#[cfg(test)] +#[embedded_test::tests] +mod tests { + use super::*; + + #[test] + #[timeout(3)] + fn test_feeding_timg0_wdt() { + let peripherals = esp_hal::init({ + let mut config = Config::default(); + config.watchdog.timg0 = + WatchdogStatus::Enabled(fugit::MicrosDurationU64::millis(500 as u64)); + config + }); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + let mut wdt0 = timg0.wdt; + let delay = Delay::new(); + + for _ in 0..4 { + wdt0.feed(); + delay.delay(250.millis()); + } + } + + #[test] + #[timeout(3)] + #[cfg(timg1)] + fn test_feeding_timg1_wdt() { + let peripherals = esp_hal::init({ + let mut config = Config::default(); + config.watchdog.timg1 = + WatchdogStatus::Enabled(fugit::MicrosDurationU64::millis(500 as u64)); + config + }); + + let timg1 = TimerGroup::new(peripherals.TIMG1); + let mut wdt1 = timg1.wdt; + let delay = Delay::new(); + + for _ in 0..4 { + wdt1.feed(); + delay.delay(250.millis()); + } + } + + #[test] + #[timeout(3)] + fn test_feeding_timg0_wdt_max_clock() { + let peripherals = esp_hal::init({ + let mut config = Config::default(); + config.cpu_clock = CpuClock::max(); + config.watchdog.timg0 = + WatchdogStatus::Enabled(fugit::MicrosDurationU64::millis(500 as u64)); + config + }); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + let mut wdt0 = timg0.wdt; + let delay = Delay::new(); + + for _ in 0..4 { + wdt0.feed(); + delay.delay(250.millis()); + } + } + + #[test] + #[timeout(4)] + fn test_feeding_rtc_wdt() { + let peripherals = esp_hal::init({ + let mut config = Config::default(); + config.watchdog.rwdt = + WatchdogStatus::Enabled(fugit::MicrosDurationU64::millis(3000 as u64)); + config + }); + + let mut rtc = Rtc::new(peripherals.LPWR); + let delay = Delay::new(); + + rtc.rwdt.feed(); + delay.delay(2500.millis()); + } + + #[test] + #[timeout(3)] + fn test_default_config() { + esp_hal::init(Config::default()); + + let delay = Delay::new(); + delay.delay(2000.millis()); + } +}