Skip to content

Commit 841c6b2

Browse files
Add watchdog driver
1 parent 316c97c commit 841c6b2

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed

src/peripherals.rs

+1
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ pub mod syscon;
4242
pub mod usbfs;
4343
pub mod usbhs;
4444
pub mod utick;
45+
pub mod wwdt;

src/peripherals/wwdt.rs

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
use core::fmt;
2+
3+
use raw::WWDT;
4+
5+
mod sealed {
6+
pub trait WwdtMode {}
7+
}
8+
9+
#[non_exhaustive]
10+
pub struct Inactive;
11+
12+
#[non_exhaustive]
13+
pub struct Active;
14+
15+
impl sealed::WwdtMode for Inactive {}
16+
impl sealed::WwdtMode for Active {}
17+
18+
/// Windowed watchdog
19+
///
20+
/// Only when `Enabled` is [`Active`] the watchdog is active
21+
/// Only when `Resetting` is [`Active`] will the watchdog reset the device when its counter reaches zero
22+
/// Only when `Protecting` is [`Active`] will the watchdog reset the device when its counter reaches zero
23+
pub struct Wwdt<
24+
Enabled: sealed::WwdtMode,
25+
Resetting: sealed::WwdtMode,
26+
Protecting: sealed::WwdtMode,
27+
> {
28+
wwdt: WWDT,
29+
_state: (Enabled, Resetting, Protecting),
30+
}
31+
32+
#[derive(Debug)]
33+
/// Returned if [`Wwdt::set_timer`][] is given an invalid count
34+
///
35+
/// The count must fit within 24 bits
36+
pub struct InvalidInterval;
37+
38+
impl fmt::Display for InvalidInterval {
39+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40+
f.write_str("The count must fit within 24 bits")
41+
}
42+
}
43+
44+
#[derive(Debug)]
45+
/// Returned if [`Wwdt::set_warning`][] is given an invalid count
46+
///
47+
/// The count must fit within 10 bits
48+
pub struct InvalidWarnInterval;
49+
50+
impl fmt::Display for InvalidWarnInterval {
51+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52+
f.write_str("The count must fit within 10 bits")
53+
}
54+
}
55+
56+
#[derive(Debug)]
57+
pub enum TryNewWatchdogError {
58+
InvalidState,
59+
/// Returned if [`Wwdt::try_new`][] is given an invalid divider
60+
///
61+
/// The divider must fit within 10 bits
62+
InvalidClkDiv,
63+
}
64+
65+
impl fmt::Display for TryNewWatchdogError {
66+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67+
match self {
68+
Self::InvalidState => f.write_str("Watchdog must be fully inactive for try_new"),
69+
Self::InvalidClkDiv => f.write_str("The clock divider must fit within 6 bits"),
70+
}
71+
}
72+
}
73+
74+
impl Wwdt<Inactive, Inactive, Inactive> {
75+
pub fn try_new(
76+
wwdt: WWDT,
77+
syscon: &crate::Syscon,
78+
clock_divider: u8,
79+
) -> Result<Self, (WWDT, TryNewWatchdogError)> {
80+
if wwdt.mod_.read().wden().bit_is_set()
81+
|| wwdt.mod_.read().wdprotect().bit_is_set()
82+
|| wwdt.mod_.read().wdreset().bit_is_set()
83+
{
84+
return Err((wwdt, TryNewWatchdogError::InvalidState));
85+
}
86+
87+
if (clock_divider & 0b11000000) != 0 {
88+
return Err((wwdt, TryNewWatchdogError::InvalidClkDiv));
89+
}
90+
91+
// Safety: divider fits in 5 bits
92+
syscon.raw.wdtclkdiv.modify(|_, w| unsafe {
93+
w.reset()
94+
.released()
95+
.halt()
96+
.clear_bit()
97+
.div()
98+
.bits(clock_divider)
99+
});
100+
101+
syscon.raw.ahbclkctrl0.modify(|_, w| w.wwdt().set_bit());
102+
103+
Ok(Self {
104+
wwdt,
105+
_state: (Inactive, Inactive, Inactive),
106+
})
107+
}
108+
}
109+
110+
impl<Resetting, Protecting> Wwdt<Inactive, Resetting, Protecting>
111+
where
112+
Resetting: sealed::WwdtMode,
113+
Protecting: sealed::WwdtMode,
114+
{
115+
/// Set the timer to TWDCLK * count * 4
116+
///
117+
/// `count` must fit within 24 bits
118+
pub fn set_timer(&mut self, count: u32) -> Result<(), InvalidInterval> {
119+
if (count & 0xFF000000) != 0 {
120+
return Err(InvalidInterval);
121+
}
122+
// Safety: The count fits in 24 bits and the watchdog is disabled
123+
self.wwdt.tc.write(|w| unsafe { w.count().bits(count) });
124+
Ok(())
125+
}
126+
127+
/// Set the counter value
128+
///
129+
/// `at_counter` must fit within 10 bits
130+
pub fn set_warning(&mut self, at_counter: u16) -> Result<(), InvalidWarnInterval> {
131+
if (at_counter & 0b1111110000000000) != 0 {
132+
return Err(InvalidWarnInterval);
133+
}
134+
// Safety: counter fits in 10 bits
135+
self.wwdt
136+
.warnint
137+
.modify(|_, w| unsafe { w.warnint().bits(at_counter) });
138+
Ok(())
139+
}
140+
141+
/// Sets the count for the window of the counter value from which the watchdog can be fed
142+
///
143+
/// The watchdog can only be fed if the counter value is below `count`
144+
pub fn set_window(&mut self, count: u32) -> Result<(), InvalidInterval> {
145+
if (count & 0xFF000000) != 0 {
146+
return Err(InvalidInterval);
147+
}
148+
149+
// Safety: count fits in 24 bits
150+
self.wwdt.window.modify(|_, w| unsafe { w.bits(count) });
151+
Ok(())
152+
}
153+
154+
/// Get the current count of the watchdog
155+
pub fn current_count(&mut self) -> u32 {
156+
self.wwdt.tv.read().bits()
157+
}
158+
}
159+
160+
impl<Resetting, Protecting> Wwdt<Inactive, Resetting, Protecting>
161+
where
162+
Resetting: sealed::WwdtMode,
163+
Protecting: sealed::WwdtMode,
164+
{
165+
/// Enable the watchdog
166+
///
167+
/// Cannot be reversed without a reset
168+
pub fn set_enabled(self) -> Wwdt<Active, Resetting, Protecting> {
169+
self.wwdt.mod_.modify(|_, w| w.wden().bit(true));
170+
let this = Wwdt {
171+
wwdt: self.wwdt,
172+
_state: (Active, self._state.1, self._state.2),
173+
};
174+
this.feed();
175+
this
176+
}
177+
}
178+
179+
impl<Enabled, Protecting> Wwdt<Enabled, Inactive, Protecting>
180+
where
181+
Enabled: sealed::WwdtMode,
182+
Protecting: sealed::WwdtMode,
183+
{
184+
/// Trigger a reset when the watchdog counter reaches zero
185+
///
186+
/// Cannot be reversed without a reset
187+
pub fn set_resetting(self) -> Wwdt<Enabled, Active, Protecting> {
188+
self.wwdt.mod_.modify(|_, w| w.wdreset().bit(true));
189+
Wwdt {
190+
wwdt: self.wwdt,
191+
_state: (self._state.0, Active, self._state.2),
192+
}
193+
}
194+
}
195+
196+
impl<Enabled, Resetting> Wwdt<Enabled, Resetting, Inactive>
197+
where
198+
Enabled: sealed::WwdtMode,
199+
Resetting: sealed::WwdtMode,
200+
{
201+
/// When set, the watchdog can only be fed when the counter is below bothe the values passed
202+
/// to set_window and set_warning
203+
pub fn set_protecting(self) -> Wwdt<Enabled, Resetting, Active> {
204+
self.wwdt.mod_.modify(|_, w| w.wdprotect().bit(true));
205+
Wwdt {
206+
wwdt: self.wwdt,
207+
_state: (self._state.0, self._state.1, Active),
208+
}
209+
}
210+
}
211+
212+
impl<Resetting, Protecting> Wwdt<Active, Resetting, Protecting>
213+
where
214+
Resetting: sealed::WwdtMode,
215+
Protecting: sealed::WwdtMode,
216+
{
217+
pub fn feed(&self) {
218+
// Safety: The watchdog is enabled
219+
self.wwdt.feed.write(|w| unsafe { w.feed().bits(0xAA) });
220+
self.wwdt.feed.write(|w| unsafe { w.feed().bits(0x55) });
221+
}
222+
223+
pub fn timer(&self) -> u32 {
224+
self.wwdt.tv.read().bits()
225+
}
226+
}

0 commit comments

Comments
 (0)