1use core::marker::PhantomData;
3
4use embassy_hal_internal::{into_ref, Peripheral};
5use stm32_metapac::iwdg::vals::{Key, Pr};
6
7use crate::rcc::LSI_FREQ;
8
9pub struct IndependentWatchdog<'d, T: Instance> {
11 wdg: PhantomData<&'d mut T>,
12}
13
14const MAX_RL: u16 = 0xFFF;
16
17const fn get_timeout_us(prescaler: u16, reload_value: u16) -> u32 {
19 1_000_000 * (reload_value + 1) as u32 / (LSI_FREQ.0 / prescaler as u32)
20}
21
22const fn reload_value(prescaler: u16, timeout_us: u32) -> u16 {
24 (timeout_us / prescaler as u32 * LSI_FREQ.0 / 1_000_000) as u16 - 1
25}
26
27impl<'d, T: Instance> IndependentWatchdog<'d, T> {
28 pub fn new(_instance: impl Peripheral<P = T> + 'd, timeout_us: u32) -> Self {
33 into_ref!(_instance);
34
35 let psc_power = unwrap!((2..=8).find(|psc_power| {
38 let psc = 2u16.pow(*psc_power);
39 timeout_us <= get_timeout_us(psc, MAX_RL)
40 }));
41
42 let psc = 2u16.pow(psc_power);
44
45 #[cfg(not(iwdg_v3))]
46 assert!(psc <= 256, "IWDG prescaler should be no more than 256");
47 #[cfg(iwdg_v3)] assert!(psc <= 1024, "IWDG prescaler should be no more than 1024");
49
50 let pr = psc_power as u8 - 2;
52
53 let rl = reload_value(psc, timeout_us);
55
56 let wdg = T::regs();
57 wdg.kr().write(|w| w.set_key(Key::ENABLE));
58 wdg.pr().write(|w| w.set_pr(Pr::from_bits(pr)));
59 wdg.rlr().write(|w| w.set_rl(rl));
60
61 trace!(
62 "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})",
63 get_timeout_us(psc, rl),
64 timeout_us,
65 pr,
66 rl
67 );
68
69 IndependentWatchdog { wdg: PhantomData }
70 }
71
72 pub fn unleash(&mut self) {
74 T::regs().kr().write(|w| w.set_key(Key::START));
75 }
76
77 pub fn pet(&mut self) {
79 T::regs().kr().write(|w| w.set_key(Key::RESET));
80 }
81}
82
83trait SealedInstance {
84 fn regs() -> crate::pac::iwdg::Iwdg;
85}
86
87#[allow(private_bounds)]
89pub trait Instance: SealedInstance {}
90
91foreach_peripheral!(
92 (iwdg, $inst:ident) => {
93 impl SealedInstance for crate::peripherals::$inst {
94 fn regs() -> crate::pac::iwdg::Iwdg {
95 crate::pac::$inst
96 }
97 }
98
99 impl Instance for crate::peripherals::$inst {}
100 };
101);
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn can_compute_timeout_us() {
109 assert_eq!(125, get_timeout_us(4, 0));
110 assert_eq!(512_000, get_timeout_us(4, MAX_RL));
111
112 assert_eq!(8_000, get_timeout_us(256, 0));
113 assert_eq!(32_768_000, get_timeout_us(256, MAX_RL));
114
115 assert_eq!(8_000_000, get_timeout_us(64, 3999));
116 }
117
118 #[test]
119 fn can_compute_reload_value() {
120 assert_eq!(0xFFF, reload_value(4, 512_000));
121 assert_eq!(0xFFF, reload_value(256, 32_768_000));
122
123 assert_eq!(3999, reload_value(64, 8_000_000));
124 }
125}