Skip to content

Commit aaf2034

Browse files
authored
Merge pull request #180 from ahdinosaur/watchdog
port watchdog
2 parents 7099b07 + 139072b commit aaf2034

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
- Support for flash.rs on bigger chips.
13+
- Implement `IndependentWatchdog` for the IWDG peripheral
1314

1415
### Changed
1516

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ pub mod ltdc;
159159
#[cfg(feature = "device-selected")]
160160
pub mod flash;
161161

162+
#[cfg(feature = "device-selected")]
163+
pub mod watchdog;
164+
162165
pub mod state {
163166
/// Indicates that a peripheral is enabled
164167
pub struct Enabled;

src/watchdog.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//! Watchdog peripherals
2+
3+
use crate::pac::{DBGMCU, IWDG};
4+
use core::fmt;
5+
use embedded_hal::watchdog::{Watchdog, WatchdogEnable};
6+
use fugit::MillisDurationU32 as MilliSeconds;
7+
8+
/// Wraps the Independent Watchdog (IWDG) peripheral
9+
pub struct IndependentWatchdog {
10+
iwdg: IWDG,
11+
}
12+
13+
/*
14+
#[cfg(feature = "defmt")]
15+
impl defmt::Format for IndependentWatchdog {
16+
fn format(&self, f: defmt::Formatter) {
17+
defmt::write!(f, "IndependentWatchdog");
18+
}
19+
}
20+
*/
21+
22+
impl fmt::Debug for IndependentWatchdog {
23+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24+
f.write_str("IndependentWatchdog")
25+
}
26+
}
27+
28+
const MAX_PR: u8 = 0b110;
29+
const MAX_RL: u16 = 0xFFF;
30+
const KR_ACCESS: u16 = 0x5555;
31+
const KR_RELOAD: u16 = 0xAAAA;
32+
const KR_START: u16 = 0xCCCC;
33+
const LSI_KHZ: u32 = 32;
34+
35+
impl IndependentWatchdog {
36+
/// Wrap and start the watchdog
37+
pub fn new(iwdg: IWDG) -> Self {
38+
IndependentWatchdog { iwdg }
39+
}
40+
41+
/// Debug independent watchdog stopped when core is halted
42+
pub fn stop_on_debug(&self, dbgmcu: &DBGMCU, stop: bool) {
43+
dbgmcu.apb1_fz.modify(|_, w| w.dbg_iwdg_stop().bit(stop));
44+
}
45+
46+
fn setup(&self, timeout_ms: u32) {
47+
let mut pr = 0;
48+
while pr < MAX_PR && Self::timeout_period(pr, MAX_RL) < timeout_ms {
49+
pr += 1;
50+
}
51+
52+
let max_period = Self::timeout_period(pr, MAX_RL);
53+
let max_rl = u32::from(MAX_RL);
54+
let rl = (timeout_ms * max_rl / max_period).min(max_rl) as u16;
55+
56+
self.access_registers(|iwdg| {
57+
iwdg.pr.modify(|_, w| w.pr().bits(pr));
58+
iwdg.rlr.modify(|_, w| w.rl().bits(rl));
59+
});
60+
}
61+
62+
fn is_pr_updating(&self) -> bool {
63+
self.iwdg.sr.read().pvu().bit()
64+
}
65+
66+
/// Returns the interval in ms
67+
pub fn interval(&self) -> MilliSeconds {
68+
while self.is_pr_updating() {}
69+
70+
let pr = self.iwdg.pr.read().pr().bits();
71+
let rl = self.iwdg.rlr.read().rl().bits();
72+
let ms = Self::timeout_period(pr, rl);
73+
MilliSeconds::from_ticks(ms)
74+
}
75+
76+
/// pr: Prescaler divider bits, rl: reload value
77+
///
78+
/// Returns ms
79+
fn timeout_period(pr: u8, rl: u16) -> u32 {
80+
let divider: u32 = match pr {
81+
0b000 => 4,
82+
0b001 => 8,
83+
0b010 => 16,
84+
0b011 => 32,
85+
0b100 => 64,
86+
0b101 => 128,
87+
0b110 => 256,
88+
0b111 => 256,
89+
_ => unreachable!(),
90+
};
91+
(u32::from(rl) + 1) * divider / LSI_KHZ
92+
}
93+
94+
fn access_registers<A, F: FnMut(&IWDG) -> A>(&self, mut f: F) -> A {
95+
// Unprotect write access to registers
96+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_ACCESS) });
97+
let a = f(&self.iwdg);
98+
99+
// Protect again
100+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_RELOAD) });
101+
a
102+
}
103+
104+
pub fn start(&mut self, period: MilliSeconds) {
105+
self.setup(period.ticks());
106+
107+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_START) });
108+
}
109+
110+
pub fn feed(&mut self) {
111+
self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_RELOAD) });
112+
}
113+
}
114+
115+
impl WatchdogEnable for IndependentWatchdog {
116+
type Time = MilliSeconds;
117+
118+
fn start<T: Into<Self::Time>>(&mut self, period: T) {
119+
self.start(period.into())
120+
}
121+
}
122+
123+
impl Watchdog for IndependentWatchdog {
124+
fn feed(&mut self) {
125+
self.feed()
126+
}
127+
}

0 commit comments

Comments
 (0)