aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchemicstry <[email protected]>2022-07-10 20:38:30 +0300
committerchemicstry <[email protected]>2022-07-10 20:38:30 +0300
commitbd01e90bfa4895b45e41ad538cb24a959b0b58ab (patch)
treeec86a61d00a087e1faba730d922e53c8f3086f2f
parent5f43c1d37e9db847c7861fe0bd821db62edba9f6 (diff)
Implement IWDG timeout calculation
-rw-r--r--embassy-stm32/src/wdg/mod.rs50
-rw-r--r--examples/stm32f4/src/bin/wdt.rs44
2 files changed, 90 insertions, 4 deletions
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index da25692ab..b4d59ff2d 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -1,21 +1,63 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy::time::Duration;
3use embassy_hal_common::{unborrow, Unborrow}; 4use embassy_hal_common::{unborrow, Unborrow};
4use stm32_metapac::iwdg::vals::Key; 5use stm32_metapac::iwdg::vals::{Key, Pr};
5pub use stm32_metapac::iwdg::vals::Pr as Prescaler; 6
7use crate::time::Hertz;
6 8
7pub struct IndependentWatchdog<'d, T: Instance> { 9pub struct IndependentWatchdog<'d, T: Instance> {
8 wdg: PhantomData<&'d mut T>, 10 wdg: PhantomData<&'d mut T>,
9} 11}
10 12
13// Some STM32 families have 40 kHz LSI clock instead of 32 kHz
14cfg_if::cfg_if! {
15 if #[cfg(any(stm32f0, stm32f1))] {
16 pub const IWDG_FREQ: Hertz = Hertz(40_000);
17 } else {
18 pub const IWDG_FREQ: Hertz = Hertz(32_000);
19 }
20}
21
22// 12-bit counter
23const MAX_RL: u16 = 0xFFF;
24
25/// Calculates maximum watchdog timeout (RL = 0xFFF) for a given prescaler
26const fn max_timeout(prescaler: u8) -> Duration {
27 Duration::from_micros(1_000_000 / (IWDG_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64)
28}
29
30/// Calculates watchdog reload value for the given prescaler and desired timeout
31const fn reload_value(prescaler: u8, timeout: Duration) -> u16 {
32 ((IWDG_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16
33}
34
11impl<'d, T: Instance> IndependentWatchdog<'d, T> { 35impl<'d, T: Instance> IndependentWatchdog<'d, T> {
12 pub fn new(_instance: impl Unborrow<Target = T> + 'd, presc: Prescaler) -> Self { 36 pub fn new(_instance: impl Unborrow<Target = T> + 'd, timeout: Duration) -> Self {
13 unborrow!(_instance); 37 unborrow!(_instance);
14 38
39 // Find lowest prescaler value, which makes watchdog period longer or equal to timeout.
40 // This iterates from 4 (2^2) to 256 (2^8).
41 let psc_power = unwrap!((2..=8).find(|psc_power| {
42 let psc = 2u8.pow(*psc_power);
43 timeout <= max_timeout(psc)
44 }));
45
46 // Prescaler value
47 let psc = 2u8.pow(psc_power);
48
49 // Convert prescaler power to PR register value
50 let pr = psc_power as u8 - 2;
51 assert!(pr <= 0b110);
52
53 // Reload value
54 let rl = reload_value(psc, timeout);
55
15 let wdg = T::regs(); 56 let wdg = T::regs();
16 unsafe { 57 unsafe {
17 wdg.kr().write(|w| w.set_key(Key::ENABLE)); 58 wdg.kr().write(|w| w.set_key(Key::ENABLE));
18 wdg.pr().write(|w| w.set_pr(presc)); 59 wdg.pr().write(|w| w.set_pr(Pr(pr)));
60 wdg.rlr().write(|w| w.set_rl(rl));
19 } 61 }
20 62
21 IndependentWatchdog { 63 IndependentWatchdog {
diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs
new file mode 100644
index 000000000..41e1f4c7b
--- /dev/null
+++ b/examples/stm32f4/src/bin/wdt.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy::executor::Spawner;
7use embassy::time::{Duration, Timer};
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::wdg::IndependentWatchdog;
10use embassy_stm32::Peripherals;
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy::main]
14async fn main(_spawner: Spawner, p: Peripherals) {
15 info!("Hello World!");
16
17 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
18
19 let mut wdt = IndependentWatchdog::new(p.IWDG, Duration::from_secs(1));
20 unsafe {
21 wdt.unleash();
22 }
23
24 let mut i = 0;
25
26 loop {
27 info!("high");
28 led.set_high();
29 Timer::after(Duration::from_millis(300)).await;
30
31 info!("low");
32 led.set_low();
33 Timer::after(Duration::from_millis(300)).await;
34
35 if i < 5 {
36 info!("Petting watchdog");
37 unsafe {
38 wdt.pet();
39 }
40 }
41
42 i += 1;
43 }
44}