Skip to content

Commit

Permalink
Merge pull request micropython#7718 from microdev1/watchdog-rp
Browse files Browse the repository at this point in the history
Update WatchDog implementation
  • Loading branch information
tannewt committed Oct 2, 2023
2 parents a3c9320 + 27fd60d commit a15c111
Show file tree
Hide file tree
Showing 23 changed files with 317 additions and 254 deletions.
30 changes: 4 additions & 26 deletions locale/circuitpython.pot
Expand Up @@ -196,6 +196,10 @@ msgstr ""
msgid "%q must be <= %d"
msgstr ""

#: ports/espressif/common-hal/watchdog/WatchDogTimer.c
msgid "%q must be <= %u"
msgstr ""

#: py/argcheck.c
msgid "%q must be >= %d"
msgstr ""
Expand Down Expand Up @@ -1164,10 +1168,6 @@ msgstr ""
msgid "Initial set pin state conflicts with initial out pin state"
msgstr ""

#: ports/espressif/common-hal/watchdog/WatchDogTimer.c
msgid "Initialization failed due to lack of memory"
msgstr ""

#: shared-bindings/bitops/__init__.c
#, c-format
msgid "Input buffer length (%d) must be a multiple of the strand count (%d)"
Expand Down Expand Up @@ -1802,11 +1802,6 @@ msgstr ""
msgid "Pull not used when direction is output."
msgstr ""

#: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c
#: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c
msgid "RAISE mode is not implemented"
msgstr ""

#: ports/raspberrypi/common-hal/countio/Counter.c
msgid "RISE_AND_FALL not available on this chip"
msgstr ""
Expand Down Expand Up @@ -2308,20 +2303,10 @@ msgstr ""
msgid "WARNING: Your code filename has two extensions\n"
msgstr ""

#: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c
#: ports/nrf/common-hal/watchdog/WatchDogTimer.c
#: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c
msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET"
msgstr ""

#: shared-bindings/watchdog/WatchDogTimer.c
msgid "WatchDogTimer is not currently running"
msgstr ""

#: shared-bindings/watchdog/WatchDogTimer.c
msgid "WatchDogTimer.mode cannot be changed once set to WatchDogMode.RESET"
msgstr ""

#: py/builtinhelp.c
#, c-format
msgid ""
Expand Down Expand Up @@ -4078,10 +4063,7 @@ msgstr ""
msgid "syntax error in uctypes descriptor"
msgstr ""

#: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c
#: ports/espressif/common-hal/watchdog/WatchDogTimer.c
#: ports/nrf/common-hal/watchdog/WatchDogTimer.c
#: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c
msgid "timeout duration exceeded the maximum supported value"
msgstr ""

Expand Down Expand Up @@ -4283,10 +4265,6 @@ msgstr ""
msgid "value out of range of target"
msgstr ""

#: ports/espressif/common-hal/watchdog/WatchDogTimer.c
msgid "watchdog not initialized"
msgstr ""

#: shared-bindings/is31fl3741/FrameBuffer.c
msgid "width must be greater than zero"
msgstr ""
Expand Down
6 changes: 6 additions & 0 deletions main.c
Expand Up @@ -241,6 +241,12 @@ void supervisor_execution_status(void) {
}
#endif

#if CIRCUITPY_WATCHDOG
pyexec_result_t *pyexec_result(void) {
return &_exec_result;
}
#endif

// Look for the first file that exists in the list of filenames, using mp_import_stat().
// Return its index. If no file found, return -1.
STATIC const char *first_existing_file_in_list(const char *const *filenames, size_t n_filenames) {
Expand Down
103 changes: 61 additions & 42 deletions ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c
Expand Up @@ -30,76 +30,95 @@

#include "shared-bindings/watchdog/__init__.h"
#include "shared-bindings/watchdog/WatchDogTimer.h"
#include "shared-bindings/microcontroller/__init__.h"

#include "common-hal/watchdog/WatchDogTimer.h"

#include "component/wdt.h"

#define SYNC_CTRL_WRITE while (WDT->SYNCBUSY.reg) {}

static void watchdog_disable(void) {
// disable watchdog
WDT->CTRLA.reg = 0;
SYNC_CTRL_WRITE
}

static void watchdog_enable(watchdog_watchdogtimer_obj_t *self) {
// disable watchdog for config
watchdog_disable();

int wdt_cycles = (int)(self->timeout * 1024);
if (wdt_cycles < 8) {
wdt_cycles = 8;
}

// ceil(log2(n)) = 32 - __builtin_clz(n - 1) when n > 1 (if int is 32 bits)
int log2_wdt_cycles = (sizeof(int) * CHAR_BIT) - __builtin_clz(wdt_cycles - 1);
int setting = log2_wdt_cycles - 3; // CYC8_Val is 0

OSC32KCTRL->OSCULP32K.bit.EN1K = 1; // Enable out 1K (for WDT)

WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt
WDT->CONFIG.bit.PER = setting; // Set period for chip reset
WDT->CTRLA.bit.WEN = 0; // Disable window mode
SYNC_CTRL_WRITE
common_hal_watchdog_feed(self); // Clear watchdog interval
WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now!
SYNC_CTRL_WRITE
}

void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) {
WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
}

void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) {
if (self->mode == WATCHDOGMODE_RESET) {
mp_raise_RuntimeError(translate("WatchDogTimer cannot be deinitialized once mode is set to RESET"));
} else {
self->mode = WATCHDOGMODE_NONE;
if (self->mode == WATCHDOGMODE_NONE) {
return;
}
watchdog_disable();
self->mode = WATCHDOGMODE_NONE;
}

mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) {
return self->timeout;
}

STATIC void setup_wdt(watchdog_watchdogtimer_obj_t *self, int setting) {
OSC32KCTRL->OSCULP32K.bit.EN1K = 1; // Enable out 1K (for WDT)

// disable watchdog for config
WDT->CTRLA.reg = 0;
while (WDT->SYNCBUSY.reg) { // Sync CTRL write
}

WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt
WDT->CONFIG.bit.PER = setting; // Set period for chip reset
WDT->CTRLA.bit.WEN = 0; // Disable window mode
while (WDT->SYNCBUSY.reg) { // Sync CTRL write
}
common_hal_watchdog_feed(self); // Clear watchdog interval
WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now!
while (WDT->SYNCBUSY.reg) {
}
}

void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t new_timeout) {
int wdt_cycles = (int)(new_timeout * 1024);
if (wdt_cycles < 8) {
wdt_cycles = 8;
}
if (wdt_cycles > 16384) {
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
if (!(self->timeout < new_timeout || self->timeout > new_timeout)) {
return;
}
// ceil(log2(n)) = 32 - __builtin_clz(n - 1) when n > 1 (if int is 32 bits)
int log2_wdt_cycles = (sizeof(int) * CHAR_BIT) - __builtin_clz(wdt_cycles - 1);
int setting = log2_wdt_cycles - 3; // CYC8_Val is 0
float timeout = (8 << setting) / 1024.f;

mp_arg_validate_int_max(new_timeout, 16, MP_QSTR_timeout);
self->timeout = new_timeout;

if (self->mode == WATCHDOGMODE_RESET) {
setup_wdt(self, setting);
watchdog_enable(self);
}
self->timeout = timeout;
}

watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_t *self) {
return self->mode;
}

void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t new_mode) {
if (self->mode != new_mode) {
if (new_mode == WATCHDOGMODE_RAISE) {
mp_raise_NotImplementedError(translate("RAISE mode is not implemented"));
} else if (new_mode == WATCHDOGMODE_NONE) {
if (self->mode == new_mode) {
return;
}

switch (new_mode) {
case WATCHDOGMODE_NONE:
common_hal_watchdog_deinit(self);
}
self->mode = new_mode;
common_hal_watchdog_set_timeout(self, self->timeout);
break;
case WATCHDOGMODE_RAISE:
mp_raise_NotImplementedError(NULL);
break;
case WATCHDOGMODE_RESET:
watchdog_enable(self);
break;
default:
return;
}

self->mode = new_mode;
}
6 changes: 3 additions & 3 deletions ports/atmel-samd/common-hal/watchdog/WatchDogTimer.h
Expand Up @@ -28,6 +28,9 @@
#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H

#include "py/obj.h"

#include "shared-module/watchdog/__init__.h"

#include "shared-bindings/watchdog/WatchDogMode.h"
#include "shared-bindings/watchdog/WatchDogTimer.h"

Expand All @@ -37,7 +40,4 @@ struct _watchdog_watchdogtimer_obj_t {
watchdog_watchdogmode_t mode;
};

// This needs to be called in order to disable the watchdog
// void watchdog_reset(void);

#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H
11 changes: 11 additions & 0 deletions ports/atmel-samd/supervisor/port.c
Expand Up @@ -388,13 +388,16 @@ void reset_port(void) {
#if CIRCUITPY_BUSIO
reset_sercoms();
#endif

#if CIRCUITPY_AUDIOIO
audio_dma_reset();
audioout_reset();
#endif

#if CIRCUITPY_AUDIOBUSIO
pdmin_reset();
#endif

#if CIRCUITPY_AUDIOBUSIO_I2SOUT
i2sout_reset();
#endif
Expand All @@ -406,14 +409,18 @@ void reset_port(void) {
#if CIRCUITPY_TOUCHIO && CIRCUITPY_TOUCHIO_USE_NATIVE
touchin_reset();
#endif

eic_reset();

#if CIRCUITPY_PULSEIO
pulsein_reset();
pulseout_reset();
#endif

#if CIRCUITPY_PWMIO
pwmout_reset();
#endif

#if CIRCUITPY_PWMIO || CIRCUITPY_AUDIOIO || CIRCUITPY_FREQUENCYIO
reset_timers();
#endif
Expand All @@ -423,6 +430,10 @@ void reset_port(void) {
analogout_reset();
#endif

#if CIRCUITPY_WATCHDOG
watchdog_reset();
#endif

reset_gclks();

#if CIRCUITPY_PEW
Expand Down

0 comments on commit a15c111

Please sign in to comment.