diff --git a/cpu/cc2538/Kconfig b/cpu/cc2538/Kconfig index 94f915537e..45b56fb25e 100644 --- a/cpu/cc2538/Kconfig +++ b/cpu/cc2538/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_CC2538 select HAS_PERIPH_GPIO_IRQ select HAS_PERIPH_HWRNG select HAS_PERIPH_UART_MODECFG + select HAS_PERIPH_WDT select HAS_CORTEXM_MPU select HAS_PUF_SRAM diff --git a/cpu/cc2538/Makefile.features b/cpu/cc2538/Makefile.features index 144a1a4641..9b09972797 100644 --- a/cpu/cc2538/Makefile.features +++ b/cpu/cc2538/Makefile.features @@ -5,6 +5,7 @@ FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += periph_uart_modecfg +FEATURES_PROVIDED += periph_wdt FEATURES_PROVIDED += cortexm_mpu FEATURES_PROVIDED += puf_sram diff --git a/cpu/cc2538/include/periph_cpu.h b/cpu/cc2538/include/periph_cpu.h index 9b39f229e9..b73732c9a4 100644 --- a/cpu/cc2538/include/periph_cpu.h +++ b/cpu/cc2538/include/periph_cpu.h @@ -346,6 +346,16 @@ typedef gpio_t adc_conf_t; #define RTT_FREQUENCY (CLOCK_OSC32K) /** @} */ +/** + * @name WDT upper and lower bound times in ms + * @{ + */ +/* Limits are in clock cycles according to data sheet. + As the WDT is clocked by a 32 kHz clock and supports 4 intervals */ +#define NWDT_TIME_LOWER_LIMIT (2U) +#define NWDT_TIME_UPPER_LIMIT (1000U) +/** @} */ + /** * @name Radio peripheral configuration * @{ diff --git a/cpu/cc2538/periph/wdt.c b/cpu/cc2538/periph/wdt.c new file mode 100644 index 0000000000..cd46fc2b65 --- /dev/null +++ b/cpu/cc2538/periph/wdt.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 Technische Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_cc2538 + * @ingroup drivers_periph_wdt + * @{ + * + * @file + * @brief WDT peripheral driver implementation for the cc2538 + * + * @author Thomas Geithner + * @author Benjamin Valentin + * + * @} + */ + +#include "cc2538.h" +#include "periph/wdt.h" + +#define CC2538_WDT_CLK 32768 +#define WTD_MS(cycles) (((cycles) * 1000 + CC2538_WDT_CLK/2) / CC2538_WDT_CLK) + +typedef union { + cc2538_reg_t WDT; + struct { + cc2538_reg_t INT :2; /**< timer interval */ + cc2538_reg_t RESERVED :1; /**< reserved */ + cc2538_reg_t EN :1; /**< enable */ + cc2538_reg_t CLR :4; /**< clear */ + cc2538_reg_t RESERVED_2 :24; /**< reserved */ + } WDTbits; +} cc2538_wdt_t; + +cc2538_wdt_t * const WDT = (cc2538_wdt_t *) &SMWDTHROSC_WDCTL; + +/* + * supported clock counter values by the cc2538 + * + * The array index corresponds to the value in the INT field of the WDT register. + * According to the "CC2538 User's Guide" [1, pp. 370], the counter values and + * corresponding timings are: + * 64 -> 1.9 ms + * 512 -> 15.6 ms + * 8192 -> 250 ms + * 32768 -> 1000 ms + * + * [1] http://www.ti.com/lit/ug/swru319c/swru319c.pdf + */ +const uint16_t clk_values_ms[] = { WTD_MS(32768), WTD_MS(8192), WTD_MS(512), WTD_MS(64) }; + +void wdt_setup_reboot(uint32_t min_time, uint32_t max_time) { + + /* window mode is not supported */ + (void) min_time; + assert(min_time == 0); + + /* check, if WDT is already enabled */ + assert(WDT->WDTbits.EN != 1); + + /* ensure valid range */ + if (max_time < NWDT_TIME_LOWER_LIMIT) { + max_time = NWDT_TIME_LOWER_LIMIT; + } + + /* get required clock count */ + unsigned i; + for (i = 0; i < ARRAY_SIZE(clk_values_ms); ++i) { + if (max_time >= clk_values_ms[i]) { + break; + } + } + + /* select the interval */ + WDT->WDTbits.INT = i; +} + +void wdt_start(void) { + WDT->WDTbits.EN = 1; +} + +void wdt_kick(void) { + /* writing WDT clear sequence */ + WDT->WDTbits.CLR = 0xa; + WDT->WDTbits.CLR = 0x5; +} diff --git a/tests/periph_wdt/tests/01-run.py b/tests/periph_wdt/tests/01-run.py index e6020c9694..30f38e5814 100755 --- a/tests/periph_wdt/tests/01-run.py +++ b/tests/periph_wdt/tests/01-run.py @@ -7,13 +7,27 @@ # directory for more details. import sys +import os import pexpect import time +import subprocess from testrunner import run +# nucleo-l152re is the default platform for this test +BOARD = os.environ.get("BOARD", "nucleo-l152re") +BOARD_CPU = subprocess.check_output([ + 'make', + 'info-debug-variable-CPU', + 'BOARD={}'.format(BOARD), + '--no-print-directory']).strip() + # We test only up to 10ms, with smaller times mcu doesn't have time to # print system time before resetting -reset_times_ms = [128, 512, 1024, 8192] +# cc2538 only supports 4 intervals [2ms, 16ms, 250ms, 1s] +if BOARD_CPU.decode("utf-8") == 'cc2538': + reset_times_ms = [16, 250, 1000] +else: + reset_times_ms = [128, 512, 1024, 8192] # We don't check for accuracy, only order of magnitude. Some MCU use an # an internal un-calibrated clock as reference which can deviate in