Skip to content

Commit

Permalink
hal: watchdog accuracy improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
XuGuohui committed Mar 23, 2023
1 parent effa36b commit 074355b
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 7 deletions.
17 changes: 12 additions & 5 deletions hal/src/nRF52840/watchdog_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class WatchdogLock {
class Nrf52Watchdog : public Watchdog {
public:
int init(const hal_watchdog_config_t* config) {
CHECK_FALSE(initialized_, SYSTEM_ERROR_INVALID_STATE);
CHECK_FALSE(started(), SYSTEM_ERROR_INVALID_STATE);
CHECK_TRUE(config && (config->size > 0), SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(config->timeout_ms >= WATCHDOG_MIN_TIMEOUT, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(config->timeout_ms <= WATCHDOG_MAX_TIMEOUT, SYSTEM_ERROR_INVALID_ARGUMENT);
Expand All @@ -80,10 +80,17 @@ class Nrf52Watchdog : public Watchdog {
} else {
nrfConfig.behaviour = NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT;
}
nrfx_err_t ret = nrfx_wdt_init(&nrfConfig, nrf52WatchdogEventHandler);
SPARK_ASSERT(ret == NRF_SUCCESS);
ret = nrfx_wdt_channel_alloc(&channelId_);
SPARK_ASSERT(ret == NRF_SUCCESS);
if (!initialized_) {
nrfx_err_t ret = nrfx_wdt_init(&nrfConfig, nrf52WatchdogEventHandler);
SPARK_ASSERT(ret == NRF_SUCCESS);
ret = nrfx_wdt_channel_alloc(&channelId_);
SPARK_ASSERT(ret == NRF_SUCCESS);
} else {
nrf_wdt_behaviour_set(nrfConfig.behaviour);
uint64_t ticks = (nrfConfig.reload_value * 32768ULL) / 1000;
SPARK_ASSERT(ticks <= UINT32_MAX);
nrf_wdt_reload_value_set((uint32_t)ticks);
}

memcpy(&info_.config, config, std::min(info_.config.size, config->size));
info_.state = HAL_WATCHDOG_STATE_CONFIGURED;
Expand Down
30 changes: 28 additions & 2 deletions hal/src/rtl872x/watchdog_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ class RtlWatchdog : public Watchdog {

WDG_InitTypeDef WDG_InitStruct = {};
uint32_t CountProcess = 0;
uint32_t DivFacProcess = 0;
WDG_Scalar(config->timeout_ms, &CountProcess, &DivFacProcess);
uint32_t DivFacProcess = 1; // Minimum requirement
calculateFactors(config->timeout_ms, &CountProcess, &DivFacProcess);
WDG_InitStruct.CountProcess = CountProcess;
WDG_InitStruct.DivFacProcess = DivFacProcess;
WDG_InitStruct.RstAllPERI = 1;
Expand Down Expand Up @@ -128,6 +128,32 @@ class RtlWatchdog : public Watchdog {

~RtlWatchdog() = default;

void calculateFactors(system_tick_t timeout, uint32_t* count, uint32_t* div) {
if (timeout == 0) {
*count = 0;
*div = 1;
return;
}
uint32_t tempDiv;
uint16_t tempCount;
bool candidate = false;
for (int8_t countId = 11; countId >= 0; countId--) {
tempCount = (0x00000001 << (countId + 1)) - 1;
tempDiv = ((timeout * 32768ULL) / tempCount / 1000);
if (tempDiv <= 1) { // minimum *div is of 1
continue;
}
if (candidate && tempDiv > 65536) {
break;
}
tempDiv = std::min(tempDiv, (uint32_t)65536);
*div = tempDiv - 1;
*count = countId;
candidate = true;
// Continue to seek smaller countId
}
}

static void rtlWatchdogEventHandler(void* context) {
WDG_IrqClear();
auto pInstance = (RtlWatchdog*)context;
Expand Down
61 changes: 61 additions & 0 deletions user/tests/wiring/watchdog/watchdog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,34 @@ test(WATCHDOG_07_notify_2) {
assertEqual(magick, 0xdeadbeef);
}

#include "nrf_wdt.h"
test(WATCHDDOG_08_reload_value_is_calculated_correctly) {
constexpr system_tick_t TEST_LOOP_CNT = 100;

WatchdogInfo info;
assertEqual(0, Watchdog.getInfo(info));

for (uint16_t i = 1; i <= TEST_LOOP_CNT; i++) {
system_tick_t expectedTo;
if (i == 1) {
expectedTo = info.minTimeout();
} else if (i == TEST_LOOP_CNT) {
expectedTo = info.maxTimeout();
} else {
expectedTo = random(info.minTimeout(), info.maxTimeout());
}
assertEqual(0, Watchdog.init(WatchdogConfiguration().timeout(expectedTo)));

uint32_t reg = nrf_wdt_reload_value_get();
uint64_t actualTo = (reg * 1000ULL) / 32768;
uint32_t delta = (expectedTo > actualTo) ? (expectedTo - actualTo) : (actualTo - expectedTo);
// Serial.printlnf("expected: %ld, actual: %lu, delta: %d", expectedTo, (uint32_t)actualTo, delta);

assertLessOrEqual(delta, 1);
assertMoreOrEqual(delta, 0);
}
}

#endif // HAL_PLATFORM_NRF52840

#if HAL_PLATFORM_RTL872X
Expand Down Expand Up @@ -218,4 +246,37 @@ test(WATCHDOG_08_reconfigurable) {
assertEqual(0, pushMailbox(MailboxEntry().type(MailboxEntry::Type::RESET_PENDING), 5000));
}

test(WATCHDDOG_09_reload_value_is_calculated_correctly) {
constexpr system_tick_t TEST_LOOP_CNT = 100;

WatchdogInfo info;
assertEqual(0, Watchdog.getInfo(info));

for (uint16_t i = 1; i <= TEST_LOOP_CNT; i++) {
system_tick_t expectedTo;
if (i == 1) {
expectedTo = info.minTimeout();
} else if (i == TEST_LOOP_CNT) {
expectedTo = info.maxTimeout();
} else {
expectedTo = random(info.minTimeout(), info.maxTimeout());
}
assertEqual(0, Watchdog.init(WatchdogConfiguration().timeout(expectedTo)));

WDG_TypeDef* WDG = ((WDG_TypeDef *)0x40002800);
uint32_t reg = WDG->VENDOR;
uint8_t countId = (reg >> 25) & 0x0000000F;
countId = std::min(countId, (uint8_t)11);
uint32_t count = (0x00000001 << (countId + 1)) - 1;
uint16_t div = reg & 0x0000FFFF;
// Serial.printlnf("id: %d, count: %d, div: %d", countId, count, div);
uint64_t actualTo = count * (div + 1) * 1000ULL / 32768;
uint32_t delta = (expectedTo > actualTo) ? (expectedTo - actualTo) : (actualTo - expectedTo);
// Serial.printlnf("expected: %ld, actual: %lu, delta: %d", expectedTo, (uint32_t)actualTo, delta);

assertLessOrEqual(delta, 200);
assertMoreOrEqual(delta, 0);
}
}

#endif // HAL_PLATFORM_RTL872X

0 comments on commit 074355b

Please sign in to comment.