Skip to content

Commit 48833c6

Browse files
authored
Merge pull request #58 from zklapow/watchdog
Independent watchdog
2 parents 5f15e0f + feceab4 commit 48833c6

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-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/time.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ pub struct KiloHertz(pub u32);
2020
#[derive(Clone, Copy)]
2121
pub struct MegaHertz(pub u32);
2222

23+
/// Time unit
24+
#[derive(PartialEq, PartialOrd, Clone, Copy)]
25+
pub struct MilliSeconds(pub u32);
26+
2327
/// Extension trait that adds convenience methods to the `u32` type
2428
pub trait U32Ext {
2529
/// Wrap in `Bps`
@@ -33,6 +37,9 @@ pub trait U32Ext {
3337

3438
/// Wrap in `MegaHertz`
3539
fn mhz(self) -> MegaHertz;
40+
41+
/// Wrap in `MilliSeconds`
42+
fn ms(self) -> MilliSeconds;
3643
}
3744

3845
impl U32Ext for u32 {
@@ -51,6 +58,10 @@ impl U32Ext for u32 {
5158
fn mhz(self) -> MegaHertz {
5259
MegaHertz(self)
5360
}
61+
62+
fn ms(self) -> MilliSeconds {
63+
MilliSeconds(self)
64+
}
5465
}
5566

5667
impl From<KiloHertz> for Hertz {

src/watchdog.rs

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

0 commit comments

Comments
 (0)