From ec24f8b6e25cda1a1b3bb3f6c2952a96e49fa239 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Sat, 18 Jan 2020 20:57:52 +0000 Subject: [PATCH] nrf: Initial WDT-in-C implementation Currently it is difficult to deploy uPy on form factor devices without a reset pin. Any mistake in the boot code risks the system getting stuck (at least until the battery goes flat). A watchdog and user button can be combined to give a long-press reset that gives the user a better shot at recovering the device before the battery runs down! --- ports/nrf/Makefile | 1 + ports/nrf/drivers/bluetooth/ble_uart.c | 5 ++ ports/nrf/drivers/wdt.c | 93 ++++++++++++++++++++++++++ ports/nrf/drivers/wdt.h | 31 +++++++++ ports/nrf/main.c | 6 +- 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 ports/nrf/drivers/wdt.c create mode 100644 ports/nrf/drivers/wdt.h diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 2ac654911..dd96d9e30 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -232,6 +232,7 @@ SRC_C += \ drivers/flash.c \ drivers/softpwm.c \ drivers/ticker.c \ + drivers/wdt.c \ drivers/bluetooth/ble_drv.c \ drivers/bluetooth/ble_uart.c \ diff --git a/ports/nrf/drivers/bluetooth/ble_uart.c b/ports/nrf/drivers/bluetooth/ble_uart.c index ac99f6973..d322b9bd8 100644 --- a/ports/nrf/drivers/bluetooth/ble_uart.c +++ b/ports/nrf/drivers/bluetooth/ble_uart.c @@ -31,6 +31,7 @@ #include "ringbuffer.h" #include "mphalport.h" #include "lib/utils/interrupt_char.h" +#include "wdt.h" #if MICROPY_PY_BLE_NUS @@ -93,10 +94,14 @@ static ubluepy_advertise_data_t m_adv_data_eddystone_url; #endif // BLUETOOTH_WEBBLUETOOTH_REPL int mp_hal_stdin_rx_chr(void) { + wdt_feed(); + while (!ble_uart_enabled()) { // wait for connection + wdt_feed(); } while (isBufferEmpty(mp_rx_ring_buffer)) { + wdt_feed(); ; } diff --git a/ports/nrf/drivers/wdt.c b/ports/nrf/drivers/wdt.c new file mode 100644 index 000000000..89ab823d7 --- /dev/null +++ b/ports/nrf/drivers/wdt.c @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Daniel Thompson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_WDT + +#include "nrf_wdt.h" + +#if MICROPY_HW_HAS_WDT_BUTTON +static void button_init(void) +{ + nrf_gpio_cfg_sense_input( + MICROPY_HW_WDT_BUTTON, + MICROPY_HW_WDT_BUTTON_PULL < 0 ? NRF_GPIO_PIN_PULLDOWN : + MICROPY_HW_WDT_BUTTON_PULL > 0 ? NRF_GPIO_PIN_PULLUP : + NRF_GPIO_PIN_NOPULL, + NRF_GPIO_PIN_NOSENSE); + +#if MICROPY_HW_WDT_BUTTON_ENABLE + nrf_gpio_cfg_output(MICROPY_HW_WDT_BUTTON_ENABLE); + nrf_gpio_pin_write(MICROPY_HW_WDT_BUTTON_ENABLE, + MICROPY_HW_WDT_BUTTON_ACTIVE); +#endif +} + +static bool button_pressed(void) +{ + return nrf_gpio_pin_read(MICROPY_HW_WDT_BUTTON) == MICROPY_HW_WDT_BUTTON_ACTIVE; +} +#endif + +void wdt_init(void) +{ + if (!nrf_wdt_started()) { + // 1 => keep running during a sleep, stop during SWD debug + nrf_wdt_behaviour_set(1); + + // timeout after 5 seconds + nrf_wdt_reload_value_set(5 * 32768); + + // enable the 0th channel + nrf_wdt_reload_request_enable(NRF_WDT_RR0); + + // set it running + nrf_wdt_task_trigger(NRF_WDT_TASK_START); + +#if MICROPY_HW_HAS_WDT_BUTTON + // if there was no bootloader to configure the WDT then it + // probably didn't setup the pins for the button either + button_init(); +#endif + } +} + +void wdt_feed(void) +{ + /* + * A WDT button allows us to feed the dog from somewhere that would + * normally be "silly", such as a periodic timer interrupt. By providing + * the user direct control over feeding the dog we are, in effect, + * implementing a (reasonably robust) long-press reset button. + */ +#if MICROPY_HW_HAS_WDT_BUTTON + if (!button_pressed()) +#endif + nrf_wdt_reload_request_set(0); +} + +#endif // MICROPY_PY_MACHINE_WDT diff --git a/ports/nrf/drivers/wdt.h b/ports/nrf/drivers/wdt.h new file mode 100644 index 000000000..3938ef8de --- /dev/null +++ b/ports/nrf/drivers/wdt.h @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Daniel Thompson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_LIB_WDT_H__ +#define __MICROPY_INCLUDED_LIB_WDT_H__ + +void wdt_init(void); +void wdt_feed(void); + +#endif // __MICROPY_INCLUDED_LIB_WDT_H__ diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 9ffe7a285..e7ba10852 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -56,6 +56,7 @@ #include "pwm.h" #endif #include "timer.h" +#include "wdt.h" #if BLUETOOTH_SD #include "nrf_sdm.h" @@ -99,9 +100,12 @@ extern uint32_t _heap_end; int main(int argc, char **argv) { - soft_reset: +#if MICROPY_PY_MACHINE_WDT + wdt_init(); +#endif + led_init(); led_state(1, 1); // MICROPY_HW_LED_1 aka MICROPY_HW_LED_RED