Merge pull request #102 from InfiniTimeOrg/support_Watchdog_restructure
sim: support upstream Watchdog driver improvement
This commit is contained in:
commit
beea678fce
2 changed files with 181 additions and 35 deletions
|
@ -1,39 +1,151 @@
|
||||||
#include "drivers/Watchdog.h"
|
#include "drivers/Watchdog.h"
|
||||||
|
//#include <mdk/nrf.h>
|
||||||
using namespace Pinetime::Drivers;
|
using namespace Pinetime::Drivers;
|
||||||
|
|
||||||
void Watchdog::Setup(uint8_t timeoutSeconds) {
|
namespace {
|
||||||
resetReason = ActualResetReason();
|
/// 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() {
|
void Watchdog::Start() {
|
||||||
|
// Write 1 in the START task to start the watchdog
|
||||||
|
// NRF_WDT->TASKS_START = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Watchdog::Kick() {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Watchdog::ResetReasons Watchdog::ActualResetReason() const {
|
const char* Pinetime::Drivers::ResetReasonToString(Watchdog::ResetReason reason) {
|
||||||
return ResetReasons::ResetPin;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Watchdog::ResetReasonToString(Watchdog::ResetReasons reason) {
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case ResetReasons::ResetPin:
|
case Watchdog::ResetReason::ResetPin:
|
||||||
return "Reset pin";
|
return "Reset pin";
|
||||||
case ResetReasons::Watchdog:
|
case Watchdog::ResetReason::Watchdog:
|
||||||
return "Watchdog";
|
return "Watchdog";
|
||||||
case ResetReasons::DebugInterface:
|
case Watchdog::ResetReason::DebugInterface:
|
||||||
return "Debug interface";
|
return "Debug interface";
|
||||||
case ResetReasons::LpComp:
|
case Watchdog::ResetReason::LpComp:
|
||||||
return "LPCOMP";
|
return "LPCOMP";
|
||||||
case ResetReasons::SystemOff:
|
case Watchdog::ResetReason::SystemOff:
|
||||||
return "System OFF";
|
return "System OFF";
|
||||||
case ResetReasons::CpuLockup:
|
case Watchdog::ResetReason::CpuLockup:
|
||||||
return "CPU Lock-up";
|
return "CPU Lock-up";
|
||||||
case ResetReasons::SoftReset:
|
case Watchdog::ResetReason::SoftReset:
|
||||||
return "Soft reset";
|
return "Soft reset";
|
||||||
case ResetReasons::NFC:
|
case Watchdog::ResetReason::NFC:
|
||||||
return "NFC";
|
return "NFC";
|
||||||
case ResetReasons::HardReset:
|
case Watchdog::ResetReason::HardReset:
|
||||||
return "Hard reset";
|
return "Hard reset";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
|
|
|
@ -1,34 +1,68 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
//#include <nrf52_bitfields.h>
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Drivers {
|
namespace Drivers {
|
||||||
|
/// Low level driver for the watchdog based on the nRF52832 Product Specification V1.1
|
||||||
|
///
|
||||||
|
/// This driver initializes the timeout and sleep and halt behaviours of the watchdog
|
||||||
|
/// in the method Watchdog::Setup().
|
||||||
|
///
|
||||||
|
/// The watchdog can then be started using the method Watchdog::Start(). At this point, the watchdog runs
|
||||||
|
/// and will reset the MCU if it's not reloaded before the timeout elapses.
|
||||||
|
///
|
||||||
|
/// The watchdog can be reloaded using Watchdog::Kick().
|
||||||
|
///
|
||||||
|
/// The watchdog also provide the cause of the last reset (reset pin, watchdog, soft reset, hard reset,... See
|
||||||
|
/// Watchdog::ResetReasons).
|
||||||
class Watchdog {
|
class Watchdog {
|
||||||
public:
|
public:
|
||||||
enum class ResetReasons { ResetPin, Watchdog, SoftReset, CpuLockup, SystemOff, LpComp, DebugInterface, NFC, HardReset };
|
/// Indicates the reasons of a reset of the MCU
|
||||||
void Setup(uint8_t timeoutSeconds);
|
enum class ResetReason { ResetPin, Watchdog, SoftReset, CpuLockup, SystemOff, LpComp, DebugInterface, NFC, HardReset };
|
||||||
|
|
||||||
|
/// Behaviours of the watchdog when the CPU is sleeping
|
||||||
|
enum class SleepBehaviour : uint8_t {
|
||||||
|
/// Pause watchdog while the CPU is sleeping
|
||||||
|
Pause = 0, // << WDT_CONFIG_SLEEP_Pos,
|
||||||
|
/// Keep the watchdog running while the CPU is sleeping
|
||||||
|
Run = 1 // << WDT_CONFIG_SLEEP_Pos
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Behaviours of the watchdog when the CPU is halted by the debugger
|
||||||
|
enum class HaltBehaviour : uint8_t {
|
||||||
|
/// Pause watchdog while the CPU is halted by the debugger
|
||||||
|
Pause = 0, // << WDT_CONFIG_HALT_Pos,
|
||||||
|
/// Keep the watchdog running while the CPU is halted by the debugger
|
||||||
|
Run = 1 // << WDT_CONFIG_HALT_Pos
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Configures the watchdog with a specific timeout, behaviour when sleeping and when 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 Setup(uint8_t timeoutSeconds, SleepBehaviour sleepBehaviour, HaltBehaviour haltBehaviour);
|
||||||
|
|
||||||
|
/// Starts the watchdog. The watchdog will reset the MCU when the timeout period is elapsed unless you call
|
||||||
|
/// Watchdog::Kick before the end of the period
|
||||||
void Start();
|
void Start();
|
||||||
void Kick();
|
|
||||||
ResetReasons ResetReason() const {
|
/// Reloads the watchdog.
|
||||||
|
///
|
||||||
|
/// Ensure that you call this function regularly with a period shorter
|
||||||
|
/// than the timeout period to prevent the watchdog from resetting the MCU.
|
||||||
|
void Reload();
|
||||||
|
|
||||||
|
/// Returns the reason of the last reset
|
||||||
|
ResetReason GetResetReason() const {
|
||||||
return resetReason;
|
return resetReason;
|
||||||
}
|
}
|
||||||
static const char* ResetReasonToString(ResetReasons reason);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResetReasons resetReason;
|
ResetReason resetReason;
|
||||||
ResetReasons ActualResetReason() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WatchdogView {
|
/// Converts a reset reason to a human readable string
|
||||||
public:
|
const char* ResetReasonToString(Watchdog::ResetReason reason);
|
||||||
WatchdogView(const Watchdog& watchdog) : watchdog {watchdog} {
|
|
||||||
}
|
|
||||||
Watchdog::ResetReasons ResetReason() const {
|
|
||||||
return watchdog.ResetReason();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Watchdog& watchdog;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue