diff --git a/bsp/gd32/risc-v/gd32vw553h-eval/board/Kconfig b/bsp/gd32/risc-v/gd32vw553h-eval/board/Kconfig index 6bb5df41373..508d4e39d6d 100644 --- a/bsp/gd32/risc-v/gd32vw553h-eval/board/Kconfig +++ b/bsp/gd32/risc-v/gd32vw553h-eval/board/Kconfig @@ -78,6 +78,31 @@ menu "On-chip Peripheral Drivers" default n endif + menuconfig BSP_USING_HWTIMER + bool "Enable timer" + default n + select RT_USING_HWTIMER + if BSP_USING_HWTIMER + config BSP_USING_HWTIMER0 + bool "Enable TIM0" + default n + config BSP_USING_HWTIMER1 + bool "Enable TIM1" + default n + config BSP_USING_HWTIMER2 + bool "Enable TIM2" + default n + config BSP_USING_HWTIMER5 + bool "Enable TIM5" + default n + config BSP_USING_HWTIMER15 + bool "Enable TIM15" + default n + config BSP_USING_HWTIMER16 + bool "Enable TIM16" + default n + endif + source "$(BSP_DIR)/../libraries/gd32_drivers/Kconfig" endmenu diff --git a/bsp/gd32/risc-v/libraries/gd32_drivers/SConscript b/bsp/gd32/risc-v/libraries/gd32_drivers/SConscript index df963f3b78a..e447912490c 100644 --- a/bsp/gd32/risc-v/libraries/gd32_drivers/SConscript +++ b/bsp/gd32/risc-v/libraries/gd32_drivers/SConscript @@ -46,6 +46,7 @@ if GetDepend('RT_USING_ADC'): src += ['drv_adc.c'] path = [cwd] +path += [cwd + "/config"] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path) diff --git a/bsp/gd32/risc-v/libraries/gd32_drivers/config/hwtimer_config.h b/bsp/gd32/risc-v/libraries/gd32_drivers/config/hwtimer_config.h new file mode 100644 index 00000000000..b7bb2b371fd --- /dev/null +++ b/bsp/gd32/risc-v/libraries/gd32_drivers/config/hwtimer_config.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-01-30 pomin first version + */ + +#ifndef __HWTIMER_CONFIG_H__ +#define __HWTIMER_CONFIG_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "drv_hwtimer.h" + +#ifdef BSP_USING_HWTIMER0 +#ifndef HWTIMER0_CONFIG +#define HWTIMER0_CONFIG \ + { \ + "timer0", \ + { \ + TIMER0, \ + TIMER0_UP_IRQn, \ + RCU_TIMER0, \ + }, \ + {0}, \ + { \ + 1000000, \ + 1000, \ + 0xffff, \ + 0, /* count up mode */ \ + } \ + } +#endif /* HWTIMER0_CONFIG */ +#endif /* BSP_USING_HWTIMER0 */ + + +#ifdef BSP_USING_HWTIMER1 +#ifndef HWTIMER1_CONFIG +#define HWTIMER1_CONFIG \ + { \ + "timer1", \ + { \ + TIMER1, \ + TIMER1_IRQn, \ + RCU_TIMER1, \ + }, \ + {0}, \ + { \ + 1000000, \ + 1000, \ + 0xffff, \ + 0, /* count up mode */ \ + } \ + } +#endif /* HWTIMER1_CONFIG */ +#endif /* BSP_USING_HWTIMER1 */ + + +#ifdef BSP_USING_HWTIMER2 +#ifndef HWTIMER2_CONFIG +#define HWTIMER2_CONFIG \ + { \ + "timer2", \ + { \ + TIMER2, \ + TIMER2_IRQn, \ + RCU_TIMER2, \ + }, \ + {0}, \ + { \ + 1000000, \ + 1000, \ + 0xffff, \ + 0, /* count up mode */ \ + } \ + } +#endif /* HWTIMER2_CONFIG */ +#endif /* BSP_USING_HWTIMER2 */ + + +#ifdef BSP_USING_HWTIMER5 +#ifndef HWTIMER5_CONFIG +#define HWTIMER5_CONFIG \ + { \ + "timer5", \ + { \ + TIMER5, \ + TIMER5_IRQn, \ + RCU_TIMER5, \ + }, \ + {0}, \ + { \ + 1000000, \ + 1000, \ + 0xffff, \ + 0, /* count up mode */ \ + } \ + } +#endif /* HWTIMER5_CONFIG */ +#endif /* BSP_USING_HWTIMER5 */ + + +#ifdef BSP_USING_HWTIMER15 +#ifndef HWTIMER15_CONFIG +#define HWTIMER15_CONFIG \ + { \ + "timer15", \ + { \ + TIMER15, \ + TIMER15_IRQn, \ + RCU_TIMER15, \ + }, \ + {0}, \ + { \ + 1000000, \ + 1000, \ + 0xffff, \ + 0, /* count up mode */ \ + } \ + } +#endif /* HWTIMER15_CONFIG */ +#endif /* BSP_USING_HWTIMER15 */ + + +#ifdef BSP_USING_HWTIMER16 +#ifndef HWTIMER16_CONFIG +#define HWTIMER16_CONFIG \ + { \ + "timer16", \ + { \ + TIMER16, \ + TIMER16_IRQn, \ + RCU_TIMER16, \ + }, \ + {0}, \ + { \ + 1000000, \ + 1000, \ + 0xffff, \ + 0, /* count up mode */ \ + } \ + } +#endif /* HWTIMER16_CONFIG */ +#endif /* BSP_USING_HWTIMER16 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __HWTIMER_CONFIG_H__ */ diff --git a/bsp/gd32/risc-v/libraries/gd32_drivers/drv_hwtimer.c b/bsp/gd32/risc-v/libraries/gd32_drivers/drv_hwtimer.c new file mode 100644 index 00000000000..271a874d8db --- /dev/null +++ b/bsp/gd32/risc-v/libraries/gd32_drivers/drv_hwtimer.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-01-30 pomin first version + */ + +#include +#include +#include "drv_hwtimer.h" +#include "hwtimer_config.h" + +#ifdef BSP_USING_HWTIMER + +/* + * static void __set_timerx_freq + * Set freq with timerx + * + * @param timerx the pointer of TIMER_TypeDef + * @param freq of the timer clock + * @retval None + */ +static void __set_timerx_freq(uint32_t timerx, uint32_t freq) +{ + uint32_t ap1freq, ap2freq; + uint16_t prescaler; + uint32_t temp; + + if (timerx == TIMER0 || timerx == TIMER15 || timerx == TIMER16) + { + ap2freq = rcu_clock_freq_get(CK_APB2); + temp = RCU_CFG0 & RCU_CFG0_APB2PSC; + temp >>= 11; + /* whether should frequency doubling */ + temp = (temp < 4) ? 0 : 1; + + prescaler = (ap2freq << temp) / freq - 1; + } + else + { + ap1freq = rcu_clock_freq_get(CK_APB1); + temp = RCU_CFG0 & RCU_CFG0_APB1PSC; + temp >>= 8; + /* whether should frequency doubling */ + temp = (temp < 4) ? 0 : 1; + + prescaler = (ap1freq << temp) / freq - 1; + } + + timer_prescaler_config(timerx, prescaler, TIMER_PSC_RELOAD_NOW); +} + +static void gd32_hwtimer_init(struct rt_hwtimer_device *timer, rt_uint32_t state) +{ + uint32_t timer_base = (uint32_t)timer->parent.user_data; + timer_parameter_struct initpara; + + if (state) + { + timer_internal_clock_config(timer_base); + timer_struct_para_init(&initpara); + initpara.period = timer->info->maxcnt; + timer_init(timer_base, &initpara); + __set_timerx_freq(timer_base, timer->info->maxfreq); + } +} + +static rt_err_t gd32_hwtimer_start(struct rt_hwtimer_device *timer, \ + rt_uint32_t cnt, rt_hwtimer_mode_t mode) +{ + uint32_t timer_base = (uint32_t)timer->parent.user_data; + + if (mode == HWTIMER_MODE_ONESHOT) + { + timer_single_pulse_mode_config(timer_base, TIMER_SP_MODE_SINGLE); + } + else if (mode == HWTIMER_MODE_PERIOD) + { + timer_single_pulse_mode_config(timer_base, TIMER_SP_MODE_REPETITIVE); + } + + timer_counter_value_config(timer_base, 0); + timer_autoreload_value_config(timer_base, cnt - 1); + timer_enable(timer_base); + + return 0; +} + +static void gd32_hwtimer_stop(struct rt_hwtimer_device *timer) +{ + uint32_t timer_base = (uint32_t)timer->parent.user_data; + + timer_disable(timer_base); +} + +static rt_uint32_t gd32_hwtimer_count_get(struct rt_hwtimer_device *timer) +{ + uint32_t timer_base = (uint32_t)timer->parent.user_data; + rt_uint32_t count; + + count = timer_counter_read(timer_base); + + return count; +} + +static rt_err_t gd32_hwtimer_control(struct rt_hwtimer_device *timer, rt_uint32_t cmd, \ + void *args) +{ + int ret = RT_EOK; + rt_int32_t freq; + rt_hwtimer_mode_t mode; + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + freq = *(rt_uint32_t *)args; + __set_timerx_freq((uint32_t)timer->parent.user_data, freq); + break; + default: + rt_kprintf("invalid cmd:%x\n", cmd); + ret = -RT_EINVAL; + break; + } + + return ret; +} + +static const struct rt_hwtimer_ops g_gd32_hwtimer_ops = { + gd32_hwtimer_init, + gd32_hwtimer_start, + gd32_hwtimer_stop, + gd32_hwtimer_count_get, + gd32_hwtimer_control, +}; + +static gd32_hwtimer_device g_gd32_hwtimer[] = { +#ifdef BSP_USING_HWTIMER0 + HWTIMER0_CONFIG, +#endif +#ifdef BSP_USING_HWTIMER1 + HWTIMER1_CONFIG, +#endif +#ifdef BSP_USING_HWTIMER2 + HWTIMER2_CONFIG, +#endif +#ifdef BSP_USING_HWTIMER5 + HWTIMER5_CONFIG, +#endif +#ifdef BSP_USING_HWTIMER15 + HWTIMER15_CONFIG, +#endif +#ifdef BSP_USING_HWTIMER16 + HWTIMER16_CONFIG, +#endif +}; + +#ifdef BSP_USING_HWTIMER0 +void TIMER0_UP_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM0_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM0_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER1 +void TIMER1_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM1_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM1_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER2 +void TIMER2_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM2_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM2_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER3 +void TIMER3_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM3_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM3_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER4 +void TIMER4_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM4_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM4_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER5 +void TIMER5_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM5_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM5_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER6 +void TIMER6_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM6_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM6_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +#ifdef BSP_USING_HWTIMER7 +void TIMER7_UP_IRQHandler(void) +{ + rt_interrupt_enter(); + rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM7_INDEX].hwtimer_dev); + timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM7_INDEX].hwtimer_dev.parent.user_data, \ + TIMER_INT_UP); + rt_interrupt_leave(); +} +#endif + +static int rt_hwtimer_init(void) +{ + int ret = 0, i = 0; + + for (; i < sizeof(g_gd32_hwtimer) / sizeof(g_gd32_hwtimer[0]); i++) + { + g_gd32_hwtimer[i].hwtimer_dev.ops = &g_gd32_hwtimer_ops; + g_gd32_hwtimer[i].hwtimer_dev.info = &g_gd32_hwtimer[i].hwtimer_info; + + rcu_periph_clock_enable(g_gd32_hwtimer[i].hw_data.rcu); + ECLIC_SetPriorityIRQ(g_gd32_hwtimer[i].hw_data.irqn, 0); + ECLIC_EnableIRQ(g_gd32_hwtimer[i].hw_data.irqn); + timer_interrupt_enable(g_gd32_hwtimer[i].hw_data.reg_base, TIMER_INT_UP); + ret = rt_device_hwtimer_register(&g_gd32_hwtimer[i].hwtimer_dev, \ + g_gd32_hwtimer[i].dev_name, (void *)g_gd32_hwtimer[i].hw_data.reg_base); + if (RT_EOK != ret) + { + rt_kprintf("failed register %s, err=%d\n", g_gd32_hwtimer[i].dev_name, \ + ret); + break; + } + } + + return ret; +} +INIT_BOARD_EXPORT(rt_hwtimer_init); +#endif diff --git a/bsp/gd32/risc-v/libraries/gd32_drivers/drv_hwtimer.h b/bsp/gd32/risc-v/libraries/gd32_drivers/drv_hwtimer.h new file mode 100644 index 00000000000..730877845b5 --- /dev/null +++ b/bsp/gd32/risc-v/libraries/gd32_drivers/drv_hwtimer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-01-30 pomin first version + */ + +#ifndef __DRV_HWTIMER_H__ +#define __DRV_HWTIMER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef RT_USING_HWTIMER + +typedef struct { + uint32_t reg_base; + IRQn_Type irqn; + rcu_periph_enum rcu; +} gd32_hwtimer_data; + +typedef struct { + char dev_name[RT_NAME_MAX]; + const gd32_hwtimer_data hw_data; + rt_hwtimer_t hwtimer_dev; + const struct rt_hwtimer_info hwtimer_info; +} gd32_hwtimer_device; + +enum timer_index_E { +#ifdef BSP_USING_HWTIMER0 + TIM0_INDEX, +#endif +#ifdef BSP_USING_HWTIMER1 + TIM1_INDEX, +#endif +#ifdef BSP_USING_HWTIMER2 + TIM2_INDEX, +#endif +#ifdef BSP_USING_HWTIMER5 + TIM5_INDEX, +#endif +#ifdef BSP_USING_HWTIMER15 + TIM15_INDEX, +#endif +#ifdef BSP_USING_HWTIMER16 + TIM16_INDEX, +#endif +}; + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __DRV_HWTIMER_H__ */