diff --git a/embassy-mcxa/src/reset_reason.rs b/embassy-mcxa/src/reset_reason.rs index f9a9ce096..1787690a7 100644 --- a/embassy-mcxa/src/reset_reason.rs +++ b/embassy-mcxa/src/reset_reason.rs @@ -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 { + 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 } } diff --git a/examples/mcxa/src/bin/reset-reason.rs b/examples/mcxa/src/bin/reset-reason.rs index c244fbe04..2d48a92b1 100644 --- a/examples/mcxa/src/bin/reset-reason.rs +++ b/examples/mcxa/src/bin/reset-reason.rs @@ -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); + } }