Skip to content

Add getResetReason() by palmerr23 #2516

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

Merged
merged 5 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions cores/rp2040/RP2040Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
#include <hardware/irq.h>
#include <hardware/pio.h>
#include <pico/unique_id.h>
#ifdef PICO_RP2350
#include <hardware/regs/powman.h>
#else
#include <hardware/regs/vreg_and_chip_reset.h>
#endif
#include <hardware/exception.h>
#include <hardware/watchdog.h>
#include <hardware/structs/rosc.h>
Expand Down Expand Up @@ -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]) {
Expand Down
5 changes: 5 additions & 0 deletions docs/rp2040.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------------
Expand Down
68 changes: 68 additions & 0 deletions libraries/rp2040/examples/RestartReason/RestartReason.ino
Original file line number Diff line number Diff line change
@@ -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 <EEPROM.h>
#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);
}
Loading