drivers: watchdog: iwdg_stm32: Fix timeout calculation
CONFIG_IWDG_STM32_TIMEOUT allowed values of 100 us for initial watchdog timeout, which was actually rounded to zero in the driver, which uses milliseconds resolution for timeouts. This resulted in the reload value being set to maximum possible (calculation: 0U - 1). This commit updates the calculation of timeout minimum and maximum values considering the actual LSI frequency of the used MCU. As the resolution of CONFIG_IWDG_STM32_TIMEOUT in microseconds doesn't make sense if the driver supports only milliseconds, it is renamed to IWDG_STM32_INITIAL_TIMEOUT (this prevents accidental wrong settings in existing firmware) and the unit is changed to ms. Signed-off-by: Martin Jäger <martin@libre.solar>
This commit is contained in:
parent
e6911bc06c
commit
916dd0f6c4
2 changed files with 43 additions and 26 deletions
|
@ -11,14 +11,21 @@ menuconfig IWDG_STM32
|
|||
help
|
||||
Enable IWDG driver for STM32 line of MCUs
|
||||
|
||||
config IWDG_STM32_TIMEOUT
|
||||
int "Value for IWDG timeout in [us]"
|
||||
config IWDG_STM32_INITIAL_TIMEOUT
|
||||
int "Value for IWDG timeout in ms"
|
||||
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.
|
||||
range 1 26214
|
||||
help
|
||||
Set initial timeout value for IWDG in ms if enabled at boot.
|
||||
|
||||
The min timeout supported is 1 ms. The max timeout depends on the
|
||||
MCU's LSI clock frequency and can be calculated with:
|
||||
|
||||
max. prescaler value (256) * max. reload ticks (4096) / LSI freq.
|
||||
|
||||
Limiting maximum timeout to a safe value of 26214 ms here, which was
|
||||
calculated for highest LSI frequency among STM32 MCUs of 40 kHz.
|
||||
|
||||
config WWDG_STM32
|
||||
bool "System Window Watchdog (WWDG) Driver for STM32 family of MCUs"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (c) 2016 Open-RnD Sp. z o.o.
|
||||
* Copyright (c) 2017 RnDity Sp. z o.o.
|
||||
* Copyright (c) 2018 qianfan Zhao
|
||||
* Copyright (c) 2020 Libre Solar Technologies GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -17,22 +18,32 @@
|
|||
|
||||
#include "wdt_iwdg_stm32.h"
|
||||
|
||||
/* Minimal timeout in microseconds. */
|
||||
#define IWDG_TIMEOUT_MIN 100
|
||||
/* Maximal timeout in microseconds. */
|
||||
#define IWDG_TIMEOUT_MAX 26214400
|
||||
#define IWDG_PRESCALER_MIN (4U)
|
||||
#define IWDG_PRESCALER_MAX (256U)
|
||||
|
||||
#define IWDG_RELOAD_MIN (0x0000U)
|
||||
#define IWDG_RELOAD_MAX (0x0FFFU)
|
||||
|
||||
/* Minimum timeout in microseconds. */
|
||||
#define IWDG_TIMEOUT_MIN (IWDG_PRESCALER_MIN * (IWDG_RELOAD_MIN + 1U) \
|
||||
* USEC_PER_SEC / LSI_VALUE)
|
||||
|
||||
/* Maximum timeout in microseconds. */
|
||||
#define IWDG_TIMEOUT_MAX ((uint64_t)IWDG_PRESCALER_MAX * \
|
||||
(IWDG_RELOAD_MAX + 1U) * \
|
||||
USEC_PER_SEC / LSI_VALUE)
|
||||
|
||||
#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.
|
||||
* Status register needs 5 LSI clock cycles divided by prescaler to be updated.
|
||||
* With highest prescaler (256) and considering clock variation, we will wait
|
||||
* maximum 6 cycles (48 ms at 32 kHz) for register update.
|
||||
*/
|
||||
|
||||
#define IWDG_DEFAULT_TIMEOUT 48u
|
||||
#define IWDG_SR_UPDATE_TIMEOUT (6U * IWDG_PRESCALER_MAX * \
|
||||
MSEC_PER_SEC / LSI_VALUE)
|
||||
|
||||
/**
|
||||
* @brief Calculates prescaler & reload values.
|
||||
|
@ -45,24 +56,23 @@ static void iwdg_stm32_convert_timeout(uint32_t timeout,
|
|||
uint32_t *prescaler,
|
||||
uint32_t *reload)
|
||||
{
|
||||
|
||||
uint16_t divider = 0U;
|
||||
uint16_t divider = 4U;
|
||||
uint8_t shift = 0U;
|
||||
|
||||
/* Convert timeout to seconds. */
|
||||
uint32_t m_timeout = (uint64_t)timeout * LSI_VALUE / 1000000;
|
||||
/* Convert timeout to LSI clock ticks. */
|
||||
uint32_t ticks = (uint64_t)timeout * LSI_VALUE / USEC_PER_SEC;
|
||||
|
||||
do {
|
||||
divider = 4 << shift;
|
||||
while ((ticks / divider) > IWDG_RELOAD_MAX) {
|
||||
shift++;
|
||||
} while ((m_timeout / divider) > 0xFFF);
|
||||
divider = 4U << shift;
|
||||
}
|
||||
|
||||
/*
|
||||
* Value of the 'shift' variable corresponds to the
|
||||
* defines of LL_IWDG_PRESCALER_XX type.
|
||||
*/
|
||||
*prescaler = --shift;
|
||||
*reload = (uint32_t)(m_timeout / divider) - 1;
|
||||
*prescaler = shift;
|
||||
*reload = (uint32_t)(ticks / divider) - 1U;
|
||||
}
|
||||
|
||||
static int iwdg_stm32_setup(const struct device *dev, uint8_t options)
|
||||
|
@ -125,7 +135,7 @@ static int iwdg_stm32_install_timeout(const struct device *dev,
|
|||
|
||||
/* Wait for the update operation completed */
|
||||
while (LL_IWDG_IsReady(iwdg) != 0) {
|
||||
if ((k_uptime_get_32() - tickstart) > IWDG_DEFAULT_TIMEOUT) {
|
||||
if ((k_uptime_get_32() - tickstart) > IWDG_SR_UPDATE_TIMEOUT) {
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +168,7 @@ static int iwdg_stm32_init(const struct device *dev)
|
|||
#ifndef CONFIG_WDT_DISABLE_AT_BOOT
|
||||
IWDG_TypeDef *iwdg = IWDG_STM32_STRUCT(dev);
|
||||
struct wdt_timeout_cfg config = {
|
||||
.window.max = CONFIG_IWDG_STM32_TIMEOUT / USEC_PER_MSEC,
|
||||
.window.max = CONFIG_IWDG_STM32_INITIAL_TIMEOUT
|
||||
};
|
||||
|
||||
LL_IWDG_Enable(iwdg);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue