[MCXA] reset_reason: process multiple bits

After testing with the pending watchdog driver, I noticed that more
than one bit got set (Warm and Wdog0), changing my original assumption
of this register being one-hot.

Update the `reset_reason()` function and example according to James
Munns' MCXA DMA Error implementation.
This commit is contained in:
Felipe Balbi 2025-12-18 08:57:15 -08:00
parent c3b5b1243f
commit 6c9345a022
2 changed files with 152 additions and 37 deletions

View File

@ -6,45 +6,158 @@
/// Reads the most recent reset reason from the Core Mode Controller
/// (CMC).
pub fn reset_reason() -> ResetReason {
pub fn reset_reason() -> ResetReasonRaw {
let regs = unsafe { &*crate::pac::Cmc::steal() };
let srs = regs.srs().read().bits();
ResetReasonRaw(srs)
}
let srs = regs.srs().read();
/// Raw reset reason bits. Can be queried or all reasons can be iterated over
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, Debug)]
pub struct ResetReasonRaw(u32);
if srs.wakeup().is_enabled() {
ResetReason::WakeUp
} else if srs.por().bit_is_set() {
ResetReason::Por
} else if srs.vd().bit_is_set() {
ResetReason::VoltageDetect
} else if srs.warm().bit_is_set() {
ResetReason::Warm
} else if srs.fatal().bit_is_set() {
ResetReason::Fatal
} else if srs.pin().bit_is_set() {
ResetReason::Pin
} else if srs.dap().bit_is_set() {
ResetReason::Dap
} else if srs.rstack().bit_is_set() {
ResetReason::ResetAckTimeout
} else if srs.lpack().bit_is_set() {
ResetReason::LowPowerAckTimeout
} else if srs.scg().bit_is_set() {
ResetReason::SystemClockGeneration
} else if srs.wwdt0().bit_is_set() {
ResetReason::Wwdt0
} else if srs.sw().bit_is_set() {
ResetReason::Software
} else if srs.lockup().bit_is_set() {
ResetReason::Lockup
} else if srs.cdog0().bit_is_set() {
ResetReason::Cdog0
} else if srs.cdog1().bit_is_set() {
ResetReason::Cdog1
} else if srs.jtag().bit_is_set() {
ResetReason::Jtag
} else {
ResetReason::Tamper
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, Debug)]
pub struct ResetReasonRawIter(u32);
impl ResetReasonRaw {
const MAP: &[(u32, ResetReason)] = &[
(1 << 0, ResetReason::WakeUp),
(1 << 1, ResetReason::Por),
(1 << 2, ResetReason::VoltageDetect),
(1 << 4, ResetReason::Warm),
(1 << 5, ResetReason::Fatal),
(1 << 8, ResetReason::Pin),
(1 << 9, ResetReason::Dap),
(1 << 10, ResetReason::ResetAckTimeout),
(1 << 11, ResetReason::LowPowerAckTimeout),
(1 << 12, ResetReason::SystemClockGeneration),
(1 << 13, ResetReason::Wwdt0),
(1 << 14, ResetReason::Software),
(1 << 15, ResetReason::Lockup),
(1 << 26, ResetReason::Cdog0),
(1 << 27, ResetReason::Cdog1),
(1 << 28, ResetReason::Jtag),
];
/// Convert to an iterator of contained reset reasons
pub fn into_iter(self) -> ResetReasonRawIter {
ResetReasonRawIter(self.0)
}
/// Wake up
#[inline]
pub fn is_wakeup(&self) -> bool {
(self.0 & (1 << 0)) != 0
}
/// Power-on Reset
#[inline]
pub fn is_por(&self) -> bool {
(self.0 & (1 << 1)) != 0
}
/// Voltage detect
#[inline]
pub fn is_voltage_detect(&self) -> bool {
(self.0 & (1 << 2)) != 0
}
/// Warm
#[inline]
pub fn is_warm(&self) -> bool {
(self.0 & (1 << 4)) != 0
}
/// Fatal
#[inline]
pub fn is_fatal(&self) -> bool {
(self.0 & (1 << 5)) != 0
}
/// Pin
#[inline]
pub fn is_pin(&self) -> bool {
(self.0 & (1 << 8)) != 0
}
/// DAP
#[inline]
pub fn is_dap(&self) -> bool {
(self.0 & (1 << 9)) != 0
}
/// Reset ack timeout
#[inline]
pub fn is_reset_ack_timeout(&self) -> bool {
(self.0 & (1 << 10)) != 0
}
/// Low power ack timeout
#[inline]
pub fn is_low_power_ack_timeout(&self) -> bool {
(self.0 & (1 << 11)) != 0
}
/// System clock generation
#[inline]
pub fn is_system_clock_generation(&self) -> bool {
(self.0 & (1 << 12)) != 0
}
/// Watchdog 0
#[inline]
pub fn is_watchdog0(&self) -> bool {
(self.0 & (1 << 13)) != 0
}
/// Software
pub fn is_software(&self) -> bool {
(self.0 & (1 << 14)) != 0
}
/// Lockup
pub fn is_lockup(&self) -> bool {
(self.0 & (1 << 15)) != 0
}
/// Code watchdog 0
pub fn is_code_watchdog0(&self) -> bool {
(self.0 & (1 << 26)) != 0
}
/// Code watchdog 1
pub fn is_code_watchdog1(&self) -> bool {
(self.0 & (1 << 27)) != 0
}
/// JTAG
pub fn is_jtag(&self) -> bool {
(self.0 & (1 << 28)) != 0
}
}
impl Iterator for ResetReasonRawIter {
type Item = ResetReason;
fn next(&mut self) -> Option<Self::Item> {
if self.0 == 0 {
return None;
}
for (mask, var) in ResetReasonRaw::MAP {
// If the bit is set...
if self.0 & mask != 0 {
// clear the bit
self.0 &= !mask;
// and return the answer
return Some(*var);
}
}
// Shouldn't happen, but oh well.
None
}
}

View File

@ -11,5 +11,7 @@ async fn main(_spawner: Spawner) {
let config = Config::default();
let _p = hal::init(config);
defmt::info!("Reset Reason: '{}'", reset_reason());
for reason in reset_reason().into_iter() {
defmt::info!("Reset Reason: '{}'", reason);
}
}