Skip to content

Commit 5734265

Browse files
committed
gd32/driver: fix inaccurate WDT clock timeout feeding issue
1 parent 5ae232b commit 5734265

File tree

1 file changed

+64
-24
lines changed

1 file changed

+64
-24
lines changed

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

Lines changed: 64 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_INFO
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,34 @@ 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+
/* Enable and wait for oscillator stabilization */
51+
rcu_osci_on(WDT_OSCI_TYPE);
52+
if (ERROR == rcu_osci_stab_wait(WDT_OSCI_TYPE))
3253
{
33-
LOG_E("failed init IRC40K clock for free watchdog.");
54+
LOG_E("failed init %s clock for free watchdog.", WDT_OSCI_TYPE);
3455
return -RT_EINVAL;
3556
}
3657

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);
58+
/* Configure RTC clock source for FWDGT */
59+
rcu_rtc_clock_config(WDT_OSCI_TYPE);
60+
61+
/* Calculate thresholds */
62+
g_wdt_dev.min_threshold_s = 1U;
63+
g_wdt_dev.max_threshold_s = ((WDT_MAX_RELOAD_VALUE + 1U) * WDT_PSC_DIVIDER) / WDT_CLOCK_FREQ;
64+
LOG_I("WDT clock: %u Hz (tick: %u Hz), threshold section [%u, %u]",
65+
WDT_CLOCK_FREQ, WDT_TICK_HZ,
66+
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
4167

68+
/* Configure FWDGT with max timeout */
4269
fwdgt_write_enable();
43-
fwdgt_config(0xfff, FWDGT_PSC_DIV256);
70+
if (fwdgt_config(WDT_MAX_RELOAD_VALUE, WDT_PSC_VALUE) != SUCCESS)
71+
{
72+
LOG_E("failed to configure FWDGT");
73+
return -RT_ERROR;
74+
}
4475
fwdgt_enable();
4576

46-
return 0;
77+
return RT_EOK;
4778
}
4879

4980
static rt_err_t gd32_wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
@@ -56,20 +87,26 @@ static rt_err_t gd32_wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
5687
fwdgt_counter_reload();
5788
break;
5889
case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
59-
param = *(rt_uint32_t *) arg;
60-
if ((param > g_wdt_dev.max_threshold_s) || \
90+
param = *(rt_uint32_t *)arg;
91+
if ((param > g_wdt_dev.max_threshold_s) ||
6192
(param < g_wdt_dev.min_threshold_s))
6293
{
63-
LOG_E("invalid param@%u.", param);
94+
LOG_E("invalid param@%u (out of [%u, %u])", param,
95+
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
6496
return -RT_EINVAL;
6597
}
6698
else
6799
{
68100
g_wdt_dev.current_threshold_s = param;
101+
rt_uint32_t reload_value = (param * WDT_TICK_HZ) - 1U;
102+
fwdgt_write_enable();
103+
if (fwdgt_config(reload_value, WDT_PSC_VALUE) != SUCCESS)
104+
{
105+
LOG_E("failed to set timeout %u s", param);
106+
return -RT_ERROR;
107+
}
108+
fwdgt_write_disable();
69109
}
70-
fwdgt_write_enable();
71-
fwdgt_config(param * 40000 >> 8, FWDGT_PSC_DIV256);
72-
fwdgt_write_disable();
73110
break;
74111
case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
75112
*(rt_uint32_t *)arg = g_wdt_dev.current_threshold_s;
@@ -92,17 +129,20 @@ static struct rt_watchdog_ops g_wdt_ops = {
92129

93130
static int rt_hw_wdt_init(void)
94131
{
95-
rt_err_t ret;
132+
rt_err_t ret = RT_EOK;
96133

97134
g_wdt_dev.wdt.ops = &g_wdt_ops;
98135
/* register watchdog device */
99-
if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt", \
100-
RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
136+
if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt",
137+
RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
101138
{
102139
LOG_E("wdt device register failed.");
103-
return -RT_ERROR;
140+
ret = -RT_ERROR;
141+
}
142+
else
143+
{
144+
LOG_D("wdt device register success.");
104145
}
105-
LOG_D("wdt device register success.");
106146

107147
return ret;
108148
}

0 commit comments

Comments
 (0)