1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-01-21 charlown first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <board.h>
14
15 #ifdef BSP_USING_PWM
16
17 #define LOG_TAG "drv.pwm"
18 #include <drv_log.h>
19
20 #ifndef ITEM_NUM
21 #define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
22 #endif
23
24 #define MAX_COUNTER 65535
25 #define MIN_COUNTER 2
26 #define MIN_PULSE 2
27
28 struct rtdevice_pwm_device
29 {
30 struct rt_device_pwm parent;
31 TIM_TypeDef *periph;
32 rt_uint8_t channel[4];
33 char *name;
34 };
35
36 /*
37 * channel = 0xFF: the channel is not use.
38 */
39 struct rtdevice_pwm_device pwm_device_list[] =
40 {
41 #ifdef BSP_USING_TIM1_PWM
42 {
43 .periph = TIM1,
44 .name = "pwm1",
45 #ifdef BSP_USING_TIM1_PWM_CH1
46 .channel[0] = TIM_Channel_1,
47 #else
48 .channel[0] = 0xFF,
49 #endif
50
51 #ifdef BSP_USING_TIM1_PWM_CH2
52 .channel[1] = TIM_Channel_2,
53 #else
54 .channel[1] = 0xFF,
55 #endif
56
57 #ifdef BSP_USING_TIM1_PWM_CH3
58 .channel[2] = TIM_Channel_3,
59 #else
60 .channel[2] = 0xFF,
61 #endif
62
63 #ifdef BSP_USING_TIM1_PWM_CH4
64 .channel[3] = TIM_Channel_4,
65 #else
66 .channel[3] = 0xFF,
67 #endif
68 },
69 #endif
70
71 #ifdef BSP_USING_TIM2_PWM
72 {
73 .periph = TIM2,
74 .name = "pwm2",
75 #ifdef BSP_USING_TIM2_PWM_CH1
76 .channel[0] = TIM_Channel_1,
77 #else
78 .channel[0] = 0xFF,
79 #endif
80
81 #ifdef BSP_USING_TIM2_PWM_CH2
82 .channel[1] = TIM_Channel_2,
83 #else
84 .channel[1] = 0xFF,
85 #endif
86
87 #ifdef BSP_USING_TIM2_PWM_CH3
88 .channel[2] = TIM_Channel_3,
89 #else
90 .channel[2] = 0xFF,
91 #endif
92
93 #ifdef BSP_USING_TIM2_PWM_CH4
94 .channel[3] = TIM_Channel_4,
95 #else
96 .channel[3] = 0xFF,
97 #endif
98 },
99 #endif
100
101 #ifdef BSP_USING_TIM3_PWM
102 {
103 .periph = TIM3,
104 .name = "pwm3",
105 #ifdef BSP_USING_TIM3_PWM_CH1
106 .channel[0] = TIM_Channel_1,
107 #else
108 .channel[0] = 0xFF,
109 #endif
110
111 #ifdef BSP_USING_TIM3_PWM_CH2
112 .channel[1] = TIM_Channel_2,
113 #else
114 .channel[1] = 0xFF,
115 #endif
116
117 #ifdef BSP_USING_TIM3_PWM_CH3
118 .channel[2] = TIM_Channel_3,
119 #else
120 .channel[2] = 0xFF,
121 #endif
122
123 #ifdef BSP_USING_TIM3_PWM_CH4
124 .channel[3] = TIM_Channel_4,
125 #else
126 .channel[3] = 0xFF,
127 #endif
128 },
129 #endif
130
131 #ifdef BSP_USING_TIM4_PWM
132 {
133 .periph = TIM4,
134 .name = "pwm4",
135 #ifdef BSP_USING_TIM4_PWM_CH1
136 .channel[0] = TIM_Channel_1,
137 #else
138 .channel[0] = 0xFF,
139 #endif
140
141 #ifdef BSP_USING_TIM4_PWM_CH2
142 .channel[1] = TIM_Channel_2,
143 #else
144 .channel[1] = 0xFF,
145 #endif
146
147 #ifdef BSP_USING_TIM4_PWM_CH3
148 .channel[2] = TIM_Channel_3,
149 #else
150 .channel[2] = 0xFF,
151 #endif
152
153 #ifdef BSP_USING_TIM4_PWM_CH4
154 .channel[3] = TIM_Channel_4,
155 #else
156 .channel[3] = 0xFF,
157 #endif
158 },
159 #endif
160
161 #ifdef BSP_USING_TIM5_PWM
162 {
163 .periph = TIM5,
164 .name = "pwm5",
165 #ifdef BSP_USING_TIM5_PWM_CH1
166 .channel[0] = TIM_Channel_1,
167 #else
168 .channel[0] = 0xFF,
169 #endif
170
171 #ifdef BSP_USING_TIM5_PWM_CH2
172 .channel[1] = TIM_Channel_2,
173 #else
174 .channel[1] = 0xFF,
175 #endif
176
177 #ifdef BSP_USING_TIM5_PWM_CH3
178 .channel[2] = TIM_Channel_3,
179 #else
180 .channel[2] = 0xFF,
181 #endif
182
183 #ifdef BSP_USING_TIM5_PWM_CH4
184 .channel[3] = TIM_Channel_4,
185 #else
186 .channel[3] = 0xFF,
187 #endif
188 },
189 #endif
190
191 #ifdef BSP_USING_TIM8_PWM
192 {
193 .periph = TIM8,
194 .name = "pwm8",
195 #ifdef BSP_USING_TIM8_PWM_CH1
196 .channel[0] = TIM_Channel_1,
197 #else
198 .channel[0] = 0xFF,
199 #endif
200
201 #ifdef BSP_USING_TIM8_PWM_CH2
202 .channel[1] = TIM_Channel_2,
203 #else
204 .channel[1] = 0xFF,
205 #endif
206
207 #ifdef BSP_USING_TIM8_PWM_CH3
208 .channel[2] = TIM_Channel_3,
209 #else
210 .channel[2] = 0xFF,
211 #endif
212
213 #ifdef BSP_USING_TIM8_PWM_CH4
214 .channel[3] = TIM_Channel_4,
215 #else
216 .channel[3] = 0xFF,
217 #endif
218 },
219 #endif
220
221 #ifdef BSP_USING_TIM9_PWM
222 {
223 .periph = TIM9,
224 .name = "pwm9",
225 #ifdef BSP_USING_TIM9_PWM_CH1
226 .channel[0] = TIM_Channel_1,
227 #else
228 .channel[0] = 0xFF,
229 #endif
230
231 #ifdef BSP_USING_TIM9_PWM_CH2
232 .channel[1] = TIM_Channel_2,
233 #else
234 .channel[1] = 0xFF,
235 #endif
236
237 #ifdef BSP_USING_TIM9_PWM_CH3
238 .channel[2] = TIM_Channel_3,
239 #else
240 .channel[2] = 0xFF,
241 #endif
242
243 #ifdef BSP_USING_TIM9_PWM_CH4
244 .channel[3] = TIM_Channel_4,
245 #else
246 .channel[3] = 0xFF,
247 #endif
248 },
249 #endif
250
251 #ifdef BSP_USING_TIM10_PWM
252 {
253 .periph = TIM10,
254 .name = "pwm10",
255 #ifdef BSP_USING_TIM10_PWM_CH1
256 .channel[0] = TIM_Channel_1,
257 #else
258 .channel[0] = 0xFF,
259 #endif
260
261 #ifdef BSP_USING_TIM10_PWM_CH2
262 .channel[1] = TIM_Channel_2,
263 #else
264 .channel[1] = 0xFF,
265 #endif
266
267 #ifdef BSP_USING_TIM10_PWM_CH3
268 .channel[2] = TIM_Channel_3,
269 #else
270 .channel[2] = 0xFF,
271 #endif
272
273 #ifdef BSP_USING_TIM10_PWM_CH4
274 .channel[3] = TIM_Channel_4,
275 #else
276 .channel[3] = 0xFF,
277 #endif
278 },
279 #endif
280
281 };
282
ch32f2_pwm_device_enable(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration,rt_bool_t enable)283 static rt_err_t ch32f2_pwm_device_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
284 {
285 struct rtdevice_pwm_device *pwm_device;
286 rt_uint32_t channel_index;
287 rt_uint16_t ccx_state;
288
289 pwm_device = (struct rtdevice_pwm_device *)device;
290 channel_index = configuration->channel;
291
292 if (enable == RT_TRUE)
293 {
294 ccx_state = TIM_CCx_Enable;
295 }
296 else
297 {
298 ccx_state = TIM_CCx_Disable;
299 }
300
301 if (channel_index <= 4 && channel_index > 0)
302 {
303 if (pwm_device->channel[channel_index - 1] == 0xFF)
304 return -RT_EINVAL;
305
306 TIM_CCxCmd(pwm_device->periph, pwm_device->channel[channel_index - 1], ccx_state);
307 }
308 else
309 {
310 return -RT_EINVAL;
311 }
312
313 TIM_Cmd(pwm_device->periph, ENABLE);
314
315 return RT_EOK;
316 }
317
ch32f2_pwm_device_get(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration)318 static rt_err_t ch32f2_pwm_device_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
319 {
320 struct rtdevice_pwm_device *pwm_device;
321 rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
322 rt_uint32_t channel_index;
323 rt_uint32_t tim_clock;
324
325 pwm_device = (struct rtdevice_pwm_device *)device;
326
327 tim_clock = ch32f2_tim_clock_get(pwm_device->periph);
328 channel_index = configuration->channel;
329 arr_counter = pwm_device->periph->ATRLR + 1;
330 prescaler = pwm_device->periph->PSC + 1;
331
332 sample_freq = (tim_clock / prescaler) / arr_counter;
333
334 /* unit:ns */
335 configuration->period = 1000000000 / sample_freq;
336
337 if (channel_index == 1)
338 {
339 ccr_counter = pwm_device->periph->CH1CVR + 1;
340 configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
341 }
342 else if (channel_index == 2)
343 {
344 ccr_counter = pwm_device->periph->CH2CVR + 1;
345 configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
346 }
347 else if (channel_index == 3)
348 {
349 ccr_counter = pwm_device->periph->CH3CVR + 1;
350 configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
351 }
352 else if (channel_index == 4)
353 {
354 ccr_counter = pwm_device->periph->CH4CVR + 1;
355 configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
356 }
357 else
358 return -RT_EINVAL;
359
360 return RT_EOK;
361 }
362
ch32f2_pwm_device_set(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration)363 static rt_err_t ch32f2_pwm_device_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
364 {
365 struct rtdevice_pwm_device *pwm_device;
366 rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
367 rt_uint32_t channel_index;
368 rt_uint32_t tim_clock;
369
370 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitType;
371 TIM_OCInitTypeDef TIM_OCInitType;
372
373 pwm_device = (struct rtdevice_pwm_device *)device;
374
375 tim_clock = ch32f2_tim_clock_get(pwm_device->periph);
376
377 channel_index = configuration->channel;
378
379 /* change to freq, unit:Hz */
380 sample_freq = 1000000000 / configuration->period;
381
382 /*counter = (tim_clk / prescaler) / sample_freq */
383 /*normally, tim_clk is not need div, if arr_counter over 65536, need div.*/
384 prescaler = 1;
385
386 arr_counter = (tim_clock / prescaler) / sample_freq;
387
388 if (arr_counter > MAX_COUNTER)
389 {
390 /* need div tim_clock
391 * and round up the prescaler value.
392 * (tim_clock >> 16) = tim_clock / 65536
393 */
394 if ((tim_clock >> 16) % sample_freq == 0)
395 prescaler = (tim_clock >> 16) / sample_freq;
396 else
397 prescaler = (tim_clock >> 16) / sample_freq + 1;
398
399 /*counter = (tim_clk / prescaler) / sample_freq */
400 arr_counter = (tim_clock / prescaler) / sample_freq;
401 }
402 /* ccr_counter = duty cycle * arr_counter */
403 ccr_counter = (configuration->pulse * 100 / configuration->period) * arr_counter / 100;
404
405 /* check arr_counter > 1, cxx_counter > 1 */
406 if (arr_counter < MIN_COUNTER)
407 {
408 arr_counter = MIN_COUNTER;
409 }
410
411 if (ccr_counter < MIN_PULSE)
412 {
413 ccr_counter = MIN_PULSE;
414 }
415
416 /* TMRe base configuration */
417 TIM_TimeBaseStructInit(&TIM_TimeBaseInitType);
418 TIM_TimeBaseInitType.TIM_Period = arr_counter - 1;
419 TIM_TimeBaseInitType.TIM_Prescaler = prescaler - 1;
420 TIM_TimeBaseInitType.TIM_ClockDivision = TIM_CKD_DIV1;
421 TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Up;
422
423 TIM_TimeBaseInit(pwm_device->periph, &TIM_TimeBaseInitType);
424
425
426 TIM_OCStructInit(&TIM_OCInitType);
427 TIM_OCInitType.TIM_OCMode = TIM_OCMode_PWM1;
428 TIM_OCInitType.TIM_OutputState = TIM_OutputState_Enable;
429 TIM_OCInitType.TIM_Pulse = ccr_counter - 1;
430 TIM_OCInitType.TIM_OCPolarity = TIM_OCPolarity_High;
431
432 if (channel_index == 1)
433 {
434 TIM_OC1Init(pwm_device->periph, &TIM_OCInitType);
435 TIM_OC1PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
436 }
437 else if (channel_index == 2)
438 {
439 TIM_OC2Init(pwm_device->periph, &TIM_OCInitType);
440 TIM_OC2PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
441 }
442 else if (channel_index == 3)
443 {
444 TIM_OC3Init(pwm_device->periph, &TIM_OCInitType);
445 TIM_OC3PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
446 }
447 else if (channel_index == 4)
448 {
449 TIM_OC4Init(pwm_device->periph, &TIM_OCInitType);
450 TIM_OC4PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
451 }
452 else
453 {
454 return -RT_EINVAL;
455 }
456
457 TIM_ARRPreloadConfig(pwm_device->periph, ENABLE);
458 TIM_CtrlPWMOutputs(pwm_device->periph, ENABLE);
459
460 return RT_EOK;
461 }
462
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)463 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
464 {
465 struct rt_pwm_configuration *configuration;
466
467 configuration = (struct rt_pwm_configuration *)arg;
468
469 switch (cmd)
470 {
471 case PWM_CMD_ENABLE:
472 return ch32f2_pwm_device_enable(device, configuration, RT_TRUE);
473 case PWM_CMD_DISABLE:
474 return ch32f2_pwm_device_enable(device, configuration, RT_FALSE);
475 case PWM_CMD_SET:
476 return ch32f2_pwm_device_set(device, configuration);
477 case PWM_CMD_GET:
478 return ch32f2_pwm_device_get(device, configuration);
479 default:
480 return -RT_EINVAL;
481 }
482 }
483
484 static struct rt_pwm_ops pwm_ops =
485 {
486 .control = drv_pwm_control};
487
rt_hw_pwm_init(void)488 static int rt_hw_pwm_init(void)
489 {
490 int result = RT_EOK;
491 int index = 0;
492 int channel_index;
493
494 for (index = 0; index < ITEM_NUM(pwm_device_list); index++)
495 {
496 ch32f2_tim_clock_init(pwm_device_list[index].periph);
497 for (channel_index = 0; channel_index < sizeof(pwm_device_list[index].channel); channel_index++)
498 {
499 if (pwm_device_list[index].channel[channel_index] != 0xFF)
500 {
501 ch32f2_pwm_io_init(pwm_device_list[index].periph, pwm_device_list[index].channel[channel_index]);
502 }
503 }
504
505 if (rt_device_pwm_register(&pwm_device_list[index].parent, pwm_device_list[index].name, &pwm_ops, RT_NULL) == RT_EOK)
506 {
507 LOG_D("%s register success", pwm_device_list[index].name);
508 }
509 else
510 {
511 LOG_D("%s register failed", pwm_device_list[index].name);
512 result = -RT_ERROR;
513 }
514 }
515
516 return result;
517 }
518
519 INIT_BOARD_EXPORT(rt_hw_pwm_init);
520
521 #endif /* BSP_USING_PWM */
522