1 /**************************************************************************//**
2 *
3 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date            Author       Notes
9 * 2021-9-22       Wayne        First version
10 *
11 ******************************************************************************/
12 
13 #include <rtconfig.h>
14 
15 #if (defined(BSP_USING_EPWM) && defined(RT_USING_PWM))
16 
17 #define LOG_TAG                 "drv.epwm"
18 #define DBG_ENABLE
19 #define DBG_SECTION_NAME        LOG_TAG
20 #define DBG_LEVEL               DBG_INFO
21 #define DBG_COLOR
22 #include <rtdbg.h>
23 
24 #include <rtdevice.h>
25 #include <rthw.h>
26 #include "NuMicro.h"
27 
28 enum
29 {
30     EPWM_START = -1,
31 #if defined(BSP_USING_EPWM0_PWM)
32     EPWM0_IDX,
33 #endif
34 #if defined(BSP_USING_EPWM1_PWM)
35     EPWM1_IDX,
36 #endif
37 #if defined(BSP_USING_EPWM2_PWM)
38     EPWM2_IDX,
39 #endif
40     EPWM_CNT
41 };
42 
43 struct nu_epwm
44 {
45     struct rt_device_pwm dev;
46     char                *name;
47     EPWM_T              *base;
48     uint32_t             rstidx;
49     uint32_t             modid;
50 };
51 
52 typedef struct nu_epwm *nu_epwm_t;
53 
54 static struct nu_epwm nu_epwm_arr [] =
55 {
56 #if defined(BSP_USING_EPWM0_PWM)
57     { .name = "epwm0", .base = EPWM0, .rstidx = EPWM0_RST, .modid = EPWM0_MODULE },
58 #endif
59 
60 #if defined(BSP_USING_EPWM1_PWM)
61     { .name = "epwm1", .base = EPWM1, .rstidx = EPWM1_RST, .modid = EPWM1_MODULE },
62 #endif
63 
64 #if defined(BSP_USING_EPWM2_PWM)
65     { .name = "epwm2", .base = EPWM2, .rstidx = EPWM2_RST, .modid = EPWM2_MODULE },
66 #endif
67 
68 }; /* epwm nu_epwm */
69 
70 static rt_err_t nu_epwm_control(struct rt_device_pwm *device, int cmd, void *arg);
71 
72 static struct rt_pwm_ops nu_epwm_ops =
73 {
74     .control = nu_epwm_control
75 };
76 
nu_epwm_enable(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration,rt_bool_t enable)77 static rt_err_t nu_epwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
78 {
79     rt_err_t result = RT_EOK;
80 
81     EPWM_T *pwm_base = ((nu_epwm_t)device)->base;
82     rt_uint32_t pwm_channel = ((struct rt_pwm_configuration *)configuration)->channel;
83 
84     if (enable == RT_TRUE)
85     {
86         EPWM_EnableOutput(pwm_base, 1 << pwm_channel);
87         EPWM_Start(pwm_base, 1 << pwm_channel);
88     }
89     else
90     {
91         EPWM_DisableOutput(pwm_base, 1 << pwm_channel);
92         EPWM_ForceStop(pwm_base, 1 << pwm_channel);
93     }
94 
95     return result;
96 }
97 
nu_epwm_set(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration)98 static rt_err_t nu_epwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
99 {
100     if ((((struct rt_pwm_configuration *)configuration)->period) <= 0)
101         return -(RT_ERROR);
102 
103     rt_uint8_t  pwm_channel_pair;
104     rt_uint32_t pwm_freq, pwm_dutycycle ;
105     EPWM_T *pwm_base = ((nu_epwm_t)device)->base;
106     rt_uint8_t pwm_channel = ((struct rt_pwm_configuration *)configuration)->channel;
107     rt_uint32_t pwm_period = ((struct rt_pwm_configuration *)configuration)->period;
108     rt_uint32_t pwm_pulse = ((struct rt_pwm_configuration *)configuration)->pulse;
109     rt_uint32_t pre_pwm_prescaler = EPWM_GET_PRESCALER(pwm_base, pwm_channel);
110 
111     if ((pwm_channel % 2) == 0)
112         pwm_channel_pair = pwm_channel + 1;
113     else
114         pwm_channel_pair = pwm_channel - 1;
115 
116     pwm_freq = (uint64_t)1000000000 / pwm_period;
117     pwm_dutycycle = (pwm_pulse * 100) / pwm_period;
118 
119     EPWM_ConfigOutputChannel(pwm_base, pwm_channel, pwm_freq, pwm_dutycycle) ;
120 
121     if ((pre_pwm_prescaler != 0) || (EPWM_GET_CNR(pwm_base, pwm_channel_pair) != 0) || (EPWM_GET_CMR(pwm_base, pwm_channel_pair) != 0))
122     {
123         if (pre_pwm_prescaler < EPWM_GET_PRESCALER(pwm_base, pwm_channel))
124         {
125             EPWM_SET_CNR(pwm_base, pwm_channel_pair, ((EPWM_GET_CNR(pwm_base, pwm_channel_pair) + 1) * (pre_pwm_prescaler + 1)) / (EPWM_GET_PRESCALER(pwm_base, pwm_channel) + 1));
126             EPWM_SET_CMR(pwm_base, pwm_channel_pair, (EPWM_GET_CMR(pwm_base, pwm_channel_pair) * (pre_pwm_prescaler + 1)) / (EPWM_GET_PRESCALER(pwm_base, pwm_channel) + 1));
127         }
128         else if (pre_pwm_prescaler > EPWM_GET_PRESCALER(pwm_base, pwm_channel))
129         {
130             EPWM_SET_CNR(pwm_base, pwm_channel, ((EPWM_GET_CNR(pwm_base, pwm_channel) + 1) * (EPWM_GET_PRESCALER(pwm_base, pwm_channel) + 1)) / (pre_pwm_prescaler + 1));
131             EPWM_SET_CMR(pwm_base, pwm_channel, (EPWM_GET_CMR(pwm_base, pwm_channel) * (EPWM_GET_PRESCALER(pwm_base, pwm_channel) + 1)) / (pre_pwm_prescaler + 1));
132         }
133     }
134     return RT_EOK;
135 }
136 
nu_epwm_clksr(struct rt_device_pwm * device)137 static rt_uint32_t nu_epwm_clksr(struct rt_device_pwm *device)
138 {
139     return CLK_GetPCLK0Freq(); //Both PCLK0 && PCLK1 are the same.
140 }
141 
nu_epwm_get(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration)142 static rt_err_t nu_epwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
143 {
144     rt_uint32_t pwm_real_period, pwm_real_duty, time_tick, u32EPWMClockSrc ;
145 
146     EPWM_T *pwm_base = ((nu_epwm_t)device)->base;
147     rt_uint32_t pwm_channel = ((struct rt_pwm_configuration *)configuration)->channel;
148     rt_uint32_t pwm_prescale = EPWM_GET_PRESCALER(pwm_base, pwm_channel);
149     rt_uint32_t pwm_period = EPWM_GET_CNR(pwm_base, pwm_channel);
150     rt_uint32_t pwm_pulse = EPWM_GET_CMR(pwm_base, pwm_channel);
151 
152     u32EPWMClockSrc = nu_epwm_clksr(device);
153     time_tick = (uint64_t)1000000000000 / u32EPWMClockSrc;
154 
155     pwm_real_period = (((pwm_prescale + 1) * (pwm_period + 1)) * time_tick) / 1000;
156     pwm_real_duty = (((pwm_prescale + 1) * pwm_pulse * time_tick)) / 1000;
157     ((struct rt_pwm_configuration *)configuration)->period = pwm_real_period;
158     ((struct rt_pwm_configuration *)configuration)->pulse = pwm_real_duty;
159 
160     LOG_I("%s %d %d %d\n", ((nu_epwm_t)device)->name, configuration->channel, configuration->period, configuration->pulse);
161 
162     return RT_EOK;
163 }
164 
nu_epwm_control(struct rt_device_pwm * device,int cmd,void * arg)165 static rt_err_t nu_epwm_control(struct rt_device_pwm *device, int cmd, void *arg)
166 {
167     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
168 
169     RT_ASSERT(device != RT_NULL);
170     RT_ASSERT(configuration != RT_NULL);
171 
172     if (((((struct rt_pwm_configuration *)configuration)->channel) + 1) > EPWM_CHANNEL_NUM)
173         return -(RT_ERROR);
174 
175     switch (cmd)
176     {
177     case PWM_CMD_ENABLE:
178         return nu_epwm_enable(device, configuration, RT_TRUE);
179     case PWM_CMD_DISABLE:
180         return nu_epwm_enable(device, configuration, RT_FALSE);
181     case PWM_CMD_SET:
182         return nu_epwm_set(device, configuration);
183     case PWM_CMD_GET:
184         return nu_epwm_get(device, configuration);
185     }
186     return -(RT_EINVAL);
187 }
188 
rt_hw_epwm_init(void)189 int rt_hw_epwm_init(void)
190 {
191     rt_err_t ret;
192     int i;
193 
194     for (i = (EPWM_START + 1); i < EPWM_CNT; i++)
195     {
196 
197         CLK_EnableModuleClock(nu_epwm_arr[i].modid);
198 
199         SYS_ResetModule(nu_epwm_arr[i].rstidx);
200 
201         ret = rt_device_pwm_register(&nu_epwm_arr[i].dev, nu_epwm_arr[i].name, &nu_epwm_ops, &nu_epwm_arr[i]);
202         RT_ASSERT(ret == RT_EOK);
203     }
204 
205     return 0;
206 }
207 
208 INIT_DEVICE_EXPORT(rt_hw_epwm_init);
209 
210 #endif
211