diff --git a/cores/rp2040/RP2040Support.h b/cores/rp2040/RP2040Support.h index 5368ecb7a..42e732df0 100644 --- a/cores/rp2040/RP2040Support.h +++ b/cores/rp2040/RP2040Support.h @@ -22,6 +22,11 @@ #include #include #include +#ifdef PICO_RP2350 +#include +#else +#include +#endif #include #include #include @@ -352,6 +357,61 @@ class RP2040 { watchdog_update(); } + enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET}; + + resetReason_t getResetReason(void) { + io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET); + + if (watchdog_caused_reboot() && watchdog_enable_caused_reboot()) { // watchdog timer + return WDT_RESET; + } + + if (*WD_reason_reg & WATCHDOG_REASON_TIMER_BITS) { // soft reset() or reboot() + return SOFT_RESET; + } + +#ifdef PICO_RP2350 + // **** RP2350 is untested **** + io_rw_32 *rrp = (io_rw_32 *)(POWMAN_BASE + POWMAN_CHIP_RESET_OFFSET); + + if (*rrp & POWMAN_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset (brownout is separately detected on RP2350) + return PWRON_RESET; + } + + if (*rrp & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { // RUN pin + return RUN_PIN_RESET; + } + + if ((*rrp & POWMAN_CHIP_RESET_HAD_DP_RESET_REQ_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_HZD_SYS_RESET_REQ_BITS)) { // DEBUG port + return DEBUG_RESET; + } + + if (*rrp & POWMAN_CHIP_RESET_HAD_GLITCH_DETECT_BITS) { // power supply glitch + return GLITCH_RESET; + } + + if (*rrp & POWMAN_CHIP_RESET_HAD_BOR_BITS) { // power supply brownout reset + return BROWNOUT_RESET; + } + +#else + io_rw_32 *rrp = (io_rw_32 *)(VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET); + + if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset or brown-out detection + return PWRON_RESET; + } + + if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { // RUN pin + return RUN_PIN_RESET; + } + + if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { // DEBUG port + return DEBUG_RESET; // **** untested **** debug reset may just cause a rebootToBootloader() + } +#endif + return UNKNOWN_RESET; + } + const char *getChipID() { static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 }; if (!id[0]) { diff --git a/docs/rp2040.rst b/docs/rp2040.rst index 67deb493e..ea3707064 100644 --- a/docs/rp2040.rst +++ b/docs/rp2040.rst @@ -57,6 +57,11 @@ void rp2040.wdt_reset() ~~~~~~~~~~~~~~~~~~~~~~~ Reloads the watchdog's counter with the amount of time set by wdt_begin. +RP2040::resetReason_t rp2040.getResetReason() +~~~~~~~~~~~~~~~~~~~~~~~ +Returns the reason for the last reset, defined in enum ``RP2040::resetReason_t``. +See example ```ResetReason``` for some details. + Memory Information ------------------ diff --git a/libraries/rp2040/examples/RestartReason/RestartReason.ino b/libraries/rp2040/examples/RestartReason/RestartReason.ino new file mode 100644 index 000000000..db62c6460 --- /dev/null +++ b/libraries/rp2040/examples/RestartReason/RestartReason.ino @@ -0,0 +1,68 @@ +// This sketch will cycle thru some possible restart reasons and shall help you understanding the rp2040.getResetReason() function +// Author: palmerr23 + +#include +#define NTESTS 5 // Number of tests, Debug port test not enabled +char resetReasonText[][24] = { "Unknown", "Power On / Brownout", "Run pin", "Software", "Watchdog Timer", "Debug reset" }; +char testText[][128] = { "Run pin\n\tShort Run pin to ground", "Power On / Brownout\n\tDisconnect / reconnect power (i.e. USB)", "Software reBOOT in 5 Secs", "Watchdog Timer in 7 Secs", "Software reSTART in 5 Secs\n\tUSB Serial does not always restart", "Debug port - do something!" }; + +// Small function that will send one dot every second over Serial, forever. +void delayCount(void) { + int t = 1; + while (1) { + Serial.print("."); + if (t % 50 == 0) { + Serial.println(); + } + delay(1000); + } +} + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + delay(1000); + Serial.println("Reset reason:"); + + RP2040::resetReason_t rr = rp2040.getResetReason(); + Serial.printf("RR %i %s\n\n", rr, resetReasonText[rr]); + + EEPROM.begin(512); + byte test = EEPROM.read(0); + if (test >= NTESTS) { // un-initialised EEPROM read is random + test = -1; + } + test = (test + 1) % NTESTS; // Go to next test, but limit to NTESTS-1 + Serial.printf("Test %i: %s\n", test, testText[test]); + EEPROM.write(0, test); + EEPROM.commit(); + delay(5000); + switch (test) { + case 0: // Run pin + delayCount(); + break; // Break to avoid compiler warnings + case 1: // Power On + delayCount(); + break; + case 2: // reboot command + rp2040.reboot(); + delayCount(); + break; + case 3: // watchdog + rp2040.wdt_begin(2000); + rp2040.wdt_reset(); + delayCount(); + break; + case 4: // restart command + rp2040.restart(); + delayCount(); + break; + } +} + +// never gets here +void loop() { + delay(100); +} \ No newline at end of file