-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[mspm0] wwdt reset detection #4732
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -240,6 +240,82 @@ impl ClosedWindowPercentage { | |
} | ||
} | ||
|
||
/// Reset cause values from SYSCTL.RSTCAUSE register. | ||
/// Based on MSPM0 Technical Reference Manual Table 2-9. | ||
#[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
#[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
#[repr(u8)] | ||
pub enum ResetCause { | ||
/// No reset since last read | ||
NoReset = 0x00, | ||
/// VDD < POR- violation, PMU trim parity fault, or SHUTDNSTOREx parity fault | ||
PorHwFailure = 0x01, | ||
/// NRST pin reset (>1s) | ||
PorExternalNrst = 0x02, | ||
/// Software-triggered POR | ||
PorSwTriggered = 0x03, | ||
/// VDD < BOR- violation | ||
BorSupplyFailure = 0x04, | ||
/// Wake from SHUTDOWN | ||
BorWakeFromShutdown = 0x05, | ||
/// Non-PMU trim parity fault | ||
BootrstNonPmuParityFault = 0x08, | ||
/// Fatal clock fault | ||
BootrstClockFault = 0x09, | ||
/// NRST pin reset (<1s) | ||
BootrstExternalNrst = 0x0C, | ||
/// Software-triggered BOOTRST | ||
BootrstSwTriggered = 0x0D, | ||
/// WWDT0 violation - This is the main watchdog reset cause we're interested in | ||
SysrstWwdt0Violation = 0x0E, | ||
/// BSL exit (if present) | ||
SysrstBslExit = 0x10, | ||
/// BSL entry (if present) | ||
SysrstBslEntry = 0x11, | ||
/// Uncorrectable flash ECC error (if present) | ||
SysrstFlashEccError = 0x14, | ||
/// CPU lockup violation | ||
SysrstCpuLockupViolation = 0x15, | ||
/// Debug-triggered SYSRST | ||
SysrstDebugTriggered = 0x1A, | ||
/// Software-triggered SYSRST | ||
SysrstSwTriggered = 0x1B, | ||
/// Debug-triggered CPURST | ||
CpurstDebugTriggered = 0x1C, | ||
/// Software-triggered CPURST | ||
CpurstSwTriggered = 0x1D, | ||
} | ||
|
||
impl TryFrom<u8> for ResetCause { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if this is public API that we want to guarantee. Since |
||
type Error = u8; | ||
|
||
fn try_from(value: u8) -> Result<Self, Self::Error> { | ||
use ResetCause::*; | ||
match value { | ||
0x00 => Ok(NoReset), | ||
0x01 => Ok(PorHwFailure), | ||
0x02 => Ok(PorExternalNrst), | ||
0x03 => Ok(PorSwTriggered), | ||
0x04 => Ok(BorSupplyFailure), | ||
0x05 => Ok(BorWakeFromShutdown), | ||
0x08 => Ok(BootrstNonPmuParityFault), | ||
0x09 => Ok(BootrstClockFault), | ||
0x0C => Ok(BootrstExternalNrst), | ||
0x0D => Ok(BootrstSwTriggered), | ||
0x0E => Ok(SysrstWwdt0Violation), | ||
0x10 => Ok(SysrstBslExit), | ||
0x11 => Ok(SysrstBslEntry), | ||
0x14 => Ok(SysrstFlashEccError), | ||
0x15 => Ok(SysrstCpuLockupViolation), | ||
0x1A => Ok(SysrstDebugTriggered), | ||
0x1B => Ok(SysrstSwTriggered), | ||
0x1C => Ok(CpurstDebugTriggered), | ||
0x1D => Ok(CpurstSwTriggered), | ||
other => Err(other), | ||
} | ||
Comment on lines
+294
to
+315
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a fun little trick you can use here given that If you write something like the following for each branch you only need to declare the u8 value once. match value {
_ if value == NoReset as u8 => Ok(NoReset),
....
} |
||
} | ||
} | ||
|
||
#[non_exhaustive] | ||
#[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
/// Watchdog Config | ||
|
@@ -324,6 +400,16 @@ impl Watchdog { | |
} | ||
} | ||
|
||
/// Read the reset cause from the SYSCTL.RSTCAUSE register. | ||
/// | ||
/// This function reads the reset cause register which indicates why the last | ||
/// system reset occurred. The register is automatically cleared after being read, | ||
/// so this should be called only once per application startup. | ||
pub fn read_reset_cause() -> Result<ResetCause, u8> { | ||
let cause_raw = pac::SYSCTL.rstcause().read().id(); | ||
ResetCause::try_from(cause_raw as u8) | ||
} | ||
|
||
Comment on lines
+403
to
+412
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does open up an interesting safety question: Should we allow the user to call this more than once? With peripheral init it makes sense to do that since otherwise memory safety errors would happen. In this case it would just produce the wrong reset value. At minimum probably a good idea to mark this function as |
||
pub(crate) trait SealedInstance { | ||
fn regs() -> &'static Regs; | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all of these can be produced on every chip. But cfg guarding when a reset cause is available is going to involve some metapac work. Either another big entry in
parts.yaml
or we try to parse the SVDs to figure out which reset causes are available (but this might require us to fix the errors that cause some SYSCTL modules erroring when extracted).I'd be fine with just leaving all variants to exist on every chip.