Skip to content

Commit db04fd1

Browse files
authored
Merge pull request #2933 from simmel-project/wdt-nrf
Add Watchdog timer and add support for NRF watchdog
2 parents aae7a45 + 7e632c9 commit db04fd1

30 files changed

+941
-28
lines changed

locale/circuitpython.pot

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PACKAGE VERSION\n"
1010
"Report-Msgid-Bugs-To: \n"
11-
"POT-Creation-Date: 2020-06-01 08:56-0500\n"
11+
"POT-Creation-Date: 2020-06-01 17:10-0700\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -1652,6 +1652,26 @@ msgstr ""
16521652
msgid "WARNING: Your code filename has two extensions\n"
16531653
msgstr ""
16541654

1655+
#: shared-bindings/watchdog/WatchDogTimer.c
1656+
msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET"
1657+
msgstr ""
1658+
1659+
#: shared-bindings/watchdog/WatchDogTimer.c
1660+
msgid "WatchDogTimer is not currently running"
1661+
msgstr ""
1662+
1663+
#: shared-bindings/watchdog/WatchDogTimer.c
1664+
msgid "WatchDogTimer.mode cannot be changed once set to WatchDogMode.RESET"
1665+
msgstr ""
1666+
1667+
#: shared-bindings/watchdog/WatchDogTimer.c
1668+
msgid "WatchDogTimer.timeout must be greater than 0"
1669+
msgstr ""
1670+
1671+
#: supervisor/shared/safe_mode.c
1672+
msgid "Watchdog timer expired."
1673+
msgstr ""
1674+
16551675
#: py/builtinhelp.c
16561676
#, c-format
16571677
msgid ""
@@ -3059,6 +3079,10 @@ msgstr ""
30593079
msgid "time.struct_time() takes a 9-sequence"
30603080
msgstr ""
30613081

3082+
#: ports/nrf/common-hal/watchdog/WatchDogTimer.c
3083+
msgid "timeout duration exceeded the maximum supported value"
3084+
msgstr ""
3085+
30623086
#: shared-bindings/busio/UART.c
30633087
msgid "timeout must be 0.0-100.0 seconds"
30643088
msgstr ""
@@ -3212,6 +3236,10 @@ msgstr ""
32123236
msgid "value_count must be > 0"
32133237
msgstr ""
32143238

3239+
#: shared-bindings/watchdog/WatchDogTimer.c
3240+
msgid "watchdog timeout must be greater than 0"
3241+
msgstr ""
3242+
32153243
#: shared-bindings/_bleio/Adapter.c
32163244
msgid "window must be <= interval"
32173245
msgstr ""

ports/nrf/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ SRC_NRFX = $(addprefix nrfx/,\
136136
drivers/src/nrfx_gpiote.c \
137137
drivers/src/nrfx_rtc.c \
138138
drivers/src/nrfx_nvmc.c \
139+
drivers/src/nrfx_wdt.c \
139140
)
140141

141142
ifdef EXTERNAL_FLASH_DEVICES

ports/nrf/boards/common.template.ld

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,6 @@ SECTIONS
7070
_etext = .; /* define a global symbol at end of code */
7171
} >FLASH_FIRMWARE
7272

73-
/*
74-
.ARM.extab :
75-
{
76-
*(.ARM.extab* .gnu.linkonce.armextab.*)
77-
} >FLASH_FIRMWARE
78-
79-
.ARM :
80-
{
81-
__exidx_start = .;
82-
*(.ARM.exidx*)
83-
__exidx_end = .;
84-
} >FLASH_FIRMWARE
85-
*/
86-
8773
/* used by the startup to initialize data */
8874
_sidata = .;
8975

@@ -147,6 +133,14 @@ SECTIONS
147133
. = ALIGN(4);
148134
} >RAM
149135

136+
/* Remove exception unwinding information, since Circuit Python
137+
does not support this GCC feature. */
138+
/DISCARD/ :
139+
{
140+
*(.ARM.extab* .gnu.linkonce.armextab.*)
141+
*(.ARM.exidx*)
142+
}
143+
150144
/* Remove information from the standard libraries */
151145
/*
152146
/DISCARD/ :

ports/nrf/boards/pca10100/mpconfigboard.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ MCU_CHIP = nrf52833
88
INTERNAL_FLASH_FILESYSTEM = 1
99

1010
CIRCUITPY_AUDIOMP3 = 0
11+
CIRCUITPY_BITBANGIO = 0
1112
CIRCUITPY_BUSIO = 1
13+
CIRCUITPY_COUNTIO = 0
1214
CIRCUITPY_DISPLAYIO = 0
1315
CIRCUITPY_FRAMEBUFFERIO = 0
16+
CIRCUITPY_FREQUENCYIO = 0
17+
CIRCUITPY_I2CSLAVE = 0
1418
CIRCUITPY_NEOPIXEL_WRITE = 0
1519
CIRCUITPY_NVM = 0
1620
CIRCUITPY_PIXELBUF = 0
@@ -20,6 +24,8 @@ CIRCUITPY_RTC = 1
2024
CIRCUITPY_TOUCHIO = 0
2125
CIRCUITPY_ULAB = 0
2226

27+
SUPEROPT_GC = 0
28+
2329
# These defines must be overridden before mpconfigboard.h is included, which is
2430
# why they are passed on the command line.
2531
CFLAGS += -DSPIM3_BUFFER_SIZE=0 -DSOFTDEVICE_RAM_SIZE='(32*1024)'

ports/nrf/boards/simmel/mpconfigboard.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
#endif
4141

4242
#define CIRCUITPY_INTERNAL_NVM_SIZE 0
43-
#define CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE (80*1024)
43+
#define CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE (76*1024)
4444

4545
#define BOOTLOADER_SIZE (0x4000) // 12 kiB
4646
#define CIRCUITPY_BLE_CONFIG_SIZE (12*1024)

ports/nrf/boards/simmel/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ CIRCUITPY_ROTARYIO = 0
2424
CIRCUITPY_RTC = 1
2525
CIRCUITPY_TOUCHIO = 0
2626
CIRCUITPY_ULAB = 0
27+
CIRCUITPY_WATCHDOG = 1
2728

2829
# Enable micropython.native
2930
#CIRCUITPY_ENABLE_MPY_NATIVE = 1

ports/nrf/common-hal/microcontroller/__init__.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
9494

9595
void common_hal_mcu_reset(void) {
9696
filesystem_flush();
97-
NVIC_SystemReset();
97+
reset_cpu();
9898
}
9999

100100
// The singleton microcontroller.Processor object, bound to microcontroller.cpu
@@ -106,7 +106,6 @@ const mcu_processor_obj_t common_hal_mcu_processor_obj = {
106106
};
107107

108108
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0
109-
110109
// The singleton nvm.ByteArray object.
111110
const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
112111
.base = {
@@ -117,6 +116,17 @@ const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
117116
};
118117
#endif
119118

119+
#if CIRCUITPY_WATCHDOG
120+
// The singleton watchdog.WatchDogTimer object.
121+
watchdog_watchdogtimer_obj_t common_hal_mcu_watchdogtimer_obj = {
122+
.base = {
123+
.type = &watchdog_watchdogtimer_type,
124+
},
125+
.timeout = 0.0f,
126+
.mode = WATCHDOGMODE_NONE,
127+
};
128+
#endif
129+
120130
STATIC const mp_rom_map_elem_t mcu_pin_globals_table[] = {
121131
{ MP_ROM_QSTR(MP_QSTR_P0_00), MP_ROM_PTR(&pin_P0_00) },
122132
{ MP_ROM_QSTR(MP_QSTR_P0_01), MP_ROM_PTR(&pin_P0_01) },

ports/nrf/common-hal/watchdog/WatchDogMode.c

Whitespace-only changes.
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019 Nick Moore for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
28+
#include <math.h>
29+
#include <string.h>
30+
31+
#include "py/obj.h"
32+
#include "py/objproperty.h"
33+
#include "py/runtime.h"
34+
35+
#include "common-hal/watchdog/WatchDogTimer.h"
36+
37+
#include "shared-bindings/microcontroller/__init__.h"
38+
#include "shared-bindings/watchdog/__init__.h"
39+
#include "shared-bindings/watchdog/WatchDogTimer.h"
40+
41+
#include "supervisor/port.h"
42+
43+
#include "nrf/timers.h"
44+
#include "nrf_wdt.h"
45+
#include "nrfx_wdt.h"
46+
#include "nrfx_timer.h"
47+
48+
STATIC uint8_t timer_refcount = 0;
49+
STATIC nrfx_timer_t *timer = NULL;
50+
STATIC nrfx_wdt_t wdt = NRFX_WDT_INSTANCE(0);
51+
STATIC nrfx_wdt_channel_id wdt_channel_id;
52+
53+
STATIC void watchdogtimer_timer_event_handler(nrf_timer_event_t event_type, void *p_context) {
54+
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(p_context);
55+
if (event_type != NRF_TIMER_EVENT_COMPARE0) {
56+
// Spurious event.
57+
return;
58+
}
59+
60+
// If the timer hits without being cleared, pause the timer and raise an exception.
61+
nrfx_timer_pause(timer);
62+
self->mode = WATCHDOGMODE_NONE;
63+
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&mp_watchdog_timeout_exception));
64+
MP_STATE_VM(mp_pending_exception) = &mp_watchdog_timeout_exception;
65+
#if MICROPY_ENABLE_SCHEDULER
66+
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
67+
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
68+
}
69+
#endif
70+
}
71+
72+
static void timer_free(void) {
73+
timer_refcount--;
74+
if (timer_refcount == 0) {
75+
nrf_peripherals_free_timer(timer);
76+
timer = NULL;
77+
}
78+
}
79+
80+
// This function is called if the timer expires. The system will reboot
81+
// in 1/16384 of a second. Issue a reboot ourselves so we can do any
82+
// cleanup necessary.
83+
STATIC void watchdogtimer_watchdog_event_handler(void) {
84+
reset_cpu();
85+
}
86+
87+
void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) {
88+
if (self->mode == WATCHDOGMODE_RESET) {
89+
nrfx_wdt_feed(&wdt);
90+
} else if (self->mode == WATCHDOGMODE_RAISE) {
91+
nrfx_timer_clear(timer);
92+
}
93+
}
94+
95+
void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) {
96+
if (timer) {
97+
timer_free();
98+
}
99+
self->mode = WATCHDOGMODE_NONE;
100+
}
101+
102+
void watchdog_reset(void) {
103+
common_hal_watchdog_deinit(&common_hal_mcu_watchdogtimer_obj);
104+
}
105+
106+
mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) {
107+
return self->timeout;
108+
}
109+
110+
void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t timeout) {
111+
if (self->mode == WATCHDOGMODE_RAISE) {
112+
// If the WatchDogTimer is already running in "RAISE" mode, reset the timer
113+
// with the new value.
114+
uint64_t ticks = timeout * 31250ULL;
115+
if (ticks > UINT32_MAX) {
116+
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
117+
}
118+
nrfx_timer_clear(timer);
119+
nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, ticks, true);
120+
}
121+
122+
self->timeout = timeout;
123+
}
124+
125+
watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_t *self) {
126+
return self->mode;
127+
}
128+
129+
void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t new_mode) {
130+
watchdog_watchdogmode_t current_mode = self->mode;
131+
132+
if (new_mode == WATCHDOGMODE_RAISE) {
133+
if (timer_refcount == 0) {
134+
timer = nrf_peripherals_allocate_timer_or_throw();
135+
}
136+
timer_refcount++;
137+
138+
nrfx_timer_config_t timer_config = {
139+
.frequency = NRF_TIMER_FREQ_31250Hz,
140+
.mode = NRF_TIMER_MODE_TIMER,
141+
.bit_width = NRF_TIMER_BIT_WIDTH_32,
142+
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
143+
.p_context = self,
144+
};
145+
146+
nrfx_timer_init(timer, &timer_config, &watchdogtimer_timer_event_handler);
147+
148+
uint64_t ticks = nrfx_timer_ms_to_ticks(timer, self->timeout * 1000);
149+
if (ticks > UINT32_MAX) {
150+
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
151+
}
152+
153+
// true enables interrupt.
154+
nrfx_timer_clear(timer);
155+
nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, ticks, true);
156+
nrfx_timer_resume(timer);
157+
158+
} else if (new_mode == WATCHDOGMODE_RESET) {
159+
uint64_t ticks = self->timeout * 1000.0f;
160+
if (ticks > UINT32_MAX) {
161+
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
162+
}
163+
164+
nrfx_wdt_config_t config = {
165+
.reload_value = ticks, // in units of ms
166+
.behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP,
167+
NRFX_WDT_IRQ_CONFIG
168+
};
169+
170+
nrfx_err_t err_code;
171+
err_code = nrfx_wdt_init(&wdt, &config, watchdogtimer_watchdog_event_handler);
172+
if (err_code != NRFX_SUCCESS) {
173+
mp_raise_OSError(1);
174+
}
175+
err_code = nrfx_wdt_channel_alloc(&wdt, &wdt_channel_id);
176+
if (err_code != NRFX_SUCCESS) {
177+
mp_raise_OSError(1);
178+
}
179+
nrfx_wdt_enable(&wdt);
180+
nrfx_wdt_feed(&wdt);
181+
}
182+
183+
// If we just switched away from RAISE, disable the timmer.
184+
if (current_mode == WATCHDOGMODE_RAISE && new_mode != WATCHDOGMODE_RAISE) {
185+
timer_free();
186+
}
187+
188+
self->mode = new_mode;
189+
}

0 commit comments

Comments
 (0)