Skip to content

Commit 09bb195

Browse files
zklapowSh3Rm4n
authored andcommitted
implement watchdog
1 parent 8416e5c commit 09bb195

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,6 @@ pub mod timer;
8181
)
8282
))]
8383
pub mod usb;
84+
85+
#[cfg(feature = "device-selected")]
86+
pub mod watchdog;

src/watchdog.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use crate::hal::watchdog::{Watchdog, WatchdogEnable};
2+
3+
use crate::stm32::{DBGMCU, IWDG};
4+
5+
const LSI_KHZ: u32 = 40;
6+
const MAX_PR: u8 = 8;
7+
const MAX_RL: u16 = 0x1000;
8+
const KR_ACCESS: u16 = 0x5555;
9+
const KR_RELOAD: u16 = 0xAAAA;
10+
const KR_START: u16 = 0xCCCC;
11+
12+
struct IndependentWatchDog {
13+
iwdg: IWDG,
14+
}
15+
16+
impl IndependentWatchDog {
17+
pub fn new(iwdg: IWDG) -> Self {
18+
IndependentWatchdog { iwdg }
19+
}
20+
21+
pub fn stop_on_debug(&self, dbg: &DBGMCU, stop: bool) {
22+
dbg.apb1_fz.modify(|_, w| w.dbg_iwdg_stop().bit(stop));
23+
}
24+
25+
fn setup(&self, timeout_ms: u32) {
26+
let mut pr = 0;
27+
while pr < MAX_PR && Self::timeout_period(pr, MAX_RL) < timeout_ms {
28+
pr += 1;
29+
}
30+
31+
let max_period = Self::timeout_period(pr, MAX_RL);
32+
let max_rl = u32::from(MAX_RL);
33+
let rl = (timeout_ms * max_rl / max_period).min(max_rl) as u16;
34+
35+
self.access_registers(|iwdg| {
36+
iwdg.pr.modify(|_, w| w.pr().bits(pr));
37+
iwdg.rlr.modify(|_, w| w.rl().bits(rl));
38+
});
39+
}
40+
41+
fn is_pr_updating(&self) -> bool {
42+
self.iwdg.sr.read().pvu().bit()
43+
}
44+
45+
/// Returns the interval in ms
46+
pub fn interval(&self) -> MilliSeconds {
47+
while self.is_pr_updating() {}
48+
49+
let pr = self.iwdg.pr.read().pr().bits();
50+
let rl = self.iwdg.rlr.read().rl().bits();
51+
let ms = Self::timeout_period(pr, rl);
52+
MilliSeconds(ms)
53+
}
54+
55+
/// pr: Prescaler divider bits, rl: reload value
56+
///
57+
/// Returns ms
58+
fn timeout_period(pr: u8, rl: u16) -> u32 {
59+
let divider: u32 = match pr {
60+
0b000 => 4,
61+
0b001 => 8,
62+
0b010 => 16,
63+
0b011 => 32,
64+
0b100 => 64,
65+
0b101 => 128,
66+
0b110 => 256,
67+
0b111 => 256,
68+
_ => panic!("Invalid IWDG prescaler divider"),
69+
};
70+
(u32::from(rl) + 1) * divider / LSI_KHZ
71+
}
72+
73+
fn access_registers<A, F: FnMut(&IWDG) -> A>(&self, mut f: F) -> A {
74+
// Unprotect write access to registers
75+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_ACCESS) });
76+
let a = f(&self.iwdg);
77+
78+
// Protect again
79+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_RELOAD) });
80+
a
81+
}
82+
}
83+
84+
impl WatchdogEnable for IndependentWatchdog {
85+
type Time = MilliSeconds;
86+
87+
fn start<T: Into<Self::Time>>(&mut self, period: T) {
88+
self.setup(period.into().0);
89+
90+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_START) });
91+
}
92+
}
93+
94+
impl Watchdog for IndependentWatchdog {
95+
fn feed(&mut self) {
96+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_RELOAD) });
97+
}
98+
}

0 commit comments

Comments
 (0)