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
//! # API for the Watchdog peripheral
//!
//! ## Examples
//!
//! - [Watchdog simple example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/wdt.rs)
use crate::time::Hertz;
use crate::{
    clock::{Clocks, PeripheralSelect},
    pac,
    prelude::SyscfgExt,
};
use crate::{disable_interrupt, enable_interrupt};

pub const WDT_UNLOCK_VALUE: u32 = 0x1ACC_E551;

pub struct WdtController {
    clock_freq: Hertz,
    wdt: pac::WatchDog,
}

/// Enable the watchdog interrupt
///
/// # Safety
///
/// This function is `unsafe` because it can break mask-based critical sections.
#[inline]
pub unsafe fn enable_wdt_interrupts() {
    enable_interrupt(pac::Interrupt::WATCHDOG)
}

#[inline]
pub fn disable_wdt_interrupts() {
    disable_interrupt(pac::Interrupt::WATCHDOG)
}

impl WdtController {
    pub fn new(
        &self,
        syscfg: &mut pac::Sysconfig,
        wdt: pac::WatchDog,
        clocks: &Clocks,
        wdt_freq_ms: u32,
    ) -> Self {
        Self::start(syscfg, wdt, clocks, wdt_freq_ms)
    }

    pub fn start(
        syscfg: &mut pac::Sysconfig,
        wdt: pac::WatchDog,
        clocks: &Clocks,
        wdt_freq_ms: u32,
    ) -> Self {
        syscfg.enable_peripheral_clock(PeripheralSelect::Watchdog);
        syscfg.assert_periph_reset_for_two_cycles(PeripheralSelect::Watchdog);

        let wdt_clock = clocks.apb2();
        let mut wdt_ctrl = Self {
            clock_freq: wdt_clock,
            wdt,
        };
        wdt_ctrl.set_freq(wdt_freq_ms);
        wdt_ctrl.wdt.wdogcontrol().write(|w| w.inten().set_bit());
        wdt_ctrl.feed();
        // Unmask the watchdog interrupt
        unsafe {
            enable_wdt_interrupts();
        }
        wdt_ctrl
    }

    #[inline]
    pub fn set_freq(&mut self, freq_ms: u32) {
        let counter = (self.clock_freq.raw() / 1000) * freq_ms;
        self.wdt.wdogload().write(|w| unsafe { w.bits(counter) });
    }

    #[inline]
    pub fn disable_reset(&mut self) {
        self.wdt.wdogcontrol().modify(|_, w| w.resen().clear_bit())
    }

    #[inline]
    pub fn enable_reset(&mut self) {
        self.wdt.wdogcontrol().modify(|_, w| w.resen().set_bit())
    }

    #[inline]
    pub fn counter(&self) -> u32 {
        self.wdt.wdogvalue().read().bits()
    }

    #[inline]
    pub fn feed(&self) {
        self.wdt.wdogintclr().write(|w| unsafe { w.bits(1) });
    }

    #[inline]
    pub fn lock(&self) {
        self.wdt.wdoglock().write(|w| unsafe { w.bits(0) });
    }

    #[inline]
    pub fn unlock(&self) {
        self.wdt
            .wdoglock()
            .write(|w| unsafe { w.bits(WDT_UNLOCK_VALUE) });
    }

    #[inline]
    pub fn is_locked(&self) -> bool {
        self.wdt.wdogload().read().bits() == 1
    }
}