فهرست منبع

[bsp][ch32v307]补全PWM设备,并为每个PWM设备添加条件编译,减少代码量 (#6548)

* 新增硬件定时器功能

* 新增定时器功能

* Update Kconfig

* Update bsp/wch/risc-v/Libraries/ch32_drivers/drv_hwtimer.h

Co-authored-by: Man, Jianting (Meco) <920369182@qq.com>

* Update Kconfig

* 添加剩余的PWM设备,并为每个PWM设备添加条件编译,减少代码量

* Update drv_pwm.c

* 根据建议进行修改

* 已根据建议修改

* Update bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c

Co-authored-by: Man, Jianting (Meco) <920369182@qq.com>

* Update bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h

Co-authored-by: Man, Jianting (Meco) <920369182@qq.com>

* Update bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c

Co-authored-by: Man, Jianting (Meco) <920369182@qq.com>

Co-authored-by: Man, Jianting (Meco) <920369182@qq.com>
self-confident neko 2 سال پیش
والد
کامیت
11f52eebcf
2فایلهای تغییر یافته به همراه1003 افزوده شده و 628 حذف شده
  1. 963 628
      bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c
  2. 40 0
      bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h

+ 963 - 628
bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c

@@ -1,628 +1,963 @@
-/*
- * Copyright (c) 2006-2022, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date           Author            Notes
- * 2021-09-23     charlown          first version
- * 2022-10-14     hg0720            the first version which add from wch
- */
-
-#include <rtthread.h>
-#include <rtdevice.h>
-#include <drivers/rt_drv_pwm.h>
-#include <drivers/hwtimer.h>
-#include <board.h>
-
-#ifdef BSP_USING_PWM
-
-#define LOG_TAG "drv.pwm"
-#include <drv_log.h>
-
-#ifndef ITEM_NUM
-#define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
-#endif
-
-#define MAX_COUNTER 65535
-#define MIN_COUNTER 2
-#define MIN_PULSE 2
-
-struct rtdevice_pwm_device
-{
-    struct rt_device_pwm parent;
-    TIM_TypeDef* periph;
-    rt_uint8_t channel[4];
-    char* name;
-};
-
-void ch32_tim_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 ch32_tim_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* ch32_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;
-}
-
-void ch32_pwm_io_init(TIM_TypeDef* timx, rt_uint8_t channel)
-{
-    GPIO_InitTypeDef GPIO_InitStructure;
-
-    if (timx == TIM1)
-    {
-        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
-        if (channel == TIM_Channel_1)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_2)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_3)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_4)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-    }
-
-    if (timx == TIM2)
-    {
-        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
-        if (channel == TIM_Channel_1)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_2)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_3)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_4)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-    }
-
-    if (timx == TIM3)
-    {
-        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
-
-        if (channel == TIM_Channel_1)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_2)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOA, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_3)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOB, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_4)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOB, &GPIO_InitStructure);
-        }
-    }
-
-    if (timx == TIM4)
-    {
-        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
-
-        if (channel == TIM_Channel_1)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOB, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_2)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOB, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_3)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOB, &GPIO_InitStructure);
-        }
-        if (channel == TIM_Channel_4)
-        {
-            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
-            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-            GPIO_Init(GPIOB, &GPIO_InitStructure);
-        }
-    }
-}
-
-/*
- * channel = 0xFF: the channel is not use.
- */
-struct rtdevice_pwm_device pwm_device_list[] =
-{
-#ifdef BSP_USING_TIM1_PWM
-    {
-        .periph = TIM1,
-        .name = "pwm1",
-#ifdef BSP_USING_TIM1_PWM_CH1
-        .channel[0] = TIM_Channel_1,
-#else
-        .channel[0] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM1_PWM_CH2
-        .channel[1] = TIM_Channel_2,
-#else
-        .channel[1] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM1_PWM_CH3
-        .channel[2] = TIM_Channel_3,
-#else
-        .channel[2] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM1_PWM_CH4
-        .channel[3] = TIM_Channel_4,
-#else
-        .channel[3] = 0xFF,
-#endif
-    },
-#endif /* BSP_USING_TIM1_PWM */
-
-#ifdef BSP_USING_TIM2_PWM
-    {
-        .periph = TIM2,
-        .name = "pwm2",
-#ifdef BSP_USING_TIM2_PWM_CH1
-        .channel[0] = TIM_Channel_1,
-#else
-        .channel[0] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM2_PWM_CH2
-        .channel[1] = TIM_Channel_2,
-#else
-        .channel[1] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM2_PWM_CH3
-        .channel[2] = TIM_Channel_3,
-#else
-        .channel[2] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM2_PWM_CH4
-        .channel[3] = TIM_Channel_4,
-#else
-        .channel[3] = 0xFF,
-#endif
-    },
-#endif /* BSP_USING_TIM2_PWM */
-
-#ifdef BSP_USING_TIM3_PWM
-    {
-        .periph = TIM3,
-        .name = "pwm3",
-#ifdef BSP_USING_TIM3_PWM_CH1
-        .channel[0] = TIM_Channel_1,
-#else
-        .channel[0] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM3_PWM_CH2
-        .channel[1] = TIM_Channel_2,
-#else
-        .channel[1] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM3_PWM_CH3
-        .channel[2] = TIM_Channel_3,
-#else
-        .channel[2] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM3_PWM_CH4
-        .channel[3] = TIM_Channel_4,
-#else
-        .channel[3] = 0xFF,
-#endif
-    },
-#endif /* BSP_USING_TIM3_PWM */
-
-#ifdef BSP_USING_TIM4_PWM
-    {
-        .periph = TIM4,
-        .name = "pwm4",
-#ifdef BSP_USING_TIM4_PWM_CH1
-        .channel[0] = TIM_Channel_1,
-#else
-        .channel[0] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM4_PWM_CH2
-        .channel[1] = TIM_Channel_2,
-#else
-        .channel[1] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM4_PWM_CH3
-        .channel[2] = TIM_Channel_3,
-#else
-        .channel[2] = 0xFF,
-#endif
-
-#ifdef BSP_USING_TIM4_PWM_CH4
-        .channel[3] = TIM_Channel_4,
-#else
-        .channel[3] = 0xFF,
-#endif
-    },
-#endif /* BSP_USING_TIM4_PWM */
-};
-
-static rt_err_t ch32_pwm_device_enable(struct rt_device_pwm* device, struct rt_pwm_configuration* configuration, rt_bool_t enable)
-{
-    struct rtdevice_pwm_device* pwm_device;
-    rt_uint32_t channel_index;
-    rt_uint16_t ccx_state;
-
-    pwm_device = (struct rtdevice_pwm_device*)device;
-    channel_index = configuration->channel;
-
-    if (enable == RT_TRUE)
-    {
-        ccx_state = TIM_CCx_Enable;
-    }
-    else
-    {
-        ccx_state = TIM_CCx_Disable;
-    }
-
-    if (channel_index <= 4 && channel_index > 0)
-    {
-        if (pwm_device->channel[channel_index - 1] == 0xFF)
-        {
-            return RT_EINVAL;
-        }
-        TIM_CCxCmd(pwm_device->periph, pwm_device->channel[channel_index - 1], ccx_state);
-    }
-    else
-    {
-        return RT_EINVAL;
-    }
-
-    TIM_Cmd(pwm_device->periph, ENABLE);
-
-    return RT_EOK;
-}
-
-static rt_err_t ch32_pwm_device_get(struct rt_device_pwm* device, struct rt_pwm_configuration* configuration)
-{
-    struct rtdevice_pwm_device* pwm_device;
-    rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
-    rt_uint32_t channel_index;
-    rt_uint32_t tim_clock;
-
-    pwm_device = (struct rtdevice_pwm_device*)device;
-    tim_clock = ch32_tim_clock_get(pwm_device->periph);
-    channel_index = configuration->channel;
-    arr_counter = pwm_device->periph->ATRLR + 1;
-    prescaler = pwm_device->periph->PSC + 1;
-    sample_freq = (tim_clock / prescaler) / arr_counter;
-
-    /* unit:ns */
-    configuration->period = 1000000000 / sample_freq;
-
-    if (channel_index == 1)
-    {
-        ccr_counter = pwm_device->periph->CH1CVR + 1;
-        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
-    }
-    else if (channel_index == 2)
-    {
-        ccr_counter = pwm_device->periph->CH2CVR + 1;
-        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
-    }
-    else if (channel_index == 3)
-    {
-        ccr_counter = pwm_device->periph->CH3CVR + 1;
-        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
-    }
-    else if (channel_index == 4)
-    {
-        ccr_counter = pwm_device->periph->CH4CVR + 1;
-        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
-    }
-    else
-    {
-        return RT_EINVAL;
-    }
-
-    return RT_EOK;
-}
-
-static rt_err_t ch32_pwm_device_set(struct rt_device_pwm* device, struct rt_pwm_configuration* configuration)
-{
-    struct rtdevice_pwm_device* pwm_device;
-    rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
-    rt_uint32_t channel_index;
-    rt_uint32_t tim_clock;
-    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitType;
-    TIM_OCInitTypeDef TIM_OCInitType;
-
-    pwm_device = (struct rtdevice_pwm_device*)device;
-    tim_clock = ch32_tim_clock_get(pwm_device->periph);
-    channel_index = configuration->channel;
-
-    /* change to freq, unit:Hz */
-    sample_freq = 1000000000 / configuration->period;
-
-    /* counter = (tim_clk / prescaler) / sample_freq */
-    /* normally, tim_clk is not need div, if arr_counter over 65536, need div. */
-    prescaler = 1;
-    arr_counter = (tim_clock / prescaler) / sample_freq;
-
-    if (arr_counter > MAX_COUNTER)
-    {
-        /* need div tim_clock
-         * and round up the prescaler value.
-         * (tim_clock >> 16) = tim_clock / 65536
-         */
-        if ((tim_clock >> 16) % sample_freq == 0)
-            prescaler = (tim_clock >> 16) / sample_freq;
-        else
-            prescaler = (tim_clock >> 16) / sample_freq + 1;
-
-        /* counter = (tim_clk / prescaler) / sample_freq */
-        arr_counter = (tim_clock / prescaler) / sample_freq;
-    }
-    /* ccr_counter = duty cycle * arr_counter */
-    ccr_counter = (configuration->pulse * 100 / configuration->period) * arr_counter / 100;
-
-    /* check arr_counter > 1, cxx_counter > 1 */
-    if (arr_counter < MIN_COUNTER)
-    {
-        arr_counter = MIN_COUNTER;
-    }
-    if (ccr_counter < MIN_PULSE)
-    {
-        ccr_counter = MIN_PULSE;
-    }
-
-    /* TMRe base configuration */
-    TIM_TimeBaseStructInit(&TIM_TimeBaseInitType);
-    TIM_TimeBaseInitType.TIM_Period = arr_counter - 1;
-    TIM_TimeBaseInitType.TIM_Prescaler = prescaler - 1;
-    TIM_TimeBaseInitType.TIM_ClockDivision = TIM_CKD_DIV1;
-    TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Up;
-    TIM_TimeBaseInit(pwm_device->periph, &TIM_TimeBaseInitType);
-
-    TIM_OCStructInit(&TIM_OCInitType);
-    TIM_OCInitType.TIM_OCMode = TIM_OCMode_PWM1;
-    TIM_OCInitType.TIM_OutputState = TIM_OutputState_Enable;
-    TIM_OCInitType.TIM_Pulse = ccr_counter - 1;
-    TIM_OCInitType.TIM_OCPolarity = TIM_OCPolarity_High;
-
-    if (channel_index == 1)
-    {
-        TIM_OC1Init(pwm_device->periph, &TIM_OCInitType);
-        TIM_OC1PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
-    }
-    else if (channel_index == 2)
-    {
-        TIM_OC2Init(pwm_device->periph, &TIM_OCInitType);
-        TIM_OC2PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
-    }
-    else if (channel_index == 3)
-    {
-        TIM_OC3Init(pwm_device->periph, &TIM_OCInitType);
-        TIM_OC3PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
-    }
-    else if (channel_index == 4)
-    {
-        TIM_OC4Init(pwm_device->periph, &TIM_OCInitType);
-        TIM_OC4PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
-    }
-    else
-    {
-        return RT_EINVAL;
-    }
-
-    TIM_ARRPreloadConfig(pwm_device->periph, ENABLE);
-    TIM_CtrlPWMOutputs(pwm_device->periph, ENABLE);
-
-    return RT_EOK;
-}
-
-static rt_err_t drv_pwm_control(struct rt_device_pwm* device, int cmd, void* arg)
-{
-    struct rt_pwm_configuration* configuration;
-
-    configuration = (struct rt_pwm_configuration*)arg;
-
-    switch (cmd)
-    {
-    case PWM_CMD_ENABLE:
-        return ch32_pwm_device_enable(device, configuration, RT_TRUE);
-    case PWM_CMD_DISABLE:
-        return ch32_pwm_device_enable(device, configuration, RT_FALSE);
-    case PWM_CMD_SET:
-        return ch32_pwm_device_set(device, configuration);
-    case PWM_CMD_GET:
-        return ch32_pwm_device_get(device, configuration);
-    default:
-        return RT_EINVAL;
-    }
-}
-
-static struct rt_pwm_ops pwm_ops =
-{
-    .control = drv_pwm_control
-};
-
-static int rt_hw_pwm_init(void)
-{
-    int result = RT_EOK;
-    int index = 0;
-    int channel_index;
-
-    for (index = 0; index < ITEM_NUM(pwm_device_list); index++)
-    {
-        ch32_tim_clock_init(pwm_device_list[index].periph);
-        for (channel_index = 0; channel_index < sizeof(pwm_device_list[index].channel); channel_index++)
-        {
-            if (pwm_device_list[index].channel[channel_index] != 0xFF)
-            {
-                ch32_pwm_io_init(pwm_device_list[index].periph, pwm_device_list[index].channel[channel_index]);
-            }
-        }
-
-        if (rt_device_pwm_register(&pwm_device_list[index].parent, pwm_device_list[index].name, &pwm_ops, RT_NULL) == RT_EOK)
-        {
-            LOG_D("%s register success", pwm_device_list[index].name);
-        }
-        else
-        {
-            LOG_D("%s register failed", pwm_device_list[index].name);
-            result = -RT_ERROR;
-        }
-    }
-
-    return result;
-}
-
-INIT_BOARD_EXPORT(rt_hw_pwm_init);
-
-#endif /* BSP_USING_PWM */
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2021-09-23     charlown          first version
+ * 2022-10-14     hg0720            the first version which add from wch
+ * 2022-10-20     MXH               add the remaining timers
+ */
+
+#include "drv_pwm.h"
+
+#ifdef BSP_USING_PWM
+
+#define LOG_TAG "drv.pwm"
+#include <drv_log.h>
+
+void ch32_tim_clock_init(TIM_TypeDef* timx)
+{
+#ifdef BSP_USING_TIM1_PWM
+    if (timx == TIM1)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+    }
+#endif/* BSP_USING_TIM1_PWM */
+
+#ifdef BSP_USING_TIM2_PWM
+    if (timx == TIM2)
+    {
+        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+    }
+#endif/* BSP_USING_TIM2_PWM */
+
+#ifdef BSP_USING_TIM3_PWM
+    if (timx == TIM3)
+    {
+        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
+    }
+#endif/* BSP_USING_TIM3_PWM */
+
+#ifdef BSP_USING_TIM4_PWM
+    if (timx == TIM4)
+    {
+        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
+    }
+#endif/* BSP_USING_TIM4_PWM */
+
+#ifdef BSP_USING_TIM5_PWM
+    if (timx == TIM5)
+    {
+        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
+    }
+#endif/* BSP_USING_TIM5_PWM */
+
+    /* TIM6 and TIM7 don't support PWM Mode. */
+
+#ifdef BSP_USING_TIM8_PWM
+    if (timx == TIM8)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
+    }
+#endif/* BSP_USING_TIM8_PWM */
+
+#ifdef BSP_USING_TIM9_PWM
+    if (timx == TIM9)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE);
+    }
+#endif/* BSP_USING_TIM9_PWM */
+
+#ifdef BSP_USING_TIM10_PWM
+    if (timx == TIM10)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);
+    }
+#endif/* BSP_USING_TIM10_PWM */
+}
+
+rt_uint32_t ch32_tim_clock_get(TIM_TypeDef* timx)
+{
+    RCC_ClocksTypeDef RCC_Clocks;
+    RCC_GetClocksFreq(&RCC_Clocks);
+
+    /*tim1~10 all in HCLK*/
+    return RCC_Clocks.HCLK_Frequency;
+}
+
+/*
+ * NOTE:  some pwm pins of some timers are reused,
+ *          please keep caution when using pwm
+ */
+
+void ch32_pwm_io_init(TIM_TypeDef* timx, rt_uint8_t channel)
+{
+    GPIO_InitTypeDef GPIO_InitStructure;
+
+#ifdef BSP_USING_TIM1_PWM
+    if (timx == TIM1)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+
+#ifdef BSP_USING_TIM1_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM1_PWM_CH1 */
+
+#ifdef BSP_USING_TIM1_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM1_PWM_CH2 */
+
+#ifdef BSP_USING_TIM1_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM1_PWM_CH3 */
+
+#ifdef BSP_USING_TIM1_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM1_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM1_PWM */
+
+#ifdef BSP_USING_TIM2_PWM
+    if (timx == TIM2)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+
+#ifdef BSP_USING_TIM2_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM2_PWM_CH1 */
+
+#ifdef BSP_USING_TIM2_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM2_PWM_CH2 */
+
+#ifdef BSP_USING_TIM2_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM2_PWM_CH3 */
+
+#ifdef BSP_USING_TIM2_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM2_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM2_PWM */
+
+#ifdef BSP_USING_TIM3_PWM
+    if (timx == TIM3)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+#ifdef BSP_USING_TIM3_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM3_PWM_CH1 */
+
+#ifdef BSP_USING_TIM3_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM3_PWM_CH2 */
+
+#ifdef BSP_USING_TIM3_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM3_PWM_CH3 */
+
+#ifdef BSP_USING_TIM3_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM3_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM3_PWM */
+
+#ifdef BSP_USING_TIM4_PWM
+    if (timx == TIM4)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+#ifdef BSP_USING_TIM4_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM4_PWM_CH1 */
+
+#ifdef BSP_USING_TIM4_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM4_PWM_CH2 */
+
+#ifdef BSP_USING_TIM4_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM4_PWM_CH3 */
+
+#ifdef BSP_USING_TIM4_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM4_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM4_PWM */
+
+#ifdef BSP_USING_TIM5_PWM
+    if (timx == TIM5)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+
+#ifdef BSP_USING_TIM5_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM5_PWM_CH1 */
+
+#ifdef BSP_USING_TIM5_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM5_PWM_CH2 */
+
+#ifdef BSP_USING_TIM5_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM5_PWM_CH3 */
+
+#ifdef BSP_USING_TIM5_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM5_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM5_PWM */
+
+    /* TIM6 and TIM7 don't support PWM Mode. */
+
+#ifdef BSP_USING_TIM8_PWM
+    if (timx == TIM8)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+
+/* I don't test it, because there is a 10M-PHY ETH port on my board,
+ * which uses the following four pins.
+ * You can try it on a board without a 10M-PHY ETH port. */
+#ifdef BSP_USING_TIM8_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM8_PWM_CH1 */
+
+#ifdef BSP_USING_TIM8_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM8_PWM_CH2 */
+
+#ifdef BSP_USING_TIM8_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM8_PWM_CH3 */
+
+#ifdef BSP_USING_TIM8_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM8_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM8_PWM */
+
+#ifdef BSP_USING_TIM9_PWM
+    if (timx == TIM9)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+
+#ifdef BSP_USING_TIM9_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM9_PWM_CH1 */
+
+#ifdef BSP_USING_TIM9_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM9_PWM_CH2 */
+
+#ifdef BSP_USING_TIM9_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOA, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM9_PWM_CH3 */
+
+#ifdef BSP_USING_TIM9_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM9_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM9_PWM */
+
+#ifdef BSP_USING_TIM10_PWM
+    if (timx == TIM10)
+    {
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+
+#ifdef BSP_USING_TIM10_PWM_CH1
+        if (channel == TIM_Channel_1)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM10_PWM_CH1 */
+
+#ifdef BSP_USING_TIM10_PWM_CH2
+        if (channel == TIM_Channel_2)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOB, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM10_PWM_CH2 */
+
+#ifdef BSP_USING_TIM10_PWM_CH3
+        if (channel == TIM_Channel_3)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM10_PWM_CH3 */
+
+#ifdef BSP_USING_TIM10_PWM_CH4
+        if (channel == TIM_Channel_4)
+        {
+            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
+            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+            GPIO_Init(GPIOC, &GPIO_InitStructure);
+        }
+#endif/* BSP_USING_TIM10_PWM_CH4 */
+    }
+#endif/* BSP_USING_TIM10_PWM */
+}
+
+/*
+ * channel = FLAG_NOT_INIT: the channel is not use.
+ */
+struct rtdevice_pwm_device pwm_device_list[] =
+{
+#ifdef BSP_USING_TIM1_PWM
+    {
+        .periph = TIM1,
+        .name = "pwm1",
+#ifdef BSP_USING_TIM1_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM1_PWM_CH1 */
+
+#ifdef BSP_USING_TIM1_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM1_PWM_CH2 */
+
+#ifdef BSP_USING_TIM1_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM1_PWM_CH3 */
+
+#ifdef BSP_USING_TIM1_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM1_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM1_PWM */
+
+#ifdef BSP_USING_TIM2_PWM
+    {
+        .periph = TIM2,
+        .name = "pwm2",
+#ifdef BSP_USING_TIM2_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM2_PWM_CH1 */
+
+#ifdef BSP_USING_TIM2_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM2_PWM_CH2 */
+
+#ifdef BSP_USING_TIM2_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM2_PWM_CH3 */
+
+#ifdef BSP_USING_TIM2_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM2_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM2_PWM */
+
+#ifdef BSP_USING_TIM3_PWM
+    {
+        .periph = TIM3,
+        .name = "pwm3",
+#ifdef BSP_USING_TIM3_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM3_PWM_CH1 */
+
+#ifdef BSP_USING_TIM3_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM3_PWM_CH2 */
+
+#ifdef BSP_USING_TIM3_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM3_PWM_CH3 */
+
+#ifdef BSP_USING_TIM3_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM3_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM3_PWM */
+
+#ifdef BSP_USING_TIM4_PWM
+    {
+        .periph = TIM4,
+        .name = "pwm4",
+#ifdef BSP_USING_TIM4_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM4_PWM_CH1 */
+
+#ifdef BSP_USING_TIM4_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM4_PWM_CH2 */
+
+#ifdef BSP_USING_TIM4_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM4_PWM_CH3 */
+
+#ifdef BSP_USING_TIM4_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM4_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM4_PWM */
+
+#ifdef BSP_USING_TIM5_PWM
+    {
+        .periph = TIM5,
+        .name = "pwm5",
+#ifdef BSP_USING_TIM5_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM5_PWM_CH1 */
+
+#ifdef BSP_USING_TIM5_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM5_PWM_CH2 */
+
+#ifdef BSP_USING_TIM5_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM5_PWM_CH3 */
+
+#ifdef BSP_USING_TIM5_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM5_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM5_PWM */
+
+#ifdef BSP_USING_TIM8_PWM
+    {
+        .periph = TIM8,
+        .name = "pwm8",
+#ifdef BSP_USING_TIM8_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM8_PWM_CH1 */
+
+#ifdef BSP_USING_TIM8_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM8_PWM_CH2 */
+
+#ifdef BSP_USING_TIM8_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM8_PWM_CH3 */
+
+#ifdef BSP_USING_TIM8_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM8_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM8_PWM */
+
+#ifdef BSP_USING_TIM9_PWM
+    {
+        .periph = TIM9,
+        .name = "pwm9",
+#ifdef BSP_USING_TIM9_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM9_PWM_CH1 */
+
+#ifdef BSP_USING_TIM9_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM9_PWM_CH2 */
+
+#ifdef BSP_USING_TIM9_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM9_PWM_CH3 */
+
+#ifdef BSP_USING_TIM9_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM9_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM9_PWM */
+
+#ifdef BSP_USING_TIM10_PWM
+    {
+        .periph = TIM10,
+        .name = "pwm10",
+#ifdef BSP_USING_TIM10_PWM_CH1
+        .channel[0] = TIM_Channel_1,
+#else
+        .channel[0] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM10_PWM_CH1 */
+
+#ifdef BSP_USING_TIM10_PWM_CH2
+        .channel[1] = TIM_Channel_2,
+#else
+        .channel[1] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM10_PWM_CH2 */
+
+#ifdef BSP_USING_TIM10_PWM_CH3
+        .channel[2] = TIM_Channel_3,
+#else
+        .channel[2] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM10_PWM_CH3 */
+
+#ifdef BSP_USING_TIM10_PWM_CH4
+        .channel[3] = TIM_Channel_4,
+#else
+        .channel[3] = FLAG_NOT_INIT,
+#endif/* BSP_USING_TIM10_PWM_CH4 */
+    },
+#endif /* BSP_USING_TIM10_PWM */
+};
+
+static rt_err_t ch32_pwm_device_enable(struct rt_device_pwm* device, struct rt_pwm_configuration* configuration, rt_bool_t enable)
+{
+    struct rtdevice_pwm_device* pwm_device;
+    rt_uint32_t channel_index;
+    rt_uint16_t ccx_state;
+
+    pwm_device = (struct rtdevice_pwm_device*)device;
+    channel_index = configuration->channel;
+
+    if (enable == RT_TRUE)
+    {
+        ccx_state = TIM_CCx_Enable;
+    }
+    else
+    {
+        ccx_state = TIM_CCx_Disable;
+    }
+
+    if (channel_index <= 4 && channel_index > 0)
+    {
+        if (pwm_device->channel[channel_index - 1] == FLAG_NOT_INIT)
+        {
+            return -RT_EINVAL;
+        }
+        TIM_CCxCmd(pwm_device->periph, pwm_device->channel[channel_index - 1], ccx_state);
+    }
+    else
+    {
+        return -RT_EINVAL;
+    }
+
+    TIM_Cmd(pwm_device->periph, ENABLE);
+
+    return RT_EOK;
+}
+
+static rt_err_t ch32_pwm_device_get(struct rt_device_pwm* device, struct rt_pwm_configuration* configuration)
+{
+    struct rtdevice_pwm_device* pwm_device;
+    rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
+    rt_uint32_t channel_index;
+    rt_uint32_t tim_clock;
+
+    pwm_device = (struct rtdevice_pwm_device*)device;
+    tim_clock = ch32_tim_clock_get(pwm_device->periph);
+    channel_index = configuration->channel;
+    arr_counter = pwm_device->periph->ATRLR + 1;
+    prescaler = pwm_device->periph->PSC + 1;
+    sample_freq = (tim_clock / prescaler) / arr_counter;
+
+    /* unit:ns */
+    configuration->period = 1000000000 / sample_freq;
+
+    if (channel_index == 1)
+    {
+        ccr_counter = pwm_device->periph->CH1CVR + 1;
+        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
+    }
+    else if (channel_index == 2)
+    {
+        ccr_counter = pwm_device->periph->CH2CVR + 1;
+        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
+    }
+    else if (channel_index == 3)
+    {
+        ccr_counter = pwm_device->periph->CH3CVR + 1;
+        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
+    }
+    else if (channel_index == 4)
+    {
+        ccr_counter = pwm_device->periph->CH4CVR + 1;
+        configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
+    }
+    else
+    {
+        return -RT_EINVAL;
+    }
+
+    return RT_EOK;
+}
+
+static rt_err_t ch32_pwm_device_set(struct rt_device_pwm* device, struct rt_pwm_configuration* configuration)
+{
+    struct rtdevice_pwm_device* pwm_device;
+    rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
+    rt_uint32_t channel_index;
+    rt_uint32_t tim_clock;
+    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitType;
+    TIM_OCInitTypeDef TIM_OCInitType;
+
+    pwm_device = (struct rtdevice_pwm_device*)device;
+    tim_clock = ch32_tim_clock_get(pwm_device->periph);
+    channel_index = configuration->channel;
+
+    /* change to freq, unit:Hz */
+    sample_freq = 1000000000 / configuration->period;
+
+    /* counter = (tim_clk / prescaler) / sample_freq */
+    /* normally, tim_clk is not need div, if arr_counter over 65536, need div. */
+    prescaler = 1;
+    arr_counter = (tim_clock / prescaler) / sample_freq;
+
+    if (arr_counter > MAX_COUNTER)
+    {
+        /* need div tim_clock
+         * and round up the prescaler value.
+         * (tim_clock >> 16) = tim_clock / 65536
+         */
+        if ((tim_clock >> 16) % sample_freq == 0)
+            prescaler = (tim_clock >> 16) / sample_freq;
+        else
+            prescaler = (tim_clock >> 16) / sample_freq + 1;
+
+        /* counter = (tim_clk / prescaler) / sample_freq */
+        arr_counter = (tim_clock / prescaler) / sample_freq;
+    }
+    /* ccr_counter = duty cycle * arr_counter */
+    ccr_counter = (configuration->pulse * 100 / configuration->period) * arr_counter / 100;
+
+    /* check arr_counter > 1, cxx_counter > 1 */
+    if (arr_counter < MIN_COUNTER)
+    {
+        arr_counter = MIN_COUNTER;
+    }
+    if (ccr_counter < MIN_PULSE)
+    {
+        ccr_counter = MIN_PULSE;
+    }
+
+    /* TMRe base configuration */
+    TIM_TimeBaseStructInit(&TIM_TimeBaseInitType);
+    TIM_TimeBaseInitType.TIM_Period = arr_counter - 1;
+    TIM_TimeBaseInitType.TIM_Prescaler = prescaler - 1;
+    TIM_TimeBaseInitType.TIM_ClockDivision = TIM_CKD_DIV1;
+    TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Up;
+    TIM_TimeBaseInit(pwm_device->periph, &TIM_TimeBaseInitType);
+
+    TIM_OCStructInit(&TIM_OCInitType);
+    TIM_OCInitType.TIM_OCMode = TIM_OCMode_PWM1;
+    TIM_OCInitType.TIM_OutputState = TIM_OutputState_Enable;
+    TIM_OCInitType.TIM_Pulse = ccr_counter - 1;
+    TIM_OCInitType.TIM_OCPolarity = TIM_OCPolarity_High;
+
+    if (channel_index == 1)
+    {
+        TIM_OC1Init(pwm_device->periph, &TIM_OCInitType);
+        TIM_OC1PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
+    }
+    else if (channel_index == 2)
+    {
+        TIM_OC2Init(pwm_device->periph, &TIM_OCInitType);
+        TIM_OC2PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
+    }
+    else if (channel_index == 3)
+    {
+        TIM_OC3Init(pwm_device->periph, &TIM_OCInitType);
+        TIM_OC3PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
+    }
+    else if (channel_index == 4)
+    {
+        TIM_OC4Init(pwm_device->periph, &TIM_OCInitType);
+        TIM_OC4PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
+    }
+    else
+    {
+        return -RT_EINVAL;
+    }
+
+    TIM_ARRPreloadConfig(pwm_device->periph, ENABLE);
+    TIM_CtrlPWMOutputs(pwm_device->periph, ENABLE);
+
+    return RT_EOK;
+}
+
+static rt_err_t drv_pwm_control(struct rt_device_pwm* device, int cmd, void* arg)
+{
+    struct rt_pwm_configuration* configuration;
+
+    configuration = (struct rt_pwm_configuration*)arg;
+
+    switch (cmd)
+    {
+    case PWM_CMD_ENABLE:
+        return ch32_pwm_device_enable(device, configuration, RT_TRUE);
+    case PWM_CMD_DISABLE:
+        return ch32_pwm_device_enable(device, configuration, RT_FALSE);
+    case PWM_CMD_SET:
+        return ch32_pwm_device_set(device, configuration);
+    case PWM_CMD_GET:
+        return ch32_pwm_device_get(device, configuration);
+    default:
+        return -RT_EINVAL;
+    }
+}
+
+static struct rt_pwm_ops pwm_ops =
+{
+    .control = drv_pwm_control
+};
+
+static int rt_hw_pwm_init(void)
+{
+    int result = RT_EOK;
+    int index = 0;
+    int channel_index;
+
+    for (index = 0; index < ITEM_NUM(pwm_device_list); index++)
+    {
+        ch32_tim_clock_init(pwm_device_list[index].periph);
+        for (channel_index = 0; channel_index < sizeof(pwm_device_list[index].channel); channel_index++)
+        {
+            if (pwm_device_list[index].channel[channel_index] != FLAG_NOT_INIT)
+            {
+                ch32_pwm_io_init(pwm_device_list[index].periph, pwm_device_list[index].channel[channel_index]);
+            }
+        }
+
+        if (rt_device_pwm_register(&pwm_device_list[index].parent, pwm_device_list[index].name, &pwm_ops, RT_NULL) == RT_EOK)
+        {
+            LOG_D("%s register success", pwm_device_list[index].name);
+        }
+        else
+        {
+            LOG_D("%s register failed", pwm_device_list[index].name);
+            result = -RT_ERROR;
+        }
+    }
+
+    return result;
+}
+
+INIT_BOARD_EXPORT(rt_hw_pwm_init);
+
+#endif /* BSP_USING_PWM */

+ 40 - 0
bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-10-20     MXH          the first version
+ */
+
+#ifndef __DRV_PWM_H__
+#define __DRV_PWM_H__
+
+#include <rtthread.h>
+#ifdef BSP_USING_PWM
+#include "ch32v30x_tim.h"
+#include <drivers/rt_drv_pwm.h>
+#include <drivers/hwtimer.h>
+#include <board.h>
+
+#ifndef ITEM_NUM
+#define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
+#endif
+
+#define MAX_COUNTER     65535
+#define MIN_COUNTER     2
+#define MIN_PULSE       2
+#define FLAG_NOT_INIT   0xFF
+
+struct rtdevice_pwm_device
+{
+    struct rt_device_pwm parent;
+    TIM_TypeDef* periph;
+    rt_uint8_t channel[4];
+    char* name;
+};
+
+#endif/* BSP_USING_PWM */
+
+#endif/* __DRV_PWM_H__ */