Skip to content

Commit 5e0dce2

Browse files
committed
update watchdog implementation for atmel-samd
1 parent 668f96e commit 5e0dce2

File tree

3 files changed

+75
-43
lines changed

3 files changed

+75
-43
lines changed

ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -34,72 +34,93 @@
3434

3535
#include "component/wdt.h"
3636

37+
#define SYNC_CTRL_WRITE while (WDT->SYNCBUSY.reg) {}
38+
39+
static void watchdog_disable(void) {
40+
// disable watchdog
41+
WDT->CTRLA.reg = 0;
42+
SYNC_CTRL_WRITE
43+
}
44+
45+
static void watchdog_enable(watchdog_watchdogtimer_obj_t *self) {
46+
// disable watchdog for config
47+
watchdog_disable();
48+
49+
int wdt_cycles = (int)(self->timeout * 1024);
50+
if (wdt_cycles < 8) {
51+
wdt_cycles = 8;
52+
}
53+
54+
// ceil(log2(n)) = 32 - __builtin_clz(n - 1) when n > 1 (if int is 32 bits)
55+
int log2_wdt_cycles = (sizeof(int) * CHAR_BIT) - __builtin_clz(wdt_cycles - 1);
56+
int setting = log2_wdt_cycles - 3; // CYC8_Val is 0
57+
58+
OSC32KCTRL->OSCULP32K.bit.EN1K = 1; // Enable out 1K (for WDT)
59+
60+
WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt
61+
WDT->CONFIG.bit.PER = setting; // Set period for chip reset
62+
WDT->CTRLA.bit.WEN = 0; // Disable window mode
63+
SYNC_CTRL_WRITE
64+
common_hal_watchdog_feed(self); // Clear watchdog interval
65+
WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now!
66+
SYNC_CTRL_WRITE
67+
}
68+
3769
void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) {
3870
WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
3971
}
4072

4173
void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) {
42-
if (self->mode == WATCHDOGMODE_RESET) {
43-
mp_raise_RuntimeError(translate("WatchDogTimer cannot be deinitialized once mode is set to RESET"));
44-
} else {
45-
self->mode = WATCHDOGMODE_NONE;
74+
if (self->mode == WATCHDOGMODE_NONE) {
75+
return;
4676
}
77+
watchdog_disable();
78+
self->mode = WATCHDOGMODE_NONE;
4779
}
4880

49-
mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) {
50-
return self->timeout;
81+
void watchdog_reset(void) {
82+
common_hal_watchdog_deinit(&common_hal_mcu_watchdogtimer_obj);
5183
}
5284

53-
STATIC void setup_wdt(watchdog_watchdogtimer_obj_t *self, int setting) {
54-
OSC32KCTRL->OSCULP32K.bit.EN1K = 1; // Enable out 1K (for WDT)
55-
56-
// disable watchdog for config
57-
WDT->CTRLA.reg = 0;
58-
while (WDT->SYNCBUSY.reg) { // Sync CTRL write
59-
}
60-
61-
WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt
62-
WDT->CONFIG.bit.PER = setting; // Set period for chip reset
63-
WDT->CTRLA.bit.WEN = 0; // Disable window mode
64-
while (WDT->SYNCBUSY.reg) { // Sync CTRL write
65-
}
66-
common_hal_watchdog_feed(self); // Clear watchdog interval
67-
WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now!
68-
while (WDT->SYNCBUSY.reg) {
69-
}
85+
mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) {
86+
return self->timeout;
7087
}
7188

7289
void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t new_timeout) {
73-
int wdt_cycles = (int)(new_timeout * 1024);
74-
if (wdt_cycles < 8) {
75-
wdt_cycles = 8;
76-
}
77-
if (wdt_cycles > 16384) {
78-
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
90+
if (!(self->timeout < new_timeout || self->timeout > new_timeout)) {
91+
return;
7992
}
80-
// ceil(log2(n)) = 32 - __builtin_clz(n - 1) when n > 1 (if int is 32 bits)
81-
int log2_wdt_cycles = (sizeof(int) * CHAR_BIT) - __builtin_clz(wdt_cycles - 1);
82-
int setting = log2_wdt_cycles - 3; // CYC8_Val is 0
83-
float timeout = (8 << setting) / 1024.f;
93+
94+
mp_arg_validate_int_max(new_timeout, 16, MP_QSTR_timeout);
95+
self->timeout = new_timeout;
8496

8597
if (self->mode == WATCHDOGMODE_RESET) {
86-
setup_wdt(self, setting);
98+
watchdog_enable(self);
8799
}
88-
self->timeout = timeout;
89100
}
90101

91102
watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_t *self) {
92103
return self->mode;
93104
}
94105

95106
void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t new_mode) {
96-
if (self->mode != new_mode) {
97-
if (new_mode == WATCHDOGMODE_RAISE) {
98-
mp_raise_NotImplementedError(translate("RAISE mode is not implemented"));
99-
} else if (new_mode == WATCHDOGMODE_NONE) {
107+
if (self->mode == new_mode) {
108+
return;
109+
}
110+
111+
switch (new_mode) {
112+
case WATCHDOGMODE_NONE:
100113
common_hal_watchdog_deinit(self);
101-
}
102-
self->mode = new_mode;
103-
common_hal_watchdog_set_timeout(self, self->timeout);
114+
break;
115+
case WATCHDOGMODE_RAISE:
116+
mp_raise_NotImplementedError(NULL);
117+
break;
118+
case WATCHDOGMODE_RESET:
119+
watchdog_enable(self);
120+
break;
121+
default:
122+
return;
104123
}
124+
125+
self->mode = new_mode;
105126
}

ports/atmel-samd/common-hal/watchdog/WatchDogTimer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ struct _watchdog_watchdogtimer_obj_t {
3838
};
3939

4040
// This needs to be called in order to disable the watchdog
41-
// void watchdog_reset(void);
41+
void watchdog_reset(void);
4242

4343
#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H

ports/atmel-samd/supervisor/port.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,13 +388,16 @@ void reset_port(void) {
388388
#if CIRCUITPY_BUSIO
389389
reset_sercoms();
390390
#endif
391+
391392
#if CIRCUITPY_AUDIOIO
392393
audio_dma_reset();
393394
audioout_reset();
394395
#endif
396+
395397
#if CIRCUITPY_AUDIOBUSIO
396398
pdmin_reset();
397399
#endif
400+
398401
#if CIRCUITPY_AUDIOBUSIO_I2SOUT
399402
i2sout_reset();
400403
#endif
@@ -406,14 +409,18 @@ void reset_port(void) {
406409
#if CIRCUITPY_TOUCHIO && CIRCUITPY_TOUCHIO_USE_NATIVE
407410
touchin_reset();
408411
#endif
412+
409413
eic_reset();
414+
410415
#if CIRCUITPY_PULSEIO
411416
pulsein_reset();
412417
pulseout_reset();
413418
#endif
419+
414420
#if CIRCUITPY_PWMIO
415421
pwmout_reset();
416422
#endif
423+
417424
#if CIRCUITPY_PWMIO || CIRCUITPY_AUDIOIO || CIRCUITPY_FREQUENCYIO
418425
reset_timers();
419426
#endif
@@ -423,6 +430,10 @@ void reset_port(void) {
423430
analogout_reset();
424431
#endif
425432

433+
#if CIRCUITPY_WATCHDOG
434+
watchdog_reset();
435+
#endif
436+
426437
reset_gclks();
427438

428439
#if CIRCUITPY_PEW

0 commit comments

Comments
 (0)