未验证 提交 11f52eeb 编写于 作者: S self-confident neko 提交者: GitHub

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

* 新增硬件定时器功能

* 新增定时器功能

* Update Kconfig

* Update bsp/wch/risc-v/Libraries/ch32_drivers/drv_hwtimer.h
Co-authored-by: mysterywolf's avatarMan, 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: mysterywolf's avatarMan, Jianting (Meco) <920369182@qq.com>

* Update bsp/wch/risc-v/Libraries/ch32_drivers/drv_pwm.h
Co-authored-by: mysterywolf's avatarMan, Jianting (Meco) <920369182@qq.com>

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