InfiniSim/sim/drivers/Watchdog.cpp

154 lines
5.6 KiB
C++

#include "drivers/Watchdog.h"
//#include <mdk/nrf.h>
using namespace Pinetime::Drivers;
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;
/// 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);
}
/// 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;
}
/// 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;
}
/// 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;
// sim: always return ResetPin
const uint32_t reason = 0x01;
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::Setup(uint8_t timeoutSeconds, SleepBehaviour sleepBehaviour, HaltBehaviour haltBehaviour) {
SetBehaviours(sleepBehaviour, haltBehaviour);
SetTimeout(timeoutSeconds);
EnableFirstReloadRegister();
resetReason = ::GetResetReason();
}
void Watchdog::Start() {
// Write 1 in the START task to start the watchdog
// NRF_WDT->TASKS_START = 1;
}
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* Pinetime::Drivers::ResetReasonToString(Watchdog::ResetReason reason) {
switch (reason) {
case Watchdog::ResetReason::ResetPin:
return "Reset pin";
case Watchdog::ResetReason::Watchdog:
return "Watchdog";
case Watchdog::ResetReason::DebugInterface:
return "Debug interface";
case Watchdog::ResetReason::LpComp:
return "LPCOMP";
case Watchdog::ResetReason::SystemOff:
return "System OFF";
case Watchdog::ResetReason::CpuLockup:
return "CPU Lock-up";
case Watchdog::ResetReason::SoftReset:
return "Soft reset";
case Watchdog::ResetReason::NFC:
return "NFC";
case Watchdog::ResetReason::HardReset:
return "Hard reset";
default:
return "Unknown";
}
}