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:
parent
2289a188ed
commit
3e2303d30c
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
83
cpu/efm32/periph/wdt_series0.c
Normal file
83
cpu/efm32/periph/wdt_series0.c
Normal 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);
|
||||
}
|
||||
181
cpu/efm32/periph/wdt_series1.c
Normal file
181
cpu/efm32/periph/wdt_series1.c
Normal 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();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user