This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit ecf46578888b15464bc49b3a447bbb56f868e470 Author: raiden00pl <[email protected]> AuthorDate: Wed Jul 15 20:03:48 2026 +0200 arch/arm/src/stm32: unify IWDG and WWDG drivers into common/stm32 Retire the H7 IWDG/WWDG and L4 IWDG copies in favor of common/stm32/stm32_iwdg_m3m4_v1.c / stm32_wwdg_m3m4_v1.c. The only delta left was naming style, the DBGMCU freeze-in-debug write is already shared through the unified DBGMCU header. Plumbing: the common WDG register header aliases the H7 IWDG1/WWDG1 instance names; l4 hardware/stm32l4_wdg.h is renamed to stm32_wdg.h and the L4/H7 stm32_wdg.h source facades are dropped in favor of the common one. The common IWDG/WWDG build gates move out of the STM32_COMMON_LEGACY block so H7/L4 reach them. Built with IWDG+WWDG+JTAG forced on: nucleo-h743zi, nucleo-l476rg, nucleo-l496zg (make and CMake), nucleo-g474re and stm32f4discovery. stm32f103-minimum fails on a pre-existing missing STM32_LSI_FREQUENCY in board.h, unrelated to this change. Verified .config equivalence on 18 configs. Signed-off-by: raiden00pl <[email protected]> Assisted-by: Claude Code --- arch/arm/src/common/stm32/CMakeLists.txt | 20 +- arch/arm/src/common/stm32/Make.defs | 18 +- .../arm/src/common/stm32/hardware/stm32_wdg_v1v2.h | 27 + arch/arm/src/common/stm32/stm32_iwdg_m3m4_v1.c | 8 +- arch/arm/src/common/stm32/stm32_wwdg_m3m4_v1.c | 30 +- arch/arm/src/stm32h5/CMakeLists.txt | 4 + arch/arm/src/stm32h7/CMakeLists.txt | 8 - arch/arm/src/stm32h7/Make.defs | 8 - arch/arm/src/stm32h7/stm32_iwdg.c | 694 ------------------ arch/arm/src/stm32h7/stm32_wdg.h | 106 --- arch/arm/src/stm32h7/stm32_wwdg.c | 796 --------------------- arch/arm/src/stm32l4/CMakeLists.txt | 4 - arch/arm/src/stm32l4/Make.defs | 4 - .../hardware/{stm32l4_wdg.h => stm32_wdg.h} | 8 +- arch/arm/src/stm32l4/stm32.h | 2 +- arch/arm/src/stm32l4/stm32l4_iwdg.c | 660 ----------------- arch/arm/src/stm32l4/stm32l4_wdg.h | 106 --- 17 files changed, 76 insertions(+), 2427 deletions(-) diff --git a/arch/arm/src/common/stm32/CMakeLists.txt b/arch/arm/src/common/stm32/CMakeLists.txt index f0a3c8f8b1d..655364ead41 100644 --- a/arch/arm/src/common/stm32/CMakeLists.txt +++ b/arch/arm/src/common/stm32/CMakeLists.txt @@ -340,14 +340,6 @@ if(CONFIG_STM32_COMMON_LEGACY) endif() endif() - if(CONFIG_STM32_IWDG AND CONFIG_STM32_HAVE_IP_WDG_M3M4_V1) - list(APPEND SRCS stm32_iwdg_m3m4_v1.c) - endif() - - if(CONFIG_STM32_WWDG AND CONFIG_STM32_HAVE_IP_WDG_M3M4_V1) - list(APPEND SRCS stm32_wwdg_m3m4_v1.c) - endif() - if(CONFIG_DEBUG_FEATURES AND CONFIG_STM32_HAVE_IP_GPIO_M3M4_V1) list(APPEND SRCS stm32_dumpgpio_m3m4_v1.c) endif() @@ -381,6 +373,18 @@ if(CONFIG_STM32_COMMON_LEGACY) endif() endif() +if(CONFIG_STM32_COMMON_LEGACY + OR CONFIG_ARCH_CHIP_STM32H7 + OR CONFIG_ARCH_CHIP_STM32L4) + if(CONFIG_STM32_IWDG AND CONFIG_STM32_HAVE_IP_WDG_M3M4_V1) + list(APPEND SRCS stm32_iwdg_m3m4_v1.c) + endif() + + if(CONFIG_STM32_WWDG AND CONFIG_STM32_HAVE_IP_WDG_M3M4_V1) + list(APPEND SRCS stm32_wwdg_m3m4_v1.c) + endif() +endif() + if(CONFIG_ARCH_CORTEXM0) list(APPEND SRCS stm32_irq_m0_v1.c stm32_start_m0_v1.c) diff --git a/arch/arm/src/common/stm32/Make.defs b/arch/arm/src/common/stm32/Make.defs index 31c55fbf87b..723da066e14 100644 --- a/arch/arm/src/common/stm32/Make.defs +++ b/arch/arm/src/common/stm32/Make.defs @@ -381,14 +381,6 @@ endif endif endif -ifeq ($(CONFIG_STM32_IWDG)$(CONFIG_STM32_HAVE_IP_WDG_M3M4_V1),yy) -CHIP_CSRCS += stm32_iwdg_m3m4_v1.c -endif - -ifeq ($(CONFIG_STM32_WWDG)$(CONFIG_STM32_HAVE_IP_WDG_M3M4_V1),yy) -CHIP_CSRCS += stm32_wwdg_m3m4_v1.c -endif - ifeq ($(CONFIG_DEBUG_FEATURES),y) ifeq ($(CONFIG_STM32_HAVE_IP_GPIO_M3M4_V1),y) CHIP_CSRCS += stm32_dumpgpio_m3m4_v1.c @@ -431,6 +423,16 @@ endif endif +ifneq ($(CONFIG_STM32_COMMON_LEGACY)$(CONFIG_ARCH_CHIP_STM32H7)$(CONFIG_ARCH_CHIP_STM32L4),) +ifeq ($(CONFIG_STM32_IWDG)$(CONFIG_STM32_HAVE_IP_WDG_M3M4_V1),yy) +CHIP_CSRCS += stm32_iwdg_m3m4_v1.c +endif + +ifeq ($(CONFIG_STM32_WWDG)$(CONFIG_STM32_HAVE_IP_WDG_M3M4_V1),yy) +CHIP_CSRCS += stm32_wwdg_m3m4_v1.c +endif +endif + ifeq ($(CONFIG_ARCH_CORTEXM0),y) CHIP_CSRCS += stm32_irq_m0_v1.c diff --git a/arch/arm/src/common/stm32/hardware/stm32_wdg_v1v2.h b/arch/arm/src/common/stm32/hardware/stm32_wdg_v1v2.h index 8febf5740cb..3f10114f811 100644 --- a/arch/arm/src/common/stm32/hardware/stm32_wdg_v1v2.h +++ b/arch/arm/src/common/stm32/hardware/stm32_wdg_v1v2.h @@ -35,6 +35,18 @@ * Pre-processor Definitions ****************************************************************************/ +/* H7 numbers its watchdog instances (IWDG1/WWDG1 belong to CPU1); alias + * them to the unnumbered names used by the common drivers. + */ + +#if !defined(STM32_IWDG_BASE) && defined(STM32_IWDG1_BASE) +# define STM32_IWDG_BASE STM32_IWDG1_BASE +#endif + +#if !defined(STM32_WWDG_BASE) && defined(STM32_WWDG1_BASE) +# define STM32_WWDG_BASE STM32_WWDG1_BASE +#endif + /* Register Offsets *********************************************************/ #define STM32_IWDG_KR_OFFSET 0x0000 /* Key register (32-bit) */ @@ -122,12 +134,27 @@ #define WWDG_CFR_W_SHIFT (0) /* Bits 6:0 W[6:0] 7-bit window value */ #define WWDG_CFR_W_MASK (0x7f << WWDG_CFR_W_SHIFT) +#if defined(CONFIG_ARCH_CHIP_STM32H7) +#define WWDG_CFR_WDGTB_SHIFT (11) /* Bits 13:11 [2:0]: Timer Base */ +#define WWDG_CFR_WDGTB_MASK (7 << WWDG_CFR_WDGTB_SHIFT) +#define WWDG_CFR_WDGTB_MAX (7) +# define WWDG_CFR_PCLK1 (0 << WWDG_CFR_WDGTB_SHIFT) /* 000: CK Counter Clock (PCLK1 div 4096) div 1 */ +# define WWDG_CFR_PCLK1d2 (1 << WWDG_CFR_WDGTB_SHIFT) /* 001: CK Counter Clock (PCLK1 div 4096) div 2 */ +# define WWDG_CFR_PCLK1d4 (2 << WWDG_CFR_WDGTB_SHIFT) /* 010: CK Counter Clock (PCLK1 div 4096) div 4 */ +# define WWDG_CFR_PCLK1d8 (3 << WWDG_CFR_WDGTB_SHIFT) /* 011: CK Counter Clock (PCLK1 div 4096) div 8 */ +# define WWDG_CFR_PCLK1d16 (4 << WWDG_CFR_WDGTB_SHIFT) /* 100: CK Counter Clock (PCLK1 div 4096) div 16 */ +# define WWDG_CFR_PCLK1d32 (5 << WWDG_CFR_WDGTB_SHIFT) /* 101: CK Counter Clock (PCLK1 div 4096) div 32 */ +# define WWDG_CFR_PCLK1d64 (6 << WWDG_CFR_WDGTB_SHIFT) /* 110: CK Counter Clock (PCLK1 div 4096) div 64 */ +# define WWDG_CFR_PCLK1d128 (7 << WWDG_CFR_WDGTB_SHIFT) /* 111: CK Counter Clock (PCLK1 div 4096) div 128 */ +#else #define WWDG_CFR_WDGTB_SHIFT (7) /* Bits 8:7 [1:0]: Timer Base */ #define WWDG_CFR_WDGTB_MASK (3 << WWDG_CFR_WDGTB_SHIFT) +#define WWDG_CFR_WDGTB_MAX (3) # define WWDG_CFR_PCLK1 (0 << WWDG_CFR_WDGTB_SHIFT) /* 00: CK Counter Clock (PCLK1 div 4096) div 1 */ # define WWDG_CFR_PCLK1d2 (1 << WWDG_CFR_WDGTB_SHIFT) /* 01: CK Counter Clock (PCLK1 div 4096) div 2 */ # define WWDG_CFR_PCLK1d4 (2 << WWDG_CFR_WDGTB_SHIFT) /* 10: CK Counter Clock (PCLK1 div 4096) div 4 */ # define WWDG_CFR_PCLK1d8 (3 << WWDG_CFR_WDGTB_SHIFT) /* 11: CK Counter Clock (PCLK1 div 4096) div 8 */ +#endif #define WWDG_CFR_EWI (1 << 9) /* Bit 9: Early Wakeup Interrupt */ diff --git a/arch/arm/src/common/stm32/stm32_iwdg_m3m4_v1.c b/arch/arm/src/common/stm32/stm32_iwdg_m3m4_v1.c index 5c66ba3b35f..e303cc71b82 100644 --- a/arch/arm/src/common/stm32/stm32_iwdg_m3m4_v1.c +++ b/arch/arm/src/common/stm32/stm32_iwdg_m3m4_v1.c @@ -685,11 +685,9 @@ void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq) #if defined(CONFIG_STM32_JTAG_FULL_ENABLE) || \ defined(CONFIG_STM32_JTAG_NOJNTRST_ENABLE) || \ defined(CONFIG_STM32_JTAG_SW_ENABLE) - { -#ifdef DBGMCU_IWDG_STOP - modifyreg32(STM32_DBGMCU_IWDG_FZ, 0, DBGMCU_IWDG_STOP); -#endif - } +# ifdef DBGMCU_IWDG_STOP + modifyreg32(STM32_DBGMCU_IWDG_FZ, 0, DBGMCU_IWDG_STOP); +# endif #endif } diff --git a/arch/arm/src/common/stm32/stm32_wwdg_m3m4_v1.c b/arch/arm/src/common/stm32/stm32_wwdg_m3m4_v1.c index 24e28d0296c..9384d5824bc 100644 --- a/arch/arm/src/common/stm32/stm32_wwdg_m3m4_v1.c +++ b/arch/arm/src/common/stm32/stm32_wwdg_m3m4_v1.c @@ -40,6 +40,10 @@ #include "hardware/stm32_dbgmcu.h" #include "stm32_wdg.h" +#if !defined(STM32_IRQ_WWDG) && defined(STM32_IRQ_WWDG1) +# define STM32_IRQ_WWDG STM32_IRQ_WWDG1 +#endif + #if defined(CONFIG_WATCHDOG) && defined(CONFIG_STM32_WWDG) /**************************************************************************** @@ -62,7 +66,8 @@ * 1000 * 64 / Fmin = 49.93 msec */ -#define WWDG_FMIN (STM32_PCLK1_FREQUENCY / 4096 / 8) +#define WWDG_FMIN (STM32_PCLK1_FREQUENCY / 4096 / \ + (1 << WWDG_CFR_WDGTB_MAX)) #define WWDG_MAXTIMEOUT (1000 * (WWDG_CR_T_MAX+1) / WWDG_FMIN) /* Configuration ************************************************************/ @@ -455,7 +460,7 @@ static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, /* Get the time remaining until the watchdog expires (in milliseconds) */ reload = (stm32_getreg(STM32_WWDG_CR) >> WWDG_CR_T_SHIFT) & 0x7f; - elapsed = priv->reload - reload; + elapsed = (WWDG_CR_T_RESET | priv->reload) - reload; status->timeleft = (priv->timeout * elapsed) / (priv->reload + 1); wdinfo("Status :\n"); @@ -508,7 +513,7 @@ static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, * * Where * Fwwwdg is the frequency of the WWDG clock - * wdgtb is one of {1, 2, 4, or 8} + * prescaler is 1 << wdgtb, wdgtb = 0..WWDG_CFR_WDGTB_MAX */ /* Select the smallest prescaler that will result in a reload field value @@ -517,11 +522,7 @@ static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, for (wdgtb = 0; ; wdgtb++) { - /* WDGTB = 0 -> Divider = 1 = 1 << 0 - * WDGTB = 1 -> Divider = 2 = 1 << 1 - * WDGTB = 2 -> Divider = 4 = 1 << 2 - * WDGTB = 3 -> Divider = 8 = 1 << 3 - */ + /* WDGTB = n -> Divider = 1 << n */ /* Get the WWDG counter frequency in Hz. */ @@ -538,7 +539,7 @@ static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, * Fwwdg is the frequency of the WWDG clock */ - reload = timeout * fwwdg / 1000 - 1; + reload = timeout * fwwdg / 1000 - 1; /* If this reload valid is less than the maximum or we are not ready * at the prescaler value, then break out of the loop to use these @@ -549,7 +550,7 @@ static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, wdinfo("wdgtb=%d fwwdg=%d reload=%d timeout=%d\n", wdgtb, fwwdg, reload, 1000 * (reload + 1) / fwwdg); #endif - if (reload <= WWDG_CR_T_MAX || wdgtb == 3) + if (reload <= WWDG_CR_T_MAX || wdgtb == WWDG_CFR_WDGTB_MAX) { /* Note that we explicitly break out of the loop rather than using * the 'for' loop termination logic because we do not want the @@ -712,6 +713,7 @@ static int stm32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd, { uint32_t window = (priv->timeout - mintime) * priv->fwwdg / 1000 - 1; + DEBUGASSERT(window < priv->reload); stm32_setwindow(priv, window | WWDG_CR_T_RESET); ret = OK; @@ -783,11 +785,9 @@ void stm32_wwdginitialize(const char *devpath) #if defined(CONFIG_STM32_JTAG_FULL_ENABLE) || \ defined(CONFIG_STM32_JTAG_NOJNTRST_ENABLE) || \ defined(CONFIG_STM32_JTAG_SW_ENABLE) - { -#ifdef DBGMCU_WWDG_STOP - modifyreg32(STM32_DBGMCU_WWDG_FZ, 0, DBGMCU_WWDG_STOP); -#endif - } +# ifdef DBGMCU_WWDG_STOP + modifyreg32(STM32_DBGMCU_WWDG_FZ, 0, DBGMCU_WWDG_STOP); +# endif #endif } diff --git a/arch/arm/src/stm32h5/CMakeLists.txt b/arch/arm/src/stm32h5/CMakeLists.txt index 01cd1a86831..4d7804912da 100644 --- a/arch/arm/src/stm32h5/CMakeLists.txt +++ b/arch/arm/src/stm32h5/CMakeLists.txt @@ -104,6 +104,10 @@ if(CONFIG_STM32_IWDG) list(APPEND SRCS stm32_iwdg.c) endif() +if(CONFIG_STM32_WWDG) + list(APPEND SRCS stm32_wwdg.c) +endif() + # Required chip type specific files if(CONFIG_STM32_STM32H5XXXX) diff --git a/arch/arm/src/stm32h7/CMakeLists.txt b/arch/arm/src/stm32h7/CMakeLists.txt index 02a83c4a23e..769e81a1433 100644 --- a/arch/arm/src/stm32h7/CMakeLists.txt +++ b/arch/arm/src/stm32h7/CMakeLists.txt @@ -191,14 +191,6 @@ if(CONFIG_PM) endif() endif() -if(CONFIG_STM32_IWDG) - list(APPEND SRCS stm32_iwdg.c) -endif() - -if(CONFIG_STM32_WWDG) - list(APPEND SRCS stm32_wwdg.c) -endif() - if(CONFIG_STM32_CRYP AND CONFIG_STM32_HAVE_IP_CRYPTO_H7) list(APPEND SRCS stm32_aes.c) endif() diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs index 6262a0e7dee..8c44408bcc4 100644 --- a/arch/arm/src/stm32h7/Make.defs +++ b/arch/arm/src/stm32h7/Make.defs @@ -195,14 +195,6 @@ CHIP_CSRCS += stm32_pminitialize.c endif endif -ifeq ($(CONFIG_STM32_IWDG),y) -CHIP_CSRCS += stm32_iwdg.c -endif - -ifeq ($(CONFIG_STM32_WWDG),y) -CHIP_CSRCS += stm32_wwdg.c -endif - ifeq ($(CONFIG_STM32_CRYP),y) ifeq ($(CONFIG_STM32_HAVE_IP_CRYPTO_H7),y) CHIP_CSRCS += stm32_aes.c diff --git a/arch/arm/src/stm32h7/stm32_iwdg.c b/arch/arm/src/stm32h7/stm32_iwdg.c deleted file mode 100644 index f6b685c0cb3..00000000000 --- a/arch/arm/src/stm32h7/stm32_iwdg.c +++ /dev/null @@ -1,694 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32h7/stm32_iwdg.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> -#include <nuttx/arch.h> - -#include <stdint.h> -#include <assert.h> -#include <errno.h> - -#include <nuttx/debug.h> -#include <nuttx/irq.h> -#include <nuttx/clock.h> -#include <nuttx/timers/watchdog.h> -#include <arch/board/board.h> - -#include "arm_internal.h" -#include "stm32_rcc.h" -#include "hardware/stm32_dbgmcu.h" -#include "stm32_wdg.h" - -#if defined(CONFIG_WATCHDOG) && defined(CONFIG_STM32_IWDG) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Clocking *****************************************************************/ - -/* The minimum frequency of the IWDG clock is: - * - * Fmin = Flsi / 256 - * - * So the maximum delay (in milliseconds) is then: - * - * 1000 * IWDG_RLR_MAX / Fmin - * - * For example, if Flsi = 30Khz (the nominal, uncalibrated value), then the - * maximum delay is: - * - * Fmin = 117.1875 - * 1000 * 4095 / Fmin = 34,944 MSec - */ - -#define IWDG_FMIN (STM32_LSI_FREQUENCY / 256) -#define IWDG_MAXTIMEOUT (1000 * IWDG_RLR_MAX / IWDG_FMIN) - -/* Configuration ************************************************************/ - -#ifndef CONFIG_STM32_IWDG_DEFTIMOUT -# define CONFIG_STM32_IWDG_DEFTIMOUT IWDG_MAXTIMEOUT -#endif - -#ifndef CONFIG_DEBUG_WATCHDOG_INFO -# undef CONFIG_STM32_IWDG_REGDEBUG -#endif - -/* REVISIT: It appears that you can only setup the prescaler and reload - * registers once. After that, the SR register's PVU and RVU bits never go - * to zero. So we defer setting up these registers until the watchdog - * is started, then refuse any further attempts to change timeout. - */ - -#define CONFIG_STM32_IWDG_ONETIMESETUP 1 - -/* REVISIT: Another possibility is that we CAN change the prescaler and - * reload values after starting the timer. This option is untested but the - * implementation place conditioned on the following: - */ - -#undef CONFIG_STM32_IWDG_DEFERREDSETUP - -/* But you can only try one at a time */ - -#if defined(CONFIG_STM32_IWDG_ONETIMESETUP) && defined(CONFIG_STM32_IWDG_DEFERREDSETUP) -# error "Both CONFIG_STM32_IWDG_ONETIMESETUP and CONFIG_STM32_IWDG_DEFERREDSETUP are defined" -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure provides the private representation of the "lower-half" - * driver state structure. This structure must be cast-compatible with the - * well-known watchdog_lowerhalf_s structure. - */ - -struct stm32_lowerhalf_s -{ - const struct watchdog_ops_s *ops; /* Lower half operations */ - uint32_t lsifreq; /* The calibrated frequency of the LSI oscillator */ - uint32_t timeout; /* The (actual) selected timeout */ - uint32_t lastreset; /* The last reset time */ - bool started; /* true: The watchdog timer has been started */ - uint8_t prescaler; /* Clock prescaler value */ - uint16_t reload; /* Timer reload value */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Register operations ******************************************************/ - -#ifdef CONFIG_STM32_IWDG_REGDEBUG -static uint16_t stm32_getreg(uint32_t addr); -static void stm32_putreg(uint16_t val, uint32_t addr); -#else -# define stm32_getreg(addr) getreg16(addr) -# define stm32_putreg(val,addr) putreg16(val,addr) -#endif - -static inline void stm32_setprescaler(struct stm32_lowerhalf_s *priv); - -/* "Lower half" driver methods **********************************************/ - -static int stm32_start(struct watchdog_lowerhalf_s *lower); -static int stm32_stop(struct watchdog_lowerhalf_s *lower); -static int stm32_keepalive(struct watchdog_lowerhalf_s *lower); -static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, - struct watchdog_status_s *status); -static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, - uint32_t timeout); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* "Lower half" driver methods */ - -static const struct watchdog_ops_s g_wdgops = -{ - .start = stm32_start, - .stop = stm32_stop, - .keepalive = stm32_keepalive, - .getstatus = stm32_getstatus, - .settimeout = stm32_settimeout, - .capture = NULL, - .ioctl = NULL, -}; - -/* "Lower half" driver state */ - -static struct stm32_lowerhalf_s g_wdgdev; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_getreg - * - * Description: - * Get the contents of an STM32 IWDG register - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_IWDG_REGDEBUG -static uint16_t stm32_getreg(uint32_t addr) -{ - static uint32_t prevaddr = 0; - static uint32_t count = 0; - static uint16_t preval = 0; - - /* Read the value from the register */ - - uint16_t val = getreg16(addr); - - /* Is this the same value that we read from the same register last time? - * Are we polling the register? If so, suppress some of the output. - */ - - if (addr == prevaddr && val == preval) - { - if (count == 0xffffffff || ++count > 3) - { - if (count == 4) - { - wdinfo("...\n"); - } - - return val; - } - } - - /* No this is a new address or value */ - - else - { - /* Did we print "..." for the previous value? */ - - if (count > 3) - { - /* Yes.. then show how many times the value repeated */ - - wdinfo("[repeats %d more times]\n", count - 3); - } - - /* Save the new address, value, and count */ - - prevaddr = addr; - preval = val; - count = 1; - } - - /* Show the register value read */ - - wdinfo("%08" PRIx32 "->%04x\n", addr, val); - return val; -} -#endif - -/**************************************************************************** - * Name: stm32_putreg - * - * Description: - * Set the contents of an STM32 register to a value - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_IWDG_REGDEBUG -static void stm32_putreg(uint16_t val, uint32_t addr) -{ - /* Show the register value being written */ - - wdinfo("%08" PRIx32 "<-%04x\n", addr, val); - - /* Write the value */ - - putreg16(val, addr); -} -#endif - -/**************************************************************************** - * Name: stm32_setprescaler - * - * Description: - * Set up the prescaler and reload values. This seems to be something - * that can only be done one time. - * - * Input Parameters: - * priv - a pointer to the internal representation of the - * "lower-half" driver state structure. - * - ****************************************************************************/ - -static inline void stm32_setprescaler(struct stm32_lowerhalf_s *priv) -{ - /* Enable write access to IWDG_PR and IWDG_RLR registers */ - - stm32_putreg(IWDG_KR_KEY_ENABLE, STM32_IWDG_KR); - - /* Wait for the PVU and RVU bits to be reset be hardware. These bits - * were set the last time that the PR register was written and may not - * yet be cleared. - * - * If the setup is only permitted one time, then this wait should not - * be necessary. - */ - -#ifndef CONFIG_STM32_IWDG_ONETIMESETUP - while ((stm32_getreg(STM32_IWDG_SR) & (IWDG_SR_PVU | IWDG_SR_RVU)) != 0); -#endif - - /* Set the prescaler */ - - stm32_putreg((uint16_t)priv->prescaler << IWDG_PR_SHIFT, STM32_IWDG_PR); - - /* Set the reload value */ - - stm32_putreg((uint16_t)priv->reload, STM32_IWDG_RLR); - - /* Reload the counter (and disable write access) */ - - stm32_putreg(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR); -} - -/**************************************************************************** - * Name: stm32_start - * - * Description: - * Start the watchdog timer, resetting the time to the current timeout, - * - * Input Parameters: - * lower - a pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_start(struct watchdog_lowerhalf_s *lower) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - irqstate_t flags; - - DEBUGASSERT(priv); - wdinfo("Entry: started=%d\n", priv->started); - - /* Have we already been started? */ - - if (!priv->started) - { - /* REVISIT: It appears that you can only setup the prescaler and - * reload registers once. After that, the SR register's PVU and RVU - * bits never go to zero. So we defer setting up these registers until - * the watchdog is started, then refuse any further attempts to change - * timeout. - */ - - /* Set up prescaler and reload value for the selected timeout before - * starting the watchdog timer. - */ - -#if defined(CONFIG_STM32_IWDG_ONETIMESETUP) || defined(CONFIG_STM32_IWDG_DEFERREDSETUP) - stm32_setprescaler(priv); -#endif - - /* Enable IWDG (the LSI oscillator will be enabled by hardware). NOTE: - * If the "Hardware watchdog" feature is enabled through the device - * option bits, the watchdog is automatically enabled at power-on. - */ - - flags = enter_critical_section(); - stm32_putreg(IWDG_KR_KEY_START, STM32_IWDG_KR); - priv->lastreset = clock_systime_ticks(); - priv->started = true; - leave_critical_section(flags); - } - - return OK; -} - -/**************************************************************************** - * Name: stm32_stop - * - * Description: - * Stop the watchdog timer - * - * Input Parameters: - * lower - a pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_stop(struct watchdog_lowerhalf_s *lower) -{ - /* There is no way to disable the IDWG timer once it has been started */ - - wdinfo("Entry\n"); - return -ENOSYS; -} - -/**************************************************************************** - * Name: stm32_keepalive - * - * Description: - * Reset the watchdog timer to the current timeout value, prevent any - * imminent watchdog timeouts. This is sometimes referred as "pinging" - * the watchdog timer or "petting the dog". - * - * Input Parameters: - * lower - a pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_keepalive(struct watchdog_lowerhalf_s *lower) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - irqstate_t flags; - - wdinfo("Entry\n"); - - /* Reload the IWDG timer */ - - flags = enter_critical_section(); - stm32_putreg(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR); - priv->lastreset = clock_systime_ticks(); - leave_critical_section(flags); - - return OK; -} - -/**************************************************************************** - * Name: stm32_getstatus - * - * Description: - * Get the current watchdog timer status - * - * Input Parameters: - * lower - a pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * status - The location to return the watchdog status information. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, - struct watchdog_status_s *status) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - uint32_t ticks; - uint32_t elapsed; - - wdinfo("Entry\n"); - DEBUGASSERT(priv); - - /* Return the status bit */ - - status->flags = WDFLAGS_RESET; - if (priv->started) - { - status->flags |= WDFLAGS_ACTIVE; - } - - /* Return the actual timeout in milliseconds */ - - status->timeout = priv->timeout; - - /* Get the elapsed time since the last ping */ - - ticks = clock_systime_ticks() - priv->lastreset; - elapsed = (int32_t)TICK2MSEC(ticks); - - if (elapsed > priv->timeout) - { - elapsed = priv->timeout; - } - - /* Return the approximate time until the watchdog timer expiration */ - - status->timeleft = priv->timeout - elapsed; - - wdinfo("Status :\n"); - wdinfo(" flags : %08"PRIx32"\n", status->flags); - wdinfo(" timeout : %"PRIu32"\n", status->timeout); - wdinfo(" timeleft : %"PRIu32"\n", status->timeleft); - return OK; -} - -/**************************************************************************** - * Name: stm32_settimeout - * - * Description: - * Set a new timeout value (and reset the watchdog timer) - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * timeout - The new timeout value in milliseconds. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, - uint32_t timeout) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - uint32_t fiwdg; - uint64_t reload; - int prescaler; - int shift; - - wdinfo("Entry: timeout=%"PRIu32"\n", timeout); - DEBUGASSERT(priv); - - /* Can this timeout be represented? */ - - if (timeout < 1 || timeout > IWDG_MAXTIMEOUT) - { - wderr("ERROR: Cannot represent timeout=%"PRIu32" > %d\n", - timeout, IWDG_MAXTIMEOUT); - return -ERANGE; - } - - /* REVISIT: It appears that you can only setup the prescaler and reload - * registers once. After that, the SR register's PVU and RVU bits never go - * to zero. - */ - -#ifdef CONFIG_STM32_IWDG_ONETIMESETUP - if (priv->started) - { - wdwarn("WARNING: Timer is already started\n"); - return -EBUSY; - } -#endif - - /* Select the smallest prescaler that will result in a reload value that is - * less than the maximum. - */ - - for (prescaler = 0; ; prescaler++) - { - /* PR = 0 -> Divider = 4 = 1 << 2 - * PR = 1 -> Divider = 8 = 1 << 3 - * PR = 2 -> Divider = 16 = 1 << 4 - * PR = 3 -> Divider = 32 = 1 << 5 - * PR = 4 -> Divider = 64 = 1 << 6 - * PR = 5 -> Divider = 128 = 1 << 7 - * PR = 6 -> Divider = 256 = 1 << 8 - * PR = n -> Divider = 1 << (n+2) - */ - - shift = prescaler + 2; - - /* Get the IWDG counter frequency in Hz. For a nominal 32Khz LSI clock, - * this is value in the range of 7500 and 125. - */ - - fiwdg = priv->lsifreq >> shift; - - /* We want: - * 1000 * reload / Fiwdg = timeout - * Or: - * reload = Fiwdg * timeout / 1000 - */ - - reload = (uint64_t)fiwdg * (uint64_t)timeout / 1000; - - /* If this reload valid is less than the maximum or we are not ready - * at the prescaler value, then break out of the loop to use these - * settings. - */ - - if (reload <= IWDG_RLR_MAX || prescaler == 6) - { - /* Note that we explicitly break out of the loop rather than using - * the 'for' loop termination logic because we do not want the - * value of prescaler to be incremented. - */ - - break; - } - } - - /* Make sure that the final reload value is within range */ - - if (reload > IWDG_RLR_MAX) - { - reload = IWDG_RLR_MAX; - } - - /* Get the actual timeout value in milliseconds. - * - * We have: - * reload = Fiwdg * timeout / 1000 - * So we want: - * timeout = 1000 * reload / Fiwdg - */ - - priv->timeout = (1000 * (uint32_t)reload) / fiwdg; - - /* Save setup values for later use */ - - priv->prescaler = prescaler; - priv->reload = reload; - - /* Write the prescaler and reload values to the IWDG registers. - * - * REVISIT: It appears that you can only setup the prescaler and reload - * registers once. After that, the SR register's PVU and RVU bits never go - * to zero. - */ - -#ifndef CONFIG_STM32_IWDG_ONETIMESETUP - /* If CONFIG_STM32_IWDG_DEFERREDSETUP is selected, then perform the - * register configuration only if the timer has been started. - */ - -#ifdef CONFIG_STM32_IWDG_DEFERREDSETUP - if (priv->started) -#endif - { - stm32_setprescaler(priv); - } -#endif - - wdinfo("prescaler=%d fiwdg=%"PRIu32" reload=%"PRIu64"\n", prescaler, fiwdg, - reload); - - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_iwdginitialize - * - * Description: - * Initialize the IWDG watchdog timer. The watchdog timer is initialized - * and registers as 'devpath'. The initial state of the watchdog timer is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * lsifreq - The calibrated LSI clock frequency - * - * Returned Value: - * None - * - ****************************************************************************/ - -void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq) -{ - struct stm32_lowerhalf_s *priv = &g_wdgdev; - - wdinfo("Entry: devpath=%s lsifreq=%"PRIu32"\n", devpath, lsifreq); - - /* NOTE we assume that clocking to the IWDG has already been provided by - * the RCC initialization logic. - */ - - /* Initialize the driver state structure. */ - - priv->ops = &g_wdgops; - priv->lsifreq = lsifreq; - priv->started = false; - - /* Make sure that the LSI oscillator is enabled. NOTE: The LSI oscillator - * is enabled here but is not disabled by this file, because this file does - * not know the global usage of the oscillator. Any clock management - * logic (say, as part of a power management scheme) needs handle other - * LSI controls outside of this file. - */ - - stm32_rcc_enablelsi(); - wdinfo("RCC CSR: %08"PRIx32"\n", getreg32(STM32_RCC_CSR)); - - /* Select an arbitrary initial timeout value. But don't start the watchdog - * yet. NOTE: If the "Hardware watchdog" feature is enabled through the - * device option bits, the watchdog is automatically enabled at power-on. - */ - - stm32_settimeout((struct watchdog_lowerhalf_s *)priv, - CONFIG_STM32_IWDG_DEFTIMOUT); - - /* Register the watchdog driver as /dev/watchdog0 */ - - watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv); - - /* When the microcontroller enters debug mode (Cortex-M4F core halted), - * the IWDG counter either continues to work normally or stops, depending - * on DBG_IWDG_STOP configuration bit in DBG module. - */ - -#if defined(CONFIG_STM32_JTAG_FULL_ENABLE) || \ - defined(CONFIG_STM32_JTAG_NOJNTRST_ENABLE) || \ - defined(CONFIG_STM32_JTAG_SW_ENABLE) - { - modifyreg32(STM32_DBGMCU_IWDG_FZ, 0, DBGMCU_IWDG_STOP); - } -#endif -} - -#endif /* CONFIG_WATCHDOG && CONFIG_STM32_IWDG */ diff --git a/arch/arm/src/stm32h7/stm32_wdg.h b/arch/arm/src/stm32h7/stm32_wdg.h deleted file mode 100644 index f5f51837661..00000000000 --- a/arch/arm/src/stm32h7/stm32_wdg.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32h7/stm32_wdg.h - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -#ifndef __ARCH_ARM_SRC_STM32H7_STM32_WDG_H -#define __ARCH_ARM_SRC_STM32H7_STM32_WDG_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include "chip.h" -#include "hardware/stm32_wdg.h" - -#ifdef CONFIG_WATCHDOG - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#ifndef __ASSEMBLY__ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" -{ -#else -#define EXTERN extern -#endif - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_iwdginitialize - * - * Description: - * Initialize the IWDG watchdog time. The watchdog timer is initialized - * and registers as 'devpath'. The initial state of the watchdog time is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * lsifreq - The calibrated LSI clock frequency - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_IWDG -void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq); -#endif - -/**************************************************************************** - * Name: stm32_wwdginitialize - * - * Description: - * Initialize the WWDG watchdog time. The watchdog timer is initialized - * and registers as 'devpath'. The initial state of the watchdog time is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_WWDG -void stm32_wwdginitialize(const char *devpath); -#endif - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - -#endif /* __ASSEMBLY__ */ -#endif /* CONFIG_WATCHDOG */ -#endif /* __ARCH_ARM_SRC_STM32H7_STM32_WDG_H */ diff --git a/arch/arm/src/stm32h7/stm32_wwdg.c b/arch/arm/src/stm32h7/stm32_wwdg.c deleted file mode 100644 index 38d5945e392..00000000000 --- a/arch/arm/src/stm32h7/stm32_wwdg.c +++ /dev/null @@ -1,796 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32h7/stm32_wwdg.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> -#include <nuttx/arch.h> - -#include <stdint.h> -#include <assert.h> -#include <errno.h> - -#include <nuttx/debug.h> -#include <nuttx/irq.h> -#include <nuttx/timers/watchdog.h> -#include <arch/board/board.h> - -#include "arm_internal.h" -#include "hardware/stm32_dbgmcu.h" -#include "stm32_wdg.h" - -#if defined(CONFIG_WATCHDOG) && defined(CONFIG_STM32_WWDG) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Clocking *****************************************************************/ - -/* The minimum frequency of the WWDG clock is: - * - * Fmin = PCLK1 / 4096 / 128 - * - * So the maximum delay (in milliseconds) is then: - * - * 1000 * (WWDG_CR_T_MAX+1) / Fmin - * - * For example, if PCLK1 = 42MHz, then the maximum delay is: - * - * Fmin = 42,000,000 / 4096 / 128 = ~80.11 Hz - * 1000 * 64 / Fmin = ~798.92 msec - */ - -#define WWDG_FMIN (STM32_PCLK1_FREQUENCY / 4096 / 128) -#define WWDG_MAXTIMEOUT (1000 * (WWDG_CR_T_MAX+1) / WWDG_FMIN) - -/* Configuration ************************************************************/ - -#ifndef CONFIG_STM32_WWDG_DEFTIMOUT -# define CONFIG_STM32_WWDG_DEFTIMOUT WWDG_MAXTIMEOUT -#endif - -#ifndef CONFIG_DEBUG_WATCHDOG_INFO -# undef CONFIG_STM32_WWDG_REGDEBUG -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure provides the private representation of the "lower-half" - * driver state structure. This structure must be cast-compatible with the - * well-known watchdog_lowerhalf_s structure. - */ - -struct stm32_lowerhalf_s -{ - const struct watchdog_ops_s *ops; /* Lower half operations */ - xcpt_t handler; /* Current EWI interrupt handler */ - uint32_t timeout; /* The actual timeout value */ - uint32_t fwwdg; /* WWDG clock frequency */ - bool started; /* The timer has been started */ - uint8_t reload; /* The 7-bit reload field reset value */ - uint8_t window; /* The 7-bit window (W) field value */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Register operations ******************************************************/ - -#ifdef CONFIG_STM32_WWDG_REGDEBUG -static uint16_t stm32_getreg(uint32_t addr); -static void stm32_putreg(uint16_t val, uint32_t addr); -#else -# define stm32_getreg(addr) getreg32(addr) -# define stm32_putreg(val,addr) putreg32(val,addr) -#endif -static void stm32_setwindow(struct stm32_lowerhalf_s *priv, - uint8_t window); - -/* Interrupt handling *******************************************************/ - -static int stm32_interrupt(int irq, void *context, void *arg); - -/* "Lower half" driver methods **********************************************/ - -static int stm32_start(struct watchdog_lowerhalf_s *lower); -static int stm32_stop(struct watchdog_lowerhalf_s *lower); -static int stm32_keepalive(struct watchdog_lowerhalf_s *lower); -static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, - struct watchdog_status_s *status); -static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, - uint32_t timeout); -static xcpt_t stm32_capture(struct watchdog_lowerhalf_s *lower, - xcpt_t handler); -static int stm32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd, - unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* "Lower half" driver methods */ - -static const struct watchdog_ops_s g_wdgops = -{ - .start = stm32_start, - .stop = stm32_stop, - .keepalive = stm32_keepalive, - .getstatus = stm32_getstatus, - .settimeout = stm32_settimeout, - .capture = stm32_capture, - .ioctl = stm32_ioctl, -}; - -/* "Lower half" driver state */ - -static struct stm32_lowerhalf_s g_wdgdev; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_getreg - * - * Description: - * Get the contents of an STM32 register - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_WWDG_REGDEBUG -static uint16_t stm32_getreg(uint32_t addr) -{ - static uint32_t prevaddr = 0; - static uint32_t count = 0; - static uint16_t preval = 0; - - /* Read the value from the register */ - - uint16_t val = getreg16(addr); - - /* Is this the same value that we read from the same register last time? - * Are we polling the register? If so, suppress some of the output. - */ - - if (addr == prevaddr && val == preval) - { - if (count == 0xffffffff || ++count > 3) - { - if (count == 4) - { - wdinfo("...\n"); - } - - return val; - } - } - - /* No this is a new address or value */ - - else - { - /* Did we print "..." for the previous value? */ - - if (count > 3) - { - /* Yes.. then show how many times the value repeated */ - - wdinfo("[repeats %d more times]\n", count - 3); - } - - /* Save the new address, value, and count */ - - prevaddr = addr; - preval = val; - count = 1; - } - - /* Show the register value read */ - - wdinfo("%08" PRIx32 "->%04x\n", addr, val); - return val; -} -#endif - -/**************************************************************************** - * Name: stm32_putreg - * - * Description: - * Set the contents of an STM32 register to a value - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_WWDG_REGDEBUG -static void stm32_putreg(uint16_t val, uint32_t addr) -{ - /* Show the register value being written */ - - wdinfo("%08" PRIx32 "<-%04x\n", addr, val); - - /* Write the value */ - - putreg16(val, addr); -} -#endif - -/**************************************************************************** - * Name: stm32_setwindow - * - * Description: - * Set the CFR window value. The window value is compared to the down- - * counter when the counter is updated. The WWDG counter should be updated - * only when the counter is below this window value (and greater than 64) - * otherwise a reset will be generated - * - ****************************************************************************/ - -static void stm32_setwindow(struct stm32_lowerhalf_s *priv, - uint8_t window) -{ - uint16_t regval; - - /* Set W[6:0] bits according to selected window value */ - - regval = stm32_getreg(STM32_WWDG_CFR); - regval &= ~WWDG_CFR_W_MASK; - regval |= window << WWDG_CFR_W_SHIFT; - stm32_putreg(regval, STM32_WWDG_CFR); - - /* Remember the window setting */ - - priv->window = window; -} - -/**************************************************************************** - * Name: stm32_interrupt - * - * Description: - * WWDG early warning interrupt - * - * Input Parameters: - * Usual interrupt handler arguments. - * - * Returned Value: - * Always returns OK. - * - ****************************************************************************/ - -static int stm32_interrupt(int irq, void *context, void *arg) -{ - struct stm32_lowerhalf_s *priv = &g_wdgdev; - uint16_t regval; - - /* Check if the EWI interrupt is really pending */ - - regval = stm32_getreg(STM32_WWDG_SR); - if ((regval & WWDG_SR_EWIF) != 0) - { - /* Is there a registered handler? */ - - if (priv->handler) - { - /* Yes... NOTE: This interrupt service routine (ISR) must reload - * the WWDG counter to prevent the reset. Otherwise, we will reset - * upon return. - */ - - priv->handler(irq, context, priv); - } - - /* The EWI interrupt is cleared by writing '0' to the EWIF bit in the - * WWDG_SR register. - */ - - regval &= ~WWDG_SR_EWIF; - stm32_putreg(regval, STM32_WWDG_SR); - } - - return OK; -} - -/**************************************************************************** - * Name: stm32_start - * - * Description: - * Start the watchdog timer, resetting the time to the current timeout, - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_start(struct watchdog_lowerhalf_s *lower) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - - wdinfo("Entry\n"); - DEBUGASSERT(priv); - - /* Clear the pending interrupt bit */ - - modifyreg32(STM32_WWDG_SR, WWDG_SR_EWIF, 0); - - /* The watchdog is always disabled after a reset. It is enabled by setting - * the WDGA bit in the WWDG_CR register, then it cannot be disabled again - * except by a reset. - */ - - stm32_putreg(WWDG_CR_WDGA | WWDG_CR_T_RESET | priv->reload, STM32_WWDG_CR); - priv->started = true; - return OK; -} - -/**************************************************************************** - * Name: stm32_stop - * - * Description: - * Stop the watchdog timer - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_stop(struct watchdog_lowerhalf_s *lower) -{ - /* The watchdog is always disabled after a reset. It is enabled by setting - * the WDGA bit in the WWDG_CR register, then it cannot be disabled again - * except by a reset. - */ - - wdinfo("Entry\n"); - return -ENOSYS; -} - -/**************************************************************************** - * Name: stm32_keepalive - * - * Description: - * Reset the watchdog timer to the current timeout value, prevent any - * imminent watchdog timeouts. This is sometimes referred as "pinging" - * the watchdog timer or "petting the dog". - * - * The application program must write in the WWDG_CR register at regular - * intervals during normal operation to prevent an MCU reset. This - * operation must occur only when the counter value is lower than the - * window register value. The value to be stored in the WWDG_CR register - * must be between 0xff and 0xC0: - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_keepalive(struct watchdog_lowerhalf_s *lower) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - - wdinfo("Entry\n"); - DEBUGASSERT(priv); - - /* Write to T[6:0] bits to configure the counter value, no need to do - * a read-modify-write; writing a 0 to WDGA bit does nothing. - */ - - stm32_putreg((WWDG_CR_T_RESET | priv->reload), STM32_WWDG_CR); - return OK; -} - -/**************************************************************************** - * Name: stm32_getstatus - * - * Description: - * Get the current watchdog timer status - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * status - The location to return the watchdog status information. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, - struct watchdog_status_s *status) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - uint32_t elapsed; - uint16_t reload; - - wdinfo("Entry\n"); - DEBUGASSERT(priv); - - /* Return the status bit */ - - status->flags = WDFLAGS_RESET; - if (priv->started) - { - status->flags |= WDFLAGS_ACTIVE; - } - - if (priv->handler) - { - status->flags |= WDFLAGS_CAPTURE; - } - - /* Return the actual timeout is milliseconds */ - - status->timeout = priv->timeout; - - /* Get the time remaining until the watchdog expires (in milliseconds) */ - - reload = (stm32_getreg(STM32_WWDG_CR) >> WWDG_CR_T_SHIFT) & 0x7f; - elapsed = (WWDG_CR_T_RESET | priv->reload) - reload; - status->timeleft = (priv->timeout * elapsed) / (priv->reload + 1); - - wdinfo("Status :\n"); - wdinfo(" flags : %08" PRIx32 "\n", status->flags); - wdinfo(" timeout : %d\n", status->timeout); - wdinfo(" timeleft : %d\n", status->timeleft); - return OK; -} - -/**************************************************************************** - * Name: stm32_settimeout - * - * Description: - * Set a new timeout value (and reset the watchdog timer) - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * timeout - The new timeout value in milliseconds. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, - uint32_t timeout) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - uint32_t fwwdg; - uint32_t reload; - uint16_t regval; - int wdgtb; - - DEBUGASSERT(priv); - wdinfo("Entry: timeout=%d\n", timeout); - - /* Can this timeout be represented? */ - - if (timeout < 1 || timeout > WWDG_MAXTIMEOUT) - { - wderr("ERROR: Cannot represent timeout=%d > %d\n", - timeout, WWDG_MAXTIMEOUT); - return -ERANGE; - } - - /* Determine prescaler value. - * - * Fwwdg = PCLK1/4096/prescaler. - * - * Where - * Fwwwdg is the frequency of the WWDG clock - * wdgtb is one of {1, 2, 4, or 8} - */ - - /* Select the smallest prescaler that will result in a reload field value - * that is less than the maximum. - */ - - for (wdgtb = 0; ; wdgtb++) - { - /* WDGTB = 0 -> Divider = 1 = 1 << 0 - * WDGTB = 1 -> Divider = 2 = 1 << 1 - * WDGTB = 2 -> Divider = 4 = 1 << 2 - * WDGTB = 3 -> Divider = 8 = 1 << 3 - */ - - /* Get the WWDG counter frequency in Hz. */ - - fwwdg = (STM32_PCLK1_FREQUENCY / 4096) >> wdgtb; - - /* The formula to calculate the timeout value is given by: - * - * timeout = 1000 * (reload + 1) / Fwwdg, OR - * reload = timeout * Fwwdg / 1000 - 1 - * - * Where - * timeout is the desired timeout in milliseconds - * reload is the contents of T{5:0] - * Fwwdg is the frequency of the WWDG clock - */ - - reload = timeout * fwwdg / 1000 - 1; - - /* If this reload valid is less than the maximum or we are not ready - * at the prescaler value, then break out of the loop to use these - * settings. - */ - -#if 0 - wdinfo("wdgtb=%d fwwdg=%d reload=%d timeout=%d\n", - wdgtb, fwwdg, reload, 1000 * (reload + 1) / fwwdg); -#endif - if (reload <= WWDG_CR_T_MAX || wdgtb == 7) - { - /* Note that we explicitly break out of the loop rather than using - * the 'for' loop termination logic because we do not want the - * value of wdgtb to be incremented. - */ - - break; - } - } - - /* Make sure that the final reload value is within range */ - - if (reload > WWDG_CR_T_MAX) - { - reload = WWDG_CR_T_MAX; - } - - /* Calculate and save the actual timeout value in milliseconds: - * - * timeout = 1000 * (reload + 1) / Fwwdg - */ - - priv->timeout = 1000 * (reload + 1) / fwwdg; - - /* Remember the selected values */ - - priv->fwwdg = fwwdg; - priv->reload = reload; - - wdinfo("wdgtb=%d fwwdg=%d reload=%d timeout=%d\n", - wdgtb, fwwdg, reload, priv->timeout); - - /* Set WDGTB[1:0] bits according to calculated value */ - - regval = stm32_getreg(STM32_WWDG_CFR); - regval &= ~WWDG_CFR_WDGTB_MASK; - regval |= (uint16_t)wdgtb << WWDG_CFR_WDGTB_SHIFT; - stm32_putreg(regval, STM32_WWDG_CFR); - - /* Reset the 7-bit window value to the maximum value...essentially - * disabling the lower limit of the watchdog reset time. - */ - - stm32_setwindow(priv, 0x7f); - return OK; -} - -/**************************************************************************** - * Name: stm32_capture - * - * Description: - * Don't reset on watchdog timer timeout; instead, call this user provider - * timeout handler. NOTE: Providing handler==NULL will restore the reset - * behavior. - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * newhandler - The new watchdog expiration function pointer. If this - * function pointer is NULL, then the reset-on-expiration - * behavior is restored, - * - * Returned Value: - * The previous watchdog expiration function pointer or NULL is there was - * no previous function pointer, i.e., if the previous behavior was - * reset-on-expiration (NULL is also returned if an error occurs). - * - ****************************************************************************/ - -static xcpt_t stm32_capture(struct watchdog_lowerhalf_s *lower, - xcpt_t handler) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - irqstate_t flags; - xcpt_t oldhandler; - uint16_t regval; - - DEBUGASSERT(priv); - wdinfo("Entry: handler=%p\n", handler); - - /* Get the old handler return value */ - - flags = enter_critical_section(); - oldhandler = priv->handler; - - /* Save the new handler */ - - priv->handler = handler; - - /* Are we attaching or detaching the handler? */ - - regval = stm32_getreg(STM32_WWDG_CFR); - if (handler) - { - /* Attaching... Enable the EWI interrupt */ - - regval |= WWDG_CFR_EWI; - stm32_putreg(regval, STM32_WWDG_CFR); - - up_enable_irq(STM32_IRQ_WWDG1); - } - else - { - /* Detaching... Disable the EWI interrupt */ - - regval &= ~WWDG_CFR_EWI; - stm32_putreg(regval, STM32_WWDG_CFR); - - up_disable_irq(STM32_IRQ_WWDG1); - } - - leave_critical_section(flags); - return oldhandler; -} - -/**************************************************************************** - * Name: stm32_ioctl - * - * Description: - * Any ioctl commands that are not recognized by the "upper-half" driver - * are forwarded to the lower half driver through this method. - * - * Input Parameters: - * lower - A pointer to the publicly visible representation of the - * "lower-half" driver state structure. - * cmd - The ioctl command value - * arg - The optional argument that accompanies the 'cmd'. The - * interpretation of this argument depends on the particular - * command. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd, - unsigned long arg) -{ - struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; - int ret = -ENOTTY; - - DEBUGASSERT(priv); - wdinfo("Entry: cmd=%d arg=%ld\n", cmd, arg); - - /* WDIOC_MINTIME: Set the minimum ping time. If two keepalive ioctls - * are received within this time, a reset event will be generated. - * Argument: A 32-bit time value in milliseconds. - */ - - if (cmd == WDIOC_MINTIME) - { - uint32_t mintime = (uint32_t)arg; - - /* The minimum time should be strictly less than the total delay - * which, in turn, will be less than or equal to WWDG_CR_T_MAX - */ - - ret = -EINVAL; - if (mintime < priv->timeout) - { - uint32_t window = (priv->timeout - mintime) * - priv->fwwdg / 1000 - 1; - DEBUGASSERT(window < priv->reload); - stm32_setwindow(priv, window | WWDG_CR_T_RESET); - ret = OK; - } - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_wwdginitialize - * - * Description: - * Initialize the WWDG watchdog timer. The watchdog timer is initialized - * and registers as 'devpath'. The initial state of the watchdog timer is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * - * Returned Value: - * None - * - ****************************************************************************/ - -void stm32_wwdginitialize(const char *devpath) -{ - struct stm32_lowerhalf_s *priv = &g_wdgdev; - - wdinfo("Entry: devpath=%s\n", devpath); - - /* NOTE we assume that clocking to the WWDG has already been provided by - * the RCC initialization logic. - */ - - /* Initialize the driver state structure. Here we assume: (1) the state - * structure lies in .bss and was zeroed at reset time. (2) This function - * is only called once so it is never necessary to re-zero the structure. - */ - - priv->ops = &g_wdgops; - - /* Attach our EWI interrupt handler (But don't enable it yet) */ - - irq_attach(STM32_IRQ_WWDG1, stm32_interrupt, NULL); - - /* Select an arbitrary initial timeout value. But don't start the watchdog - * yet. NOTE: If the "Hardware watchdog" feature is enabled through the - * device option bits, the watchdog is automatically enabled at power-on. - */ - - stm32_settimeout((struct watchdog_lowerhalf_s *)priv, - CONFIG_STM32_WWDG_DEFTIMOUT); - - /* Register the watchdog driver as /dev/watchdog0 */ - - watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv); - - /* When the microcontroller enters debug mode (Cortex-M core halted), - * the WWDG counter either continues to work normally or stops, depending - * on the WWDG1 STOP configuration bit in DBG module. - */ - -#if defined(CONFIG_STM32_JTAG_FULL_ENABLE) || \ - defined(CONFIG_STM32_JTAG_NOJNTRST_ENABLE) || \ - defined(CONFIG_STM32_JTAG_SW_ENABLE) - { - modifyreg32(STM32_DBGMCU_WWDG_FZ, 0, DBGMCU_WWDG_STOP); - } -#endif -} - -#endif /* CONFIG_WATCHDOG && CONFIG_STM32_WWDG */ diff --git a/arch/arm/src/stm32l4/CMakeLists.txt b/arch/arm/src/stm32l4/CMakeLists.txt index d05274df91a..cfcedd6ad45 100644 --- a/arch/arm/src/stm32l4/CMakeLists.txt +++ b/arch/arm/src/stm32l4/CMakeLists.txt @@ -160,10 +160,6 @@ if(CONFIG_STM32_FIREWALL) list(APPEND SRCS stm32l4_firewall.c) endif() -if(CONFIG_STM32_IWDG) - list(APPEND SRCS stm32l4_iwdg.c) -endif() - if(CONFIG_STM32_SDMMC1) list(APPEND SRCS stm32l4_sdmmc.c) endif() diff --git a/arch/arm/src/stm32l4/Make.defs b/arch/arm/src/stm32l4/Make.defs index f6c621cc181..2df41b48e33 100644 --- a/arch/arm/src/stm32l4/Make.defs +++ b/arch/arm/src/stm32l4/Make.defs @@ -159,10 +159,6 @@ ifeq ($(CONFIG_STM32_FIREWALL),y) CHIP_CSRCS += stm32l4_firewall.c endif -ifeq ($(CONFIG_STM32_IWDG),y) -CHIP_CSRCS += stm32l4_iwdg.c -endif - ifeq ($(CONFIG_STM32_SDMMC1),y) CHIP_CSRCS += stm32l4_sdmmc.c endif diff --git a/arch/arm/src/stm32l4/hardware/stm32l4_wdg.h b/arch/arm/src/stm32l4/hardware/stm32_wdg.h similarity index 96% rename from arch/arm/src/stm32l4/hardware/stm32l4_wdg.h rename to arch/arm/src/stm32l4/hardware/stm32_wdg.h index 1ceca936c55..50d4db55d6b 100644 --- a/arch/arm/src/stm32l4/hardware/stm32l4_wdg.h +++ b/arch/arm/src/stm32l4/hardware/stm32_wdg.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32l4/hardware/stm32l4_wdg.h + * arch/arm/src/stm32l4/hardware/stm32_wdg.h * * SPDX-License-Identifier: Apache-2.0 * @@ -20,8 +20,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32L4_WDG_H -#define __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32L4_WDG_H +#ifndef __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32_WDG_H +#define __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32_WDG_H /**************************************************************************** * Included Files @@ -138,4 +138,4 @@ * Public Functions Prototypes ****************************************************************************/ -#endif /* __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32L4_WDG_H */ +#endif /* __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32_WDG_H */ diff --git a/arch/arm/src/stm32l4/stm32.h b/arch/arm/src/stm32l4/stm32.h index a76e37f4fc1..17b142fccac 100644 --- a/arch/arm/src/stm32l4/stm32.h +++ b/arch/arm/src/stm32l4/stm32.h @@ -54,7 +54,7 @@ #include "stm32l4_spi.h" #include "stm32l4_uart.h" #include "stm32l4_usbdev.h" -#include "stm32l4_wdg.h" +#include "stm32_wdg.h" #include "stm32l4_lowputc.h" /**************************************************************************** diff --git a/arch/arm/src/stm32l4/stm32l4_iwdg.c b/arch/arm/src/stm32l4/stm32l4_iwdg.c deleted file mode 100644 index 0349e9f5c03..00000000000 --- a/arch/arm/src/stm32l4/stm32l4_iwdg.c +++ /dev/null @@ -1,660 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32l4/stm32l4_iwdg.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> -#include <nuttx/arch.h> - -#include <inttypes.h> -#include <assert.h> -#include <errno.h> - -#include <nuttx/debug.h> -#include <nuttx/irq.h> -#include <nuttx/clock.h> -#include <nuttx/timers/watchdog.h> -#include <arch/board/board.h> - -#include "arm_internal.h" -#include "stm32l4_rcc.h" -#include "stm32_dbgmcu.h" -#include "stm32l4_wdg.h" - -#if defined(CONFIG_WATCHDOG) && defined(CONFIG_STM32_IWDG) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Clocking *****************************************************************/ - -/* The minimum frequency of the IWDG clock is: - * - * Fmin = Flsi / 256 - * - * So the maximum delay (in milliseconds) is then: - * - * 1000 * IWDG_RLR_MAX / Fmin - * - * For example, if Flsi = 30Khz (the nominal, uncalibrated value), then the - * maximum delay is: - * - * Fmin = 117.1875 - * 1000 * 4095 / Fmin = 34,944 MSec - */ - -#define IWDG_FMIN (STM32_LSI_FREQUENCY / 256) -#define IWDG_MAXTIMEOUT (1000 * IWDG_RLR_MAX / IWDG_FMIN) - -/* Configuration ************************************************************/ - -#ifndef CONFIG_STM32_IWDG_DEFTIMOUT -# define CONFIG_STM32_IWDG_DEFTIMOUT IWDG_MAXTIMEOUT -#endif - -#ifndef CONFIG_DEBUG_WATCHDOG_INFO -# undef CONFIG_STM32_IWDG_REGDEBUG -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure provides the private representation of the "lower-half" - * driver state structure. This structure must be cast-compatible with the - * well-known watchdog_lowerhalf_s structure. - */ - -struct stm32_lowerhalf_s -{ - const struct watchdog_ops_s *ops; /* Lower half operations */ - uint32_t lsifreq; /* The calibrated frequency of the LSI oscillator */ - uint32_t timeout; /* The (actual) selected timeout */ - uint32_t lastreset; /* The last reset time */ - bool started; /* true: The watchdog timer has been started */ - uint8_t prescaler; /* Clock prescaler value */ - uint16_t reload; /* Timer reload value */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Register operations ******************************************************/ - -#ifdef CONFIG_STM32_IWDG_REGDEBUG -static uint16_t stm32_getreg(uint32_t addr); -static void stm32_putreg(uint16_t val, uint32_t addr); -#else -# define stm32_getreg(addr) getreg16(addr) -# define stm32_putreg(val,addr) putreg16(val,addr) -#endif - -static inline void -stm32_setprescaler(struct stm32_lowerhalf_s *priv); - -/* "Lower half" driver methods **********************************************/ - -static int stm32_start(struct watchdog_lowerhalf_s *lower); -static int stm32_stop(struct watchdog_lowerhalf_s *lower); -static int stm32_keepalive(struct watchdog_lowerhalf_s *lower); -static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, - struct watchdog_status_s *status); -static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, - uint32_t timeout); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* "Lower half" driver methods */ - -static const struct watchdog_ops_s g_wdgops = -{ - .start = stm32_start, - .stop = stm32_stop, - .keepalive = stm32_keepalive, - .getstatus = stm32_getstatus, - .settimeout = stm32_settimeout, - .capture = NULL, - .ioctl = NULL, -}; - -/* "Lower half" driver state */ - -static struct stm32_lowerhalf_s g_wdgdev; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_getreg - * - * Description: - * Get the contents of an STM32 IWDG register - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_IWDG_REGDEBUG -static uint16_t stm32_getreg(uint32_t addr) -{ - static uint32_t prevaddr = 0; - static uint32_t count = 0; - static uint16_t preval = 0; - - /* Read the value from the register */ - - uint16_t val = getreg16(addr); - - /* Is this the same value that we read from the same register last time? - * Are we polling the register? If so, suppress some of the output. - */ - - if (addr == prevaddr && val == preval) - { - if (count == 0xffffffff || ++count > 3) - { - if (count == 4) - { - wdinfo("...\n"); - } - - return val; - } - } - - /* No this is a new address or value */ - - else - { - /* Did we print "..." for the previous value? */ - - if (count > 3) - { - /* Yes.. then show how many times the value repeated */ - - wdinfo("[repeats %d more times]\n", count - 3); - } - - /* Save the new address, value, and count */ - - prevaddr = addr; - preval = val; - count = 1; - } - - /* Show the register value read */ - - wdinfo("%08" PRIx32 "->%04x\n", addr, val); - return val; -} -#endif - -/**************************************************************************** - * Name: stm32_putreg - * - * Description: - * Set the contents of an STM32 register to a value - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_IWDG_REGDEBUG -static void stm32_putreg(uint16_t val, uint32_t addr) -{ - /* Show the register value being written */ - - wdinfo("%08" PRIx32 "<-%04x\n", addr, val); - - /* Write the value */ - - putreg16(val, addr); -} -#endif - -/**************************************************************************** - * Name: stm32_setprescaler - * - * Description: - * Set up the prescaler and reload values. - * - * Input Parameters: - * priv - A pointer the internal representation of the "lower-half" - * driver state structure. - * - ****************************************************************************/ - -static inline void stm32_setprescaler(struct stm32_lowerhalf_s *priv) -{ - irqstate_t flags; - - flags = enter_critical_section(); - - /* Enable write access to IWDG_PR and IWDG_RLR registers */ - - stm32_putreg(IWDG_KR_KEY_ENABLE, STM32_IWDG_KR); - - /* Wait for the PVU and RVU bits to be reset by hardware. These bits - * were set the last time that the PR register was written and may not - * yet be cleared. - */ - - while (stm32_getreg(STM32_IWDG_SR) & (IWDG_SR_PVU | IWDG_SR_RVU)); - - /* Set the prescaler */ - - stm32_putreg(priv->prescaler << IWDG_PR_SHIFT, STM32_IWDG_PR); - - /* Set the reload value */ - - stm32_putreg((uint16_t)priv->reload, STM32_IWDG_RLR); - - /* Reload the counter (and disable write access) */ - - stm32_putreg(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR); - - /* Wait for the PVU and RVU bits to be reset by hardware. This is - * to wait for the change to take effect before exiting critical section, - * as we are not allowed to enter any low-power modes while this update is - * in progress. - * - * REVISIT: PVU and RVU don't get cleared as promised, until the IWDG is - * started by writing IWDG_KR_KEY_START into IWDG_KR, regardless of whether - * LSI has been started explicitly previously, or not. RM does not document - * this behavior. Lets hope no low-power mode entry happens in this case - * during the next up to five RC 40 kHz cycles. - */ - - if (priv->started) - { - while (stm32_getreg(STM32_IWDG_SR) & (IWDG_SR_PVU | IWDG_SR_RVU)); - } - - leave_critical_section(flags); -} - -/**************************************************************************** - * Name: stm32_start - * - * Description: - * Start the watchdog timer, resetting the time to the current timeout, - * - * Input Parameters: - * lower - A pointer the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_start(struct watchdog_lowerhalf_s *lower) -{ - struct stm32_lowerhalf_s *priv = - (struct stm32_lowerhalf_s *)lower; - irqstate_t flags; - - wdinfo("Entry: started\n"); - DEBUGASSERT(priv); - - /* Have we already been started? */ - - if (!priv->started) - { - /* Set up prescaler and reload value for the selected timeout before - * starting the watchdog timer. - */ - - stm32_setprescaler(priv); - - /* Enable IWDG (the LSI oscillator will be enabled by hardware). NOTE: - * If the "Hardware watchdog" feature is enabled through the device - * option bits, the watchdog is automatically enabled at power-on. - */ - - flags = enter_critical_section(); - stm32_putreg(IWDG_KR_KEY_START, STM32_IWDG_KR); - priv->lastreset = clock_systime_ticks(); - priv->started = true; - leave_critical_section(flags); - } - - return OK; -} - -/**************************************************************************** - * Name: stm32_stop - * - * Description: - * Stop the watchdog timer - * - * Input Parameters: - * lower - A pointer the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_stop(struct watchdog_lowerhalf_s *lower) -{ - /* There is no way to disable the IDWG timer once it has been started */ - - wdinfo("Entry\n"); - return -ENOSYS; -} - -/**************************************************************************** - * Name: stm32_keepalive - * - * Description: - * Reset the watchdog timer to the current timeout value, prevent any - * imminent watchdog timeouts. This is sometimes referred as "pinging" - * the watchdog timer or "petting the dog". - * - * Input Parameters: - * lower - A pointer the publicly visible representation of the - * "lower-half" driver state structure. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_keepalive(struct watchdog_lowerhalf_s *lower) -{ - struct stm32_lowerhalf_s *priv = - (struct stm32_lowerhalf_s *)lower; - irqstate_t flags; - - wdinfo("Entry\n"); - - /* Reload the IWDG timer */ - - flags = enter_critical_section(); - stm32_putreg(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR); - priv->lastreset = clock_systime_ticks(); - leave_critical_section(flags); - - return OK; -} - -/**************************************************************************** - * Name: stm32_getstatus - * - * Description: - * Get the current watchdog timer status - * - * Input Parameters: - * lower - A pointer the publicly visible representation of the - * "lower-half" driver state structure. - * status - The location to return the watchdog status information. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, - struct watchdog_status_s *status) -{ - struct stm32_lowerhalf_s *priv = - (struct stm32_lowerhalf_s *)lower; - uint32_t ticks; - uint32_t elapsed; - - wdinfo("Entry\n"); - DEBUGASSERT(priv); - - /* Return the status bit */ - - status->flags = WDFLAGS_RESET; - if (priv->started) - { - status->flags |= WDFLAGS_ACTIVE; - } - - /* Return the actual timeout in milliseconds */ - - status->timeout = priv->timeout; - - /* Get the elapsed time since the last ping */ - - ticks = clock_systime_ticks() - priv->lastreset; - elapsed = (int32_t)TICK2MSEC(ticks); - - if (elapsed > priv->timeout) - { - elapsed = priv->timeout; - } - - /* Return the approximate time until the watchdog timer expiration */ - - status->timeleft = priv->timeout - elapsed; - - wdinfo("Status :\n"); - wdinfo(" flags : %08" PRIx32 "\n", status->flags); - wdinfo(" timeout : %" PRId32 "\n", status->timeout); - wdinfo(" timeleft : %" PRId32 "\n", status->timeleft); - return OK; -} - -/**************************************************************************** - * Name: stm32_settimeout - * - * Description: - * Set a new timeout value (and reset the watchdog timer) - * - * Input Parameters: - * lower - A pointer the publicly visible representation of the - * "lower-half" driver state structure. - * timeout - The new timeout value in milliseconds. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, - uint32_t timeout) -{ - struct stm32_lowerhalf_s *priv = - (struct stm32_lowerhalf_s *)lower; - uint32_t fiwdg; - uint64_t reload; - int prescaler; - int shift; - - wdinfo("Entry: timeout=%" PRId32 "\n", timeout); - DEBUGASSERT(priv); - - /* Can this timeout be represented? */ - - if (timeout < 1 || timeout > IWDG_MAXTIMEOUT) - { - wderr("ERROR: Cannot represent timeout=%" PRId32 " > %d\n", - timeout, IWDG_MAXTIMEOUT); - return -ERANGE; - } - - /* Select the smallest prescaler that will result in a reload value that is - * less than the maximum. - */ - - for (prescaler = 0; ; prescaler++) - { - /* PR = 0 -> Divider = 4 = 1 << 2 - * PR = 1 -> Divider = 8 = 1 << 3 - * PR = 2 -> Divider = 16 = 1 << 4 - * PR = 3 -> Divider = 32 = 1 << 5 - * PR = 4 -> Divider = 64 = 1 << 6 - * PR = 5 -> Divider = 128 = 1 << 7 - * PR = 6 -> Divider = 256 = 1 << 8 - * PR = n -> Divider = 1 << (n+2) - */ - - shift = prescaler + 2; - - /* Get the IWDG counter frequency in Hz. For a nominal 32Khz LSI clock, - * this is value in the range of 7500 and 125. - */ - - fiwdg = priv->lsifreq >> shift; - - /* We want: - * 1000 * reload / Fiwdg = timeout - * Or: - * reload = Fiwdg * timeout / 1000 - */ - - reload = (uint64_t)fiwdg * (uint64_t)timeout / 1000; - - /* If this reload valid is less than the maximum or we are not ready - * at the prescaler value, then break out of the loop to use these - * settings. - */ - - if (reload <= IWDG_RLR_MAX || prescaler == 6) - { - /* Note that we explicitly break out of the loop rather than using - * the 'for' loop termination logic because we do not want the - * value of prescaler to be incremented. - */ - - break; - } - } - - /* Make sure that the final reload value is within range */ - - if (reload > IWDG_RLR_MAX) - { - reload = IWDG_RLR_MAX; - } - - /* Get the actual timeout value in milliseconds. - * - * We have: - * reload = Fiwdg * timeout / 1000 - * So we want: - * timeout = 1000 * reload / Fiwdg - */ - - priv->timeout = (1000 * (uint32_t)reload) / fiwdg; - - /* Save setup values for later use */ - - priv->prescaler = prescaler; - priv->reload = reload; - - /* Write the prescaler and reload values to the IWDG registers. */ - - if (priv->started) - { - stm32_setprescaler(priv); - } - - wdinfo("prescaler=%d fiwdg=%" PRId32 " reload=%" PRId64 "\n", - prescaler, fiwdg, reload); - - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_iwdginitialize - * - * Description: - * Initialize the IWDG watchdog timer. The watchdog timer is initialized - * and registers as 'devpath'. The initial state of the watchdog timer is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * lsifreq - The calibrated LSI clock frequency - * - * Returned Value: - * None - * - ****************************************************************************/ - -void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq) -{ - struct stm32_lowerhalf_s *priv = &g_wdgdev; - - wdinfo("Entry: devpath=%s lsifreq=%" PRId32 "\n", devpath, lsifreq); - - /* NOTE we assume that clocking to the IWDG has already been provided by - * the RCC initialization logic. - */ - - /* Initialize the driver state structure. */ - - priv->ops = &g_wdgops; - priv->lsifreq = lsifreq; - priv->started = false; - - /* Make sure that the LSI oscillator is enabled. NOTE: The LSI oscillator - * is enabled here but is not disabled by this file, because this file does - * not know the global usage of the oscillator. Any clock management - * logic (say, as part of a power management scheme) needs handle other - * LSI controls outside of this file. - */ - - stm32_rcc_enablelsi(); - wdinfo("RCC CSR: %08" PRIx32 "\n", getreg32(STM32_RCC_CSR)); - - /* Select an arbitrary initial timeout value. But don't start the watchdog - * yet. NOTE: If the "Hardware watchdog" feature is enabled through the - * device option bits, the watchdog is automatically enabled at power-on. - */ - - stm32_settimeout((struct watchdog_lowerhalf_s *)priv, - CONFIG_STM32_IWDG_DEFTIMOUT); - - /* Register the watchdog driver as /dev/watchdog0 */ - - watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv); - - /* When the microcontroller enters debug mode (Cortex-M4F core halted), - * the IWDG counter either continues to work normally or stops, depending - * on DBG_IWDG_STOP configuration bit in DBG module. - */ - -#if defined(CONFIG_STM32_JTAG_FULL_ENABLE) || \ - defined(CONFIG_STM32_JTAG_NOJNTRST_ENABLE) || \ - defined(CONFIG_STM32_JTAG_SW_ENABLE) - { - modifyreg32(STM32_DBGMCU_IWDG_FZ, 0, DBGMCU_IWDG_STOP); - } -#endif -} - -#endif /* CONFIG_WATCHDOG && CONFIG_STM32_IWDG */ diff --git a/arch/arm/src/stm32l4/stm32l4_wdg.h b/arch/arm/src/stm32l4/stm32l4_wdg.h deleted file mode 100644 index aced6a146c9..00000000000 --- a/arch/arm/src/stm32l4/stm32l4_wdg.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32l4/stm32l4_wdg.h - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -#ifndef __ARCH_ARM_SRC_STM32L4_STM32L4_WDG_H -#define __ARCH_ARM_SRC_STM32L4_STM32L4_WDG_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include "chip.h" -#include "hardware/stm32l4_wdg.h" - -#ifdef CONFIG_WATCHDOG - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#ifndef __ASSEMBLY__ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" -{ -#else -#define EXTERN extern -#endif - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_iwdginitialize - * - * Description: - * Initialize the IWDG watchdog time. The watchdog timer is initialized - * and registers as 'devpath. The initial state of the watchdog time is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * lsifreq - The calibrated LSI clock frequency - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_IWDG -void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq); -#endif - -/**************************************************************************** - * Name: stm32_wwdginitialize - * - * Description: - * Initialize the WWDG watchdog time. The watchdog timer is initialized - * and registers as 'devpath. The initial state of the watchdog time is - * disabled. - * - * Input Parameters: - * devpath - The full path to the watchdog. This should be of the form - * /dev/watchdog0 - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_WWDG -void stm32_wwdginitialize(const char *devpath); -#endif - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - -#endif /* __ASSEMBLY__ */ -#endif /* CONFIG_WATCHDOG */ -#endif /* __ARCH_ARM_SRC_STM32L4_STM32L4_WDG_H */
