1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::hal::watchdog;
use crate::pac::{IWDG, WWDG};
use crate::rcc::Rcc;
use crate::time::Hertz;

pub struct IndependedWatchdog {
    iwdg: IWDG,
}

impl IndependedWatchdog {
    pub fn set_config(&mut self, pre: u8, reload: u16) {
        self.iwdg.kr.write(|w| w.key().reset());
        self.iwdg.kr.write(|w| w.key().enable());

        while self.iwdg.sr.read().pvu().bit() {}
        self.iwdg.pr.write(|w| w.pr().bits(pre));

        while self.iwdg.sr.read().rvu().bit() {}
        self.iwdg.rlr.write(|w| w.rl().bits(reload));

        self.iwdg.kr.write(|w| w.key().start());
        self.iwdg.kr.write(|w| w.key().reset());
    }
}

impl watchdog::Watchdog for IndependedWatchdog {
    fn feed(&mut self) {
        self.iwdg.kr.write(|w| w.key().reset());
    }
}

impl watchdog::WatchdogEnable for IndependedWatchdog {
    type Time = Hertz;

    fn start<T>(&mut self, period: T)
    where
        T: Into<Hertz>,
    {
        const LSI_CLOCK: u32 = 38_000_u32;

        let freq = period.into().0;
        let mut timeout = LSI_CLOCK / freq / 4;
        let mut pre = 0;
        let mut reload = 0;
        while pre < 7 {
            reload = timeout;
            if reload <= 0xFFF {
                break;
            }
            pre += 1;
            timeout /= 2;
        }
        self.set_config(pre, reload as u16);
    }
}

pub trait IndependedWatchdogExt {
    fn watchdog(self) -> IndependedWatchdog;
}

impl IndependedWatchdogExt for IWDG {
    fn watchdog(self) -> IndependedWatchdog {
        IndependedWatchdog { iwdg: self }
    }
}

pub struct WindowWatchdog {
    wwdg: WWDG,
    clk: u32,
}

impl watchdog::Watchdog for WindowWatchdog {
    fn feed(&mut self) {
        self.wwdg.cr.write(|w| w.t().bits(0xFF));
    }
}

impl WindowWatchdog {
    pub fn set_window<T>(&mut self, window: T)
    where
        T: Into<Hertz>,
    {
        let freq = window.into().0;
        let mut ticks = self.clk / freq;
        let mut pre = 0;
        let mut threshold = 0;
        while pre < 3 {
            threshold = ticks;
            if threshold <= 0x7F {
                break;
            }
            pre += 1;
            ticks /= 2;
        }

        let window_bits = if threshold >= 0xFF {
            0
        } else {
            0xFF - threshold as u8
        };
        self.wwdg
            .cfr
            .write(|w| w.wdgtb().bits(pre).w().bits(window_bits));
    }

    pub fn listen(&mut self) {
        self.wwdg.cfr.write(|w| w.ewi().set_bit());
    }
}

impl watchdog::WatchdogEnable for WindowWatchdog {
    type Time = Hertz;

    fn start<T>(&mut self, period: T)
    where
        T: Into<Hertz>,
    {
        self.set_window(period);
        self.wwdg.cr.write(|w| w.wdga().set_bit().t().bits(0xFF));
    }
}

pub trait WindowWatchdogExt {
    fn watchdog(self, rcc: &mut Rcc) -> WindowWatchdog;
}

impl WindowWatchdogExt for WWDG {
    fn watchdog(self, rcc: &mut Rcc) -> WindowWatchdog {
        rcc.rb.apb1enr.modify(|_, w| w.wwdgen().set_bit());
        WindowWatchdog {
            wwdg: self,
            clk: rcc.clocks.apb1_clk().0 / 4096,
        }
    }
}