|
| 1 | +//! API for the IWDG |
| 2 | +//! |
| 3 | +//! You can activate the watchdog by calling `start` or the setting appropriate |
| 4 | +//! device option bit when programming. |
| 5 | +//! |
| 6 | +//! After activating the watchdog, you'll have to regularly `feed` the watchdog. |
| 7 | +//! If more time than `timeout` has gone by since the last `feed`, your |
| 8 | +//! microcontroller will be reset. |
| 9 | +//! |
| 10 | +//! This is useful if you fear that your program may get stuck. In that case it |
| 11 | +//! won't feed the watchdog anymore, the watchdog will reset the microcontroller |
| 12 | +//! and thus your program will function again. |
| 13 | +//! |
| 14 | +//! **Attention**: |
| 15 | +//! |
| 16 | +//! The IWDG runs on a separate 40kHz low-accuracy clock (30kHz-60kHz). You may |
| 17 | +//! want to some buffer in your interval. |
| 18 | +//! |
| 19 | +//! Per default the iwdg continues to run even when you stopped execution of code via a debugger. |
| 20 | +//! You may want to disable the watchdog when the cpu is stopped |
| 21 | +//! |
| 22 | +//! ``` ignore |
| 23 | +//! let dbgmcu = p.DBGMCU; |
| 24 | +//! dbgmcu.apb1_fz.modify(|_, w| w.dbg_iwdg_stop().set_bit()); |
| 25 | +//! ``` |
| 26 | +//! |
| 27 | +//! # Example |
| 28 | +//! ``` no_run |
| 29 | +//! use stm32f0xx_hal as hal; |
| 30 | +//! |
| 31 | +//! use crate::hal::stm32; |
| 32 | +//! use crate::hal::prelude::*; |
| 33 | +//! use crate::hal:watchdog::Watchdog; |
| 34 | +//! use crate::hal:time::Hertz; |
| 35 | +//! |
| 36 | +//! let mut p = stm32::Peripherals::take().unwrap(); |
| 37 | +//! |
| 38 | +//! let mut iwdg = Watchdog::new(p.iwdg); |
| 39 | +//! iwdg.start(Hertz(100)); |
| 40 | +//! loop {} |
| 41 | +//! // Whoops, got stuck, the watchdog issues a reset after 10 ms |
| 42 | +//! iwdg.feed(); |
| 43 | +//! ``` |
| 44 | +use embedded_hal::watchdog; |
| 45 | + |
| 46 | +use crate::stm32::IWDG; |
| 47 | +use crate::time::Hertz; |
| 48 | + |
| 49 | +/// Watchdog instance |
| 50 | +pub struct Watchdog { |
| 51 | + iwdg: IWDG, |
| 52 | +} |
| 53 | + |
| 54 | +impl watchdog::Watchdog for Watchdog { |
| 55 | + /// Feed the watchdog, so that at least one `period` goes by before the next |
| 56 | + /// reset |
| 57 | + fn feed(&mut self) { |
| 58 | + self.iwdg.kr.write(|w| w.key().reset()); |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +/// Timeout configuration for the IWDG |
| 63 | +#[derive(PartialEq, PartialOrd, Clone, Copy)] |
| 64 | +pub struct IwdgTimeout { |
| 65 | + psc: u8, |
| 66 | + reload: u16, |
| 67 | +} |
| 68 | + |
| 69 | +impl Into<IwdgTimeout> for Hertz { |
| 70 | + /// This converts the value so it's usable by the IWDG |
| 71 | + /// Due to conversion losses, the specified frequency is a maximum |
| 72 | + /// |
| 73 | + /// It can also only represent values < 10000 Hertz |
| 74 | + fn into(self) -> IwdgTimeout { |
| 75 | + let mut time = 40_000 / 4 / self.0; |
| 76 | + let mut psc = 0; |
| 77 | + let mut reload = 0; |
| 78 | + while psc < 7 { |
| 79 | + reload = time; |
| 80 | + if reload < 0x1000 { |
| 81 | + break; |
| 82 | + } |
| 83 | + psc += 1; |
| 84 | + time /= 2; |
| 85 | + } |
| 86 | + // As we get an integer value, reload is always below 0xFFF |
| 87 | + let reload = reload as u16; |
| 88 | + IwdgTimeout { psc, reload } |
| 89 | + } |
| 90 | +} |
| 91 | +impl Watchdog { |
| 92 | + pub fn new(iwdg: IWDG) -> Self { |
| 93 | + Self { iwdg } |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +impl watchdog::WatchdogEnable for Watchdog { |
| 98 | + type Time = IwdgTimeout; |
| 99 | + fn start<T>(&mut self, period: T) |
| 100 | + where |
| 101 | + T: Into<IwdgTimeout>, |
| 102 | + { |
| 103 | + let time: IwdgTimeout = period.into(); |
| 104 | + // Feed the watchdog in case it's already running |
| 105 | + // (Waiting for the registers to update takes sometime) |
| 106 | + self.iwdg.kr.write(|w| w.key().reset()); |
| 107 | + // Enable the watchdog |
| 108 | + self.iwdg.kr.write(|w| w.key().start()); |
| 109 | + self.iwdg.kr.write(|w| w.key().enable()); |
| 110 | + // Wait until it's safe to write to the registers |
| 111 | + while self.iwdg.sr.read().pvu().bit() {} |
| 112 | + self.iwdg.pr.write(|w| w.pr().bits(time.psc)); |
| 113 | + while self.iwdg.sr.read().rvu().bit() {} |
| 114 | + self.iwdg.rlr.write(|w| w.rl().bits(time.reload)); |
| 115 | + // Wait until the registers are updated before issuing a reset with |
| 116 | + // (potentially false) values |
| 117 | + while self.iwdg.sr.read().bits() != 0 {} |
| 118 | + self.iwdg.kr.write(|w| w.key().reset()); |
| 119 | + } |
| 120 | +} |
0 commit comments