diff options
author | chemicstry <chemicstry@gmail.com> | 2022-07-10 20:38:30 +0300 |
---|---|---|
committer | chemicstry <chemicstry@gmail.com> | 2022-07-10 20:38:30 +0300 |
commit | bd01e90bfa4895b45e41ad538cb24a959b0b58ab (patch) | |
tree | ec86a61d00a087e1faba730d922e53c8f3086f2f /embassy-stm32 | |
parent | 5f43c1d37e9db847c7861fe0bd821db62edba9f6 (diff) | |
download | embassy-bd01e90bfa4895b45e41ad538cb24a959b0b58ab.zip |
Implement IWDG timeout calculation
Diffstat (limited to 'embassy-stm32')
-rw-r--r-- | embassy-stm32/src/wdg/mod.rs | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index da25692a..b4d59ff2 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -1,21 +1,63 @@ use core::marker::PhantomData; +use embassy::time::Duration; use embassy_hal_common::{unborrow, Unborrow}; -use stm32_metapac::iwdg::vals::Key; -pub use stm32_metapac::iwdg::vals::Pr as Prescaler; +use stm32_metapac::iwdg::vals::{Key, Pr}; + +use crate::time::Hertz; pub struct IndependentWatchdog<'d, T: Instance> { wdg: PhantomData<&'d mut T>, } +// Some STM32 families have 40 kHz LSI clock instead of 32 kHz +cfg_if::cfg_if! { + if #[cfg(any(stm32f0, stm32f1))] { + pub const IWDG_FREQ: Hertz = Hertz(40_000); + } else { + pub const IWDG_FREQ: Hertz = Hertz(32_000); + } +} + +// 12-bit counter +const MAX_RL: u16 = 0xFFF; + +/// Calculates maximum watchdog timeout (RL = 0xFFF) for a given prescaler +const fn max_timeout(prescaler: u8) -> Duration { + Duration::from_micros(1_000_000 / (IWDG_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64) +} + +/// Calculates watchdog reload value for the given prescaler and desired timeout +const fn reload_value(prescaler: u8, timeout: Duration) -> u16 { + ((IWDG_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16 +} + impl<'d, T: Instance> IndependentWatchdog<'d, T> { - pub fn new(_instance: impl Unborrow<Target = T> + 'd, presc: Prescaler) -> Self { + pub fn new(_instance: impl Unborrow<Target = T> + 'd, timeout: Duration) -> Self { unborrow!(_instance); + // Find lowest prescaler value, which makes watchdog period longer or equal to timeout. + // This iterates from 4 (2^2) to 256 (2^8). + let psc_power = unwrap!((2..=8).find(|psc_power| { + let psc = 2u8.pow(*psc_power); + timeout <= max_timeout(psc) + })); + + // Prescaler value + let psc = 2u8.pow(psc_power); + + // Convert prescaler power to PR register value + let pr = psc_power as u8 - 2; + assert!(pr <= 0b110); + + // Reload value + let rl = reload_value(psc, timeout); + let wdg = T::regs(); unsafe { wdg.kr().write(|w| w.set_key(Key::ENABLE)); - wdg.pr().write(|w| w.set_pr(presc)); + wdg.pr().write(|w| w.set_pr(Pr(pr))); + wdg.rlr().write(|w| w.set_rl(rl)); } IndependentWatchdog { |