mspm0-watchdog: add main implementation

This commit is contained in:
Siarhei B 2025-08-21 09:29:22 +02:00
parent a7c64fd6bf
commit 55eea8b029
3 changed files with 347 additions and 0 deletions

View File

@ -554,6 +554,7 @@ fn generate_peripheral_instances() -> TokenStream {
let tokens = match peripheral.kind {
"uart" => Some(quote! { impl_uart_instance!(#peri); }),
"i2c" => Some(quote! { impl_i2c_instance!(#peri, #fifo_size); }),
"wwdt" => Some(quote! { impl_wwdt_instance!(#peri); }),
_ => None,
};

View File

@ -18,6 +18,7 @@ pub mod gpio;
pub mod i2c;
pub mod timer;
pub mod uart;
pub mod watchdog;
/// Operating modes for peripherals.
pub mod mode {

View File

@ -0,0 +1,345 @@
//! Window Watchdog Timer (WWDT) driver.
//!
//! This HAL implements a basic window watchdog timer with handles.
#![macro_use]
use core::marker::PhantomData;
use embassy_hal_internal::PeripheralType;
use crate::pac::wwdt::{vals, Wwdt as Regs};
use crate::pac::{self};
use crate::Peri;
/// Possible watchdog timeout values.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Timeout {
USec1950,
USec3910,
USec5860,
USec7810,
USec9770,
USec11720,
USec13670,
USec15630,
USec23440,
USec31250,
USec32250,
USec39060,
USec46880,
USec54690,
USec62500,
USec93750,
USec125000,
USec156250,
USec187500,
USec218750,
MSec130,
MSec250,
MSec380,
MSec500,
MSec630,
MSec750,
MSec880,
Sec1,
Sec2,
Sec3,
Sec4,
Sec5,
Sec6,
Sec7,
Sec8,
Sec16,
Sec24,
Sec32,
Sec40,
Sec48,
Sec56,
Sec64,
Sec128, // 2.13 min
Sec192, // 3.20 min
Sec256, // 4.27 min
Sec320, // 5.33 min
Sec384, // 6.40 min
Sec448, // 7.47 min
Sec512, // 8.53 min
Sec1024, // 17.07 min
Sec2048, // 34.13 min
Sec3072, // 51.20 min
Sec4096, // 68.27 min
Sec5120, // 85.33 min
Sec6144, // 102.40 min
Sec7168, // 119.47 min
Sec8192, // 136.53 min
}
impl Timeout {
fn get_period(self) -> vals::Per {
match self {
// period count is 2**25
Self::Sec1024
| Self::Sec2048
| Self::Sec3072
| Self::Sec4096
| Self::Sec5120
| Self::Sec6144
| Self::Sec7168
| Self::Sec8192 => vals::Per::EN_25,
// period count is 2**21
Self::Sec64
| Self::Sec128
| Self::Sec192
| Self::Sec256
| Self::Sec320
| Self::Sec384
| Self::Sec448
| Self::Sec512 => vals::Per::EN_21,
// period count is 2**18
Self::Sec8 | Self::Sec16 | Self::Sec24 | Self::Sec32 | Self::Sec40 | Self::Sec48 | Self::Sec56 => {
vals::Per::EN_18
}
// period count is 2**15
Self::Sec1 | Self::Sec2 | Self::Sec3 | Self::Sec4 | Self::Sec5 | Self::Sec6 | Self::Sec7 => {
vals::Per::EN_15
}
// period count is 2**12
Self::MSec130
| Self::MSec250
| Self::MSec380
| Self::MSec500
| Self::MSec630
| Self::MSec750
| Self::MSec880 => vals::Per::EN_12,
// period count is 2**10
Self::USec31250
| Self::USec62500
| Self::USec93750
| Self::USec125000
| Self::USec156250
| Self::USec187500
| Self::USec218750 => vals::Per::EN_10,
// period count is 2**8
Self::USec7810
| Self::USec15630
| Self::USec23440
| Self::USec32250
| Self::USec39060
| Self::USec46880
| Self::USec54690 => vals::Per::EN_8,
// period count is 2**6
Self::USec1950 | Self::USec3910 | Self::USec5860 | Self::USec9770 | Self::USec11720 | Self::USec13670 => {
vals::Per::EN_6
}
}
}
fn get_clkdiv(self) -> u8 {
match self {
// divide by 1
Self::USec1950
| Self::USec7810
| Self::USec31250
| Self::MSec130
| Self::Sec1
| Self::Sec8
| Self::Sec64
| Self::Sec1024 => 0u8,
// divide by 2
Self::USec3910
| Self::USec15630
| Self::USec62500
| Self::MSec250
| Self::Sec2
| Self::Sec16
| Self::Sec128
| Self::Sec2048 => 1u8,
// divide by 3
Self::USec5860
| Self::USec23440
| Self::USec93750
| Self::MSec380
| Self::Sec3
| Self::Sec24
| Self::Sec192
| Self::Sec3072 => 2u8,
// divide by 4
Self::USec32250
| Self::USec125000
| Self::MSec500
| Self::Sec4
| Self::Sec32
| Self::Sec256
| Self::Sec4096 => 3u8,
// divide by 5
Self::USec9770
| Self::USec39060
| Self::USec156250
| Self::MSec630
| Self::Sec5
| Self::Sec40
| Self::Sec320
| Self::Sec5120 => 4u8,
// divide by 6
Self::USec11720
| Self::USec46880
| Self::USec187500
| Self::MSec750
| Self::Sec6
| Self::Sec48
| Self::Sec384
| Self::Sec6144 => 5u8,
// divide by 7
Self::USec13670
| Self::USec54690
| Self::USec218750
| Self::MSec880
| Self::Sec7
| Self::Sec56
| Self::Sec448
| Self::Sec7168 => 6u8,
// divide by 8
Self::Sec512 | Self::Sec8192 => 7u8,
}
}
}
/// Timeout percentage that is treated as "too early" and generates violation.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ClosedWindowPercentage {
// window period is not used
Zero,
// 12.5% percents
Twelve,
// 18.75% percents
Eighteen,
// 25% percents
TwentyFive,
// 50% percents
Fifty,
// 75% percents
SeventyFive,
// 81.25% percents
EightyOne,
// 87.5% percents
EightySeven,
}
impl ClosedWindowPercentage {
fn get_native_size(self) -> vals::Window {
match self {
Self::Zero => vals::Window::SIZE_0,
Self::Twelve => vals::Window::SIZE_12,
Self::Eighteen => vals::Window::SIZE_18,
Self::TwentyFive => vals::Window::SIZE_25,
Self::Fifty => vals::Window::SIZE_50,
Self::SeventyFive => vals::Window::SIZE_75,
Self::EightyOne => vals::Window::SIZE_81,
Self::EightySeven => vals::Window::SIZE_87,
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Watchdog Config
pub struct Config {
/// Watchdog timeout
pub timeout: Timeout,
/// closed window percentage
pub closed_window: ClosedWindowPercentage,
}
impl Default for Config {
fn default() -> Self {
Self {
timeout: Timeout::Sec1,
closed_window: ClosedWindowPercentage::Zero,
}
}
}
pub struct Watchdog<'d, T: Instance> {
wdt: PhantomData<&'d mut T>,
}
impl<'d, T: Instance> Watchdog<'d, T> {
/// Watchdog initialization.
pub fn new(_instance: Peri<'d, T>, config: Config) -> Self {
// Init power for watchdog
T::REGS.gprcm(0).rstctl().write(|w| {
w.set_resetstkyclr(true);
w.set_resetassert(true);
w.set_key(vals::ResetKey::KEY);
});
// Enable power for watchdog
T::REGS.gprcm(0).pwren().write(|w| {
w.set_enable(true);
w.set_key(vals::PwrenKey::KEY);
});
// init delay, 16 cycles
cortex_m::asm::delay(16);
//init watchdog
T::REGS.wwdtctl0().write(|w| {
w.set_clkdiv(config.timeout.get_clkdiv());
w.set_per(config.timeout.get_period());
w.set_mode(vals::Mode::WINDOW);
w.set_window0(config.closed_window.get_native_size());
w.set_window1(vals::Window::SIZE_0);
w.set_key(vals::Wwdtctl0Key::KEY);
});
// Set Window0 as active window
T::REGS.wwdtctl1().write(|w| {
w.set_winsel(vals::Winsel::WIN0);
w.set_key(vals::Wwdtctl1Key::KEY);
});
critical_section::with(|_| {
// make sure watchdog triggers BOOTRST
pac::SYSCTL.systemcfg().write(|w| {
if T::REGS == pac::WWDT0 {
w.set_wwdtlp0rstdis(false);
}
#[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x))]
if T::REGS == pac::WWDT1 {
w.set_wwdtlp1rstdis(false);
}
});
});
Watchdog { wdt: PhantomData }
}
/// Pet (reload, refresh) the watchdog.
pub fn pet(&mut self) {
T::REGS.wwdtcntrst().write(|w| {
w.set_restart(vals::WwdtcntrstRestart::RESTART);
});
}
}
pub(crate) trait SealedInstance {
const REGS: Regs;
}
/// WWDT instance trait
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType {}
macro_rules! impl_wwdt_instance {
($instance: ident) => {
impl crate::watchdog::SealedInstance for crate::peripherals::$instance {
const REGS: crate::pac::wwdt::Wwdt = crate::pac::$instance;
}
impl crate::watchdog::Instance for crate::peripherals::$instance {}
};
}