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