Skip to content

Commit e72182d

Browse files
kurisaWRbb666
authored andcommitted
gd32/driver: fix inaccurate WDT clock timeout feeding issue
1 parent b2d6e2c commit e72182d

File tree

1 file changed

+63
-24
lines changed

1 file changed

+63
-24
lines changed

bsp/gd32/arm/libraries/gd32_drivers/drv_wdt.c

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,42 @@
11
/*
2-
* Copyright (c) 2006-2022, RT-Thread Development Team
2+
* Copyright (c) 2006-2025, RT-Thread Development Team
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*
66
* Change Logs:
77
* Date Author Notes
88
* 2022-01-25 iysheng first version
9+
* 2025-10-09 kurisaw fix inaccurate WDT clock timeout feeding issue
910
*/
1011

12+
#include <rtthread.h>
13+
#include <rtdevice.h>
14+
#include <rthw.h>
1115
#include <board.h>
1216

13-
#define DBG_TAG "drv.wdt"
14-
#define DBG_LVL DBG_INFO
17+
#define DBG_TAG "drv.wdt"
18+
#define DBG_LVL DBG_LOG
1519
#include <rtdbg.h>
1620

1721
#ifdef RT_USING_WDT
1822

19-
typedef struct {
23+
/* User-configurable macros for WDT clock source and prescaler */
24+
/* Default select oscillator type: RCU_LXTAL */
25+
#define WDT_OSCI_TYPE RCU_LXTAL
26+
27+
/* Prescaler divider value (must match WDT_PSC_VALUE) */
28+
#define WDT_PSC_DIVIDER 256U
29+
/* Prescaler register value */
30+
#define WDT_PSC_VALUE FWDGT_PSC_DIV256
31+
32+
/* Derived values */
33+
#define WDT_CLOCK_FREQ LXTAL_VALUE
34+
35+
#define WDT_TICK_HZ (WDT_CLOCK_FREQ / WDT_PSC_DIVIDER)
36+
#define WDT_MAX_RELOAD_VALUE 0xfffU
37+
38+
typedef struct
39+
{
2040
struct rt_watchdog_device wdt;
2141
rt_uint32_t min_threshold_s;
2242
rt_uint32_t max_threshold_s;
@@ -27,23 +47,33 @@ static gd32_wdt_device_t g_wdt_dev;
2747

2848
static rt_err_t gd32_wdt_init(rt_watchdog_t *wdt)
2949
{
30-
rcu_osci_on(RCU_IRC40K);
31-
if (ERROR == rcu_osci_stab_wait(RCU_IRC40K))
50+
#if defined(SOC_SERIES_GD32H7xx)
51+
/* Enable and wait for oscillator stabilization */
52+
rcu_osci_on(WDT_OSCI_TYPE);
53+
if (ERROR == rcu_osci_stab_wait(WDT_OSCI_TYPE))
3254
{
33-
LOG_E("failed init IRC40K clock for free watchdog.");
55+
LOG_E("failed init %u clock for free watchdog.", WDT_OSCI_TYPE);
3456
return -RT_EINVAL;
3557
}
58+
#endif
3659

37-
g_wdt_dev.min_threshold_s = 1;
38-
g_wdt_dev.max_threshold_s = (0xfff << 8) / 40000;
39-
LOG_I("threshold section [%u, %d]", \
40-
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
60+
/* Calculate thresholds */
61+
g_wdt_dev.min_threshold_s = 1U;
62+
g_wdt_dev.max_threshold_s = ((WDT_MAX_RELOAD_VALUE + 1U) * WDT_PSC_DIVIDER) / WDT_CLOCK_FREQ;
63+
LOG_I("WDT clock: %u Hz (tick: %u Hz), threshold section [%u, %u]",
64+
WDT_CLOCK_FREQ, WDT_TICK_HZ,
65+
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
4166

67+
/* Configure FWDGT with max timeout */
4268
fwdgt_write_enable();
43-
fwdgt_config(0xfff, FWDGT_PSC_DIV256);
69+
if (fwdgt_config(WDT_MAX_RELOAD_VALUE, WDT_PSC_VALUE) != SUCCESS)
70+
{
71+
LOG_E("failed to configure FWDGT");
72+
return -RT_ERROR;
73+
}
4474
fwdgt_enable();
4575

46-
return 0;
76+
return RT_EOK;
4777
}
4878

4979
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)
5686
fwdgt_counter_reload();
5787
break;
5888
case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
59-
param = *(rt_uint32_t *) arg;
60-
if ((param > g_wdt_dev.max_threshold_s) || \
89+
param = *(rt_uint32_t *)arg;
90+
if ((param > g_wdt_dev.max_threshold_s) ||
6191
(param < g_wdt_dev.min_threshold_s))
6292
{
63-
LOG_E("invalid param@%u.", param);
93+
LOG_E("invalid param@%u (out of [%u, %u])", param,
94+
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
6495
return -RT_EINVAL;
6596
}
6697
else
6798
{
6899
g_wdt_dev.current_threshold_s = param;
100+
rt_uint32_t reload_value = (param * WDT_TICK_HZ) - 1U;
101+
fwdgt_write_enable();
102+
if (fwdgt_config(reload_value, WDT_PSC_VALUE) != SUCCESS)
103+
{
104+
LOG_E("failed to set timeout %u s", param);
105+
return -RT_ERROR;
106+
}
107+
fwdgt_write_disable();
69108
}
70-
fwdgt_write_enable();
71-
fwdgt_config(param * 40000 >> 8, FWDGT_PSC_DIV256);
72-
fwdgt_write_disable();
73109
break;
74110
case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
75111
*(rt_uint32_t *)arg = g_wdt_dev.current_threshold_s;
@@ -92,17 +128,20 @@ static struct rt_watchdog_ops g_wdt_ops = {
92128

93129
static int rt_hw_wdt_init(void)
94130
{
95-
rt_err_t ret;
131+
rt_err_t ret = RT_EOK;
96132

97133
g_wdt_dev.wdt.ops = &g_wdt_ops;
98134
/* register watchdog device */
99-
if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt", \
100-
RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
135+
if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt",
136+
RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
101137
{
102138
LOG_E("wdt device register failed.");
103-
return -RT_ERROR;
139+
ret = -RT_ERROR;
140+
}
141+
else
142+
{
143+
LOG_D("wdt device register success.");
104144
}
105-
LOG_D("wdt device register success.");
106145

107146
return ret;
108147
}

0 commit comments

Comments
 (0)