From 11f52eebcfce960386ce8918114ec2f99e2125e2 Mon Sep 17 00:00:00 2001 From: self-confident neko <45762837+muaxiaohei@users.noreply.github.com> Date: Sat, 22 Oct 2022 23:07:04 +0800 Subject: [PATCH] =?UTF-8?q?[bsp][ch32v307]=E8=A1=A5=E5=85=A8PWM=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=EF=BC=8C=E5=B9=B6=E4=B8=BA=E6=AF=8F=E4=B8=AAPWM?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=B7=BB=E5=8A=A0=E6=9D=A1=E4=BB=B6=E7=BC=96?= =?UTF-8?q?=E8=AF=91=EF=BC=8C=E5=87=8F=E5=B0=91=E4=BB=A3=E7=A0=81=E9=87=8F?= =?UTF-8?q?=20(#6548)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 新增硬件定时器功能 * 新增定时器功能 * 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> --- .../risc-v/Libraries/ch32_drivers/drv_pwm.c | 1591 ++++++++++------- .../risc-v/Libraries/ch32_drivers/drv_pwm.h | 40 + 2 files changed, 1003 insertions(+), 628 deletions(-) create mode 100644 bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h diff --git a/bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c b/bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c index e4a81b9852..8b317364a6 100644 --- a/bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.c +++ b/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 -#include -#include -#include -#include - -#ifdef BSP_USING_PWM - -#define LOG_TAG "drv.pwm" -#include - -#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 + +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 */ diff --git a/bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h b/bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h new file mode 100644 index 0000000000..c72edd6d0e --- /dev/null +++ b/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 +#ifdef BSP_USING_PWM +#include "ch32v30x_tim.h" +#include +#include +#include + +#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__ */ -- GitLab