172 lines
5.3 KiB
C
172 lines
5.3 KiB
C
|
/*
|
||
|
* Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2019-03-11 wangyq the first version
|
||
|
* 2019-11-01 wangyq update libraries
|
||
|
*/
|
||
|
|
||
|
#include <rthw.h>
|
||
|
#include <rtthread.h>
|
||
|
#include <rtdevice.h>
|
||
|
#include <board.h>
|
||
|
#include <ald_cmu.h>
|
||
|
#include <ald_timer.h>
|
||
|
#include <ald_gpio.h>
|
||
|
|
||
|
static void pwm_set_freq(timer_handle_t *timer_initstruct, uint32_t ns)
|
||
|
{
|
||
|
uint64_t _arr = (uint64_t)ald_cmu_get_pclk1_clock() * ns / 1000000000 /
|
||
|
(timer_initstruct->init.prescaler + 1);
|
||
|
|
||
|
WRITE_REG(timer_initstruct->perh->AR, (uint32_t)_arr);
|
||
|
timer_initstruct->init.period = (uint32_t)_arr;
|
||
|
}
|
||
|
|
||
|
static void pwm_set_duty(timer_handle_t *timer_initstruct, timer_channel_t ch, uint32_t ns)
|
||
|
{
|
||
|
uint64_t tmp = (uint64_t)ald_cmu_get_pclk1_clock() * ns / 1000000000 /
|
||
|
(timer_initstruct->init.prescaler + 1);
|
||
|
|
||
|
if (ch == TIMER_CHANNEL_1)
|
||
|
WRITE_REG(timer_initstruct->perh->CCVAL1, (uint32_t)tmp);
|
||
|
else if (ch == TIMER_CHANNEL_2)
|
||
|
WRITE_REG(timer_initstruct->perh->CCVAL2, (uint32_t)tmp);
|
||
|
else if (ch == TIMER_CHANNEL_3)
|
||
|
WRITE_REG(timer_initstruct->perh->CCVAL3, (uint32_t)tmp);
|
||
|
else if (ch == TIMER_CHANNEL_4)
|
||
|
WRITE_REG(timer_initstruct->perh->CCVAL4, (uint32_t)tmp);
|
||
|
}
|
||
|
|
||
|
static rt_err_t es32f3_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
|
||
|
{
|
||
|
rt_err_t ret = RT_EOK;
|
||
|
uint32_t _ccep;
|
||
|
timer_channel_t pwm_channel;
|
||
|
timer_oc_init_t tim_ocinit;
|
||
|
timer_handle_t *timer_initstruct = (timer_handle_t *)device->parent.user_data;
|
||
|
struct rt_pwm_configuration *cfg = (struct rt_pwm_configuration *)arg;
|
||
|
|
||
|
RT_ASSERT(timer_initstruct != RT_NULL);
|
||
|
|
||
|
tim_ocinit.oc_mode = TIMER_OC_MODE_PWM1;
|
||
|
tim_ocinit.oc_polarity = TIMER_OC_POLARITY_HIGH;
|
||
|
tim_ocinit.oc_fast_en = DISABLE;
|
||
|
tim_ocinit.ocn_polarity = TIMER_OCN_POLARITY_HIGH;
|
||
|
tim_ocinit.ocn_idle = TIMER_OCN_IDLE_RESET;
|
||
|
tim_ocinit.oc_idle = TIMER_OC_IDLE_RESET;
|
||
|
|
||
|
/* select pwm output channel */
|
||
|
if (1 == cfg->channel)
|
||
|
pwm_channel = TIMER_CHANNEL_1;
|
||
|
|
||
|
else if (2 == cfg->channel)
|
||
|
pwm_channel = TIMER_CHANNEL_2;
|
||
|
|
||
|
else if (3 == cfg->channel)
|
||
|
pwm_channel = TIMER_CHANNEL_3;
|
||
|
|
||
|
else if (4 == cfg->channel)
|
||
|
pwm_channel = TIMER_CHANNEL_4;
|
||
|
|
||
|
else
|
||
|
return RT_EINVAL;
|
||
|
|
||
|
switch (cmd)
|
||
|
{
|
||
|
case PWM_CMD_ENABLE:
|
||
|
ald_timer_pwm_start(timer_initstruct, pwm_channel);
|
||
|
break;
|
||
|
|
||
|
case PWM_CMD_DISABLE:
|
||
|
ald_timer_pwm_stop(timer_initstruct, pwm_channel);
|
||
|
break;
|
||
|
|
||
|
case PWM_CMD_SET:
|
||
|
_ccep = timer_initstruct->perh->CCEP;
|
||
|
/* count registers max 0xFFFF, auto adjust prescaler */
|
||
|
do
|
||
|
{
|
||
|
pwm_set_freq(timer_initstruct, cfg->period);
|
||
|
timer_initstruct->init.prescaler ++;
|
||
|
}
|
||
|
while (timer_initstruct->init.period > 0xFFFF);
|
||
|
/* update prescaler */
|
||
|
WRITE_REG(timer_initstruct->perh->PRES, --timer_initstruct->init.prescaler);
|
||
|
ald_timer_oc_config_channel(timer_initstruct, &tim_ocinit, pwm_channel);
|
||
|
pwm_set_duty(timer_initstruct, pwm_channel, cfg->pulse);
|
||
|
timer_initstruct->perh->CCEP = _ccep;
|
||
|
break;
|
||
|
|
||
|
case PWM_CMD_GET:
|
||
|
cfg->pulse = ald_timer_read_capture_value(timer_initstruct, pwm_channel) * 100 /
|
||
|
READ_REG(timer_initstruct->perh->AR);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
const static struct rt_pwm_ops es32f3_pwm_ops =
|
||
|
{
|
||
|
es32f3_pwm_control
|
||
|
};
|
||
|
|
||
|
int rt_hw_pwm_init(void)
|
||
|
{
|
||
|
rt_err_t ret = RT_EOK;
|
||
|
gpio_init_t gpio_initstructure;
|
||
|
|
||
|
gpio_initstructure.mode = GPIO_MODE_OUTPUT;
|
||
|
gpio_initstructure.odos = GPIO_PUSH_PULL;
|
||
|
gpio_initstructure.pupd = GPIO_PUSH_UP;
|
||
|
gpio_initstructure.podrv = GPIO_OUT_DRIVE_6;
|
||
|
gpio_initstructure.nodrv = GPIO_OUT_DRIVE_6;
|
||
|
gpio_initstructure.flt = GPIO_FILTER_DISABLE;
|
||
|
gpio_initstructure.type = GPIO_TYPE_TTL;
|
||
|
|
||
|
#ifdef BSP_USING_PWM0 /* 4 channels */
|
||
|
static struct rt_device_pwm pwm_dev0;
|
||
|
static timer_handle_t timer_initstruct0;
|
||
|
|
||
|
timer_initstruct0.perh = GP16C4T0;
|
||
|
ald_timer_pwm_init(&timer_initstruct0);
|
||
|
|
||
|
/* gpio initialization */
|
||
|
gpio_initstructure.func = GPIO_FUNC_2;
|
||
|
ald_gpio_init(GPIOB, GPIO_PIN_6, &gpio_initstructure);
|
||
|
ald_gpio_init(GPIOB, GPIO_PIN_7, &gpio_initstructure);
|
||
|
ald_gpio_init(GPIOB, GPIO_PIN_8, &gpio_initstructure);
|
||
|
ald_gpio_init(GPIOB, GPIO_PIN_9, &gpio_initstructure);
|
||
|
|
||
|
ret = rt_device_pwm_register(&pwm_dev0, "pwm0", &es32f3_pwm_ops,
|
||
|
&timer_initstruct0);
|
||
|
#endif
|
||
|
|
||
|
#ifdef BSP_USING_PWM1 /* 4 channels */
|
||
|
static struct rt_device_pwm pwm_dev1;
|
||
|
static timer_handle_t timer_initstruct1;
|
||
|
|
||
|
timer_initstruct1.perh = GP16C4T1;
|
||
|
ald_timer_pwm_init(&timer_initstruct1);
|
||
|
|
||
|
/* gpio initialization */
|
||
|
gpio_initstructure.func = GPIO_FUNC_5;
|
||
|
ald_gpio_init(GPIOA, GPIO_PIN_0, &gpio_initstructure);
|
||
|
ald_gpio_init(GPIOA, GPIO_PIN_1, &gpio_initstructure);
|
||
|
ald_gpio_init(GPIOA, GPIO_PIN_2, &gpio_initstructure);
|
||
|
ald_gpio_init(GPIOA, GPIO_PIN_3, &gpio_initstructure);
|
||
|
|
||
|
ret = rt_device_pwm_register(&pwm_dev1, "pwm1", &es32f3_pwm_ops,
|
||
|
&timer_initstruct1);
|
||
|
#endif
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
INIT_DEVICE_EXPORT(rt_hw_pwm_init);
|