iwdg: make independent watchdog driver compliant with STM32Cube LL API

Appropriate inclusion done for F1/F3/F4/L4 families in SoC tree.

JIRA: ZEP-2347

Signed-off-by: Adam Podogrocki <adam.podogrocki@rndity.com>
This commit is contained in:
Adam Podogrocki 2017-06-21 10:36:18 +02:00 committed by Kumar Gala
commit 6d4da19602
7 changed files with 160 additions and 140 deletions

View file

@ -48,6 +48,10 @@
#include <stm32f1xx_ll_i2c.h> #include <stm32f1xx_ll_i2c.h>
#endif #endif
#ifdef CONFIG_IWDG_STM32
#include <stm32f1xx_ll_iwdg.h>
#endif
#endif /* !_ASMLANGUAGE */ #endif /* !_ASMLANGUAGE */
#endif /* _STM32F1_SOC_H_ */ #endif /* _STM32F1_SOC_H_ */

View file

@ -49,6 +49,10 @@
#include <stm32f3xx_ll_i2c.h> #include <stm32f3xx_ll_i2c.h>
#endif #endif
#ifdef CONFIG_IWDG_STM32
#include <stm32f3xx_ll_iwdg.h>
#endif
#endif /* !_ASMLANGUAGE */ #endif /* !_ASMLANGUAGE */
#endif /* _STM32F3_SOC_H_ */ #endif /* _STM32F3_SOC_H_ */

View file

@ -52,6 +52,10 @@
#include <stm32f4xx_ll_rng.h> #include <stm32f4xx_ll_rng.h>
#endif #endif
#ifdef CONFIG_IWDG_STM32
#include <stm32f4xx_ll_iwdg.h>
#endif
/* For IMG_MANAGER */ /* For IMG_MANAGER */
#if defined(CONFIG_SOC_FLASH_STM32) #if defined(CONFIG_SOC_FLASH_STM32)
#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_STM32_DEV_NAME #define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_STM32_DEV_NAME

View file

@ -47,6 +47,10 @@
#include <stm32l4xx_ll_i2c.h> #include <stm32l4xx_ll_i2c.h>
#endif #endif
#ifdef CONFIG_IWDG_STM32
#include <stm32l4xx_ll_iwdg.h>
#endif
/* For IMG_MANAGER */ /* For IMG_MANAGER */
#if defined(CONFIG_SOC_FLASH_STM32) #if defined(CONFIG_SOC_FLASH_STM32)
#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_STM32_DEV_NAME #define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_STM32_DEV_NAME

View file

@ -1,43 +1,21 @@
# Kconfig - STM32 IWDG configuration # Kconfig - STM32 IWDG configuration
# #
# Copyright (c) 2016 Open-RnD Sp. z o.o. # Copyright (c) 2016 Open-RnD Sp. z o.o.
# Copyright (c) 2017 RnDity Sp. z o.o.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
if SOC_FAMILY_STM32 menuconfig IWDG_STM32
config IWDG_STM32
bool "Independent Watchdog (IWDG) Driver for STM32 family of MCUs" bool "Independent Watchdog (IWDG) Driver for STM32 family of MCUs"
depends on SOC_FAMILY_STM32
help help
Enable IWDG driver for STM32 line of MCUs Enable IWDG driver for STM32 line of MCUs
config IWDG_STM32_PRESCALER
int "Prescaler divider for clock feeding the IWDG"
depends on IWDG_STM32
default 4
range 4 256
help
Set the prescaler divider for the clock feeding the Independent
Watchdog. Higher values indicate that the watchdog will need to
be reloaded more frequently. Allowed values: 4, 8, 16, 32, 64,
128, 256. This setting combined with reload counter defines the
watchdog countdown time.
config IWDG_STM32_RELOAD_COUNTER
int "Value for IWDG counter"
depends on IWDG_STM32
default 2048
range 0 4095
help
Configure the value to be loaded into the watchdog's counter each
time a reload operation is performed. This value combined with
prescaler setting defines the watchdog countdown time.
config IWDG_STM32_START_AT_BOOT config IWDG_STM32_START_AT_BOOT
bool "Start IWDG during boot" bool "Start IWDG during boot"
depends on IWDG_STM32 depends on IWDG_STM32
default n default y
help help
Enable this setting to allow IWDG to be automatically started Enable this setting to allow IWDG to be automatically started
during device initialization. Note that once IWDG is started during device initialization. Note that once IWDG is started
@ -51,4 +29,11 @@ config IWDG_STM32_DEVICE_NAME
help help
Set the name used by IWDG device during registration. Set the name used by IWDG device during registration.
endif # SOC_FAMILY_STM32 config IWDG_STM32_TIMEOUT
int "Value for IWDG timeout in [us]"
depends on IWDG_STM32
default 100
range 100 26214400
help
Set timeout value for IWDG in microseconds.
The min timeout supported is 0.1ms, the max timeout is 26214.4ms.

View file

@ -1,36 +1,71 @@
/* /*
* Copyright (c) 2016 Open-RnD Sp. z o.o. * Copyright (c) 2016 Open-RnD Sp. z o.o.
* Copyright (c) 2017 RnDity Sp. z o.o.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
/**
* @brief Driver for Independent Watchdog (IWDG) for STM32 MCUs
*
* Based on reference manual:
* STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx
* advanced ARM ® -based 32-bit MCUs
*
* Chapter 19: Independent watchdog (IWDG)
*
*/
#include <watchdog.h> #include <watchdog.h>
#include <soc.h> #include <soc.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include "iwdg_stm32.h" #include "iwdg_stm32.h"
#define AS_IWDG(__base_addr) \ /* Minimal timeout in microseconds. */
(struct iwdg_stm32 *)(__base_addr) #define IWDG_TIMEOUT_MIN 100
/* Maximal timeout in microseconds. */
#define IWDG_TIMEOUT_MAX 26214400
#define IS_IWDG_TIMEOUT(__TIMEOUT__) \
(((__TIMEOUT__) >= IWDG_TIMEOUT_MIN) && \
((__TIMEOUT__) <= IWDG_TIMEOUT_MAX))
/*
* Status register need 5 RC LSI divided by prescaler clock to be updated.
* With higher prescaler (256U), and according to HSI variation,
* we need to wait at least 6 cycles so 48 ms.
*/
#define IWDG_DEFAULT_TIMEOUT 48u
/**
* @brief Calculates prescaler & reload values.
*
* @param timeout Timeout value in microseconds.
* @param prescaler Pointer to prescaler value.
* @param reload Pointer to reload value.
*/
static void iwdg_stm32_convert_timeout(u32_t timeout,
u32_t *prescaler,
u32_t *reload)
{
assert(IS_IWDG_TIMEOUT(timeout));
u16_t divider = 0;
u8_t shift = 0;
/* Convert timeout to seconds. */
float m_timeout = (float)timeout / 1000000 * LSI_VALUE;
do {
divider = 4 << shift;
shift++;
} while ((m_timeout / divider) > 0xFFF);
/*
* Value of the 'shift' variable corresponds to the
* defines of LL_IWDG_PRESCALER_XX type.
*/
*prescaler = --shift;
*reload = (uint32_t)(m_timeout / divider) - 1;
}
static void iwdg_stm32_enable(struct device *dev) static void iwdg_stm32_enable(struct device *dev)
{ {
volatile struct iwdg_stm32 *iwdg = AS_IWDG(IWDG_BASE); IWDG_TypeDef *iwdg = IWDG_STM32_STRUCT(dev);
ARG_UNUSED(dev); LL_IWDG_Enable(iwdg);
iwdg->kr.bit.key = STM32_IWDG_KR_START;
} }
static void iwdg_stm32_disable(struct device *dev) static void iwdg_stm32_disable(struct device *dev)
@ -40,30 +75,62 @@ static void iwdg_stm32_disable(struct device *dev)
} }
static int iwdg_stm32_set_config(struct device *dev, static int iwdg_stm32_set_config(struct device *dev,
struct wdt_config *config) struct wdt_config *config)
{ {
ARG_UNUSED(dev); IWDG_TypeDef *iwdg = IWDG_STM32_STRUCT(dev);
ARG_UNUSED(config); u32_t timeout = config->timeout;
u32_t prescaler = 0;
u32_t reload = 0;
u32_t tickstart;
/* no configuration */ assert(IS_IWDG_TIMEOUT(timeout));
return -ENOTSUP; iwdg_stm32_convert_timeout(timeout, &prescaler, &reload);
assert(IS_IWDG_PRESCALER(prescaler));
assert(IS_IWDG_RELOAD(reload));
LL_IWDG_EnableWriteAccess(iwdg);
LL_IWDG_SetPrescaler(iwdg, prescaler);
LL_IWDG_SetReloadCounter(iwdg, reload);
#if defined(CONFIG_SOC_SERIES_STM32F3X) || defined(CONFIG_SOC_SERIES_STM32L4X)
/* Neither STM32F1X nor STM32F4 series supports window option. */
LL_IWDG_SetWindow(iwdg, 0x0FFF);
#endif
tickstart = k_uptime_get_32();
while (LL_IWDG_IsReady(iwdg) == 0) {
if ((k_uptime_get_32() - tickstart) > IWDG_DEFAULT_TIMEOUT) {
return -ENODEV;
}
}
LL_IWDG_ReloadCounter(iwdg);
return 0;
} }
static void iwdg_stm32_get_config(struct device *dev, static void iwdg_stm32_get_config(struct device *dev,
struct wdt_config *config) struct wdt_config *config)
{ {
ARG_UNUSED(dev); IWDG_TypeDef *iwdg = IWDG_STM32_STRUCT(dev);
ARG_UNUSED(config);
u32_t prescaler = LL_IWDG_GetPrescaler(iwdg);
u32_t reload = LL_IWDG_GetReloadCounter(iwdg);
/* Timeout given in microseconds. */
config->timeout = (u32_t)((4 << prescaler) * (reload + 1)
* (1000000 / LSI_VALUE));
} }
static void iwdg_stm32_reload(struct device *dev) static void iwdg_stm32_reload(struct device *dev)
{ {
volatile struct iwdg_stm32 *iwdg = AS_IWDG(IWDG_BASE); IWDG_TypeDef *iwdg = IWDG_STM32_STRUCT(dev);
ARG_UNUSED(dev); LL_IWDG_ReloadCounter(iwdg);
iwdg->kr.bit.key = STM32_IWDG_KR_RELOAD;
} }
static const struct wdt_driver_api iwdg_stm32_api = { static const struct wdt_driver_api iwdg_stm32_api = {
@ -74,43 +141,36 @@ static const struct wdt_driver_api iwdg_stm32_api = {
.reload = iwdg_stm32_reload, .reload = iwdg_stm32_reload,
}; };
static inline int __iwdg_stm32_prescaler(int setting)
{
int v;
int i = 0;
/* prescaler range 4 - 256 */
for (v = 4; v < 256; v *= 2, i++) {
if (v == setting)
return i;
}
return i;
}
static int iwdg_stm32_init(struct device *dev) static int iwdg_stm32_init(struct device *dev)
{ {
volatile struct iwdg_stm32 *iwdg = AS_IWDG(IWDG_BASE); IWDG_TypeDef *iwdg = IWDG_STM32_STRUCT(dev);
struct wdt_config config;
/* clock setup is not required, once the watchdog is enabled config.timeout = CONFIG_IWDG_STM32_TIMEOUT;
* LSI oscillator will be forced on and fed to IWD after
* stabilization period LL_IWDG_Enable(iwdg);
iwdg_stm32_set_config(dev, &config);
/*
* The ST production value for the option bytes where WDG_SW bit is
* present is 0x00FF55AA, namely the Software watchdog mode is
* enabled by default.
* If the IWDG is started by either hardware option or software access,
* the LSI oscillator is forced ON and cannot be disabled.
*
* t_IWDG(ms) = t_LSI(ms) x 4 x 2^(IWDG_PR[2:0]) x (IWDG_RLR[11:0] + 1)
*/ */
/* unlock access to configuration registers */
iwdg->kr.bit.key = STM32_IWDG_KR_UNLOCK;
iwdg->pr.bit.pr =
__iwdg_stm32_prescaler(CONFIG_IWDG_STM32_PRESCALER);
iwdg->rlr.bit.rl = CONFIG_IWDG_STM32_RELOAD_COUNTER;
#ifdef CONFIG_IWDG_STM32_START_AT_BOOT
iwdg_stm32_enable(dev);
#endif
return 0; return 0;
} }
DEVICE_AND_API_INIT(iwdg_stm32, CONFIG_IWDG_STM32_DEVICE_NAME, iwdg_stm32_init, static struct iwdg_stm32_data iwdg_stm32_dev_data = {
NULL, NULL, .Instance = IWDG
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, };
DEVICE_AND_API_INIT(iwdg_stm32, CONFIG_IWDG_STM32_DEVICE_NAME,
iwdg_stm32_init, &iwdg_stm32_dev_data, NULL,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&iwdg_stm32_api); &iwdg_stm32_api);

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2016 Open-RnD Sp. z o.o. * Copyright (c) 2016 Open-RnD Sp. z o.o.
* Copyright (c) 2017 RnDity Sp. z o.o.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -12,65 +13,23 @@
/** /**
* @brief Driver for Independent Watchdog (IWDG) for STM32 MCUs * @brief Driver for Independent Watchdog (IWDG) for STM32 MCUs
* *
* Based on reference manual: * The driver targets all STM32 SoCs. For details please refer to
* STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx * an appropriate reference manual and look for chapter called:
* advanced ARM(r)-based 32-bit MCUs
* *
* Chapter 19: Independent watchdog (IWDG) * Independent watchdog (IWDG)
* *
*/ */
/* driver data */
/* counter reload trigger */ struct iwdg_stm32_data {
#define STM32_IWDG_KR_RELOAD 0xaaaa /* IWDG peripheral instance. */
/* magic value for unlocking write access to PR and RLR */ IWDG_TypeDef *Instance;
#define STM32_IWDG_KR_UNLOCK 0x5555
/* watchdog start */
#define STM32_IWDG_KR_START 0xcccc
/* 19.4.1 IWDG_KR */
union __iwdg_kr {
u32_t val;
struct {
u16_t key;
u16_t rsvd;
} bit;
}; };
/* 19.4.2 IWDG_PR */ #define IWDG_STM32_DATA(dev) \
union __iwdg_pr { ((struct iwdg_stm32_data * const)(dev)->driver_data)
u32_t val;
struct {
u32_t pr :3 __packed;
u32_t rsvd__3_31 :29 __packed;
} bit;
};
/* 19.4.3 IWDG_RLR */ #define IWDG_STM32_STRUCT(dev) \
union __iwdg_rlr { ((IWDG_TypeDef *)(IWDG_STM32_DATA(dev))->Instance)
u32_t val;
struct {
u32_t rl :12 __packed;
u32_t rsvd__12_31 :20 __packed;
} bit;
};
/* 19.4.4 IWDG_SR */
union __iwdg_sr {
u32_t val;
struct {
u32_t pvu :1 __packed;
u32_t rvu :1 __packed;
u32_t rsvd__2_31 :30 __packed;
} bit;
};
/* 19.4.5 IWDG register map */
struct iwdg_stm32 {
union __iwdg_kr kr;
union __iwdg_pr pr;
union __iwdg_rlr rlr;
union __iwdg_sr sr;
};
#endif /* _STM32_IWDG_H_ */ #endif /* _STM32_IWDG_H_ */