From 2b540b4eae2ddf1526f27aeb4508b131998f1c92 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 14 Sep 2023 08:51:48 +0200 Subject: [PATCH 1/3] Added src/independent_watchdog.rs and example from stm32h7xx-hal - completely untouched --- examples/independent_watchdog.rs | 62 +++++++++++ src/independent_watchdog.rs | 176 +++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 examples/independent_watchdog.rs create mode 100644 src/independent_watchdog.rs diff --git a/examples/independent_watchdog.rs b/examples/independent_watchdog.rs new file mode 100644 index 00000000..48994409 --- /dev/null +++ b/examples/independent_watchdog.rs @@ -0,0 +1,62 @@ +#![no_main] +#![no_std] + +#[macro_use] +mod utilities; +use stm32h7xx_hal::{ + independent_watchdog::IndependentWatchdog, pac, prelude::*, +}; + +use cortex_m_rt::entry; + +use log::info; + +#[entry] +fn main() -> ! { + utilities::logger::init(); + let dp = pac::Peripherals::take().unwrap(); + + // Constrain and Freeze power + info!("Setup PWR... "); + let pwr = dp.PWR.constrain(); + let pwrcfg = example_power!(pwr).freeze(); + + // Constrain and Freeze clock + info!("Setup RCC... "); + let rcc = dp.RCC.constrain(); + let _ccdr = rcc.sys_ck(96.MHz()).freeze(pwrcfg, &dp.SYSCFG); + + #[cfg(any(feature = "rm0433", feature = "rm0455"))] + let mut watchdog = IndependentWatchdog::new(dp.IWDG); + + // Dual core parts + #[cfg(all(feature = "rm0399", feature = "cm7"))] + let mut watchdog = IndependentWatchdog::new(dp.IWDG1); + #[cfg(all(feature = "rm0399", feature = "cm4"))] + let mut watchdog = IndependentWatchdog::new(dp.IWDG2); + + // RM0468 + #[cfg(all(feature = "rm0468"))] + let mut watchdog = IndependentWatchdog::new(dp.IWDG1); + + info!(""); + info!("stm32h7xx-hal example - Watchdog"); + info!(""); + + // If the watchdog is working correctly this print should + // appear again and again as the chip gets restarted + info!("Watchdog restarted! "); + + // Enable the watchdog with a limit of 32.76 seconds (which is the maximum this watchdog can do) and wait forever + // -> restart the chip + watchdog.start(32_760.millis()); + + // Alternatively, there's also a windowed option where if the watchdog is fed before the window time, it will reset the chip as well + // watchdog.start_windowed(100.millis(), 200.millis()); + + loop { + // We can feed the watchdog like this: + // watchdog.feed(); + cortex_m::asm::nop() + } +} diff --git a/src/independent_watchdog.rs b/src/independent_watchdog.rs new file mode 100644 index 00000000..b43f3bf5 --- /dev/null +++ b/src/independent_watchdog.rs @@ -0,0 +1,176 @@ +//! Independent Watchdog +//! +//! This module implements the embedded-hal +//! [Watchdog](https://docs.rs/embedded-hal/latest/embedded_hal/watchdog/trait.Watchdog.html) +//! trait for the Independent Watchdog peripheral. +//! +//! The Independent Watchdog peripheral triggers a system reset when its internal counter expires. +//! +//! # Peripheral Naming +//! +//! The naming of the Independent Watchdog peripheral varies between parts +//! +//! | Parts | IWDG Peripheral | Second IWDG Peripheral | +//! | --- | --- | --- | +//! | stm32H742/743/750/753/7a3/7b0/7b3 | IWDG | - | +//! | stm32h745/747/755/757 | IWDG1 | IWDG2 | +//! | stm32h723/725/730/733/735 | IWDG1 | - | +//! +//! # Examples +//! +//! - [IWDG Example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/independent_watchdog.rs) +use crate::{prelude::*, time::MilliSeconds}; + +#[cfg(any(feature = "rm0433", feature = "rm0455"))] +use crate::stm32::iwdg::pr::PR_A; +#[cfg(any(feature = "rm0433", feature = "rm0455"))] +use crate::stm32::IWDG; + +#[cfg(any(all(feature = "rm0399", feature = "cm7"), feature = "rm0468"))] +use crate::stm32::iwdg1::pr::PR_A; +#[cfg(any(all(feature = "rm0399", feature = "cm7"), feature = "rm0468"))] +use crate::stm32::IWDG1 as IWDG; + +#[cfg(all(feature = "rm0399", feature = "cm4"))] +use crate::stm32::iwdg2::pr::PR_A; +#[cfg(all(feature = "rm0399", feature = "cm4"))] +use crate::stm32::IWDG2 as IWDG; + +/// The implementation of the hardware IWDG +pub struct IndependentWatchdog { + iwdg: IWDG, +} + +impl IndependentWatchdog { + const CLOCK_SPEED: u32 = 32000; + const MAX_COUNTER_VALUE: u32 = 0x00000FFF; + const MAX_MILLIS_FOR_PRESCALER: [(PR_A, u32); 8] = [ + ( + PR_A::DivideBy4, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 4), + ), + ( + PR_A::DivideBy8, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 8), + ), + ( + PR_A::DivideBy16, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 16), + ), + ( + PR_A::DivideBy32, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 32), + ), + ( + PR_A::DivideBy64, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 64), + ), + ( + PR_A::DivideBy128, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 128), + ), + ( + PR_A::DivideBy256, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256), + ), + ( + PR_A::DivideBy256bis, + (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256), + ), + ]; + + /// Create a new instance + pub fn new(iwdg: IWDG) -> Self { + Self { iwdg } + } + + /// Feed the watchdog, resetting the timer to 0 + pub fn feed(&mut self) { + self.iwdg.kr.write(|w| w.key().reset()); + } + + /// Start the watchdog where it must be fed before the max time is over and + /// not before the min time has passed + pub fn start_windowed>( + &mut self, + min_window_time: T, + max_window_time: T, + ) { + let min_window_time: MilliSeconds = min_window_time.into(); + let max_window_time: MilliSeconds = max_window_time.into(); + + // Start the watchdog + self.iwdg.kr.write(|w| w.key().start()); + // Enable register access + self.iwdg.kr.write(|w| w.key().enable()); + + // Set the prescaler + let (prescaler, _) = Self::MAX_MILLIS_FOR_PRESCALER + .iter() + .find(|(_, max_millis)| *max_millis >= max_window_time.to_millis()) + .expect("IWDG max time is greater than is possible"); + while self.iwdg.sr.read().pvu().bit_is_set() { + cortex_m::asm::nop(); + } + self.iwdg.pr.write(|w| w.pr().variant(*prescaler)); + + // Reset the window value + while self.iwdg.sr.read().wvu().bit_is_set() { + cortex_m::asm::nop(); + } + self.iwdg + .winr + .write(|w| w.win().bits(Self::MAX_COUNTER_VALUE as u16)); + + // Calculate the counter values + let reload_value = max_window_time.to_millis() + * (Self::CLOCK_SPEED / 1000) + / Self::get_prescaler_divider(prescaler); + let window_value = min_window_time.to_millis() + * (Self::CLOCK_SPEED / 1000) + / Self::get_prescaler_divider(prescaler); + + // Set the reload value + while self.iwdg.sr.read().rvu().bit_is_set() { + cortex_m::asm::nop(); + } + self.iwdg.rlr.write(|w| w.rl().bits(reload_value as u16)); + + self.feed(); + // Enable register access + self.iwdg.kr.write(|w| w.key().enable()); + + // Set the window value + while self.iwdg.sr.read().wvu().bit_is_set() { + cortex_m::asm::nop(); + } + self.iwdg + .winr + .write(|w| w.win().bits((reload_value - window_value) as u16)); + + // Wait until everything is set + while self.iwdg.sr.read().bits() != 0 { + cortex_m::asm::nop(); + } + + self.feed(); + } + + /// Start the watchdog with the given max time and no minimal time + pub fn start>(&mut self, max_time: T) { + self.start_windowed(0_u32.millis(), max_time.into()); + } + + fn get_prescaler_divider(prescaler: &PR_A) -> u32 { + match prescaler { + PR_A::DivideBy4 => 4, + PR_A::DivideBy8 => 8, + PR_A::DivideBy16 => 16, + PR_A::DivideBy32 => 32, + PR_A::DivideBy64 => 64, + PR_A::DivideBy128 => 128, + PR_A::DivideBy256 => 256, + PR_A::DivideBy256bis => 256, + } + } +} From 6f8b36ff1f74ef7737c94fed119128b56eaa6316 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 14 Sep 2023 09:57:21 +0200 Subject: [PATCH 2/3] Adapted watchdog for this crate --- examples/independent_watchdog.rs | 47 +++++++++++------------------- src/independent_watchdog.rs | 50 ++++++++++---------------------- src/lib.rs | 1 + 3 files changed, 33 insertions(+), 65 deletions(-) diff --git a/examples/independent_watchdog.rs b/examples/independent_watchdog.rs index 48994409..b1e3ce55 100644 --- a/examples/independent_watchdog.rs +++ b/examples/independent_watchdog.rs @@ -1,46 +1,33 @@ +// Originaly from stm32h7xx-hal, adapted for stm32g4xx-hal + #![no_main] #![no_std] -#[macro_use] -mod utilities; -use stm32h7xx_hal::{ - independent_watchdog::IndependentWatchdog, pac, prelude::*, +//#[macro_use] +//mod utils; +use stm32g4xx_hal::{ + independent_watchdog::IndependentWatchdog, prelude::*, + stm32::Peripherals }; use cortex_m_rt::entry; -use log::info; +// TODO: Use utils instead +use defmt_rtt as _; // global logger +use panic_probe as _; +pub use defmt::Logger; + +use defmt::info; // TODO: Use utils::logger instead #[entry] fn main() -> ! { - utilities::logger::init(); - let dp = pac::Peripherals::take().unwrap(); - - // Constrain and Freeze power - info!("Setup PWR... "); - let pwr = dp.PWR.constrain(); - let pwrcfg = example_power!(pwr).freeze(); + //utils::logger::init(); + let dp = Peripherals::take().unwrap(); - // Constrain and Freeze clock - info!("Setup RCC... "); - let rcc = dp.RCC.constrain(); - let _ccdr = rcc.sys_ck(96.MHz()).freeze(pwrcfg, &dp.SYSCFG); - - #[cfg(any(feature = "rm0433", feature = "rm0455"))] let mut watchdog = IndependentWatchdog::new(dp.IWDG); - // Dual core parts - #[cfg(all(feature = "rm0399", feature = "cm7"))] - let mut watchdog = IndependentWatchdog::new(dp.IWDG1); - #[cfg(all(feature = "rm0399", feature = "cm4"))] - let mut watchdog = IndependentWatchdog::new(dp.IWDG2); - - // RM0468 - #[cfg(all(feature = "rm0468"))] - let mut watchdog = IndependentWatchdog::new(dp.IWDG1); - info!(""); - info!("stm32h7xx-hal example - Watchdog"); + info!("stm32g4xx-hal example - Watchdog"); info!(""); // If the watchdog is working correctly this print should @@ -49,7 +36,7 @@ fn main() -> ! { // Enable the watchdog with a limit of 32.76 seconds (which is the maximum this watchdog can do) and wait forever // -> restart the chip - watchdog.start(32_760.millis()); + watchdog.start(32_760.ms()); // Alternatively, there's also a windowed option where if the watchdog is fed before the window time, it will reset the chip as well // watchdog.start_windowed(100.millis(), 200.millis()); diff --git a/src/independent_watchdog.rs b/src/independent_watchdog.rs index b43f3bf5..a7481cec 100644 --- a/src/independent_watchdog.rs +++ b/src/independent_watchdog.rs @@ -6,35 +6,15 @@ //! //! The Independent Watchdog peripheral triggers a system reset when its internal counter expires. //! -//! # Peripheral Naming -//! -//! The naming of the Independent Watchdog peripheral varies between parts -//! -//! | Parts | IWDG Peripheral | Second IWDG Peripheral | -//! | --- | --- | --- | -//! | stm32H742/743/750/753/7a3/7b0/7b3 | IWDG | - | -//! | stm32h745/747/755/757 | IWDG1 | IWDG2 | -//! | stm32h723/725/730/733/735 | IWDG1 | - | -//! //! # Examples //! -//! - [IWDG Example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/independent_watchdog.rs) -use crate::{prelude::*, time::MilliSeconds}; - -#[cfg(any(feature = "rm0433", feature = "rm0455"))] -use crate::stm32::iwdg::pr::PR_A; -#[cfg(any(feature = "rm0433", feature = "rm0455"))] -use crate::stm32::IWDG; - -#[cfg(any(all(feature = "rm0399", feature = "cm7"), feature = "rm0468"))] -use crate::stm32::iwdg1::pr::PR_A; -#[cfg(any(all(feature = "rm0399", feature = "cm7"), feature = "rm0468"))] -use crate::stm32::IWDG1 as IWDG; - -#[cfg(all(feature = "rm0399", feature = "cm4"))] -use crate::stm32::iwdg2::pr::PR_A; -#[cfg(all(feature = "rm0399", feature = "cm4"))] -use crate::stm32::IWDG2 as IWDG; +//! - [IWDG Example](todo-insert-link-here) +//! +//! Originally from stm32h7-hal, adapted for stm32g4xx-hal +use crate::{time::{MicroSecond, U32Ext}, stm32::{ + IWDG, + iwdg::pr::PR_A, +}}; /// The implementation of the hardware IWDG pub struct IndependentWatchdog { @@ -91,13 +71,13 @@ impl IndependentWatchdog { /// Start the watchdog where it must be fed before the max time is over and /// not before the min time has passed - pub fn start_windowed>( + pub fn start_windowed>( &mut self, min_window_time: T, max_window_time: T, ) { - let min_window_time: MilliSeconds = min_window_time.into(); - let max_window_time: MilliSeconds = max_window_time.into(); + let min_window_time: MicroSecond = min_window_time.into(); + let max_window_time: MicroSecond = max_window_time.into(); // Start the watchdog self.iwdg.kr.write(|w| w.key().start()); @@ -107,7 +87,7 @@ impl IndependentWatchdog { // Set the prescaler let (prescaler, _) = Self::MAX_MILLIS_FOR_PRESCALER .iter() - .find(|(_, max_millis)| *max_millis >= max_window_time.to_millis()) + .find(|(_, max_millis)| *max_millis >= max_window_time.0 / 1000) .expect("IWDG max time is greater than is possible"); while self.iwdg.sr.read().pvu().bit_is_set() { cortex_m::asm::nop(); @@ -123,10 +103,10 @@ impl IndependentWatchdog { .write(|w| w.win().bits(Self::MAX_COUNTER_VALUE as u16)); // Calculate the counter values - let reload_value = max_window_time.to_millis() + let reload_value = (max_window_time.0 / 1000) * (Self::CLOCK_SPEED / 1000) / Self::get_prescaler_divider(prescaler); - let window_value = min_window_time.to_millis() + let window_value = (min_window_time.0 / 1000) * (Self::CLOCK_SPEED / 1000) / Self::get_prescaler_divider(prescaler); @@ -157,8 +137,8 @@ impl IndependentWatchdog { } /// Start the watchdog with the given max time and no minimal time - pub fn start>(&mut self, max_time: T) { - self.start_windowed(0_u32.millis(), max_time.into()); + pub fn start>(&mut self, max_time: T) { + self.start_windowed(0_u32.ms(), max_time.into()); } fn get_prescaler_divider(prescaler: &PR_A) -> u32 { diff --git a/src/lib.rs b/src/lib.rs index 0b7d3ee4..43640ce6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,3 +85,4 @@ pub mod syscfg; pub mod time; pub mod timer; // pub mod watchdog; +pub mod independent_watchdog; From 6b1c43d4b076c6fcf97d99e2aad21a40b3b6c145 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 14 Sep 2023 10:16:16 +0200 Subject: [PATCH 3/3] IWDT fmt --- examples/independent_watchdog.rs | 7 ++----- src/independent_watchdog.rs | 22 ++++++++-------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/examples/independent_watchdog.rs b/examples/independent_watchdog.rs index b1e3ce55..5fd5783f 100644 --- a/examples/independent_watchdog.rs +++ b/examples/independent_watchdog.rs @@ -5,17 +5,14 @@ //#[macro_use] //mod utils; -use stm32g4xx_hal::{ - independent_watchdog::IndependentWatchdog, prelude::*, - stm32::Peripherals -}; +use stm32g4xx_hal::{independent_watchdog::IndependentWatchdog, prelude::*, stm32::Peripherals}; use cortex_m_rt::entry; // TODO: Use utils instead +use defmt::Logger; use defmt_rtt as _; // global logger use panic_probe as _; -pub use defmt::Logger; use defmt::info; // TODO: Use utils::logger instead diff --git a/src/independent_watchdog.rs b/src/independent_watchdog.rs index a7481cec..58151f3a 100644 --- a/src/independent_watchdog.rs +++ b/src/independent_watchdog.rs @@ -9,12 +9,12 @@ //! # Examples //! //! - [IWDG Example](todo-insert-link-here) -//! +//! //! Originally from stm32h7-hal, adapted for stm32g4xx-hal -use crate::{time::{MicroSecond, U32Ext}, stm32::{ - IWDG, - iwdg::pr::PR_A, -}}; +use crate::{ + stm32::{iwdg::pr::PR_A, IWDG}, + time::{MicroSecond, U32Ext}, +}; /// The implementation of the hardware IWDG pub struct IndependentWatchdog { @@ -71,11 +71,7 @@ impl IndependentWatchdog { /// Start the watchdog where it must be fed before the max time is over and /// not before the min time has passed - pub fn start_windowed>( - &mut self, - min_window_time: T, - max_window_time: T, - ) { + pub fn start_windowed>(&mut self, min_window_time: T, max_window_time: T) { let min_window_time: MicroSecond = min_window_time.into(); let max_window_time: MicroSecond = max_window_time.into(); @@ -103,11 +99,9 @@ impl IndependentWatchdog { .write(|w| w.win().bits(Self::MAX_COUNTER_VALUE as u16)); // Calculate the counter values - let reload_value = (max_window_time.0 / 1000) - * (Self::CLOCK_SPEED / 1000) + let reload_value = (max_window_time.0 / 1000) * (Self::CLOCK_SPEED / 1000) / Self::get_prescaler_divider(prescaler); - let window_value = (min_window_time.0 / 1000) - * (Self::CLOCK_SPEED / 1000) + let window_value = (min_window_time.0 / 1000) * (Self::CLOCK_SPEED / 1000) / Self::get_prescaler_divider(prescaler); // Set the reload value