embassy/embassy-stm32/src/wdg/mod.rs

87 lines
2.4 KiB
Rust
Raw Normal View History

use core::marker::PhantomData;
2022-07-10 19:38:30 +02:00
use embassy::time::Duration;
2022-06-28 12:51:08 +02:00
use embassy_hal_common::{unborrow, Unborrow};
2022-07-10 19:38:30 +02:00
use stm32_metapac::iwdg::vals::{Key, Pr};
use crate::rcc::LSI_FREQ;
pub struct IndependentWatchdog<'d, T: Instance> {
wdg: PhantomData<&'d mut T>,
}
2022-07-10 19:38:30 +02:00
// 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 / (LSI_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64)
2022-07-10 19:38:30 +02:00
}
/// Calculates watchdog reload value for the given prescaler and desired timeout
const fn reload_value(prescaler: u8, timeout: Duration) -> u16 {
((LSI_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16
2022-07-10 19:38:30 +02:00
}
impl<'d, T: Instance> IndependentWatchdog<'d, T> {
2022-07-10 19:38:30 +02:00
pub fn new(_instance: impl Unborrow<Target = T> + 'd, timeout: Duration) -> Self {
unborrow!(_instance);
2022-07-10 19:38:30 +02:00
// 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));
2022-07-10 19:38:30 +02:00
wdg.pr().write(|w| w.set_pr(Pr(pr)));
wdg.rlr().write(|w| w.set_rl(rl));
}
IndependentWatchdog {
wdg: PhantomData::default(),
}
}
pub unsafe fn unleash(&mut self) {
T::regs().kr().write(|w| w.set_key(Key::START));
}
2022-06-24 14:19:29 +02:00
pub unsafe fn pet(&mut self) {
T::regs().kr().write(|w| w.set_key(Key::RESET));
}
}
mod sealed {
pub trait Instance {
fn regs() -> crate::pac::iwdg::Iwdg;
}
}
pub trait Instance: sealed::Instance {}
2022-06-28 13:15:23 +02:00
foreach_peripheral!(
(iwdg, $inst:ident) => {
impl sealed::Instance for crate::peripherals::$inst {
fn regs() -> crate::pac::iwdg::Iwdg {
crate::pac::$inst
}
}
2022-06-28 13:15:23 +02:00
impl Instance for crate::peripherals::$inst {}
};
);