aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0/src/wwdt.rs
diff options
context:
space:
mode:
authorSiarhei B <[email protected]>2025-08-26 08:19:12 +0200
committerSiarhei B <[email protected]>2025-08-28 10:16:03 +0200
commit2eb643bac66844dccddc11065c3debbaef468595 (patch)
treeb150fc47c5ef8071d2839fa98e68b849d567fe0f /embassy-mspm0/src/wwdt.rs
parent93ba2c9c95721f1fe16269f09c219b161b2969cb (diff)
mspm0-watchdog: rename mod watchdog to wwdt
Diffstat (limited to 'embassy-mspm0/src/wwdt.rs')
-rw-r--r--embassy-mspm0/src/wwdt.rs345
1 files changed, 345 insertions, 0 deletions
diff --git a/embassy-mspm0/src/wwdt.rs b/embassy-mspm0/src/wwdt.rs
new file mode 100644
index 000000000..9864b3d94
--- /dev/null
+++ b/embassy-mspm0/src/wwdt.rs
@@ -0,0 +1,345 @@
1//! Window Watchdog Timer (WWDT) driver.
2//!
3//! This HAL implements a basic window watchdog timer with handles.
4
5#![macro_use]
6
7use core::marker::PhantomData;
8
9use embassy_hal_internal::PeripheralType;
10
11use crate::pac::wwdt::{vals, Wwdt as Regs};
12use crate::pac::{self};
13use crate::Peri;
14
15/// Possible watchdog timeout values.
16#[derive(Clone, Copy, PartialEq, Eq, Debug)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Timeout {
19 USec1950,
20 USec3910,
21 USec5860,
22 USec7810,
23 USec9770,
24 USec11720,
25 USec13670,
26 USec15630,
27 USec23440,
28 USec31250,
29 USec32250,
30 USec39060,
31 USec46880,
32 USec54690,
33 USec62500,
34 USec93750,
35 USec125000,
36 USec156250,
37 USec187500,
38 USec218750,
39 MSec130,
40 MSec250,
41 MSec380,
42 MSec500,
43 MSec630,
44 MSec750,
45 MSec880,
46 Sec1,
47 Sec2,
48 Sec3,
49 Sec4,
50 Sec5,
51 Sec6,
52 Sec7,
53 Sec8,
54 Sec16,
55 Sec24,
56 Sec32,
57 Sec40,
58 Sec48,
59 Sec56,
60 Sec64,
61 Sec128, // 2.13 min
62 Sec192, // 3.20 min
63 Sec256, // 4.27 min
64 Sec320, // 5.33 min
65 Sec384, // 6.40 min
66 Sec448, // 7.47 min
67 Sec512, // 8.53 min
68 Sec1024, // 17.07 min
69 Sec2048, // 34.13 min
70 Sec3072, // 51.20 min
71 Sec4096, // 68.27 min
72 Sec5120, // 85.33 min
73 Sec6144, // 102.40 min
74 Sec7168, // 119.47 min
75 Sec8192, // 136.53 min
76}
77
78impl Timeout {
79 fn get_period(self) -> vals::Per {
80 match self {
81 // period count is 2**25
82 Self::Sec1024
83 | Self::Sec2048
84 | Self::Sec3072
85 | Self::Sec4096
86 | Self::Sec5120
87 | Self::Sec6144
88 | Self::Sec7168
89 | Self::Sec8192 => vals::Per::EN_25,
90 // period count is 2**21
91 Self::Sec64
92 | Self::Sec128
93 | Self::Sec192
94 | Self::Sec256
95 | Self::Sec320
96 | Self::Sec384
97 | Self::Sec448
98 | Self::Sec512 => vals::Per::EN_21,
99 // period count is 2**18
100 Self::Sec8 | Self::Sec16 | Self::Sec24 | Self::Sec32 | Self::Sec40 | Self::Sec48 | Self::Sec56 => {
101 vals::Per::EN_18
102 }
103 // period count is 2**15
104 Self::Sec1 | Self::Sec2 | Self::Sec3 | Self::Sec4 | Self::Sec5 | Self::Sec6 | Self::Sec7 => {
105 vals::Per::EN_15
106 }
107 // period count is 2**12
108 Self::MSec130
109 | Self::MSec250
110 | Self::MSec380
111 | Self::MSec500
112 | Self::MSec630
113 | Self::MSec750
114 | Self::MSec880 => vals::Per::EN_12,
115 // period count is 2**10
116 Self::USec31250
117 | Self::USec62500
118 | Self::USec93750
119 | Self::USec125000
120 | Self::USec156250
121 | Self::USec187500
122 | Self::USec218750 => vals::Per::EN_10,
123 // period count is 2**8
124 Self::USec7810
125 | Self::USec15630
126 | Self::USec23440
127 | Self::USec32250
128 | Self::USec39060
129 | Self::USec46880
130 | Self::USec54690 => vals::Per::EN_8,
131 // period count is 2**6
132 Self::USec1950 | Self::USec3910 | Self::USec5860 | Self::USec9770 | Self::USec11720 | Self::USec13670 => {
133 vals::Per::EN_6
134 }
135 }
136 }
137
138 fn get_clkdiv(self) -> u8 {
139 match self {
140 // divide by 1
141 Self::USec1950
142 | Self::USec7810
143 | Self::USec31250
144 | Self::MSec130
145 | Self::Sec1
146 | Self::Sec8
147 | Self::Sec64
148 | Self::Sec1024 => 0u8,
149 // divide by 2
150 Self::USec3910
151 | Self::USec15630
152 | Self::USec62500
153 | Self::MSec250
154 | Self::Sec2
155 | Self::Sec16
156 | Self::Sec128
157 | Self::Sec2048 => 1u8,
158 // divide by 3
159 Self::USec5860
160 | Self::USec23440
161 | Self::USec93750
162 | Self::MSec380
163 | Self::Sec3
164 | Self::Sec24
165 | Self::Sec192
166 | Self::Sec3072 => 2u8,
167 // divide by 4
168 Self::USec32250
169 | Self::USec125000
170 | Self::MSec500
171 | Self::Sec4
172 | Self::Sec32
173 | Self::Sec256
174 | Self::Sec4096 => 3u8,
175 // divide by 5
176 Self::USec9770
177 | Self::USec39060
178 | Self::USec156250
179 | Self::MSec630
180 | Self::Sec5
181 | Self::Sec40
182 | Self::Sec320
183 | Self::Sec5120 => 4u8,
184 // divide by 6
185 Self::USec11720
186 | Self::USec46880
187 | Self::USec187500
188 | Self::MSec750
189 | Self::Sec6
190 | Self::Sec48
191 | Self::Sec384
192 | Self::Sec6144 => 5u8,
193 // divide by 7
194 Self::USec13670
195 | Self::USec54690
196 | Self::USec218750
197 | Self::MSec880
198 | Self::Sec7
199 | Self::Sec56
200 | Self::Sec448
201 | Self::Sec7168 => 6u8,
202 // divide by 8
203 Self::Sec512 | Self::Sec8192 => 7u8,
204 }
205 }
206}
207
208/// Timeout percentage that is treated as "too early" and generates violation.
209#[derive(Clone, Copy, PartialEq, Eq, Debug)]
210#[cfg_attr(feature = "defmt", derive(defmt::Format))]
211pub enum ClosedWindowPercentage {
212 // window period is not used
213 Zero,
214 // 12.5% percents
215 Twelve,
216 // 18.75% percents
217 Eighteen,
218 // 25% percents
219 TwentyFive,
220 // 50% percents
221 Fifty,
222 // 75% percents
223 SeventyFive,
224 // 81.25% percents
225 EightyOne,
226 // 87.5% percents
227 EightySeven,
228}
229
230impl ClosedWindowPercentage {
231 fn get_native_size(self) -> vals::Window {
232 match self {
233 Self::Zero => vals::Window::SIZE_0,
234 Self::Twelve => vals::Window::SIZE_12,
235 Self::Eighteen => vals::Window::SIZE_18,
236 Self::TwentyFive => vals::Window::SIZE_25,
237 Self::Fifty => vals::Window::SIZE_50,
238 Self::SeventyFive => vals::Window::SIZE_75,
239 Self::EightyOne => vals::Window::SIZE_81,
240 Self::EightySeven => vals::Window::SIZE_87,
241 }
242 }
243}
244
245#[non_exhaustive]
246#[derive(Clone, Copy, PartialEq, Eq, Debug)]
247/// Watchdog Config
248pub struct Config {
249 /// Watchdog timeout
250 pub timeout: Timeout,
251
252 /// closed window percentage
253 pub closed_window: ClosedWindowPercentage,
254}
255
256impl Default for Config {
257 fn default() -> Self {
258 Self {
259 timeout: Timeout::Sec1,
260 closed_window: ClosedWindowPercentage::Zero,
261 }
262 }
263}
264
265pub struct Watchdog<'d, T: Instance> {
266 wdt: PhantomData<&'d mut T>,
267}
268
269impl<'d, T: Instance> Watchdog<'d, T> {
270 /// Watchdog initialization.
271 pub fn new(_instance: Peri<'d, T>, config: Config) -> Self {
272 // Init power for watchdog
273 T::REGS.gprcm(0).rstctl().write(|w| {
274 w.set_resetstkyclr(true);
275 w.set_resetassert(true);
276 w.set_key(vals::ResetKey::KEY);
277 });
278
279 // Enable power for watchdog
280 T::REGS.gprcm(0).pwren().write(|w| {
281 w.set_enable(true);
282 w.set_key(vals::PwrenKey::KEY);
283 });
284
285 // init delay, 16 cycles
286 cortex_m::asm::delay(16);
287
288 //init watchdog
289 T::REGS.wwdtctl0().write(|w| {
290 w.set_clkdiv(config.timeout.get_clkdiv());
291 w.set_per(config.timeout.get_period());
292 w.set_mode(vals::Mode::WINDOW);
293 w.set_window0(config.closed_window.get_native_size());
294 w.set_window1(vals::Window::SIZE_0);
295 w.set_key(vals::Wwdtctl0Key::KEY);
296 });
297
298 // Set Window0 as active window
299 T::REGS.wwdtctl1().write(|w| {
300 w.set_winsel(vals::Winsel::WIN0);
301 w.set_key(vals::Wwdtctl1Key::KEY);
302 });
303
304 critical_section::with(|_| {
305 // make sure watchdog triggers BOOTRST
306 pac::SYSCTL.systemcfg().write(|w| {
307 if T::REGS == pac::WWDT0 {
308 w.set_wwdtlp0rstdis(false);
309 }
310
311 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x))]
312 if T::REGS == pac::WWDT1 {
313 w.set_wwdtlp1rstdis(false);
314 }
315 });
316 });
317
318 Watchdog { wdt: PhantomData }
319 }
320
321 /// Pet (reload, refresh) the watchdog.
322 pub fn pet(&mut self) {
323 T::REGS.wwdtcntrst().write(|w| {
324 w.set_restart(vals::WwdtcntrstRestart::RESTART);
325 });
326 }
327}
328
329pub(crate) trait SealedInstance {
330 const REGS: Regs;
331}
332
333/// WWDT instance trait
334#[allow(private_bounds)]
335pub trait Instance: SealedInstance + PeripheralType {}
336
337macro_rules! impl_wwdt_instance {
338 ($instance: ident) => {
339 impl crate::wwdt::SealedInstance for crate::peripherals::$instance {
340 const REGS: crate::pac::wwdt::Wwdt = crate::pac::$instance;
341 }
342
343 impl crate::wwdt::Instance for crate::peripherals::$instance {}
344 };
345}