1 /*
2 * Copyright (c) 2006-2024 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-07-13 Rbb666 first version
9 */
10 #include "drv_pwm.h"
11
12 #ifdef RT_USING_PWM
13
14 #include <drivers/dev_pwm.h>
15 #include "drv_gpio.h"
16
17 /*#define DRV_DEBUG*/
18 #define LOG_TAG "drv.pwm"
19 #include <drv_log.h>
20
21 struct rt_device_pwm pwm_device;
22
23 struct ifx_pwm
24 {
25 struct rt_device_pwm pwm_device;
26 cyhal_pwm_t *pwm_obj;
27 rt_uint8_t channel;
28 char *name;
29 rt_uint8_t gpio;
30 };
31
32 static struct ifx_pwm ifx_pwm_obj[] =
33 {
34 #ifdef BSP_USING_PWM0_CH0_PORT0
35 PWM0_CH0_PORT0_CONFIG,
36 #endif
37
38 #ifdef BSP_USING_PWM0_CH2_PORT11_COMPL
39 PWM0_CH2_PORT11_COMPL_CONFIG,
40 #endif
41
42 #ifdef BSP_USING_PWM0_CH3_PORT11
43 PWM0_CH3_PORT11_CONFIG,
44 #endif
45
46 #ifdef BSP_USING_PWM0_CH4_PORT5_COMPL
47 PWM0_CH4_PORT5_COMPL_CONFIG,
48 #endif
49
50 #ifdef BSP_USING_PWM0_CH7_PORT2
51 PWM0_CH7_PORT2_CONFIG,
52 #endif
53
54 #ifdef BSP_USING_PWM0_CH7_PORT5
55 PWM0_CH7_PORT5_CONFIG,
56 #endif
57
58 #ifdef BSP_USING_PWM0_CH7_PORT5_COMPL
59 PWM0_CH7_PORT5_COMPL_CONFIG,
60 #endif
61
62 #ifdef BSP_USING_PWM0_CH7_PORT7
63 PWM0_CH7_PORT7_CONFIG,
64 #endif
65
66 #ifdef BSP_USING_PWM0_CH7_PORT9
67 PWM0_CH7_PORT9_CONFIG,
68 #endif
69
70 #ifdef BSP_USING_PWM0_CH7_PORT10
71 PWM0_CH7_PORT10_CONFIG,
72 #endif
73
74 #ifdef BSP_USING_PWM0_CH7_PORT12
75 PWM0_CH7_PORT12_CONFIG,
76 #endif
77
78 #ifdef BSP_USING_PWM0_CH7_PORT13
79 PWM0_CH3_PORT13_CONFIG,
80 #endif
81 };
82
drv_pwm_enable(cyhal_pwm_t * htim,struct rt_pwm_configuration * configuration,rt_bool_t enable)83 static rt_err_t drv_pwm_enable(cyhal_pwm_t *htim, struct rt_pwm_configuration *configuration, rt_bool_t enable)
84 {
85 /* get the value of channel */
86 rt_uint32_t channel = configuration->channel;
87
88 if (!configuration->complementary || configuration->complementary)
89 {
90 if (!enable)
91 {
92 htim->tcpwm.resource.channel_num = channel;
93 cyhal_pwm_stop(htim);
94 }
95 else
96 {
97 htim->tcpwm.resource.channel_num = channel;
98 cyhal_pwm_start(htim);
99 }
100 }
101
102 return RT_EOK;
103 }
104
drv_pwm_set(cyhal_pwm_t * htim,struct rt_pwm_configuration * configuration)105 static rt_err_t drv_pwm_set(cyhal_pwm_t *htim, struct rt_pwm_configuration *configuration)
106 {
107 rt_uint64_t tim_clock;
108 rt_uint32_t period, pulse;
109
110 tim_clock = (rt_uint32_t)(htim->tcpwm.clock_hz);
111
112 htim->tcpwm.resource.channel_num = configuration->channel;
113
114 period = (unsigned long long)configuration->period / 1000ULL;
115
116 pulse = (unsigned long long)configuration->pulse / 1000ULL;
117
118 cyhal_pwm_set_period(htim, period, pulse);
119
120 return RT_EOK;
121 }
122
drv_pwm_get(cyhal_pwm_t * htim,struct rt_pwm_configuration * configuration)123 static rt_err_t drv_pwm_get(cyhal_pwm_t *htim, struct rt_pwm_configuration *configuration)
124 {
125 uint32_t Period = Cy_TCPWM_PWM_GetPeriod0(htim->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(htim->tcpwm.resource));
126
127 uint32_t Compare = Cy_TCPWM_PWM_GetCounter(htim->tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER(htim->tcpwm.resource));
128
129 configuration->period = Period;
130
131 configuration->pulse = Compare;
132
133 return RT_EOK;
134 }
135
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)136 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
137 {
138 struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
139 cyhal_pwm_t *htim = (cyhal_pwm_t *)device->parent.user_data;
140
141 switch (cmd)
142 {
143 case PWMN_CMD_ENABLE:
144 configuration->complementary = RT_TRUE;
145
146 case PWM_CMD_ENABLE:
147 return drv_pwm_enable(htim, configuration, RT_TRUE);
148
149 case PWMN_CMD_DISABLE:
150 configuration->complementary = RT_FALSE;
151
152 case PWM_CMD_DISABLE:
153 return drv_pwm_enable(htim, configuration, RT_FALSE);
154
155 case PWM_CMD_SET:
156 return drv_pwm_set(htim, configuration);
157
158 case PWM_CMD_GET:
159 return drv_pwm_get(htim, configuration);
160
161 default:
162 return -RT_EINVAL;
163 }
164 }
165
166 static struct rt_pwm_ops drv_ops = {drv_pwm_control};
167
ifx_hw_pwm_init(struct ifx_pwm * device)168 static rt_err_t ifx_hw_pwm_init(struct ifx_pwm *device)
169 {
170 rt_err_t result = RT_EOK;
171
172 RT_ASSERT(device != RT_NULL);
173
174 if (cyhal_pwm_init_adv(device->pwm_obj, device->gpio, NC, CYHAL_PWM_LEFT_ALIGN, true, 0u, false, RT_NULL) != RT_EOK)
175 {
176 LOG_E("%s channel%d config failed", device->name, device->channel);
177 result = -RT_ERROR;
178 goto __exit;
179 }
180
181 __exit:
182 return result;
183 }
184
rt_hw_pwm_init(void)185 static int rt_hw_pwm_init(void)
186 {
187 int i;
188 int result = RT_EOK;
189
190 for (i = 0; i < sizeof(ifx_pwm_obj) / sizeof(ifx_pwm_obj[0]); i++)
191 {
192 ifx_pwm_obj[i].pwm_obj = rt_malloc(sizeof(cyhal_pwm_t));
193 RT_ASSERT(ifx_pwm_obj[i].pwm_obj != RT_NULL);
194
195 /* pwm init */
196 if (ifx_hw_pwm_init(&ifx_pwm_obj[i]) != RT_EOK)
197 {
198 LOG_E("%s init failed", ifx_pwm_obj[i].name);
199 result = -RT_ERROR;
200 goto __exit;
201 }
202 else
203 {
204 if (rt_device_pwm_register(&ifx_pwm_obj[i].pwm_device, ifx_pwm_obj[i].name, &drv_ops, ifx_pwm_obj[i].pwm_obj) == RT_EOK)
205 {
206 LOG_D("%s register success", ifx_pwm_obj[i].name);
207 }
208 else
209 {
210 LOG_D("%s register failed", ifx_pwm_obj[i].name);
211 result = -RT_ERROR;
212 }
213 }
214 }
215
216 __exit:
217 return result;
218 }
219 INIT_BOARD_EXPORT(rt_hw_pwm_init);
220
221 #define PWM_DEV_NAME "pwm0"
222 #define PWM_DEV_CHANNEL 4
223
224 struct rt_device_pwm *pwm_dev;
225
pwm_sample(int argc,char * argv[])226 static int pwm_sample(int argc, char *argv[])
227 {
228 rt_uint32_t period, pulse, dir;
229
230 period = 1 * 1000 * 1000;
231 dir = 1;
232 pulse = 0;
233
234 pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
235
236 if (pwm_dev == RT_NULL)
237 {
238 rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
239 return -RT_ERROR;
240 }
241
242 rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
243 rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
244
245 rt_kprintf("Now PWM[%s] Channel[%d] Period[%d] Pulse[%d]\n", PWM_DEV_NAME, PWM_DEV_CHANNEL, period, pulse);
246
247 while (1)
248 {
249 rt_thread_mdelay(50);
250
251 if (dir)
252 {
253 pulse += 100000;
254 }
255 else
256 {
257 pulse -= 100000;
258 }
259
260 if (pulse >= period)
261 {
262 dir = 0;
263 }
264
265 if (0 == pulse)
266 {
267 dir = 1;
268 }
269
270 rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
271 }
272 }
273 MSH_CMD_EXPORT(pwm_sample, <pwm0> channel7 sample);
274 #endif
275