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
2848static 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
4980static 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
93130static 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