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