diff --git a/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h b/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h index cbc43a6..861b0af 100644 --- a/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h +++ b/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h @@ -8,6 +8,7 @@ #define _HARDWARE_WATCHDOG_H #include "pico.h" +#include "hardware/structs/watchdog.h" /** \file hardware/watchdog.h * \defgroup hardware_watchdog hardware_watchdog @@ -66,6 +67,11 @@ void watchdog_update(void); * * By default the SDK assumes a 12MHz XOSC and sets the \ref watchdog_start_tick appropriately. * + * This method sets a marker in the watchdog scratch register 4 that is checked by \ref watchdog_enable_caused_reboot. + * If the device is subsequently reset via a call to watchdog_reboot (including for example by dragging a UF2 + * onto the RPI-RP2), then this value will be cleared, and so \ref watchdog_enable_caused_reboot will + * return false. + * * \param delay_ms Number of milliseconds before watchdog will reboot without watchdog_update being called. Maximum of 0x7fffff, which is approximately 8.3 seconds * \param pause_on_debug If the watchdog should be paused when the debugger is stepping through code */ @@ -80,6 +86,23 @@ void watchdog_enable(uint32_t delay_ms, bool pause_on_debug); */ bool watchdog_caused_reboot(void); +/** + * \brief Did watchdog_enable cause the last reboot? + * \ingroup hardware_watchdog + * + * Perform additional checking along with \ref watchdog_caused_reboot to determine if a watchdog timeout initiated by + * \ref watchdog_enable caused the last reboot. + * + * This method checks for a special value in watchdog scratch register 4 placed there by \ref watchdog_enable. + * This would not be present if a watchdog reset is initiated by \ref watchdog_reboot or by the RP2040 bootrom + * (e.g. dragging a UF2 onto the RPI-RP2 drive). + * + * @return true if the watchdog timer or a watchdog force caused (see \reg watchdog_caused_reboot) the last reboot + * and the watchdog reboot happened after \ref watchdog_enable was called + * @return false there has been no watchdog reboot since run has been + */ +bool watchdog_enable_caused_reboot(void); + /** * @brief Returns the number of microseconds before the watchdog will reboot the chip. * \ingroup hardware_watchdog diff --git a/src/rp2_common/hardware_watchdog/watchdog.c b/src/rp2_common/hardware_watchdog/watchdog.c index 7421064..9545205 100644 --- a/src/rp2_common/hardware_watchdog/watchdog.c +++ b/src/rp2_common/hardware_watchdog/watchdog.c @@ -65,10 +65,12 @@ void _watchdog_enable(uint32_t delay_ms, bool pause_on_debug) { } // end::watchdog_enable[] +#define WATCHDOG_NON_REBOOT_MAGIC 0x6ab73121 + void watchdog_enable(uint32_t delay_ms, bool pause_on_debug) { - // This watchdog enable doesn't reboot so clear scratch register - // with magic word to jump into code - watchdog_hw->scratch[4] = 0; + // update scratch[4] to distinguish from magic used for reboot to specific address, or 0 used to reboot + // into regular flash path + watchdog_hw->scratch[4] = WATCHDOG_NON_REBOOT_MAGIC; _watchdog_enable(delay_ms, pause_on_debug); } @@ -97,4 +99,8 @@ void watchdog_reboot(uint32_t pc, uint32_t sp, uint32_t delay_ms) { bool watchdog_caused_reboot(void) { // If any reason bits are set this is true return watchdog_hw->reason; +} + +bool watchdog_enable_caused_reboot(void) { + return watchdog_hw->reason && watchdog_hw->scratch[4] == WATCHDOG_NON_REBOOT_MAGIC; } \ No newline at end of file