diff options
| -rw-r--r-- | embassy-mspm0/build.rs | 1 | ||||
| -rw-r--r-- | embassy-mspm0/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-mspm0/src/watchdog.rs | 345 |
3 files changed, 347 insertions, 0 deletions
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..8ee182c12 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 watchdog; | ||
| 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/watchdog.rs b/embassy-mspm0/src/watchdog.rs new file mode 100644 index 000000000..95e5b97f3 --- /dev/null +++ b/embassy-mspm0/src/watchdog.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 core::marker::PhantomData; | ||
| 8 | |||
| 9 | use embassy_hal_internal::PeripheralType; | ||
| 10 | |||
| 11 | use crate::pac::wwdt::{vals, Wwdt as Regs}; | ||
| 12 | use crate::pac::{self}; | ||
| 13 | use crate::Peri; | ||
| 14 | |||
| 15 | /// Possible watchdog timeout values. | ||
| 16 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
| 17 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 18 | pub 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 | |||
| 78 | impl 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))] | ||
| 211 | pub 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 | |||
| 230 | impl 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 | ||
| 248 | pub struct Config { | ||
| 249 | /// Watchdog timeout | ||
| 250 | pub timeout: Timeout, | ||
| 251 | |||
| 252 | /// closed window percentage | ||
| 253 | pub closed_window: ClosedWindowPercentage, | ||
| 254 | } | ||
| 255 | |||
| 256 | impl Default for Config { | ||
| 257 | fn default() -> Self { | ||
| 258 | Self { | ||
| 259 | timeout: Timeout::Sec1, | ||
| 260 | closed_window: ClosedWindowPercentage::Zero, | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | pub struct Watchdog<'d, T: Instance> { | ||
| 266 | wdt: PhantomData<&'d mut T>, | ||
| 267 | } | ||
| 268 | |||
| 269 | impl<'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 | |||
| 329 | pub(crate) trait SealedInstance { | ||
| 330 | const REGS: Regs; | ||
| 331 | } | ||
| 332 | |||
| 333 | /// WWDT instance trait | ||
| 334 | #[allow(private_bounds)] | ||
| 335 | pub trait Instance: SealedInstance + PeripheralType {} | ||
| 336 | |||
| 337 | macro_rules! impl_wwdt_instance { | ||
| 338 | ($instance: ident) => { | ||
| 339 | impl crate::watchdog::SealedInstance for crate::peripherals::$instance { | ||
| 340 | const REGS: crate::pac::wwdt::Wwdt = crate::pac::$instance; | ||
| 341 | } | ||
| 342 | |||
| 343 | impl crate::watchdog::Instance for crate::peripherals::$instance {} | ||
| 344 | }; | ||
| 345 | } | ||
