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}