aboutsummaryrefslogtreecommitdiffstats
path: root/src/drivers/Watchdog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/Watchdog.cpp')
-rw-r--r--src/drivers/Watchdog.cpp168
1 files changed, 121 insertions, 47 deletions
diff --git a/src/drivers/Watchdog.cpp b/src/drivers/Watchdog.cpp
index d0907a65..6c2c963b 100644
--- a/src/drivers/Watchdog.cpp
+++ b/src/drivers/Watchdog.cpp
@@ -2,74 +2,148 @@
#include <mdk/nrf.h>
using namespace Pinetime::Drivers;
-void Watchdog::Setup(uint8_t timeoutSeconds) {
- NRF_WDT->CONFIG &= ~(WDT_CONFIG_SLEEP_Msk << WDT_CONFIG_SLEEP_Pos);
- NRF_WDT->CONFIG |= (WDT_CONFIG_HALT_Run << WDT_CONFIG_SLEEP_Pos);
+namespace {
+ /// The watchdog is always driven by a 32768kHz clock
+ constexpr uint32_t ClockFrequency = 32768;
+ /// Write this value in the reload register to reload the watchdog
+ constexpr uint32_t ReloadValue = 0x6E524635UL;
- NRF_WDT->CONFIG &= ~(WDT_CONFIG_HALT_Msk << WDT_CONFIG_HALT_Pos);
- NRF_WDT->CONFIG |= (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos);
+ /// Configures the behaviours (pause or run) of the watchdog while the CPU is sleeping or halted by the debugger
+ ///
+ /// @param sleepBehaviour Configure the watchdog to either be paused, or kept running, while the CPU is sleeping
+ /// @param haltBehaviour Configure the watchdog to either be paused, or kept running, while the CPU is halted by the debugger
+ void SetBehaviours(Watchdog::SleepBehaviour sleepBehaviour, Watchdog::HaltBehaviour haltBehaviour) {
+ // NRF_WDT->CONFIG : only the 1st and 4th bits are relevant.
+ // Bit 0 : Behavior when the CPU is sleeping
+ // Bit 3 : Behavior when the CPU is halted by the debugger
+ // O means that the CPU is paused during sleep/halt, 1 means that the watchdog is kept running
+ NRF_WDT->CONFIG = static_cast<uint32_t>(sleepBehaviour) | static_cast<uint32_t>(haltBehaviour);
+ }
- /* timeout (s) = (CRV + 1) / 32768 */
- // JF : 7500 = 7.5s
- uint32_t crv = (((timeoutSeconds * 1000u) << 15u) / 1000) - 1;
- NRF_WDT->CRV = crv;
+ /// Configure the timeout delay of the watchdog (called CRV, Counter Reload Value, in the documentation).
+ ///
+ /// @param timeoutSeconds Timeout of the watchdog, expressed in seconds
+ void SetTimeout(uint8_t timeoutSeconds) {
+ // According to the documentation:
+ // Clock = 32768
+ // timeout [s] = ( CRV + 1 ) / Clock
+ // -> CRV = (timeout [s] * Clock) -1
+ NRF_WDT->CRV = (timeoutSeconds * ClockFrequency) - 1;
+ }
- /* Enable reload requests */
- NRF_WDT->RREN = (WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos);
+ /// Enables the first reload register
+ ///
+ /// The hardware provides 8 reload registers. To reload the watchdog, all enabled
+ /// register must be refreshed.
+ ///
+ /// This driver only enables the first reload register.
+ void EnableFirstReloadRegister() {
+ // RRED (Reload Register Enable) is a bitfield of 8 bits. Each bit represent
+ // one of the eight reload registers available.
+ // In this case, we enable only the first one.
+ NRF_WDT->RREN |= 1;
+ }
- resetReason = ActualResetReason();
-}
+ /// Returns the reset reason provided by the POWER subsystem
+ Watchdog::ResetReason GetResetReason() {
+ /* NRF_POWER->RESETREAS
+ * -------------------------------------------------------------------------------------------------------------------- *
+ * Bit | Reason (if bit is set to 1)
+ * ----|---------------------------------------------------------------------------------------------------------------- *
+ * 0 | Reset from the pin reset
+ * 1 | Reset from the watchdog
+ * 2 | Reset from soft reset
+ * 3 | Reset from CPU lock-up
+ * 16 | Reset due to wake up from System OFF mode when wakeup is triggered from DETECT signal from GPIO
+ * 17 | Reset due to wake up from System OFF mode when wakeup is triggered from ANADETECT signal from LPCOMP
+ * 18 | Reset due to wake up from System OFF mode when wakeup is triggered from entering into debug interface mode
+ * 19 | Reset due to wake up from System OFF mode by NFC field detect
+ * -------------------------------------------------------------------------------------------------------------------- */
+ const uint32_t reason = NRF_POWER->RESETREAS;
+ NRF_POWER->RESETREAS = 0xffffffff;
-void Watchdog::Start() {
- NRF_WDT->TASKS_START = 1;
+ uint32_t value = reason & 0x01; // avoid implicit conversion to bool using this temporary variable.
+ if (value != 0) {
+ return Watchdog::ResetReason::ResetPin;
+ }
+
+ value = (reason >> 1u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::Watchdog;
+ }
+
+ value = (reason >> 2u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::SoftReset;
+ }
+
+ value = (reason >> 3u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::CpuLockup;
+ }
+
+ value = (reason >> 16u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::SystemOff;
+ }
+
+ value = (reason >> 17u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::LpComp;
+ }
+
+ value = (reason >> 18u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::DebugInterface;
+ }
+
+ value = (reason >> 19u) & 0x01u;
+ if (value != 0) {
+ return Watchdog::ResetReason::NFC;
+ }
+
+ return Watchdog::ResetReason::HardReset;
+ }
}
-void Watchdog::Kick() {
- NRF_WDT->RR[0] = WDT_RR_RR_Reload;
+void Watchdog::Setup(uint8_t timeoutSeconds, SleepBehaviour sleepBehaviour, HaltBehaviour haltBehaviour) {
+ SetBehaviours(sleepBehaviour, haltBehaviour);
+ SetTimeout(timeoutSeconds);
+ EnableFirstReloadRegister();
+
+ resetReason = ::GetResetReason();
}
-Watchdog::ResetReasons Watchdog::ActualResetReason() const {
- uint32_t reason = NRF_POWER->RESETREAS;
- NRF_POWER->RESETREAS = 0xffffffff;
+void Watchdog::Start() {
+ // Write 1 in the START task to start the watchdog
+ NRF_WDT->TASKS_START = 1;
+}
- if (reason & 0x01u)
- return ResetReasons::ResetPin;
- if ((reason >> 1u) & 0x01u)
- return ResetReasons::Watchdog;
- if ((reason >> 2u) & 0x01u)
- return ResetReasons::SoftReset;
- if ((reason >> 3u) & 0x01u)
- return ResetReasons::CpuLockup;
- if ((reason >> 16u) & 0x01u)
- return ResetReasons::SystemOff;
- if ((reason >> 17u) & 0x01u)
- return ResetReasons::LpComp;
- if ((reason) &0x01u)
- return ResetReasons::DebugInterface;
- if ((reason >> 19u) & 0x01u)
- return ResetReasons::NFC;
- return ResetReasons::HardReset;
+void Watchdog::Reload() {
+ // Write the reload value 0x6E524635UL to the reload register to reload the watchdog.
+ // NOTE : This driver enables only the 1st reload register.
+ NRF_WDT->RR[0] = ReloadValue;
}
-const char* Watchdog::ResetReasonToString(Watchdog::ResetReasons reason) {
+const char* Pinetime::Drivers::ResetReasonToString(Watchdog::ResetReason reason) {
switch (reason) {
- case ResetReasons::ResetPin:
+ case Watchdog::ResetReason::ResetPin:
return "Reset pin";
- case ResetReasons::Watchdog:
+ case Watchdog::ResetReason::Watchdog:
return "Watchdog";
- case ResetReasons::DebugInterface:
+ case Watchdog::ResetReason::DebugInterface:
return "Debug interface";
- case ResetReasons::LpComp:
+ case Watchdog::ResetReason::LpComp:
return "LPCOMP";
- case ResetReasons::SystemOff:
+ case Watchdog::ResetReason::SystemOff:
return "System OFF";
- case ResetReasons::CpuLockup:
+ case Watchdog::ResetReason::CpuLockup:
return "CPU Lock-up";
- case ResetReasons::SoftReset:
+ case Watchdog::ResetReason::SoftReset:
return "Soft reset";
- case ResetReasons::NFC:
+ case Watchdog::ResetReason::NFC:
return "NFC";
- case ResetReasons::HardReset:
+ case Watchdog::ResetReason::HardReset:
return "Hard reset";
default:
return "Unknown";