123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /**************************************************************************//**
- *
- * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-02-04 klcheng First version
- *
- ******************************************************************************/
- #include <rtconfig.h>
- #if defined(BSP_USING_PWM)
- #define LOG_TAG "drv.pwm"
- #define DBG_ENABLE
- #define DBG_SECTION_NAME LOG_TAG
- #define DBG_LEVEL DBG_INFO
- #define DBG_COLOR
- #include <rtdbg.h>
- #include <stdint.h>
- #include <rtdevice.h>
- #include <rthw.h>
- #include "NuMicro.h"
- enum
- {
- PWM_START = -1,
- #if defined(BSP_USING_PWM0)
- PWM0_IDX,
- #endif
- #if defined(BSP_USING_PWM1)
- PWM1_IDX,
- #endif
- PWM_CNT
- };
- struct nu_pwm
- {
- struct rt_device_pwm dev;
- char *name;
- PWM_T *pwm_base;
- rt_int32_t pwm_period_time;
- };
- typedef struct nu_pwm *nu_pwm_t;
- static struct nu_pwm nu_pwm_arr [] =
- {
- #if defined(BSP_USING_PWM0)
- {
- .name = "pwm0",
- .pwm_base = PWM0,
- },
- #endif
- #if defined(BSP_USING_PWM1)
- {
- .name = "pwm1",
- .pwm_base = PWM1,
- },
- #endif
- {0}
- }; /* pwm nu_pwm */
- static rt_err_t nu_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
- static struct rt_pwm_ops nu_pwm_ops =
- {
- .control = nu_pwm_control
- };
- static rt_err_t nu_pwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
- {
- rt_err_t result = RT_EOK;
- PWM_T *pwm_base = ((nu_pwm_t)device)->pwm_base;
- rt_uint32_t pwm_channel = ((struct rt_pwm_configuration *)configuration)->channel;
- if (enable == RT_TRUE)
- {
- PWM_EnableOutput(pwm_base, 1 << pwm_channel);
- PWM_Start(pwm_base, 1 << pwm_channel);
- }
- else
- {
- PWM_DisableOutput(pwm_base, 1 << pwm_channel);
- PWM_ForceStop(pwm_base, 1 << pwm_channel);
- }
- return result;
- }
- static rt_err_t nu_pwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
- {
- if ((((struct rt_pwm_configuration *)configuration)->period) <= 0)
- return -(RT_ERROR);
- rt_uint8_t pwm_channel_pair;
- rt_uint32_t pwm_freq, pwm_dutycycle ;
- PWM_T *pwm_base = ((nu_pwm_t)device)->pwm_base;
- rt_uint8_t pwm_channel = ((struct rt_pwm_configuration *)configuration)->channel;
- rt_uint32_t pwm_period = ((struct rt_pwm_configuration *)configuration)->period;
- rt_uint32_t pwm_pulse = ((struct rt_pwm_configuration *)configuration)->pulse;
- //rt_uint32_t pre_pwm_prescaler = PWM_GET_PRESCALER(pwm_base, pwm_channel);
- if ((pwm_channel % 2) == 0)
- pwm_channel_pair = pwm_channel + 1;
- else
- pwm_channel_pair = pwm_channel - 1;
- if (PWM_GET_CNR(pwm_base, pwm_channel_pair!= 0))
- {
- pwm_period = ((nu_pwm_t)device)->pwm_period_time;
- LOG_I("%s output frequency is determined, user can only change the duty\n", ((nu_pwm_t)device)->name);
- }
- else
- {
- ((nu_pwm_t)device)->pwm_period_time = pwm_period;
- }
- pwm_freq = 1000000000 / pwm_period;
- pwm_dutycycle = (pwm_pulse * 100) / pwm_period;
- PWM_ConfigOutputChannel(pwm_base, pwm_channel, pwm_freq, pwm_dutycycle) ;
- return RT_EOK;
- }
- static rt_uint32_t nu_pwm_clksr(struct rt_device_pwm *device)
- {
- rt_uint32_t u32Src, u32PWMClockSrc;
- PWM_T *pwm_base = ((nu_pwm_t)device)->pwm_base;
- if (pwm_base == PWM0)
- {
- u32Src = CLK->CLKSEL2 & CLK_CLKSEL2_PWM0SEL_Msk;
- }
- else /* (pwm == PWM1) */
- {
- u32Src = CLK->CLKSEL2 & CLK_CLKSEL2_PWM1SEL_Msk;
- }
- if (u32Src == 0U)
- {
- /* clock source is from PLL clock */
- u32PWMClockSrc = CLK_GetPLLClockFreq();
- }
- else
- {
- /* clock source is from PCLK */
- SystemCoreClockUpdate();
- if (pwm_base == PWM0)
- {
- u32PWMClockSrc = CLK_GetPCLK0Freq();
- }
- else /* (pwm == PWM1) */
- {
- u32PWMClockSrc = CLK_GetPCLK1Freq();
- }
- }
- return u32PWMClockSrc;
- }
- static rt_err_t nu_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
- {
- rt_uint32_t pwm_real_period, pwm_real_duty, time_tick, u32PWMClockSrc ;
- PWM_T *pwm_base = ((nu_pwm_t)device)->pwm_base;
- rt_uint32_t pwm_channel = ((struct rt_pwm_configuration *)configuration)->channel;
- rt_uint32_t pwm_prescale = PWM_GET_PRESCALER(pwm_base, pwm_channel);
- rt_uint32_t pwm_period = PWM_GET_CNR(pwm_base, pwm_channel);
- rt_uint32_t pwm_pulse = PWM_GET_CMR(pwm_base, pwm_channel);
- u32PWMClockSrc = nu_pwm_clksr(device);
- time_tick = 1000000000000 / u32PWMClockSrc;
- pwm_real_period = (((pwm_prescale + 1) * (pwm_period + 1)) * time_tick) / 1000;
- pwm_real_duty = (((pwm_prescale + 1) * pwm_pulse * time_tick)) / 1000;
- ((struct rt_pwm_configuration *)configuration)->period = pwm_real_period;
- ((struct rt_pwm_configuration *)configuration)->pulse = pwm_real_duty;
- LOG_I("%s %d %d %d\n", ((nu_pwm_t)device)->name, configuration->channel, configuration->period, configuration->pulse);
- return RT_EOK;
- }
- static rt_err_t nu_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
- {
- struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
- RT_ASSERT(device != RT_NULL);
- RT_ASSERT(configuration != RT_NULL);
- if (((((struct rt_pwm_configuration *)configuration)->channel) + 1) > PWM_CHANNEL_NUM)
- return -(RT_ERROR);
- switch (cmd)
- {
- case PWM_CMD_ENABLE:
- return nu_pwm_enable(device, configuration, RT_TRUE);
- case PWM_CMD_DISABLE:
- return nu_pwm_enable(device, configuration, RT_FALSE);
- case PWM_CMD_SET:
- return nu_pwm_set(device, configuration);
- case PWM_CMD_GET:
- return nu_pwm_get(device, configuration);
- }
- return -(RT_EINVAL);
- }
- int rt_hw_pwm_init(void)
- {
- rt_err_t ret;
- int i;
- for (i = (PWM_START + 1); i < PWM_CNT; i++)
- {
- ret = rt_device_pwm_register(&nu_pwm_arr[i].dev, nu_pwm_arr[i].name, &nu_pwm_ops, RT_NULL);
- RT_ASSERT(ret == RT_EOK);
- }
- return 0;
- }
- INIT_DEVICE_EXPORT(rt_hw_pwm_init);
- #ifdef RT_USING_FINSH
- #include <finsh.h>
- #ifdef FINSH_USING_MSH
- static int xpwm_get(int argc, char **argv)
- {
- int result = 0;
- struct rt_device_pwm *device = RT_NULL;
- struct rt_pwm_configuration configuration = {0};
- if (argc != 3)
- {
- rt_kprintf("Usage: pwm_get pwm1 1\n");
- result = -RT_ERROR;
- goto _exit;
- }
- device = (struct rt_device_pwm *)rt_device_find(argv[1]);
- if (!device)
- {
- result = -RT_EIO;
- goto _exit;
- }
- configuration.channel = atoi(argv[2]);
- result = rt_device_control(&device->parent, PWM_CMD_GET, &configuration);
- _exit:
- return result;
- }
- MSH_CMD_EXPORT(xpwm_get, xpwm_get <pwm_dev> <channel>);
- #endif /* FINSH_USING_MSH */
- #endif /* RT_USING_FINSH */
- #endif
|