|
| 1 | +//! Independent Watchdog |
| 2 | +
|
| 3 | +use stm32f103xx::IWDG; |
| 4 | +use hal::watchdog::{Watchdog, WatchdogEnable}; |
| 5 | + |
| 6 | +use rcc::CSR; |
| 7 | + |
| 8 | + |
| 9 | +pub struct IndependentWatchdog { |
| 10 | + iwdg: IWDG, |
| 11 | +} |
| 12 | + |
| 13 | +enum Key { |
| 14 | + Feed = 0xAAAA, |
| 15 | + Unlock = 0x5555, |
| 16 | + Lock = 0x0, |
| 17 | + Start = 0xCCCC, |
| 18 | +} |
| 19 | + |
| 20 | +impl IndependentWatchdog { |
| 21 | + /// Wrap the watchdog peripheral into a struct that implements the |
| 22 | + /// embedded_hal `Watchdog` and `WatchdogEnable` traits. |
| 23 | + /// |
| 24 | + /// Pass a `rcc.csr` to initialize the LSI clock. |
| 25 | + pub fn new(iwdg: IWDG, csr: &mut CSR) -> Self { |
| 26 | + csr.enable_lsi(); |
| 27 | + |
| 28 | + IndependentWatchdog { iwdg } |
| 29 | + } |
| 30 | + |
| 31 | + fn write_key(&self, key: Key) { |
| 32 | + self.iwdg.kr.write(|w| unsafe { w.key().bits(key as u16) }); |
| 33 | + } |
| 34 | + |
| 35 | + fn unlocked<F, R>(&mut self, f: F) -> R |
| 36 | + where |
| 37 | + F: FnOnce(&mut IWDG) -> R, |
| 38 | + { |
| 39 | + self.write_key(Key::Unlock); |
| 40 | + let r = f(&mut self.iwdg); |
| 41 | + self.write_key(Key::Lock); |
| 42 | + r |
| 43 | + } |
| 44 | + |
| 45 | + fn configure(&mut self, prescaler: u8, reload: u16) { |
| 46 | + self.unlocked(|iwdg| { |
| 47 | + iwdg.pr.write(|w| unsafe { |
| 48 | + w.pr().bits(prescaler) |
| 49 | + }); |
| 50 | + iwdg.rlr.write(|w| unsafe { |
| 51 | + w.rl().bits(reload) |
| 52 | + }); |
| 53 | + }); |
| 54 | + } |
| 55 | + |
| 56 | + /// Maximum watchdog timeout is 26.214 seconds |
| 57 | + pub const MAX_TIMEOUT_MS: u32 = 26214; |
| 58 | + |
| 59 | + const MAX_RELOAD: u16 = 0xFFF; |
| 60 | + const MAX_PRESCALE: u8 = 6; |
| 61 | +} |
| 62 | + |
| 63 | +impl WatchdogEnable for IndependentWatchdog { |
| 64 | + type Time = u32; |
| 65 | + |
| 66 | + fn start<T>(&mut self, period: T) where T: Into<Self::Time> { |
| 67 | + let timeout_ms = period.into(); |
| 68 | + |
| 69 | + let mut max_timeout_ms = Self::MAX_TIMEOUT_MS; |
| 70 | + assert!(timeout_ms <= max_timeout_ms); |
| 71 | + |
| 72 | + let mut prescaler = Self::MAX_PRESCALE; |
| 73 | + while prescaler > 0 && timeout_ms <= max_timeout_ms / 2 { |
| 74 | + prescaler -= 1; |
| 75 | + max_timeout_ms /= 2; |
| 76 | + } |
| 77 | + |
| 78 | + let reload = ((Self::MAX_RELOAD as u32) * timeout_ms / max_timeout_ms) as u16; |
| 79 | + self.configure(prescaler, reload); |
| 80 | + self.write_key(Key::Start); |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +impl Watchdog for IndependentWatchdog { |
| 85 | + fn feed(&mut self) { |
| 86 | + self.write_key(Key::Feed); |
| 87 | + } |
| 88 | +} |
0 commit comments