summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcharlown <[email protected]>2021-09-08 16:45:55 +0800
committercharlown <[email protected]>2021-09-08 16:45:55 +0800
commit84111766f959685fb7b1af99f3f26bca5f7ef7d2 (patch)
tree3f9b1a94d371b21dd7dd992ea73e416b10876197
parent7aa4dfec8b1cc2a9ec5754555fe77babb235416f (diff)
[bsp/wch/arm/Libraries/ch32_drivers]: support ch32f10x hwtimer.
[bsp/wch/arm/ch32f103c8-core]: add hwtimer1~4.
-rw-r--r--bsp/wch/arm/Libraries/ch32_drivers/SConscript3
-rw-r--r--bsp/wch/arm/Libraries/ch32_drivers/drv_hwtimer_ch32f10x.c372
-rw-r--r--bsp/wch/arm/ch32f103c8-core/board/Kconfig168
-rw-r--r--bsp/wch/arm/ch32f103c8-core/board/board.c91
-rw-r--r--bsp/wch/arm/ch32f103c8-core/board/board.h3
5 files changed, 637 insertions, 0 deletions
diff --git a/bsp/wch/arm/Libraries/ch32_drivers/SConscript b/bsp/wch/arm/Libraries/ch32_drivers/SConscript
index 5a6ad33b67..c20517b2e4 100644
--- a/bsp/wch/arm/Libraries/ch32_drivers/SConscript
+++ b/bsp/wch/arm/Libraries/ch32_drivers/SConscript
@@ -29,6 +29,9 @@ if GetDepend('SOC_ARM_SERIES_CH32F103'):
if GetDepend(['RT_USING_WDT', 'BSP_USING_IWDT']):
src += ['drv_iwdt_ch32f10x.c']
+ if GetDepend(['RT_USING_HWTIMER', 'BSP_USING_HWTIMER']):
+ src += ['drv_hwtimer_ch32f10x.c']
+
src += ['drv_common.c']
path = [cwd]
diff --git a/bsp/wch/arm/Libraries/ch32_drivers/drv_hwtimer_ch32f10x.c b/bsp/wch/arm/Libraries/ch32_drivers/drv_hwtimer_ch32f10x.c
new file mode 100644
index 0000000000..6b22e0d5d4
--- /dev/null
+++ b/bsp/wch/arm/Libraries/ch32_drivers/drv_hwtimer_ch32f10x.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-08-10 charlown first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <board.h>
+
+#ifdef BSP_USING_HWTIMER
+
+#define LOG_TAG "drv.hwtimer"
+#include <drv_log.h>
+
+struct hwtimer_device
+{
+ struct rt_hwtimer_device parent;
+ TIM_TypeDef *periph;
+ IRQn_Type irqn;
+ char *name;
+};
+
+#ifdef BSP_USING_TIM1_HWTIMER
+struct hwtimer_device hwtimer_device1 =
+ {
+ .periph = TIM1,
+ .irqn = TIM1_UP_IRQn,
+ .name = "timer1"};
+#endif
+
+#ifdef BSP_USING_TIM2_HWTIMER
+struct hwtimer_device hwtimer_device2 =
+ {
+ .periph = TIM2,
+ .irqn = TIM2_IRQn,
+ .name = "timer2"};
+#endif
+
+#ifdef BSP_USING_TIM3_HWTIMER
+struct hwtimer_device hwtimer_device3 =
+ {
+ .periph = TIM3,
+ .irqn = TIM3_IRQn,
+ .name = "timer3"};
+#endif
+
+#ifdef BSP_USING_TIM4_HWTIMER
+struct hwtimer_device hwtimer_device4 =
+ {
+ .periph = TIM4,
+ .irqn = TIM4_IRQn,
+ .name = "timer4"};
+#endif
+
+static void ch32f1_hwtimer_init(struct rt_hwtimer_device *device, rt_uint32_t state)
+{
+ struct hwtimer_device *hwtimer_dev;
+ struct rt_hwtimer_info *hwtimer_info;
+ rt_uint32_t clk = 0;
+ rt_uint16_t prescaler_value = 0;
+
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseInitType;
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ RT_ASSERT(device != RT_NULL);
+
+ hwtimer_dev = (struct hwtimer_device *)device;
+
+ if (state)
+ {
+ ch32f1_hwtimer_clock_init(hwtimer_dev->periph);
+
+ hwtimer_info = ch32f1_hwtimer_info_config_get(hwtimer_dev->periph);
+
+ clk = ch32f1_hwtimer_clock_get(hwtimer_dev->periph);
+
+ prescaler_value = (rt_uint16_t)(clk / hwtimer_info->minfreq) - 1;
+
+ /*
+ * set interrupt callback one or each time need total time =
+ * (cnt + 1) * (1 / (clk/(prescaler_value + 1) ) )
+ */
+
+ TIM_TimeBaseInitType.TIM_Period = hwtimer_info->maxcnt - 1;
+ TIM_TimeBaseInitType.TIM_Prescaler = prescaler_value;
+ TIM_TimeBaseInitType.TIM_ClockDivision = TIM_CKD_DIV1;
+ TIM_TimeBaseInitType.TIM_RepetitionCounter = 0;
+
+ if (hwtimer_info == RT_NULL)
+ {
+ TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Up;
+ }
+ else
+ {
+ if (hwtimer_info->cntmode == HWTIMER_CNTMODE_UP)
+ {
+ TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Up;
+ }
+ else
+ {
+ TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Down;
+ }
+ }
+
+ TIM_TimeBaseInit(hwtimer_dev->periph, &TIM_TimeBaseInitType);
+
+ NVIC_InitStructure.NVIC_IRQChannel = hwtimer_dev->irqn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ TIM_ITConfig(hwtimer_dev->periph, TIM_IT_Update, ENABLE);
+ TIM_ClearITPendingBit(hwtimer_dev->periph, TIM_IT_Update);
+
+ LOG_D("%s init success", hwtimer_dev->name);
+ }
+}
+
+static rt_err_t ch32f1_hwtimer_start(struct rt_hwtimer_device *device, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
+{
+
+ struct hwtimer_device *hwtimer_dev;
+
+ RT_ASSERT(device != RT_NULL);
+
+ hwtimer_dev = (struct hwtimer_device *)device;
+
+ /*
+ * interrupt callback one or each time need total time =
+ * (cnt + 1) * (1 / (clk/(prescaler_value + 1) ) )
+ */
+
+ TIM_SetCounter(hwtimer_dev->periph, 0);
+ TIM_SetAutoreload(hwtimer_dev->periph, cnt - 1);
+
+ if (mode == HWTIMER_MODE_ONESHOT)
+ {
+ TIM_SelectOnePulseMode(hwtimer_dev->periph, TIM_OPMode_Single);
+ }
+ else
+ {
+ TIM_SelectOnePulseMode(hwtimer_dev->periph, TIM_OPMode_Repetitive);
+ }
+
+ TIM_Cmd(hwtimer_dev->periph, ENABLE);
+
+ LOG_D("%s start, cnt = %d", hwtimer_dev->name, cnt);
+
+ return RT_EOK;
+}
+
+static void ch32f1_hwtimer_stop(struct rt_hwtimer_device *device)
+{
+ struct hwtimer_device *hwtimer_dev;
+
+ RT_ASSERT(device != RT_NULL);
+
+ hwtimer_dev = (struct hwtimer_device *)device;
+
+ TIM_Cmd(hwtimer_dev->periph, DISABLE);
+
+ TIM_SetCounter(hwtimer_dev->periph, 0);
+}
+
+static rt_uint32_t ch32f1_hwtimer_counter_get(struct rt_hwtimer_device *device)
+{
+ struct hwtimer_device *hwtimer_dev;
+
+ RT_ASSERT(device != RT_NULL);
+
+ hwtimer_dev = (struct hwtimer_device *)device;
+
+ return hwtimer_dev->periph->CNT;
+}
+
+static rt_err_t ch32f1_hwtimer_control(struct rt_hwtimer_device *device, rt_uint32_t cmd, void *arg)
+{
+ struct hwtimer_device *hwtimer_dev;
+ rt_err_t result = RT_EOK;
+
+ RT_ASSERT(device != RT_NULL);
+
+ hwtimer_dev = (struct hwtimer_device *)device;
+
+ switch (cmd)
+ {
+ case HWTIMER_CTRL_FREQ_SET:
+ {
+ rt_uint32_t freq = 0;
+ rt_uint32_t clk = 0;
+ rt_uint16_t prescaler_value = 0;
+
+ /*
+ *set interrupt callback one or each time need total time =
+ * (cnt + 1) * (1 / (clk/(prescaler_value + 1) ) )
+ */
+ if (arg != RT_NULL)
+ {
+
+ freq = *((rt_uint32_t *)arg);
+
+ clk = ch32f1_hwtimer_clock_get(hwtimer_dev->periph);
+
+ prescaler_value = (rt_uint16_t)(clk / freq) - 1;
+
+ TIM_PrescalerConfig(hwtimer_dev->periph, prescaler_value, TIM_PSCReloadMode_Immediate);
+ }
+ else
+ {
+ result = RT_EINVAL;
+ }
+ }
+ break;
+
+ default:
+ result = RT_ENOSYS;
+ break;
+ }
+
+ return result;
+}
+
+static const struct rt_hwtimer_ops hwtimer_ops =
+ {
+ .init = ch32f1_hwtimer_init,
+ .start = ch32f1_hwtimer_start,
+ .stop = ch32f1_hwtimer_stop,
+ .count_get = ch32f1_hwtimer_counter_get,
+ .control = ch32f1_hwtimer_control,
+};
+
+static int rt_hw_hwtimer_init(void)
+{
+ rt_err_t ret;
+ struct rt_hwtimer_info *hwtimer_info;
+
+#ifdef BSP_USING_TIM1_HWTIMER
+ hwtimer_info = ch32f1_hwtimer_info_config_get(hwtimer_device1.periph);
+ hwtimer_device1.parent.info = hwtimer_info;
+ hwtimer_device1.parent.ops = &hwtimer_ops;
+ ret = rt_device_hwtimer_register(&hwtimer_device1.parent, hwtimer_device1.name, RT_NULL);
+ if (ret == RT_EOK)
+ {
+ LOG_D("hwtimer: %s register success.", hwtimer_device1.name);
+ }
+ else
+ {
+ LOG_D("hwtimer: %s register failed.", hwtimer_device1.name);
+ }
+#endif
+
+#ifdef BSP_USING_TIM2_HWTIMER
+ hwtimer_info = ch32f1_hwtimer_info_config_get(hwtimer_device2.periph);
+ hwtimer_device2.parent.info = hwtimer_info;
+ hwtimer_device2.parent.ops = &hwtimer_ops;
+ ret = rt_device_hwtimer_register(&hwtimer_device2.parent, hwtimer_device2.name, RT_NULL);
+ if (ret == RT_EOK)
+ {
+ LOG_D("hwtimer: %s register success.", hwtimer_device2.name);
+ }
+ else
+ {
+ LOG_D("hwtimer: %s register failed.", hwtimer_device2.name);
+ }
+#endif
+
+#ifdef BSP_USING_TIM3_HWTIMER
+ hwtimer_info = ch32f1_hwtimer_info_config_get(hwtimer_device3.periph);
+ hwtimer_device3.parent.info = hwtimer_info;
+ hwtimer_device3.parent.ops = &hwtimer_ops;
+ ret = rt_device_hwtimer_register(&hwtimer_device3.parent, hwtimer_device3.name, RT_NULL);
+ if (ret == RT_EOK)
+ {
+ LOG_D("hwtimer: %s register success.", hwtimer_device3.name);
+ }
+ else
+ {
+ LOG_D("hwtimer: %s register failed.", hwtimer_device3.name);
+ }
+#endif
+
+#ifdef BSP_USING_TIM4_HWTIMER
+ hwtimer_info = ch32f1_hwtimer_info_config_get(hwtimer_device4.periph);
+ hwtimer_device4.parent.info = hwtimer_info;
+ hwtimer_device4.parent.ops = &hwtimer_ops;
+ ret = rt_device_hwtimer_register(&hwtimer_device4.parent, hwtimer_device4.name, RT_NULL);
+ if (ret == RT_EOK)
+ {
+ LOG_D("hwtimer: %s register success.", hwtimer_device4.name);
+ }
+ else
+ {
+ LOG_D("hwtimer: %s register failed.", hwtimer_device4.name);
+ }
+#endif
+
+ return RT_EOK;
+}
+INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
+
+#ifdef BSP_USING_TIM1_HWTIMER
+void TIM1_UP_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ if (TIM_GetITStatus(hwtimer_device1.periph, TIM_IT_Update) == SET)
+ {
+ TIM_ClearITPendingBit(hwtimer_device1.periph, TIM_IT_Update);
+ rt_device_hwtimer_isr(&hwtimer_device1.parent);
+ }
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_TIM2_HWTIMER
+void TIM2_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ if (TIM_GetITStatus(hwtimer_device2.periph, TIM_IT_Update) == SET)
+ {
+ TIM_ClearITPendingBit(hwtimer_device2.periph, TIM_IT_Update);
+ rt_device_hwtimer_isr(&hwtimer_device2.parent);
+ }
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_TIM3_HWTIMER
+void TIM3_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ if (TIM_GetITStatus(hwtimer_device3.periph, TIM_IT_Update) == SET)
+ {
+ TIM_ClearITPendingBit(hwtimer_device3.periph, TIM_IT_Update);
+ rt_device_hwtimer_isr(&hwtimer_device3.parent);
+ }
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_TIM4_HWTIMER
+void TIM4_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ if (TIM_GetITStatus(hwtimer_device4.periph, TIM_IT_Update) == SET)
+ {
+ TIM_ClearITPendingBit(hwtimer_device4.periph, TIM_IT_Update);
+ rt_device_hwtimer_isr(&hwtimer_device4.parent);
+ }
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+
+#endif /* BSP_USING_HWTIMER */
+
diff --git a/bsp/wch/arm/ch32f103c8-core/board/Kconfig b/bsp/wch/arm/ch32f103c8-core/board/Kconfig
index 2bea1a66b5..f3a0c18f94 100644
--- a/bsp/wch/arm/ch32f103c8-core/board/Kconfig
+++ b/bsp/wch/arm/ch32f103c8-core/board/Kconfig
@@ -80,6 +80,174 @@ config LSI_VALUE
int
default 40000
+config BSP_USING_TIM
+ bool "using TIMx"
+ default n
+
+ if BSP_USING_TIM
+ config BSP_USING_HWTIMER
+ bool
+ select RT_USING_HWTIMER
+ default n
+
+ config BSP_USING_PWM
+ bool
+ select RT_USING_PWM
+ default n
+
+ config BSP_USING_TIM1
+ bool "using TIM1"
+ default n
+
+ if BSP_USING_TIM1
+ choice
+ prompt "using TIM1 as hwtimer or pwm mode"
+ default BSP_USING_TIM1_HWTIMER
+
+ config BSP_USING_TIM1_HWTIMER
+ bool "using TIM1 as hwtimer mode"
+ select BSP_USING_HWTIMER
+
+ config BSP_USING_TIM1_PWM
+ bool "using TIM1 as pwm mode"
+ select BSP_USING_PWM
+
+ endchoice
+
+ if BSP_USING_TIM1_PWM
+ config BSP_USING_TIM1_PWM_CH1
+ bool "using TIM1 channel 1 as pwm"
+ default n
+
+ config BSP_USING_TIM1_PWM_CH2
+ bool "using TIM1 channel 2 as pwm"
+ default n
+
+ config BSP_USING_TIM1_PWM_CH3
+ bool "using TIM1 channel 3 as pwm"
+
+ config BSP_USING_TIM1_PWM_CH4
+ bool "using TIM1 channel 4 as pwm"
+
+ endif
+
+ endif
+
+ config BSP_USING_TIM2
+ bool "using TIM2"
+ default n
+
+ if BSP_USING_TIM2
+ choice
+ prompt "using TIM2 as hwtimer or pwm mode"
+ default BSP_USING_TIM2_HWTIMER
+
+ config BSP_USING_TIM2_HWTIMER
+ bool "using TIM2 as hwtimer mode"
+ select BSP_USING_HWTIMER
+
+ config BSP_USING_TIM2_PWM
+ bool "using TIM2 as pwm mode"
+ select BSP_USING_PWM
+
+ endchoice
+
+ if BSP_USING_TIM2_PWM
+ config BSP_USING_TIM2_PWM_CH1
+ bool "using TIM2 channel 1 as pwm"
+ default n
+
+ config BSP_USING_TIM2_PWM_CH2
+ bool "using TIM2 channel 2 as pwm"
+ default n
+
+ config BSP_USING_TIM2_PWM_CH3
+ bool "using TIM2 channel 3 as pwm"
+
+ config BSP_USING_TIM2_PWM_CH4
+ bool "using TIM2 channel 4 as pwm"
+
+ endif
+
+ endif
+
+ config BSP_USING_TIM3
+ bool "using TIM3"
+ default n
+
+ if BSP_USING_TIM3
+ choice
+ prompt "using TIM3 as hwtimer or pwm mode"
+ default BSP_USING_TIM3_HWTIMER
+
+ config BSP_USING_TIM3_HWTIMER
+ bool "using TIM3 as hwtimer mode"
+ select BSP_USING_HWTIMER
+
+ config BSP_USING_TIM3_PWM
+ bool "using TIM3 as pwm mode"
+ select BSP_USING_PWM
+
+ endchoice
+
+ if BSP_USING_TIM3_PWM
+ config BSP_USING_TIM3_PWM_CH1
+ bool "using TIM3 channel 1 as pwm"
+ default n
+
+ config BSP_USING_TIM3_PWM_CH2
+ bool "using TIM3 channel 2 as pwm"
+ default n
+
+ config BSP_USING_TIM3_PWM_CH3
+ bool "using TIM3 channel 3 as pwm"
+
+ config BSP_USING_TIM3_PWM_CH4
+ bool "using TIM3 channel 4 as pwm"
+
+ endif
+
+ endif
+
+ config BSP_USING_TIM4
+ bool "using TIM4"
+ default n
+
+ if BSP_USING_TIM4
+ choice
+ prompt "using TIM4 as hwtimer or pwm mode"
+ default BSP_USING_TIM4_HWTIMER
+
+ config BSP_USING_TIM4_HWTIMER
+ bool "using TIM4 as hwtimer mode"
+ select BSP_USING_HWTIMER
+
+ config BSP_USING_TIM4_PWM
+ bool "using TIM4 as pwm mode"
+ select BSP_USING_PWM
+
+ endchoice
+
+ if BSP_USING_TIM4_PWM
+ config BSP_USING_TIM4_PWM_CH1
+ bool "using TIM4 channel 1 as pwm"
+ default n
+
+ config BSP_USING_TIM4_PWM_CH2
+ bool "using TIM4 channel 2 as pwm"
+ default n
+
+ config BSP_USING_TIM4_PWM_CH3
+ bool "using TIM4 channel 3 as pwm"
+
+ config BSP_USING_TIM4_PWM_CH4
+ bool "using TIM4 channel 4 as pwm"
+
+ endif
+
+ endif
+
+ endif
endmenu
menu "Onboard Peripheral Drivers"
diff --git a/bsp/wch/arm/ch32f103c8-core/board/board.c b/bsp/wch/arm/ch32f103c8-core/board/board.c
index c0494597a4..fe6b3df8da 100644
--- a/bsp/wch/arm/ch32f103c8-core/board/board.c
+++ b/bsp/wch/arm/ch32f103c8-core/board/board.c
@@ -200,4 +200,95 @@ void ch32f1_i2c_config(I2C_TypeDef *i2cx)
}
}
+void ch32f1_hwtimer_clock_init(TIM_TypeDef *timx)
+{
+ if (timx == TIM1)
+ {
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+ }
+
+ if (timx == TIM2)
+ {
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+ }
+
+ if (timx == TIM3)
+ {
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
+ }
+
+ if (timx == TIM4)
+ {
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
+ }
+}
+
+rt_uint32_t ch32f1_hwtimer_clock_get(TIM_TypeDef *timx)
+{
+ RCC_ClocksTypeDef RCC_Clocks;
+
+ RCC_GetClocksFreq(&RCC_Clocks);
+
+ /*tim1~4 all in HCLK*/
+ return RCC_Clocks.HCLK_Frequency;
+}
+
+struct rt_hwtimer_info hwtimer_info1 =
+ {
+ .maxfreq = 1000000,
+ .minfreq = 2000,
+ .maxcnt = 0xFFFF,
+ .cntmode = HWTIMER_CNTMODE_UP,
+};
+
+struct rt_hwtimer_info hwtimer_info2 =
+ {
+ .maxfreq = 1000000,
+ .minfreq = 2000,
+ .maxcnt = 0xFFFF,
+ .cntmode = HWTIMER_CNTMODE_UP,
+
+};
+
+struct rt_hwtimer_info hwtimer_info3 =
+ {
+ .maxfreq = 1000000,
+ .minfreq = 2000,
+ .maxcnt = 0xFFFF,
+ .cntmode = HWTIMER_CNTMODE_UP,
+
+};
+
+struct rt_hwtimer_info hwtimer_info4 =
+ {
+ .maxfreq = 1000000,
+ .minfreq = 2000,
+ .maxcnt = 0xFFFF,
+ .cntmode = HWTIMER_CNTMODE_UP,
+
+};
+
+struct rt_hwtimer_info *ch32f1_hwtimer_info_config_get(TIM_TypeDef *timx)
+{
+ struct rt_hwtimer_info *info = RT_NULL;
+
+ if (timx == TIM1)
+ {
+ info = &hwtimer_info1;
+ }
+ else if (timx == TIM2)
+ {
+ info = &hwtimer_info2;
+ }
+ else if (timx == TIM3)
+ {
+ info = &hwtimer_info3;
+ }
+ else if (timx == TIM4)
+ {
+ info = &hwtimer_info4;
+ }
+
+ return info;
+}
diff --git a/bsp/wch/arm/ch32f103c8-core/board/board.h b/bsp/wch/arm/ch32f103c8-core/board/board.h
index ad171c6d02..8bf4b819e4 100644
--- a/bsp/wch/arm/ch32f103c8-core/board/board.h
+++ b/bsp/wch/arm/ch32f103c8-core/board/board.h
@@ -50,6 +50,9 @@ void ch32f1_spi_clock_and_io_init(SPI_TypeDef* spix);
rt_uint32_t ch32f1_spi_clock_get(SPI_TypeDef* spix);
void ch32f1_i2c_clock_and_io_init(I2C_TypeDef* i2cx);
void ch32f1_i2c_config(I2C_TypeDef* i2cx);
+void ch32f1_hwtimer_clock_init(TIM_TypeDef *timx);
+rt_uint32_t ch32f1_hwtimer_clock_get(TIM_TypeDef *timx);
+struct rt_hwtimer_info* ch32f1_hwtimer_info_config_get(TIM_TypeDef *timx);