|
|
@@ -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 <board.h>
|
|
|
+#include <rtdevice.h>
|
|
|
+#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
|