sim: support upstream Watchdog driver improvement
Fixes: https://github.com/InfiniTimeOrg/InfiniSim/issues/101
This commit is contained in:
parent
22c02bace6
commit
7613571f96
2 changed files with 181 additions and 35 deletions
|
@ -1,39 +1,151 @@
|
|||
#include "drivers/Watchdog.h"
|
||||
//#include <mdk/nrf.h>
|
||||
using namespace Pinetime::Drivers;
|
||||
|
||||
void Watchdog::Setup(uint8_t timeoutSeconds) {
|
||||
resetReason = ActualResetReason();
|
||||
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::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 {
|
||||
return ResetReasons::ResetPin;
|
||||
}
|
||||
|
||||
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";
|
||||
|
|
|
@ -1,34 +1,68 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
//#include <nrf52_bitfields.h>
|
||||
|
||||
namespace Pinetime {
|
||||
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 {
|
||||
public:
|
||||
enum class ResetReasons { ResetPin, Watchdog, SoftReset, CpuLockup, SystemOff, LpComp, DebugInterface, NFC, HardReset };
|
||||
void Setup(uint8_t timeoutSeconds);
|
||||
/// Indicates the reasons of a reset of the MCU
|
||||
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 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;
|
||||
}
|
||||
static const char* ResetReasonToString(ResetReasons reason);
|
||||
|
||||
private:
|
||||
ResetReasons resetReason;
|
||||
ResetReasons ActualResetReason() const;
|
||||
ResetReason resetReason;
|
||||
};
|
||||
|
||||
class WatchdogView {
|
||||
public:
|
||||
WatchdogView(const Watchdog& watchdog) : watchdog {watchdog} {
|
||||
}
|
||||
Watchdog::ResetReasons ResetReason() const {
|
||||
return watchdog.ResetReason();
|
||||
}
|
||||
|
||||
private:
|
||||
const Watchdog& watchdog;
|
||||
};
|
||||
/// Converts a reset reason to a human readable string
|
||||
const char* ResetReasonToString(Watchdog::ResetReason reason);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue