drivers/watchdog: wwdg stm32: fix prescaler setup for newer series.

Series STM32G0, STM32G4, STM32H7, STM32L5, STM32WB, STM32WL have
a newer wwdg ip and store the prescaler value not in bits[8:7],
but bits bits[13:11], use the definitions from ll to account for that.

Remove IS_WWDG_PRESCALER, this is not required as the prescaler
is not calculated, but known valid prescaler values are tested until a
valid counter is found.

Signed-off-by: Thomas Stranger <thomas.stranger@outlook.com>
This commit is contained in:
Thomas Stranger 2021-03-05 17:26:35 +01:00 committed by Carles Cufí
commit e85b929cc6

View file

@ -26,6 +26,13 @@ LOG_MODULE_REGISTER(wdt_wwdg_stm32);
#define WWDG_COUNTER_MIN 0x40
#define WWDG_COUNTER_MAX 0x7f
#if defined WWDG_CFR_WDGTB_Pos
#define WWDG_PRESCALER_POS WWDG_CFR_WDGTB_Pos
#define WWDG_PRESCALER_MASK WWDG_CFR_WDGTB_Msk
#else
#error "WWDG CFR WDGTB position not defined for soc"
#endif
/* The timeout of the WWDG in milliseconds is calculated by the below formula:
*
* t_WWDG = 1000 * ((counter & 0x3F) + 1) / f_WWDG (ms)
@ -85,15 +92,15 @@ static uint32_t wwdg_stm32_get_pclk(const struct device *dev)
* @brief Calculates the timeout in microseconds.
*
* @param dev Pointer to device structure.
* @param prescaler The prescaler value.
* @param prescaler_exp The prescaler exponend value(Base 2).
* @param counter The counter value.
* @return The timeout calculated in microseconds.
*/
static uint32_t wwdg_stm32_get_timeout(const struct device *dev,
uint32_t prescaler,
uint32_t prescaler_exp,
uint32_t counter)
{
uint32_t divider = WWDG_INTERNAL_DIVIDER * (1 << (prescaler >> 7));
uint32_t divider = WWDG_INTERNAL_DIVIDER * (1 << prescaler_exp);
float f_wwdg = (float)wwdg_stm32_get_pclk(dev) / divider;
return USEC_PER_SEC * (((counter & 0x3F) + 1) / f_wwdg);
@ -104,39 +111,37 @@ static uint32_t wwdg_stm32_get_timeout(const struct device *dev,
*
* @param dev Pointer to device structure.
* @param timeout Timeout value in microseconds.
* @param prescaler Pointer to prescaler value.
* @param prescaler_exp Pointer to prescaler exponent value(Base 2).
* @param counter Pointer to counter value.
*/
static void wwdg_stm32_convert_timeout(const struct device *dev,
uint32_t timeout,
uint32_t *prescaler,
uint32_t *prescaler_exp,
uint32_t *counter)
{
uint32_t clock_freq = wwdg_stm32_get_pclk(dev);
uint8_t divider = 0U;
uint8_t shift = 0U;
/* Convert timeout to seconds. */
float timeout_s = (float)timeout / USEC_PER_SEC;
float wwdg_freq;
*prescaler = 0;
*prescaler_exp = 0U;
*counter = 0;
for (divider = 0; divider <= 3; divider++) {
wwdg_freq = ((float)clock_freq) / WWDG_INTERNAL_DIVIDER / (1 << divider);
for (*prescaler_exp = 0; *prescaler_exp <= 3; (*prescaler_exp)++) {
wwdg_freq = ((float)clock_freq) / WWDG_INTERNAL_DIVIDER / (1 << *prescaler_exp);
/* +1 to ceil the result, which may lose from truncation */
*counter = (uint32_t)(timeout_s * wwdg_freq + 1) - 1;
*counter += WWDG_RESET_LIMIT;
*prescaler = shift << 7;
if (*counter <= WWDG_COUNTER_MAX) {
break;
return;
}
shift++;
*counter = WWDG_COUNTER_MAX;
}
/* timeout longer than wwdg can provide, set to max possible value */
*counter = WWDG_COUNTER_MAX;
*prescaler_exp = WWDG_PRESCALER_EXPONENT_MAX;
}
static int wwdg_stm32_setup(const struct device *dev, uint8_t options)
@ -181,20 +186,21 @@ static int wwdg_stm32_install_timeout(const struct device *dev,
WWDG_TypeDef *wwdg = WWDG_STM32_STRUCT(dev);
uint32_t timeout = config->window.max * USEC_PER_MSEC;
uint32_t calculated_timeout;
uint32_t prescaler = 0U;
uint32_t prescaler_exp = 0U;
uint32_t counter = 0U;
if (config->callback != NULL) {
data->callback = config->callback;
}
wwdg_stm32_convert_timeout(dev, timeout, &prescaler, &counter);
calculated_timeout = wwdg_stm32_get_timeout(dev, prescaler, counter);
wwdg_stm32_convert_timeout(dev, timeout, &prescaler_exp, &counter);
calculated_timeout = wwdg_stm32_get_timeout(dev, prescaler_exp, counter);
LOG_DBG("prescaler: %d", (1 << prescaler_exp));
LOG_DBG("Desired WDT: %d us", timeout);
LOG_DBG("Set WDT: %d us", calculated_timeout);
if (!(IS_WWDG_PRESCALER(prescaler) && IS_WWDG_COUNTER(counter) &&
if (!(IS_WWDG_COUNTER(counter) &&
IS_WWDG_TIMEOUT(timeout, calculated_timeout))) {
/* One of the parameters provided is invalid */
return -EINVAL;
@ -204,7 +210,8 @@ static int wwdg_stm32_install_timeout(const struct device *dev,
/* Configure WWDG */
/* Set the programmable prescaler */
LL_WWDG_SetPrescaler(wwdg, prescaler);
LL_WWDG_SetPrescaler(wwdg,
(prescaler_exp << WWDG_PRESCALER_POS) & WWDG_PRESCALER_MASK);
/* Set window the same as the counter to be able to feed the WWDG almost
* immediately