209 lines
6.3 KiB
C
209 lines
6.3 KiB
C
|
/*
|
||
|
* Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2019-10-23 yuzrain the first version
|
||
|
*/
|
||
|
|
||
|
#include <rthw.h>
|
||
|
#include <rtthread.h>
|
||
|
#include <rtdevice.h>
|
||
|
#include <board.h>
|
||
|
#include "md_gpio.h"
|
||
|
|
||
|
/* PWM device control struct */
|
||
|
struct pwm_dev_ctrl {
|
||
|
AD16C4T_TypeDef *timx;
|
||
|
rt_uint8_t chnm; /* Cannel number */
|
||
|
struct rt_pwm_configuration *cfg;
|
||
|
};
|
||
|
|
||
|
#ifdef BSP_USING_PWM_GP16C2T1
|
||
|
|
||
|
/* Remember channel configuration */
|
||
|
static struct rt_pwm_configuration pwm_ch_cfg_gp16c2t1[2] = {
|
||
|
[0] = {
|
||
|
.channel = 1,
|
||
|
.period = 0,
|
||
|
.pulse = 0
|
||
|
},
|
||
|
[1] = {
|
||
|
.channel = 2,
|
||
|
.period = 0,
|
||
|
.pulse = 0
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* Define static device */
|
||
|
static struct rt_device_pwm pwm_dev_gp16c2t1;
|
||
|
static struct pwm_dev_ctrl pwm_dev_gp16c2t1_ctrl;
|
||
|
#endif
|
||
|
#ifdef BSP_USING_PWM_GP16C2T4
|
||
|
|
||
|
/* Remember channel configuration */
|
||
|
static struct rt_pwm_configuration pwm_ch_cfg_gp16c2t4[2] = {
|
||
|
[0] = {
|
||
|
.channel = 1,
|
||
|
.period = 0,
|
||
|
.pulse = 0
|
||
|
},
|
||
|
[1] = {
|
||
|
.channel = 2,
|
||
|
.period = 0,
|
||
|
.pulse = 0
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* Define static device */
|
||
|
static struct rt_device_pwm pwm_dev_gp16c2t4;
|
||
|
static struct pwm_dev_ctrl pwm_dev_gp16c2t4_ctrl;
|
||
|
#endif
|
||
|
|
||
|
static void pwm_auto_config_freq(AD16C4T_TypeDef *timerx, uint32_t ns)
|
||
|
{
|
||
|
uint32_t temp_ar;
|
||
|
uint32_t temp_pres = timerx->PRES & 0xFFFF;
|
||
|
uint32_t err_cnt = 0;
|
||
|
|
||
|
/* Automatic setting frequency division ratio */
|
||
|
while (err_cnt++ < 65536)
|
||
|
{
|
||
|
temp_ar = (uint64_t)SystemCoreClock * ns / 1000000000 / (temp_pres + 1);
|
||
|
if (temp_ar <= 0xFFFF)
|
||
|
break;
|
||
|
temp_pres++;
|
||
|
}
|
||
|
|
||
|
/* Write back to PRES */
|
||
|
timerx->PRES = (uint16_t)(temp_pres & 0xFFFF);
|
||
|
timerx->AR = temp_ar;
|
||
|
}
|
||
|
|
||
|
static void pwm_set_duty(AD16C4T_TypeDef *timerx, uint8_t ch, uint32_t ns)
|
||
|
{
|
||
|
uint32_t temp_pres = timerx->PRES & 0xFFFF;
|
||
|
uint64_t tmp = (uint64_t)SystemCoreClock * ns / 1000000000 / (temp_pres + 1);
|
||
|
|
||
|
if (ch == 1)
|
||
|
WRITE_REG(timerx->CCVAL1, (uint32_t)tmp);
|
||
|
else if (ch == 2)
|
||
|
WRITE_REG(timerx->CCVAL2, (uint32_t)tmp);
|
||
|
}
|
||
|
|
||
|
static rt_err_t es32f0_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
|
||
|
{
|
||
|
rt_err_t ret = RT_EOK;
|
||
|
struct pwm_dev_ctrl *dev_ctrl
|
||
|
= (struct pwm_dev_ctrl *)device->parent.user_data;
|
||
|
struct rt_pwm_configuration *cfg = (struct rt_pwm_configuration *)arg;
|
||
|
AD16C4T_TypeDef *timerx = (AD16C4T_TypeDef *)dev_ctrl->timx;
|
||
|
|
||
|
switch (cmd)
|
||
|
{
|
||
|
case PWM_CMD_ENABLE:
|
||
|
{
|
||
|
if (cfg->channel == 1)
|
||
|
SET_BIT(timerx->CCEP, AD16C4T_CCEP_CC1EN_MSK);
|
||
|
else if (cfg->channel == 2)
|
||
|
SET_BIT(timerx->CCEP, AD16C4T_CCEP_CC2EN_MSK);
|
||
|
break;
|
||
|
}
|
||
|
case PWM_CMD_DISABLE:
|
||
|
{
|
||
|
if (cfg->channel == 1)
|
||
|
CLEAR_BIT(timerx->CCEP, AD16C4T_CCEP_CC1EN_MSK);
|
||
|
else if (cfg->channel == 2)
|
||
|
CLEAR_BIT(timerx->CCEP, AD16C4T_CCEP_CC2EN_MSK);
|
||
|
break;
|
||
|
}
|
||
|
case PWM_CMD_SET:
|
||
|
{
|
||
|
/* count registers max 0xFFFF, auto adjust prescaler */
|
||
|
pwm_auto_config_freq(timerx, cfg->period);
|
||
|
pwm_set_duty(timerx, cfg->channel, cfg->pulse);
|
||
|
/* Remember configuration */
|
||
|
dev_ctrl->cfg[cfg->channel-1].period = cfg->period;
|
||
|
dev_ctrl->cfg[cfg->channel-1].pulse = cfg->pulse;
|
||
|
break;
|
||
|
}
|
||
|
case PWM_CMD_GET:
|
||
|
{
|
||
|
cfg->period = dev_ctrl->cfg[cfg->channel-1].period;
|
||
|
cfg->pulse = dev_ctrl->cfg[cfg->channel-1].pulse;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
const static struct rt_pwm_ops es32f0_pwm_ops =
|
||
|
{
|
||
|
es32f0_pwm_control
|
||
|
};
|
||
|
|
||
|
int rt_hw_pwm_init(void)
|
||
|
{
|
||
|
rt_err_t ret = RT_EOK;
|
||
|
|
||
|
#ifdef BSP_USING_PWM_GP16C2T1 /* 2 channels */
|
||
|
/* Open clock */
|
||
|
SET_BIT(RCU->APB2EN, RCU_APB2EN_GP16C2T1EN_MSK);
|
||
|
|
||
|
/* GPIO configuration */
|
||
|
md_gpio_set_mode (GPIOB, MD_GPIO_PIN_1, MD_GPIO_MODE_FUNCTION);
|
||
|
md_gpio_set_mode (GPIOB, MD_GPIO_PIN_2, MD_GPIO_MODE_FUNCTION);
|
||
|
md_gpio_set_function0_7 (GPIOB, MD_GPIO_PIN_1, MD_GPIO_AF5);
|
||
|
md_gpio_set_function0_7 (GPIOB, MD_GPIO_PIN_2, MD_GPIO_AF5);
|
||
|
|
||
|
/* Timer configuration */
|
||
|
MODIFY_REG(GP16C2T1->CHMR1, AD16C4T_CHMR1_OUTPUT_CH1MOD_MSK,
|
||
|
(6 << AD16C4T_CHMR1_OUTPUT_CH1MOD_POSS));
|
||
|
MODIFY_REG(GP16C2T1->CHMR1, AD16C4T_CHMR1_OUTPUT_CH2MOD_MSK,
|
||
|
(6 << AD16C4T_CHMR1_OUTPUT_CH2MOD_POSS));
|
||
|
SET_BIT(GP16C2T1->BDCFG, AD16C4T_BDCFG_GOEN_MSK);
|
||
|
SET_BIT(GP16C2T1->CON1, AD16C4T_CON1_CNTEN_MSK);
|
||
|
|
||
|
pwm_dev_gp16c2t1_ctrl.chnm = 2;
|
||
|
pwm_dev_gp16c2t1_ctrl.timx = GP16C2T1;
|
||
|
pwm_dev_gp16c2t1_ctrl.cfg = pwm_ch_cfg_gp16c2t1;
|
||
|
/* Register PWM device */
|
||
|
ret = rt_device_pwm_register(&pwm_dev_gp16c2t1,
|
||
|
"pwm1", &es32f0_pwm_ops, &pwm_dev_gp16c2t1_ctrl);
|
||
|
#endif
|
||
|
|
||
|
#ifdef BSP_USING_PWM_GP16C2T4 /* 2 channels */
|
||
|
/* Open clock */
|
||
|
SET_BIT(RCU->APB2EN, RCU_APB2EN_GP16C2T4EN_MSK);
|
||
|
|
||
|
/* GPIO configuration */
|
||
|
md_gpio_set_mode (GPIOB, MD_GPIO_PIN_12, MD_GPIO_MODE_FUNCTION);
|
||
|
md_gpio_set_mode (GPIOB, MD_GPIO_PIN_14, MD_GPIO_MODE_FUNCTION);
|
||
|
md_gpio_set_function8_15(GPIOB, MD_GPIO_PIN_12, MD_GPIO_AF5);
|
||
|
md_gpio_set_function8_15(GPIOB, MD_GPIO_PIN_14, MD_GPIO_AF5);
|
||
|
|
||
|
/* Timer configuration */
|
||
|
MODIFY_REG(GP16C2T4->CHMR1, AD16C4T_CHMR1_OUTPUT_CH1MOD_MSK,
|
||
|
(6 << AD16C4T_CHMR1_OUTPUT_CH1MOD_POSS));
|
||
|
MODIFY_REG(GP16C2T4->CHMR1, AD16C4T_CHMR1_OUTPUT_CH2MOD_MSK,
|
||
|
(6 << AD16C4T_CHMR1_OUTPUT_CH2MOD_POSS));
|
||
|
SET_BIT(GP16C2T4->BDCFG, AD16C4T_BDCFG_GOEN_MSK);
|
||
|
SET_BIT(GP16C2T4->CON1, AD16C4T_CON1_CNTEN_MSK);
|
||
|
|
||
|
pwm_dev_gp16c2t4_ctrl.chnm = 2;
|
||
|
pwm_dev_gp16c2t4_ctrl.timx = GP16C2T4;
|
||
|
pwm_dev_gp16c2t4_ctrl.cfg = pwm_ch_cfg_gp16c2t4;
|
||
|
/* Register PWM device */
|
||
|
ret = rt_device_pwm_register(&pwm_dev_gp16c2t4,
|
||
|
"pwm2", &es32f0_pwm_ops, &pwm_dev_gp16c2t4_ctrl);
|
||
|
#endif
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
INIT_DEVICE_EXPORT(rt_hw_pwm_init);
|