diff options
| author | i509VCB <[email protected]> | 2025-08-28 16:52:44 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-28 16:52:44 +0000 |
| commit | d3c84ee1d34329e61464c9acbedab74e9076ac0d (patch) | |
| tree | ad9324f2fa27c1a11c90066a4405a886b4f0da2b /embassy-mspm0 | |
| parent | fc412837a62ee05dc22b4df37d635775fbd8a454 (diff) | |
| parent | cdb2354418a3ef7eda64d364e61c0ce9da437f15 (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.md | 1 | ||||
| -rw-r--r-- | embassy-mspm0/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-mspm0/build.rs | 1 | ||||
| -rw-r--r-- | embassy-mspm0/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-mspm0/src/wwdt.rs | 345 |
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" | |||
| 69 | critical-section = "1.2.0" | 69 | critical-section = "1.2.0" |
| 70 | 70 | ||
| 71 | # mspm0-metapac = { version = "" } | 71 | # mspm0-metapac = { version = "" } |
| 72 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-df572e257eabf06e6e0ae6c9077e0a2fec1fb5e1" } | 72 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-fe17d879548757ca29821da66a1bebf2debd4846" } |
| 73 | 73 | ||
| 74 | [build-dependencies] | 74 | [build-dependencies] |
| 75 | proc-macro2 = "1.0.94" | 75 | proc-macro2 = "1.0.94" |
| @@ -77,7 +77,7 @@ quote = "1.0.40" | |||
| 77 | cfg_aliases = "0.2.1" | 77 | cfg_aliases = "0.2.1" |
| 78 | 78 | ||
| 79 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } | 79 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } |
| 80 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-df572e257eabf06e6e0ae6c9077e0a2fec1fb5e1", default-features = false, features = ["metadata"] } | 80 | mspm0-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] |
| 83 | default = ["rt"] | 83 | default = ["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; | |||
| 18 | pub mod i2c; | 18 | pub mod i2c; |
| 19 | pub mod timer; | 19 | pub mod timer; |
| 20 | pub mod uart; | 20 | pub mod uart; |
| 21 | pub mod wwdt; | ||
| 21 | 22 | ||
| 22 | /// Operating modes for peripherals. | 23 | /// Operating modes for peripherals. |
| 23 | pub mod mode { | 24 | pub 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 | |||
| 7 | use embassy_hal_internal::PeripheralType; | ||
| 8 | |||
| 9 | use crate::pac::wwdt::{vals, Wwdt as Regs}; | ||
| 10 | use crate::pac::{self}; | ||
| 11 | use crate::Peri; | ||
| 12 | |||
| 13 | /// Possible watchdog timeout values. | ||
| 14 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
| 15 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 16 | pub 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 | |||
| 76 | impl 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))] | ||
| 209 | pub 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 | |||
| 228 | impl 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 | ||
| 246 | pub struct Config { | ||
| 247 | /// Watchdog timeout | ||
| 248 | pub timeout: Timeout, | ||
| 249 | |||
| 250 | /// closed window percentage | ||
| 251 | pub closed_window: ClosedWindowPercentage, | ||
| 252 | } | ||
| 253 | |||
| 254 | impl Default for Config { | ||
| 255 | fn default() -> Self { | ||
| 256 | Self { | ||
| 257 | timeout: Timeout::Sec1, | ||
| 258 | closed_window: ClosedWindowPercentage::Zero, | ||
| 259 | } | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | pub struct Watchdog { | ||
| 264 | regs: &'static Regs, | ||
| 265 | } | ||
| 266 | |||
| 267 | impl 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 | |||
| 327 | pub(crate) trait SealedInstance { | ||
| 328 | fn regs() -> &'static Regs; | ||
| 329 | } | ||
| 330 | |||
| 331 | /// WWDT instance trait | ||
| 332 | #[allow(private_bounds)] | ||
| 333 | pub trait Instance: SealedInstance + PeripheralType {} | ||
| 334 | |||
| 335 | macro_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 | } | ||
