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
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+ #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
4979static 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
93129static 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