summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkurisaw <[email protected]>2025-10-11 13:28:37 +0800
committerR b b666 <[email protected]>2025-10-11 15:27:51 +0800
commite72182d7f46af798cb3587c40e52ac95b1f649c1 (patch)
tree3583b9a22dbde3c4c50d241599dedf2b0fbc9c1a
parentb2d6e2c2686a7ecfdbdd97bb2bdefc231ecf8433 (diff)
gd32/driver: fix inaccurate WDT clock timeout feeding issue
-rw-r--r--bsp/gd32/arm/libraries/gd32_drivers/drv_wdt.c87
1 files changed, 63 insertions, 24 deletions
diff --git a/bsp/gd32/arm/libraries/gd32_drivers/drv_wdt.c b/bsp/gd32/arm/libraries/gd32_drivers/drv_wdt.c
index 8ef5096caf..6f218e2b16 100644
--- a/bsp/gd32/arm/libraries/gd32_drivers/drv_wdt.c
+++ b/bsp/gd32/arm/libraries/gd32_drivers/drv_wdt.c
@@ -1,22 +1,42 @@
/*
- * Copyright (c) 2006-2022, RT-Thread Development Team
+ * Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-01-25 iysheng first version
+ * 2025-10-09 kurisaw fix inaccurate WDT clock timeout feeding issue
*/
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
#include <board.h>
-#define DBG_TAG "drv.wdt"
-#define DBG_LVL DBG_INFO
+#define DBG_TAG "drv.wdt"
+#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#ifdef RT_USING_WDT
-typedef struct {
+/* User-configurable macros for WDT clock source and prescaler */
+/* Default select oscillator type: RCU_LXTAL */
+#define WDT_OSCI_TYPE RCU_LXTAL
+
+/* Prescaler divider value (must match WDT_PSC_VALUE) */
+#define WDT_PSC_DIVIDER 256U
+/* Prescaler register value */
+#define WDT_PSC_VALUE FWDGT_PSC_DIV256
+
+/* Derived values */
+#define WDT_CLOCK_FREQ LXTAL_VALUE
+
+#define WDT_TICK_HZ (WDT_CLOCK_FREQ / WDT_PSC_DIVIDER)
+#define WDT_MAX_RELOAD_VALUE 0xfffU
+
+typedef struct
+{
struct rt_watchdog_device wdt;
rt_uint32_t min_threshold_s;
rt_uint32_t max_threshold_s;
@@ -27,23 +47,33 @@ static gd32_wdt_device_t g_wdt_dev;
static rt_err_t gd32_wdt_init(rt_watchdog_t *wdt)
{
- rcu_osci_on(RCU_IRC40K);
- if (ERROR == rcu_osci_stab_wait(RCU_IRC40K))
+#if defined(SOC_SERIES_GD32H7xx)
+ /* Enable and wait for oscillator stabilization */
+ rcu_osci_on(WDT_OSCI_TYPE);
+ if (ERROR == rcu_osci_stab_wait(WDT_OSCI_TYPE))
{
- LOG_E("failed init IRC40K clock for free watchdog.");
+ LOG_E("failed init %u clock for free watchdog.", WDT_OSCI_TYPE);
return -RT_EINVAL;
}
+#endif
- g_wdt_dev.min_threshold_s = 1;
- g_wdt_dev.max_threshold_s = (0xfff << 8) / 40000;
- LOG_I("threshold section [%u, %d]", \
- g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
+ /* Calculate thresholds */
+ g_wdt_dev.min_threshold_s = 1U;
+ g_wdt_dev.max_threshold_s = ((WDT_MAX_RELOAD_VALUE + 1U) * WDT_PSC_DIVIDER) / WDT_CLOCK_FREQ;
+ LOG_I("WDT clock: %u Hz (tick: %u Hz), threshold section [%u, %u]",
+ WDT_CLOCK_FREQ, WDT_TICK_HZ,
+ g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
+ /* Configure FWDGT with max timeout */
fwdgt_write_enable();
- fwdgt_config(0xfff, FWDGT_PSC_DIV256);
+ if (fwdgt_config(WDT_MAX_RELOAD_VALUE, WDT_PSC_VALUE) != SUCCESS)
+ {
+ LOG_E("failed to configure FWDGT");
+ return -RT_ERROR;
+ }
fwdgt_enable();
- return 0;
+ return RT_EOK;
}
static rt_err_t gd32_wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
@@ -56,20 +86,26 @@ static rt_err_t gd32_wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
fwdgt_counter_reload();
break;
case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
- param = *(rt_uint32_t *) arg;
- if ((param > g_wdt_dev.max_threshold_s) || \
+ param = *(rt_uint32_t *)arg;
+ if ((param > g_wdt_dev.max_threshold_s) ||
(param < g_wdt_dev.min_threshold_s))
{
- LOG_E("invalid param@%u.", param);
+ LOG_E("invalid param@%u (out of [%u, %u])", param,
+ g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
return -RT_EINVAL;
}
else
{
g_wdt_dev.current_threshold_s = param;
+ rt_uint32_t reload_value = (param * WDT_TICK_HZ) - 1U;
+ fwdgt_write_enable();
+ if (fwdgt_config(reload_value, WDT_PSC_VALUE) != SUCCESS)
+ {
+ LOG_E("failed to set timeout %u s", param);
+ return -RT_ERROR;
+ }
+ fwdgt_write_disable();
}
- fwdgt_write_enable();
- fwdgt_config(param * 40000 >> 8, FWDGT_PSC_DIV256);
- fwdgt_write_disable();
break;
case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
*(rt_uint32_t *)arg = g_wdt_dev.current_threshold_s;
@@ -92,17 +128,20 @@ static struct rt_watchdog_ops g_wdt_ops = {
static int rt_hw_wdt_init(void)
{
- rt_err_t ret;
+ rt_err_t ret = RT_EOK;
g_wdt_dev.wdt.ops = &g_wdt_ops;
/* register watchdog device */
- if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt", \
- RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
+ if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt",
+ RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
{
LOG_E("wdt device register failed.");
- return -RT_ERROR;
+ ret = -RT_ERROR;
+ }
+ else
+ {
+ LOG_D("wdt device register success.");
}
- LOG_D("wdt device register success.");
return ret;
}