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