195 lines
4.3 KiB
C
195 lines
4.3 KiB
C
/*
|
|
* Copyright (c) 2019 Winner Microelectronics Co., Ltd.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2018-11-22 fanwenl 1st version
|
|
*/
|
|
|
|
#include <rtthread.h>
|
|
#include <rtdevice.h>
|
|
#include "wm_type_def.h"
|
|
#include "wm_cpu.h"
|
|
#include "wm_pwm.h"
|
|
#include "wm_gpio_afsel.h"
|
|
#include "drv_pwm.h"
|
|
#include "pin_map.h"
|
|
|
|
#ifdef BSP_USING_PWM
|
|
#define MAX_PERIOD 255
|
|
#define MIN_PERIOD 2
|
|
#define MIN_PULSE 1
|
|
|
|
#define MAX_CLKDIV 65535
|
|
|
|
static rt_err_t wm_pwm_set(rt_uint8_t channel, struct rt_pwm_configuration *configuration)
|
|
{
|
|
rt_uint32_t period, pulse;
|
|
rt_uint32_t psc;
|
|
|
|
pwm_init_param pwm_param;
|
|
int ret = WM_FAILED;
|
|
tls_sys_clk sysclk;
|
|
|
|
tls_sys_clk_get(&sysclk);
|
|
|
|
rt_memset(&pwm_param, 0, sizeof(pwm_init_param));
|
|
|
|
pwm_param.channel = channel;
|
|
pwm_param.cnt_type = WM_PWM_CNT_TYPE_EDGE_ALIGN_OUT;
|
|
pwm_param.loop_type = WM_PWM_LOOP_TYPE_LOOP;
|
|
pwm_param.mode = WM_PWM_OUT_MODE_INDPT;
|
|
pwm_param.inverse_en = DISABLE;
|
|
pwm_param.pnum = 0;
|
|
pwm_param.pnum_int = DISABLE;
|
|
|
|
period = (unsigned long long)configuration->period * sysclk.apbclk / 1000ULL;
|
|
psc = period / MAX_PERIOD + 1;
|
|
if (psc > MAX_CLKDIV)
|
|
{
|
|
psc = MAX_CLKDIV;
|
|
}
|
|
pwm_param.clkdiv = psc;
|
|
|
|
period = period / psc;
|
|
|
|
if (period < MIN_PERIOD)
|
|
{
|
|
period = MIN_PERIOD;
|
|
}
|
|
else if (period > MAX_PERIOD)
|
|
{
|
|
period = MAX_PERIOD;
|
|
}
|
|
pwm_param.period = period - 1;
|
|
|
|
pulse = (unsigned long long)configuration->pulse * sysclk.apbclk / psc / 1000ULL;
|
|
if (pulse < MIN_PULSE)
|
|
{
|
|
pulse = MIN_PULSE;
|
|
}
|
|
else if (pulse > period)
|
|
{
|
|
pulse = period;
|
|
}
|
|
pwm_param.duty = pulse - 1;
|
|
|
|
ret = tls_pwm_out_init(pwm_param);
|
|
if (ret == WM_SUCCESS)
|
|
{
|
|
return RT_EOK;
|
|
}
|
|
else
|
|
{
|
|
return RT_ERROR;
|
|
}
|
|
}
|
|
|
|
static rt_err_t wm_pwm_get(rt_uint8_t channel, struct rt_pwm_configuration *configuration)
|
|
{
|
|
tls_sys_clk sysclk;
|
|
uint32_t clkdiv;
|
|
uint8_t duty, period;
|
|
|
|
tls_sys_clk_get(&sysclk);
|
|
|
|
tls_pwm_get_info(channel, &clkdiv, &duty, &period);
|
|
|
|
configuration->period = (period + 1) * clkdiv * 1000UL / sysclk.apbclk;
|
|
configuration->pulse = (duty + 1) * clkdiv * 1000UL / sysclk.apbclk;
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t wm_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
|
|
{
|
|
struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
|
|
|
|
int ret = WM_FAILED;
|
|
rt_uint32_t channel = 0;
|
|
|
|
channel = configuration->channel - 1;
|
|
|
|
if (channel > 4)
|
|
return -RT_EINVAL;
|
|
|
|
switch (cmd)
|
|
{
|
|
case PWM_CMD_ENABLE:
|
|
ret = tls_pwm_start(channel);
|
|
if (ret == WM_SUCCESS)
|
|
return RT_EOK;
|
|
else
|
|
return RT_ERROR;
|
|
case PWM_CMD_DISABLE:
|
|
ret = tls_pwm_stop(channel);
|
|
if (ret == WM_SUCCESS)
|
|
return RT_EOK;
|
|
else
|
|
return RT_ERROR;
|
|
case PWM_CMD_SET:
|
|
return wm_pwm_set(channel, configuration);
|
|
case PWM_CMD_GET:
|
|
return wm_pwm_get(channel, configuration);
|
|
default:
|
|
return -RT_EINVAL;
|
|
}
|
|
}
|
|
|
|
static struct rt_pwm_ops drv_ops =
|
|
{
|
|
wm_pwm_control
|
|
};
|
|
static struct rt_device_pwm wm_pwm;
|
|
|
|
int wm_hw_pwm_init(void)
|
|
{
|
|
rt_int16_t gpio_pin;
|
|
/*io config*/
|
|
#ifdef USING_PWM_CH1
|
|
gpio_pin = wm_get_pin(WM_PWM_CH1_PIN);
|
|
if (gpio_pin >= 0)
|
|
{
|
|
wm_pwm1_config((enum tls_io_name)gpio_pin);
|
|
}
|
|
#endif
|
|
#ifdef USING_PWM_CH2
|
|
gpio_pin = wm_get_pin(WM_PWM_CH2_PIN);
|
|
if (gpio_pin >= 0)
|
|
{
|
|
wm_pwm2_config((enum tls_io_name)gpio_pin);
|
|
}
|
|
#endif
|
|
#ifdef USING_PWM_CH3
|
|
gpio_pin = wm_get_pin(WM_PWM_CH3_PIN);
|
|
if (gpio_pin >= 0)
|
|
{
|
|
wm_pwm3_config((enum tls_io_name)gpio_pin);
|
|
}
|
|
#endif
|
|
#ifdef USING_PWM_CH4
|
|
gpio_pin = wm_get_pin(WM_PWM_CH4_PIN);
|
|
if (gpio_pin >= 0)
|
|
{
|
|
wm_pwm4_config((enum tls_io_name)gpio_pin);
|
|
}
|
|
#endif
|
|
#ifdef USING_PWM_CH5
|
|
gpio_pin = wm_get_pin(WM_PWM_CH5_PIN);
|
|
if (gpio_pin >= 0)
|
|
{
|
|
wm_pwm5_config((enum tls_io_name)gpio_pin);
|
|
}
|
|
#endif
|
|
#if defined(USING_PWM_CH1) || defined(USING_PWM_CH2) || defined(USING_PWM_CH3) || \
|
|
defined(USING_PWM_CH4) || defined(USING_PWM_CH5)
|
|
rt_device_pwm_register(&wm_pwm, "pwm", &drv_ops, 0);
|
|
#endif
|
|
return RT_EOK;
|
|
}
|
|
INIT_DEVICE_EXPORT(wm_hw_pwm_init);
|
|
|
|
#endif /* BSP_USING_PWM */
|