avr_hal_generic/wdt.rs
1//! WDT Implementation
2use core::marker::PhantomData;
3
4/// Watchdog Timeout
5#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
6pub enum Timeout {
7 /// 16 milliseconds
8 Ms16,
9 /// 32 milliseconds
10 Ms32,
11 /// 64 milliseconds
12 Ms64,
13 /// 125 milliseconds
14 Ms125,
15 /// 250 milliseconds
16 Ms250,
17 /// 500 milliseconds
18 Ms500,
19 /// 1 second
20 Ms1000,
21 /// 2 seconds
22 Ms2000,
23 /// 4 seconds
24 Ms4000,
25 /// 8 seconds
26 Ms8000,
27}
28
29/// Internal trait for low-level watchdog operations.
30///
31/// **HAL users should use the [`Wdt`] type instead.**
32pub trait WdtOps<H> {
33 type MCUSR;
34
35 /// Initialize the watchdog timer.
36 ///
37 /// **Warning**: This is a low-level method and should not be called directly from user code.
38 fn raw_init(&mut self, m: &Self::MCUSR);
39
40 /// Start the watchdog timer with the specified timeout.
41 ///
42 /// If the timeout value is not supported, `Err(())` should be returned.
43 ///
44 /// **Warning**: This is a low-level method and should not be called directly from user code.
45 fn raw_start(&mut self, timeout: Timeout) -> Result<(), ()>;
46
47 /// Feed this watchdog, to reset its period.
48 ///
49 /// **Warning**: This is a low-level method and should not be called directly from user code.
50 fn raw_feed(&mut self);
51
52 /// Disable/stop this watchdog again.
53 ///
54 /// **Warning**: This is a low-level method and should not be called directly from user code.
55 fn raw_stop(&mut self);
56}
57
58pub struct Wdt<H, WDT> {
59 p: WDT,
60 _h: PhantomData<H>,
61}
62
63impl<H, WDT: WdtOps<H>> Wdt<H, WDT> {
64 pub fn new(mut p: WDT, m: &WDT::MCUSR) -> Self {
65 p.raw_init(m);
66 Self { p, _h: PhantomData }
67 }
68
69 pub fn start(&mut self, timeout: Timeout) -> Result<(), ()> {
70 self.p.raw_start(timeout)
71 }
72
73 pub fn feed(&mut self) {
74 self.p.raw_feed()
75 }
76
77 pub fn stop(&mut self) {
78 self.p.raw_stop()
79 }
80}
81
82#[macro_export]
83macro_rules! impl_wdt {
84 (
85 hal: $HAL:ty,
86 peripheral: $WDT:ty,
87 mcusr: $MCUSR:ty,
88 wdtcsr_name: $wdtcsr:ident,
89 timeout: |$to:ident, $w:ident| $to_match:expr,
90 ) => {
91 impl $crate::wdt::WdtOps<$HAL> for $WDT {
92 type MCUSR = $MCUSR;
93
94 #[inline]
95 fn raw_init(&mut self, m: &Self::MCUSR) {
96 /// If a prior reset was provided by the watchdog, the WDRF in MCUSR would be set,
97 /// so WDRF is also cleared to allow for re-enabling the watchdog.
98 m.modify(|_, w| w.wdrf().clear_bit());
99 }
100
101 #[inline]
102 fn raw_start(&mut self, timeout: Timeout) -> Result<(), ()> {
103 // The sequence for changing time-out configuration is as follows:
104 //
105 // 1. In the same operation, write a logic one to the Watchdog change enable bit
106 // (WDCE) and WDE. A logic one must be written to WDE regardless of the
107 // previous value of the WDE bit.
108 // 2. Within the next four clock cycles, write the WDE and Watchdog prescaler
109 // bits (WDP) as desired, but with the WDCE bit cleared. This must be done in
110 // one operation.
111 $crate::avr_device::interrupt::free(|_| {
112 // Reset the watchdog timer.
113 self.raw_feed();
114 // Enable watchdog configuration mode.
115 self.$wdtcsr
116 .modify(|_, w| w.wdce().set_bit().wde().set_bit());
117 // Enable watchdog and set interval.
118 self.$wdtcsr.write(|w| {
119 let $to = timeout;
120 let $w = w;
121 ($to_match).wde().set_bit().wdce().clear_bit()
122 });
123
124 Ok(())
125 })
126 }
127
128 #[inline]
129 fn raw_feed(&mut self) {
130 avr_device::asm::wdr();
131 }
132
133 #[inline]
134 fn raw_stop(&mut self) {
135 // The sequence for clearing WDE is as follows:
136 //
137 // 1. In the same operation, write a logic one to the Watchdog change enable bit
138 // (WDCE) and WDE. A logic one must be written to WDE regardless of the
139 // previous value of the WDE bit.
140 // 2. Within the next four clock cycles, clear the WDE and WDCE bits.
141 // This must be done in one operation.
142 $crate::avr_device::interrupt::free(|_| {
143 // Reset the watchdog timer.
144 self.raw_feed();
145 // Enable watchdog configuration mode.
146 self.$wdtcsr
147 .modify(|_, w| w.wdce().set_bit().wde().set_bit());
148 // Disable watchdog.
149 self.$wdtcsr.reset();
150 })
151 }
152 }
153 };
154}