Skip to content

Commit 2b540b4

Browse files
committed
Added src/independent_watchdog.rs and example from stm32h7xx-hal - completely untouched
1 parent 5e8f456 commit 2b540b4

File tree

2 files changed

+238
-0
lines changed

2 files changed

+238
-0
lines changed

examples/independent_watchdog.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
#[macro_use]
5+
mod utilities;
6+
use stm32h7xx_hal::{
7+
independent_watchdog::IndependentWatchdog, pac, prelude::*,
8+
};
9+
10+
use cortex_m_rt::entry;
11+
12+
use log::info;
13+
14+
#[entry]
15+
fn main() -> ! {
16+
utilities::logger::init();
17+
let dp = pac::Peripherals::take().unwrap();
18+
19+
// Constrain and Freeze power
20+
info!("Setup PWR... ");
21+
let pwr = dp.PWR.constrain();
22+
let pwrcfg = example_power!(pwr).freeze();
23+
24+
// Constrain and Freeze clock
25+
info!("Setup RCC... ");
26+
let rcc = dp.RCC.constrain();
27+
let _ccdr = rcc.sys_ck(96.MHz()).freeze(pwrcfg, &dp.SYSCFG);
28+
29+
#[cfg(any(feature = "rm0433", feature = "rm0455"))]
30+
let mut watchdog = IndependentWatchdog::new(dp.IWDG);
31+
32+
// Dual core parts
33+
#[cfg(all(feature = "rm0399", feature = "cm7"))]
34+
let mut watchdog = IndependentWatchdog::new(dp.IWDG1);
35+
#[cfg(all(feature = "rm0399", feature = "cm4"))]
36+
let mut watchdog = IndependentWatchdog::new(dp.IWDG2);
37+
38+
// RM0468
39+
#[cfg(all(feature = "rm0468"))]
40+
let mut watchdog = IndependentWatchdog::new(dp.IWDG1);
41+
42+
info!("");
43+
info!("stm32h7xx-hal example - Watchdog");
44+
info!("");
45+
46+
// If the watchdog is working correctly this print should
47+
// appear again and again as the chip gets restarted
48+
info!("Watchdog restarted! ");
49+
50+
// Enable the watchdog with a limit of 32.76 seconds (which is the maximum this watchdog can do) and wait forever
51+
// -> restart the chip
52+
watchdog.start(32_760.millis());
53+
54+
// Alternatively, there's also a windowed option where if the watchdog is fed before the window time, it will reset the chip as well
55+
// watchdog.start_windowed(100.millis(), 200.millis());
56+
57+
loop {
58+
// We can feed the watchdog like this:
59+
// watchdog.feed();
60+
cortex_m::asm::nop()
61+
}
62+
}

src/independent_watchdog.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//! Independent Watchdog
2+
//!
3+
//! This module implements the embedded-hal
4+
//! [Watchdog](https://docs.rs/embedded-hal/latest/embedded_hal/watchdog/trait.Watchdog.html)
5+
//! trait for the Independent Watchdog peripheral.
6+
//!
7+
//! The Independent Watchdog peripheral triggers a system reset when its internal counter expires.
8+
//!
9+
//! # Peripheral Naming
10+
//!
11+
//! The naming of the Independent Watchdog peripheral varies between parts
12+
//!
13+
//! | Parts | IWDG Peripheral | Second IWDG Peripheral |
14+
//! | --- | --- | --- |
15+
//! | stm32H742/743/750/753/7a3/7b0/7b3 | IWDG | - |
16+
//! | stm32h745/747/755/757 | IWDG1 | IWDG2 |
17+
//! | stm32h723/725/730/733/735 | IWDG1 | - |
18+
//!
19+
//! # Examples
20+
//!
21+
//! - [IWDG Example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/independent_watchdog.rs)
22+
use crate::{prelude::*, time::MilliSeconds};
23+
24+
#[cfg(any(feature = "rm0433", feature = "rm0455"))]
25+
use crate::stm32::iwdg::pr::PR_A;
26+
#[cfg(any(feature = "rm0433", feature = "rm0455"))]
27+
use crate::stm32::IWDG;
28+
29+
#[cfg(any(all(feature = "rm0399", feature = "cm7"), feature = "rm0468"))]
30+
use crate::stm32::iwdg1::pr::PR_A;
31+
#[cfg(any(all(feature = "rm0399", feature = "cm7"), feature = "rm0468"))]
32+
use crate::stm32::IWDG1 as IWDG;
33+
34+
#[cfg(all(feature = "rm0399", feature = "cm4"))]
35+
use crate::stm32::iwdg2::pr::PR_A;
36+
#[cfg(all(feature = "rm0399", feature = "cm4"))]
37+
use crate::stm32::IWDG2 as IWDG;
38+
39+
/// The implementation of the hardware IWDG
40+
pub struct IndependentWatchdog {
41+
iwdg: IWDG,
42+
}
43+
44+
impl IndependentWatchdog {
45+
const CLOCK_SPEED: u32 = 32000;
46+
const MAX_COUNTER_VALUE: u32 = 0x00000FFF;
47+
const MAX_MILLIS_FOR_PRESCALER: [(PR_A, u32); 8] = [
48+
(
49+
PR_A::DivideBy4,
50+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 4),
51+
),
52+
(
53+
PR_A::DivideBy8,
54+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 8),
55+
),
56+
(
57+
PR_A::DivideBy16,
58+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 16),
59+
),
60+
(
61+
PR_A::DivideBy32,
62+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 32),
63+
),
64+
(
65+
PR_A::DivideBy64,
66+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 64),
67+
),
68+
(
69+
PR_A::DivideBy128,
70+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 128),
71+
),
72+
(
73+
PR_A::DivideBy256,
74+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256),
75+
),
76+
(
77+
PR_A::DivideBy256bis,
78+
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256),
79+
),
80+
];
81+
82+
/// Create a new instance
83+
pub fn new(iwdg: IWDG) -> Self {
84+
Self { iwdg }
85+
}
86+
87+
/// Feed the watchdog, resetting the timer to 0
88+
pub fn feed(&mut self) {
89+
self.iwdg.kr.write(|w| w.key().reset());
90+
}
91+
92+
/// Start the watchdog where it must be fed before the max time is over and
93+
/// not before the min time has passed
94+
pub fn start_windowed<T: Into<MilliSeconds>>(
95+
&mut self,
96+
min_window_time: T,
97+
max_window_time: T,
98+
) {
99+
let min_window_time: MilliSeconds = min_window_time.into();
100+
let max_window_time: MilliSeconds = max_window_time.into();
101+
102+
// Start the watchdog
103+
self.iwdg.kr.write(|w| w.key().start());
104+
// Enable register access
105+
self.iwdg.kr.write(|w| w.key().enable());
106+
107+
// Set the prescaler
108+
let (prescaler, _) = Self::MAX_MILLIS_FOR_PRESCALER
109+
.iter()
110+
.find(|(_, max_millis)| *max_millis >= max_window_time.to_millis())
111+
.expect("IWDG max time is greater than is possible");
112+
while self.iwdg.sr.read().pvu().bit_is_set() {
113+
cortex_m::asm::nop();
114+
}
115+
self.iwdg.pr.write(|w| w.pr().variant(*prescaler));
116+
117+
// Reset the window value
118+
while self.iwdg.sr.read().wvu().bit_is_set() {
119+
cortex_m::asm::nop();
120+
}
121+
self.iwdg
122+
.winr
123+
.write(|w| w.win().bits(Self::MAX_COUNTER_VALUE as u16));
124+
125+
// Calculate the counter values
126+
let reload_value = max_window_time.to_millis()
127+
* (Self::CLOCK_SPEED / 1000)
128+
/ Self::get_prescaler_divider(prescaler);
129+
let window_value = min_window_time.to_millis()
130+
* (Self::CLOCK_SPEED / 1000)
131+
/ Self::get_prescaler_divider(prescaler);
132+
133+
// Set the reload value
134+
while self.iwdg.sr.read().rvu().bit_is_set() {
135+
cortex_m::asm::nop();
136+
}
137+
self.iwdg.rlr.write(|w| w.rl().bits(reload_value as u16));
138+
139+
self.feed();
140+
// Enable register access
141+
self.iwdg.kr.write(|w| w.key().enable());
142+
143+
// Set the window value
144+
while self.iwdg.sr.read().wvu().bit_is_set() {
145+
cortex_m::asm::nop();
146+
}
147+
self.iwdg
148+
.winr
149+
.write(|w| w.win().bits((reload_value - window_value) as u16));
150+
151+
// Wait until everything is set
152+
while self.iwdg.sr.read().bits() != 0 {
153+
cortex_m::asm::nop();
154+
}
155+
156+
self.feed();
157+
}
158+
159+
/// Start the watchdog with the given max time and no minimal time
160+
pub fn start<T: Into<MilliSeconds>>(&mut self, max_time: T) {
161+
self.start_windowed(0_u32.millis(), max_time.into());
162+
}
163+
164+
fn get_prescaler_divider(prescaler: &PR_A) -> u32 {
165+
match prescaler {
166+
PR_A::DivideBy4 => 4,
167+
PR_A::DivideBy8 => 8,
168+
PR_A::DivideBy16 => 16,
169+
PR_A::DivideBy32 => 32,
170+
PR_A::DivideBy64 => 64,
171+
PR_A::DivideBy128 => 128,
172+
PR_A::DivideBy256 => 256,
173+
PR_A::DivideBy256bis => 256,
174+
}
175+
}
176+
}

0 commit comments

Comments
 (0)