转载请注明:https://mp.csdn.net/postedit/84571003
经过一天的实践,将基于标准库+RT-Thread的pwm驱动写完并通过示波器验证,此驱动目前不支持TIM1和TIM8,其他的定时器通道可以在rtconfig.h文件中配置,然后再在驱动文件中加上配置,此驱动目前只实现了TIM3的四个通道
typedef struct
{
TIM_TypeDef *Instance; /*!< Register base address */
TIM_TimeBaseInitTypeDef Init; /*!< TIM Time Base required parameters */
uint16_t Channel; /*!< Active channel */
}TIM_HandleTypeDef;
static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
static struct rt_pwm_ops drv_ops =
{
drv_pwm_control
};
static rt_err_t drv_pwm_enable(TIM_TypeDef *htim, struct rt_pwm_configuration *configuration, rt_bool_t enable)
{
if((htim == TIM1) || (htim == TIM8))
{
rt_kprintf("The TIMX error\n");
return RT_ERROR;
}
if((configuration->channel != TIM_Channel_1) && (configuration->channel != TIM_Channel_2) &&
(configuration->channel != TIM_Channel_3) && (configuration->channel != TIM_Channel_4))
{
rt_kprintf("The TIMX Chx %d error\n",configuration->channel);
return RT_ERROR;
}
if(enable)
{
TIM_CCxCmd(htim,configuration->channel,TIM_CCx_Enable);
}
else
{
TIM_CCxCmd(htim,configuration->channel,TIM_CCx_Disable);
}
return RT_EOK;
}
static rt_err_t pwm_set(TIM_TypeDef *htim, struct rt_pwm_configuration *configuration)
{
rt_uint32_t period, pulse;
rt_uint32_t tim_clock, psc;
if((htim == TIM1) || (htim == TIM8))
{
rt_kprintf("The TIMX error\n");
return RT_ERROR;
}
if((configuration->channel != TIM_Channel_1) && (configuration->channel != TIM_Channel_2) &&
(configuration->channel != TIM_Channel_3) && (configuration->channel != TIM_Channel_4))
{
rt_kprintf("The TIMX Chx %d error\n",configuration->channel);
return RT_ERROR;
}
TIM_SetAutoreload(htim,configuration->period);
#ifdef BSP_USING_CH1
TIM_SetCompare1(htim,configuration->pulse);
#endif
#ifdef BSP_USING_CH2
TIM_SetCompare2(htim,configuration->pulse);
#endif
#ifdef BSP_USING_CH3
TIM_SetCompare3(htim,configuration->pulse);
#endif
#ifdef BSP_USING_CH4
TIM_SetCompare4(htim,configuration->pulse);
#endif
return RT_EOK;
}
static rt_err_t pwm_get(TIM_TypeDef *htim, struct rt_pwm_configuration *configuration)
{
return RT_EOK;
}
static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
{
struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
TIM_HandleTypeDef *htim = (TIM_HandleTypeDef *)device->parent.user_data;
switch(cmd)
{
case PWM_CMD_ENABLE:
return drv_pwm_enable(htim->Instance,configuration,RT_TRUE);
case PWM_CMD_DISABLE:
return drv_pwm_enable(htim->Instance,configuration,RT_FALSE);
case PWM_CMD_SET:
return pwm_set(htim->Instance,configuration);
case PWM_CMD_GET:
return pwm_get(htim->Instance,configuration);
default:
return RT_EINVAL;
}
}
TIM_HandleTypeDef htim;
//ĬÈÏ TIM2 : ch1 = PA0,ch2 = PA1,ch3 = PA2,ch4 = PA3
static rt_err_t Timex_PWMChannelx_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//³õʼ»¯TIMx
htim.Init.TIM_Period = 0;
htim.Init.TIM_Prescaler = 9;
htim.Init.TIM_ClockDivision = 0;
htim.Init.TIM_CounterMode = TIM_CounterMode_Up;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //Ñ¡Ôñ¶¨Ê±Æ÷ģʽ:TIMÂö³å¿í¶Èµ÷ÖÆģʽ2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±È½ÏÊä³öʹÄÜ
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Êä³ö¼«ÐÔ:TIMÊä³ö±È½Ï¼«ÐÔ¸ß
#ifdef BSP_USING_PWM3
htim.Instance = TIM3;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //ʹÄܶ¨Ê±Æ÷3ʱÖÓ
#ifdef BSP_USING_CH1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜGPIOÍâÉèºÍAFIO¸´Óù¦ÄÜÄ£¿éʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //TIM_CH2
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIO
TIM_OC1Init(htim.Instance, &TIM_OCInitStructure); //¸ù¾ÝTÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIM2 OC2
TIM_OC1PreloadConfig(htim.Instance, TIM_OCPreload_Enable); //ʹÄÜTIM3ÔÚCCR2ÉϵÄԤװÔؼĴæÆ÷
#endif
#ifdef BSP_USING_CH2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜGPIOÍâÉèºÍAFIO¸´Óù¦ÄÜÄ£¿éʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIO
TIM_OC2Init(htim.Instance, &TIM_OCInitStructure); //¸ù¾ÝTÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIM2 OC2
TIM_OC2PreloadConfig(htim.Instance, TIM_OCPreload_Enable); //ʹÄÜTIM3ÔÚCCR2ÉϵÄԤװÔؼĴæÆ÷
#endif
#ifdef BSP_USING_CH3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //ʹÄÜGPIOÍâÉèºÍAFIO¸´Óù¦ÄÜÄ£¿éʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM_CH2
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯GPIO
TIM_OC3Init(htim.Instance, &TIM_OCInitStructure); //¸ù¾ÝTÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIM2 OC2
TIM_OC3PreloadConfig(htim.Instance, TIM_OCPreload_Enable); //ʹÄÜTIM3ÔÚCCR2ÉϵÄԤװÔؼĴæÆ÷
#endif
#ifdef BSP_USING_CH4
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //ʹÄÜGPIOÍâÉèºÍAFIO¸´Óù¦ÄÜÄ£¿éʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH2
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯GPIO
TIM_OC4Init(htim.Instance, &TIM_OCInitStructure); //¸ù¾ÝTÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIM2 OC2
TIM_OC4PreloadConfig(htim.Instance, TIM_OCPreload_Enable); //ʹÄÜTIM3ÔÚCCR2ÉϵÄԤװÔؼĴæÆ÷
#endif
#endif
TIM_TimeBaseInit(htim.Instance, &htim.Init);
TIM_Cmd(htim.Instance, ENABLE);
}
int drv_pwm_init(void)
{
#ifdef BSP_USING_PWM1
MX_TIM1_Init();
rt_device_pwm_register(rt_calloc(1, sizeof(struct rt_device_pwm)), "pwm1", &drv_ops, &htim1);
#endif
#ifdef BSP_USING_PWM3
Timex_PWMChannelx_Config();
rt_device_pwm_register(rt_calloc(1, sizeof(struct rt_device_pwm)), "pwm3", &drv_ops, &htim);
#endif
return 0;
}
INIT_DEVICE_EXPORT(drv_pwm_init);