stm32f0xx_hal/
watchdog.rs

1//! API for the IWDG
2//!
3//! You can activate the watchdog by calling `start` or the setting appropriate
4//! device option bit when programming.
5//!
6//! After activating the watchdog, you'll have to regularly `feed` the watchdog.
7//! If more time than `timeout` has gone by since the last `feed`, your
8//! microcontroller will be reset.
9//!
10//! This is useful if you fear that your program may get stuck. In that case it
11//! won't feed the watchdog anymore, the watchdog will reset the microcontroller
12//! and thus your program will function again.
13//!
14//! **Attention**:
15//!
16//! The IWDG runs on a separate 40kHz low-accuracy clock (30kHz-60kHz). You may
17//! want to some buffer in your interval.
18//!
19//! Per default the iwdg continues to run even when you stopped execution of code via a debugger.
20//! You may want to disable the watchdog when the cpu is stopped
21//!
22//! ``` ignore
23//! let dbgmcu = p.DBGMCU;
24//! dbgmcu.apb1_fz.modify(|_, w| w.dbg_iwdg_stop().set_bit());
25//! ```
26//!
27//! # Example
28//! ``` no_run
29//! use stm32f0xx_hal as hal;
30//!
31//! use crate::hal::pac;
32//! use crate::hal::prelude::*;
33//! use crate::hal:watchdog::Watchdog;
34//! use crate::hal:time::Hertz;
35//!
36//! let mut p = pac::Peripherals::take().unwrap();
37//!
38//! let mut iwdg = Watchdog::new(p.iwdg);
39//! iwdg.start(Hertz(100));
40//! loop {}
41//! // Whoops, got stuck, the watchdog issues a reset after 10 ms
42//! iwdg.feed();
43//! ```
44use embedded_hal::watchdog;
45
46use crate::pac::IWDG;
47use crate::time::Hertz;
48
49/// Watchdog instance
50pub struct Watchdog {
51    iwdg: IWDG,
52}
53
54impl watchdog::Watchdog for Watchdog {
55    /// Feed the watchdog, so that at least one `period` goes by before the next
56    /// reset
57    fn feed(&mut self) {
58        self.iwdg.kr.write(|w| w.key().reset());
59    }
60}
61
62/// Timeout configuration for the IWDG
63#[derive(PartialEq, PartialOrd, Clone, Copy)]
64pub struct IwdgTimeout {
65    psc: u8,
66    reload: u16,
67}
68
69impl From<Hertz> for IwdgTimeout {
70    /// This converts the value so it's usable by the IWDG
71    /// Due to conversion losses, the specified frequency is a maximum
72    ///
73    /// It can also only represent values < 10000 Hertz
74    fn from(hz: Hertz) -> Self {
75        let mut time = 40_000 / 4 / hz.0;
76        let mut psc = 0;
77        let mut reload = 0;
78        while psc < 7 {
79            reload = time;
80            if reload < 0x1000 {
81                break;
82            }
83            psc += 1;
84            time /= 2;
85        }
86        // As we get an integer value, reload is always below 0xFFF
87        let reload = reload as u16;
88        IwdgTimeout { psc, reload }
89    }
90}
91
92impl Watchdog {
93    pub fn new(iwdg: IWDG) -> Self {
94        Self { iwdg }
95    }
96}
97
98impl watchdog::WatchdogEnable for Watchdog {
99    type Time = IwdgTimeout;
100    fn start<T>(&mut self, period: T)
101    where
102        T: Into<IwdgTimeout>,
103    {
104        let time: IwdgTimeout = period.into();
105        // Feed the watchdog in case it's already running
106        // (Waiting for the registers to update takes sometime)
107        self.iwdg.kr.write(|w| w.key().reset());
108        // Enable the watchdog
109        self.iwdg.kr.write(|w| w.key().start());
110        self.iwdg.kr.write(|w| w.key().enable());
111        // Wait until it's safe to write to the registers
112        while self.iwdg.sr.read().pvu().bit() {}
113        self.iwdg.pr.write(|w| w.pr().bits(time.psc));
114        while self.iwdg.sr.read().rvu().bit() {}
115        self.iwdg.rlr.write(|w| w.rl().bits(time.reload));
116        // Wait until the registers are updated before issuing a reset with
117        // (potentially false) values
118        while self.iwdg.sr.read().bits() != 0 {}
119        self.iwdg.kr.write(|w| w.key().reset());
120    }
121}