|
2 | 2 | #include <mdk/nrf.h> |
3 | 3 | using namespace Pinetime::Drivers; |
4 | 4 |
|
5 | | -void Watchdog::Setup(uint8_t timeoutSeconds) { |
6 | | - NRF_WDT->CONFIG &= ~(WDT_CONFIG_SLEEP_Msk << WDT_CONFIG_SLEEP_Pos); |
7 | | - NRF_WDT->CONFIG |= (WDT_CONFIG_HALT_Run << WDT_CONFIG_SLEEP_Pos); |
| 5 | +namespace { |
| 6 | + /// The watchdog is always driven by a 32768kHz clock |
| 7 | + constexpr uint32_t ClockFrequency = 32768; |
| 8 | + /// Write this value in the reload register to reload the watchdog |
| 9 | + constexpr uint32_t ReloadValue = 0x6E524635UL; |
8 | 10 |
|
9 | | - NRF_WDT->CONFIG &= ~(WDT_CONFIG_HALT_Msk << WDT_CONFIG_HALT_Pos); |
10 | | - NRF_WDT->CONFIG |= (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos); |
| 11 | + /// Configures the behaviours (pause or run) of the watchdog while the CPU is sleeping or halted by the debugger |
| 12 | + /// |
| 13 | + /// @param sleepBehaviour Configure the watchdog to either be paused, or kept running, while the CPU is sleeping |
| 14 | + /// @param haltBehaviour Configure the watchdog to either be paused, or kept running, while the CPU is halted by the debugger |
| 15 | + void SetBehaviours(Watchdog::SleepBehaviour sleepBehaviour, Watchdog::HaltBehaviour haltBehaviour) { |
| 16 | + // NRF_WDT->CONFIG : only the 1st and 4th bits are relevant. |
| 17 | + // Bit 0 : Behavior when the CPU is sleeping |
| 18 | + // Bit 3 : Behavior when the CPU is halted by the debugger |
| 19 | + // O means that the CPU is paused during sleep/halt, 1 means that the watchdog is kept running |
| 20 | + NRF_WDT->CONFIG = static_cast<uint32_t>(sleepBehaviour) | static_cast<uint32_t>(haltBehaviour); |
| 21 | + } |
| 22 | + |
| 23 | + /// Configure the timeout delay of the watchdog (called CRV, Counter Reload Value, in the documentation). |
| 24 | + /// |
| 25 | + /// @param timeoutSeconds Timeout of the watchdog, expressed in seconds |
| 26 | + void SetTimeout(uint8_t timeoutSeconds) { |
| 27 | + // According to the documentation: |
| 28 | + // Clock = 32768 |
| 29 | + // timeout [s] = ( CRV + 1 ) / Clock |
| 30 | + // -> CRV = (timeout [s] * Clock) -1 |
| 31 | + NRF_WDT->CRV = (timeoutSeconds * ClockFrequency) - 1; |
| 32 | + } |
| 33 | + |
| 34 | + /// Enables the first reload register |
| 35 | + /// |
| 36 | + /// The hardware provides 8 reload registers. To reload the watchdog, all enabled |
| 37 | + /// register must be refreshed. |
| 38 | + /// |
| 39 | + /// This driver only enables the first reload register. |
| 40 | + void EnableFirstReloadRegister() { |
| 41 | + // RRED (Reload Register Enable) is a bitfield of 8 bits. Each bit represent |
| 42 | + // one of the eight reload registers available. |
| 43 | + // In this case, we enable only the first one. |
| 44 | + NRF_WDT->RREN |= 1; |
| 45 | + } |
| 46 | + |
| 47 | + /// Returns the reset reason provided by the POWER subsystem |
| 48 | + Watchdog::ResetReason GetResetReason() { |
| 49 | + /* NRF_POWER->RESETREAS |
| 50 | + * -------------------------------------------------------------------------------------------------------------------- * |
| 51 | + * Bit | Reason (if bit is set to 1) |
| 52 | + * ----|---------------------------------------------------------------------------------------------------------------- * |
| 53 | + * 0 | Reset from the pin reset |
| 54 | + * 1 | Reset from the watchdog |
| 55 | + * 2 | Reset from soft reset |
| 56 | + * 3 | Reset from CPU lock-up |
| 57 | + * 16 | Reset due to wake up from System OFF mode when wakeup is triggered from DETECT signal from GPIO |
| 58 | + * 17 | Reset due to wake up from System OFF mode when wakeup is triggered from ANADETECT signal from LPCOMP |
| 59 | + * 18 | Reset due to wake up from System OFF mode when wakeup is triggered from entering into debug interface mode |
| 60 | + * 19 | Reset due to wake up from System OFF mode by NFC field detect |
| 61 | + * -------------------------------------------------------------------------------------------------------------------- */ |
| 62 | + const uint32_t reason = NRF_POWER->RESETREAS; |
| 63 | + NRF_POWER->RESETREAS = 0xffffffff; |
| 64 | + |
| 65 | + uint32_t value = reason & 0x01; // avoid implicit conversion to bool using this temporary variable. |
| 66 | + if (value != 0) { |
| 67 | + return Watchdog::ResetReason::ResetPin; |
| 68 | + } |
| 69 | + |
| 70 | + value = (reason >> 1u) & 0x01u; |
| 71 | + if (value != 0) { |
| 72 | + return Watchdog::ResetReason::Watchdog; |
| 73 | + } |
| 74 | + |
| 75 | + value = (reason >> 2u) & 0x01u; |
| 76 | + if (value != 0) { |
| 77 | + return Watchdog::ResetReason::SoftReset; |
| 78 | + } |
11 | 79 |
|
12 | | - /* timeout (s) = (CRV + 1) / 32768 */ |
13 | | - // JF : 7500 = 7.5s |
14 | | - uint32_t crv = (((timeoutSeconds * 1000u) << 15u) / 1000) - 1; |
15 | | - NRF_WDT->CRV = crv; |
| 80 | + value = (reason >> 3u) & 0x01u; |
| 81 | + if (value != 0) { |
| 82 | + return Watchdog::ResetReason::CpuLockup; |
| 83 | + } |
16 | 84 |
|
17 | | - /* Enable reload requests */ |
18 | | - NRF_WDT->RREN = (WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos); |
| 85 | + value = (reason >> 16u) & 0x01u; |
| 86 | + if (value != 0) { |
| 87 | + return Watchdog::ResetReason::SystemOff; |
| 88 | + } |
19 | 89 |
|
20 | | - resetReason = ActualResetReason(); |
| 90 | + value = (reason >> 17u) & 0x01u; |
| 91 | + if (value != 0) { |
| 92 | + return Watchdog::ResetReason::LpComp; |
| 93 | + } |
| 94 | + |
| 95 | + value = (reason >> 18u) & 0x01u; |
| 96 | + if (value != 0) { |
| 97 | + return Watchdog::ResetReason::DebugInterface; |
| 98 | + } |
| 99 | + |
| 100 | + value = (reason >> 19u) & 0x01u; |
| 101 | + if (value != 0) { |
| 102 | + return Watchdog::ResetReason::NFC; |
| 103 | + } |
| 104 | + |
| 105 | + return Watchdog::ResetReason::HardReset; |
| 106 | + } |
21 | 107 | } |
22 | 108 |
|
23 | | -void Watchdog::Start() { |
24 | | - NRF_WDT->TASKS_START = 1; |
| 109 | +void Watchdog::Setup(uint8_t timeoutSeconds, SleepBehaviour sleepBehaviour, HaltBehaviour haltBehaviour) { |
| 110 | + SetBehaviours(sleepBehaviour, haltBehaviour); |
| 111 | + SetTimeout(timeoutSeconds); |
| 112 | + EnableFirstReloadRegister(); |
| 113 | + |
| 114 | + resetReason = ::GetResetReason(); |
25 | 115 | } |
26 | 116 |
|
27 | | -void Watchdog::Kick() { |
28 | | - NRF_WDT->RR[0] = WDT_RR_RR_Reload; |
| 117 | +void Watchdog::Start() { |
| 118 | + // Write 1 in the START task to start the watchdog |
| 119 | + NRF_WDT->TASKS_START = 1; |
29 | 120 | } |
30 | 121 |
|
31 | | -Watchdog::ResetReasons Watchdog::ActualResetReason() const { |
32 | | - uint32_t reason = NRF_POWER->RESETREAS; |
33 | | - NRF_POWER->RESETREAS = 0xffffffff; |
34 | | - |
35 | | - if (reason & 0x01u) |
36 | | - return ResetReasons::ResetPin; |
37 | | - if ((reason >> 1u) & 0x01u) |
38 | | - return ResetReasons::Watchdog; |
39 | | - if ((reason >> 2u) & 0x01u) |
40 | | - return ResetReasons::SoftReset; |
41 | | - if ((reason >> 3u) & 0x01u) |
42 | | - return ResetReasons::CpuLockup; |
43 | | - if ((reason >> 16u) & 0x01u) |
44 | | - return ResetReasons::SystemOff; |
45 | | - if ((reason >> 17u) & 0x01u) |
46 | | - return ResetReasons::LpComp; |
47 | | - if ((reason) &0x01u) |
48 | | - return ResetReasons::DebugInterface; |
49 | | - if ((reason >> 19u) & 0x01u) |
50 | | - return ResetReasons::NFC; |
51 | | - return ResetReasons::HardReset; |
| 122 | +void Watchdog::Reload() { |
| 123 | + // Write the reload value 0x6E524635UL to the reload register to reload the watchdog. |
| 124 | + // NOTE : This driver enables only the 1st reload register. |
| 125 | + NRF_WDT->RR[0] = ReloadValue; |
52 | 126 | } |
53 | 127 |
|
54 | | -const char* Watchdog::ResetReasonToString(Watchdog::ResetReasons reason) { |
| 128 | +const char* Pinetime::Drivers::ResetReasonToString(Watchdog::ResetReason reason) { |
55 | 129 | switch (reason) { |
56 | | - case ResetReasons::ResetPin: |
| 130 | + case Watchdog::ResetReason::ResetPin: |
57 | 131 | return "Reset pin"; |
58 | | - case ResetReasons::Watchdog: |
| 132 | + case Watchdog::ResetReason::Watchdog: |
59 | 133 | return "Watchdog"; |
60 | | - case ResetReasons::DebugInterface: |
| 134 | + case Watchdog::ResetReason::DebugInterface: |
61 | 135 | return "Debug interface"; |
62 | | - case ResetReasons::LpComp: |
| 136 | + case Watchdog::ResetReason::LpComp: |
63 | 137 | return "LPCOMP"; |
64 | | - case ResetReasons::SystemOff: |
| 138 | + case Watchdog::ResetReason::SystemOff: |
65 | 139 | return "System OFF"; |
66 | | - case ResetReasons::CpuLockup: |
| 140 | + case Watchdog::ResetReason::CpuLockup: |
67 | 141 | return "CPU Lock-up"; |
68 | | - case ResetReasons::SoftReset: |
| 142 | + case Watchdog::ResetReason::SoftReset: |
69 | 143 | return "Soft reset"; |
70 | | - case ResetReasons::NFC: |
| 144 | + case Watchdog::ResetReason::NFC: |
71 | 145 | return "NFC"; |
72 | | - case ResetReasons::HardReset: |
| 146 | + case Watchdog::ResetReason::HardReset: |
73 | 147 | return "Hard reset"; |
74 | 148 | default: |
75 | 149 | return "Unknown"; |
|
0 commit comments