1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-27 07:21:18 +01:00

cpu/efm32: add watchdog peripheral

This commit is contained in:
Bas Stottelaar 2020-01-12 22:55:50 +01:00 committed by Alexandre Abadie
parent 2289a188ed
commit 3e2303d30c
No known key found for this signature in database
GPG Key ID: 1C919A403CAE1405
13 changed files with 306 additions and 0 deletions

View File

@ -13,6 +13,14 @@ config CPU_COMMON_EFM32
select HAS_PERIPH_FLASHPAGE_RAW
select HAS_PERIPH_GPIO
select HAS_PERIPH_GPIO_IRQ
select HAS_PERIPH_WDT
config CPU_EFM32_SERIES0
bool
config CPU_EFM32_SERIES1
bool
select HAS_PERIPH_WDT_CB
## Definition of specific features
config HAS_ARCH_EFM32

View File

@ -6,6 +6,10 @@ ifneq (,$(filter periph_rtt,$(USEMODULE)))
USEMODULE += periph_rtt_series$(EFM32_SERIES)
endif
ifneq (,$(filter periph_wdt,$(USEMODULE)))
USEMODULE += periph_wdt_series$(EFM32_SERIES)
endif
# include Gecko SDK package
USEPKG += gecko_sdk

View File

@ -13,6 +13,7 @@ FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_wdt
FEATURES_CONFLICT += periph_rtc:periph_rtt
FEATURES_CONFLICT_MSG += "On the EFM32, the RTC and RTT map to the same hardware peripheral."
@ -21,6 +22,10 @@ ifeq (1,$(EFM32_TRNG))
FEATURES_PROVIDED += periph_hwrng
endif
ifeq (1,$(EFM32_SERIES))
FEATURES_PROVIDED += periph_wdt_cb
endif
ifeq (1,$(EFM32_LEUART_ENABLED))
CFLAGS += -DEFM32_LEUART_ENABLED=1
endif

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFM32GG
bool
select CPU_CORE_CORTEX_M3
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES0
select HAS_CORTEXM_MPU
## CPU Models

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFM32LG
bool
select CPU_CORE_CORTEX_M3
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES0
select HAS_CORTEXM_MPU
## CPU Models

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFM32PG12B
bool
select CPU_CORE_CORTEX_M4F
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES1
select HAS_PERIPH_HWRNG
select HAS_CORTEXM_MPU

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFM32PG1B
bool
select CPU_CORE_CORTEX_M4F
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES1
select HAS_CORTEXM_MPU
## CPU Models

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFM32ZG
bool
select CPU_CORE_CORTEX_M0PLUS
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES0
## CPU Models
config CPU_MODEL_EFM32ZG222F16

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFR32MG12P
bool
select CPU_CORE_CORTEX_M4F
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES1
select HAS_PERIPH_HWRNG
select HAS_CORTEXM_MPU

View File

@ -8,6 +8,7 @@ config CPU_FAM_EFR32MG1P
bool
select CPU_CORE_CORTEX_M4F
select CPU_COMMON_EFM32
select CPU_EFM32_SERIES1
select HAS_CORTEXM_MPU
## CPU Models

View File

@ -31,6 +31,7 @@
#include "em_gpio.h"
#include "em_timer.h"
#include "em_usart.h"
#include "em_wdog.h"
#if defined(_SILICON_LABS_32B_SERIES_0)
#include "em_dac.h"
#endif
@ -437,6 +438,23 @@ typedef struct {
*/
#define PM_NUM_MODES (2U)
/**
* @name Watchdog timer (WDT) configuration
* @{
*/
#define WDT_CLOCK_HZ (1000U)
#define NWDT_TIME_LOWER_LIMIT ((1U << (3U + wdogPeriod_9)) + 1U)
#define NWDT_TIME_UPPER_LIMIT ((1U << (3U + wdogPeriod_256k)) + 1U)
#ifdef _SILICON_LABS_32B_SERIES_1
#define WDT_TIME_LOWER_LIMIT NWDT_TIME_LOWER_LIMIT
#define WDT_TIME_UPPER_LIMIT NWDT_TIME_UPPER_LIMIT
#endif
#define WDT_HAS_STOP (1U)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2020 Bas Stottelaar <basstottelaar@gmail.com>
*
* 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_efm32
* @ingroup drivers_periph_wdt
* @{
*
* @file
* @brief Watchdog timer peripheral driver implementation for
* EFM32 Series 0 MCUs
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
* @}
*/
#include <stdlib.h>
#include <assert.h>
#include "cpu.h"
#include "periph/wdt.h"
#include "em_cmu.h"
#include "em_wdog.h"
#include "timex.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static WDOG_PeriodSel_TypeDef _get_prescaler(uint32_t max_time)
{
const uint32_t cycles = (max_time * WDT_CLOCK_HZ) / 1000;
DEBUG("[wdt_series0] _get_prescaler: cycles=%" PRIu32 "\n", cycles);
return (WDOG_PeriodSel_TypeDef) (32 - __builtin_clz(cycles - 1) - 3);
}
void wdt_kick(void)
{
WDOGn_Feed(WDOG);
}
void wdt_start(void)
{
WDOGn_Enable(WDOG, true);
}
void wdt_stop(void)
{
WDOGn_Enable(WDOG, false);
}
void wdt_setup_reboot(uint32_t min_time, uint32_t max_time)
{
/* assert timings */
assert(min_time == 0);
assert(max_time > NWDT_TIME_LOWER_LIMIT ||
max_time < NWDT_TIME_UPPER_LIMIT);
/* initialize clock */
CMU_ClockEnable(cmuClock_HFLE, true);
/* initialize watchdog */
WDOG_Init_TypeDef init = WDOG_INIT_DEFAULT;
init.enable = false;
init.clkSel = wdogClkSelULFRCO;
init.perSel = _get_prescaler(max_time);
DEBUG("[wdt_series0] wdt_setup_reboot: prescaler=%d calculated_time=%" PRIu32 "\n",
(int) init.perSel,
((1 << (3 + (int)init.perSel)) + 1 ) / WDT_CLOCK_HZ * MS_PER_SEC);
WDOGn_Init(WDOG, &init);
}

View File

@ -0,0 +1,181 @@
/*
* Copyright (C) 2020 Bas Stottelaar <basstottelaar@gmail.com>
*
* 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_efm32
* @ingroup drivers_periph_wdt
* @{
*
* @file
* @brief Watchdog timer peripheral driver implementation for
* EFM32 Series 1 MCUs
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
* @}
*/
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include "cpu.h"
#include "periph/pm.h"
#include "periph/wdt.h"
#include "em_cmu.h"
#include "em_wdog.h"
#include "timex.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifdef MODULE_PERIPH_WDT_CB
static wdt_cb_t wdt_cb;
static void *wdt_arg;
#endif
static uint32_t _get_calculated_time(WDOG_PeriodSel_TypeDef period)
{
return ((1 << (3 + (int)period)) + 1) / WDT_CLOCK_HZ * MS_PER_SEC;
}
static WDOG_PeriodSel_TypeDef _get_period(uint32_t max_time)
{
const uint32_t cycles = (max_time * WDT_CLOCK_HZ) / MS_PER_SEC;
DEBUG("[wdt_series1] _get_period: cycles=%" PRIu32 "\n", cycles);
return (WDOG_PeriodSel_TypeDef) (32 - __builtin_clz(cycles - 1) - 3);
}
static WDOG_WinSel_TypeDef _get_illegal_window(uint32_t min_time, uint32_t calculated_time)
{
if (min_time == 0) {
return wdogIllegalWindowDisable;
}
uint32_t slice = calculated_time / 8;
for (unsigned i = 1; i < 8; i++) {
if (min_time < (i * slice)) {
return (WDOG_WinSel_TypeDef) i;
}
}
return wdogIllegalWindowDisable;
}
static void _init(uint32_t min_time, uint32_t max_time, bool warn)
{
#ifndef MODULE_PERIPH_WDT_CB
(void)warn;
#endif
/* assert timings */
if (min_time == 0) {
assert(max_time > NWDT_TIME_LOWER_LIMIT ||
max_time < NWDT_TIME_UPPER_LIMIT);
}
else {
assert(max_time > WDT_TIME_LOWER_LIMIT ||
max_time < WDT_TIME_UPPER_LIMIT);
}
/* initialize clock */
CMU_ClockEnable(cmuClock_HFLE, true);
/* initialize watchdog */
WDOG_Init_TypeDef init = WDOG_INIT_DEFAULT;
init.enable = false;
init.em2Run = true;
init.clkSel = wdogClkSelULFRCO;
init.perSel = _get_period(max_time);
uint32_t calculated_time = _get_calculated_time(init.perSel);
init.winSel = _get_illegal_window(min_time, calculated_time);
DEBUG("[wdt_series1] _init: prescaler=%d, winsel=%d, calculated=%" PRIu32 "\n",
(int) init.perSel, (int) init.winSel, calculated_time);
#ifdef MODULE_PERIPH_WDT_CB
if (warn) {
init.warnSel = wdogWarnTime50pct;
}
#endif
WDOGn_Init(WDOG0, &init);
/* Configure interrupts */
WDOGn_IntEnable(WDOG0, WDOG_IEN_WIN);
#ifdef MODULE_PERIPH_WDT_CB
if (warn) {
WDOGn_IntEnable(WDOG0, WDOG_IEN_WARN);
}
#endif
NVIC_EnableIRQ(WDOG0_IRQn);
}
void wdt_kick(void)
{
WDOGn_Feed(WDOG0);
}
void wdt_start(void)
{
WDOGn_Enable(WDOG0, true);
}
void wdt_stop(void)
{
WDOGn_Enable(WDOG0, false);
}
void wdt_setup_reboot(uint32_t min_time, uint32_t max_time)
{
_init(min_time, max_time, false);
}
#if defined(MODULE_PERIPH_WDT_CB)
void wdt_setup_reboot_with_callback(uint32_t min_time, uint32_t max_time,
wdt_cb_t cb, void *arg)
{
wdt_cb = cb;
wdt_arg = arg;
_init(min_time, max_time, true);
}
#endif
void isr_wdog0(void)
{
uint32_t flags = WDOGn_IntGet(WDOG0);
if (flags & WDOG_IEN_WIN) {
WDOGn_IntClear(WDOG0, WDOG_IEN_WIN);
pm_reboot();
}
#if defined(MODULE_PERIPH_WDT_CB)
if (flags & WDOG_IEN_WARN) {
WDOGn_IntClear(WDOG0, WDOG_IEN_WARN);
if (wdt_cb) {
wdt_cb(wdt_arg);
}
}
#endif
cortexm_isr_end();
}