1 /*
2  * Copyright (c) 2006-2023
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2023-06-05     zengjianwei       first version
9  * 2025-06-23     Yucai Liu         Support for non-complementary PWM output with advanced timers
10  */
11 
12 #include <board.h>
13 #include <gd32f30x.h>
14 #include <rtdevice.h>
15 #include <rtthread.h>
16 
17 #ifdef RT_USING_PWM
18 
19 /* #define DRV_DEBUG */
20 #define LOG_TAG "drv.pwm"
21 #include <rtdbg.h>
22 
23 #define MAX_PERIOD 65535
24 #define MIN_PERIOD 3
25 #define MIN_PULSE  2
26 
27 typedef struct
28 {
29     rt_int8_t   TimerIndex; /* timer index:0~13 */
30     rt_uint32_t Port;       /* gpio port:GPIOA/GPIOB/GPIOC/... */
31     rt_uint32_t pin;        /* gpio pin:GPIO_PIN_0~GPIO_PIN_15 */
32     /* timer channel: -2 is ch_1n, -1 is ch_0n, 0 is ch0, 1 is ch1 */
33     rt_int16_t channel;
34     char      *name;
35 } TIMER_PORT_CHANNEL_MAP_S;
36 
37 struct gd32_pwm
38 {
39     struct rt_device_pwm     pwm_device;
40     TIMER_PORT_CHANNEL_MAP_S tim_handle;
41 };
42 
43 static struct gd32_pwm gd32_pwm_obj[] = {
44 #ifdef RT_USING_PWM1
45     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm1"}},
46 #endif
47 
48 #ifdef RT_USING_PWM2
49     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm2"}},
50 #endif
51 
52 #ifdef RT_USING_PWM3
53     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm3"}},
54 #endif
55 
56 #ifdef RT_USING_PWM4
57     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm4"}},
58 #endif
59 
60 #ifdef RT_USING_PWM5
61     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm5"}},
62 #endif
63 
64 #ifdef RT_USING_PWM6
65     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm6"}},
66 #endif
67 
68 #ifdef RT_USING_PWM7
69     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm7"}},
70 #endif
71 
72 #ifdef RT_USING_PWM8
73     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm8"}},
74 #endif
75 
76 #ifdef RT_USING_PWM9
77     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm9"}},
78 #endif
79 
80 #ifdef RT_USING_PWM10
81     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm10"}},
82 #endif
83 
84 #ifdef RT_USING_PWM11
85     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm11"}},
86 #endif
87 
88 #ifdef RT_USING_PWM12
89     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm12"}},
90 #endif
91 
92 #ifdef RT_USING_PWM13
93     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm13"}},
94 #endif
95 
96 #ifdef RT_USING_PWM14
97     {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm14"}},
98 #endif
99 };
100 
101 typedef struct
102 {
103     rt_uint32_t Port[7];
104     rt_int8_t   TimerIndex[14];
105 } TIMER_PERIPH_LIST_S;
106 
107 static TIMER_PERIPH_LIST_S gd32_timer_periph_list = {
108     .Port       = {0, 0, 0, 0, 0, 0, 0},
109     .TimerIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
110 };
111 
112 /*
113  * 将所有用到的 gpio port 和 timer 不重复地列举出来,以方便后面不重复地初始化
114  */
pwm_find_timer_periph(void)115 static rt_err_t pwm_find_timer_periph(void)
116 {
117     rt_int16_t i, j, k;
118 
119     /* find gpio port of defined table */
120     for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
121     {
122         /* find -1 of gd32_periph_list's member of Port */
123         for (j = 0; j < sizeof(gd32_timer_periph_list.Port) / sizeof(gd32_timer_periph_list.Port[0]); ++j)
124         {
125             if (0 == gd32_timer_periph_list.Port[j])
126             {
127                 break;
128             }
129         }
130 
131         if (j >= sizeof(gd32_timer_periph_list.Port) / sizeof(gd32_timer_periph_list.Port[0]))
132         {
133             LOG_E("Can not find -1 of gd32_periph_list's member of Port!\n");
134             break;
135         }
136 
137         /* find the different of Port */
138         for (k = 0; k < j; ++k)
139         {
140             if (gd32_pwm_obj[i].tim_handle.Port == gd32_timer_periph_list.Port[k])
141             {
142                 break;
143             }
144         }
145 
146         /* if can not find the same Port */
147         if (k == j)
148         {
149             gd32_timer_periph_list.Port[j] = gd32_pwm_obj[i].tim_handle.Port;
150         }
151     }
152 
153     /* find timer periph of defined table */
154     for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
155     {
156         /* find -1 of gd32_periph_list's member of TimerIndex */
157         for (j = 0; j < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++j)
158         {
159             if (-1 == gd32_timer_periph_list.TimerIndex[j])
160             {
161                 break;
162             }
163         }
164 
165         if (j >= sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]))
166         {
167             LOG_E("Can not find -1 of gd32_periph_list's member of TimerIndex!\n");
168             break;
169         }
170 
171         /* find the different of TimerIndex */
172         for (k = 0; k < j; ++k)
173         {
174             if (gd32_pwm_obj[i].tim_handle.TimerIndex == gd32_timer_periph_list.TimerIndex[k])
175             {
176                 break;
177             }
178         }
179 
180         /* if can not find the same TimerIndex */
181         if (k == j)
182         {
183             gd32_timer_periph_list.TimerIndex[j] = gd32_pwm_obj[i].tim_handle.TimerIndex;
184         }
185     }
186 
187     return RT_EOK;
188 }
189 
index_to_timer(rt_int8_t TimerIndex)190 static rt_uint32_t index_to_timer(rt_int8_t TimerIndex)
191 {
192     switch (TimerIndex)
193     {
194     case 0:
195         return TIMER0;
196     case 1:
197         return TIMER1;
198     case 2:
199         return TIMER2;
200     case 3:
201         return TIMER3;
202     case 4:
203         return TIMER4;
204     case 5:
205         return TIMER5;
206     case 6:
207         return TIMER6;
208     case 7:
209         return TIMER7;
210     case 8:
211         return TIMER8;
212     case 9:
213         return TIMER9;
214     case 10:
215         return TIMER10;
216     case 11:
217         return TIMER11;
218     case 12:
219         return TIMER12;
220     case 13:
221         return TIMER13;
222 
223     default:
224         LOG_E("Unsport timer periph!\n");
225     }
226     return TIMER0;
227 }
228 
gpio_clock_enable(rt_uint32_t Port)229 static void gpio_clock_enable(rt_uint32_t Port)
230 {
231     switch (Port)
232     {
233     case GPIOA:
234         rcu_periph_clock_enable(RCU_GPIOA);
235         break;
236     case GPIOB:
237         rcu_periph_clock_enable(RCU_GPIOB);
238         break;
239     case GPIOC:
240         rcu_periph_clock_enable(RCU_GPIOC);
241         break;
242     case GPIOD:
243         rcu_periph_clock_enable(RCU_GPIOD);
244         break;
245     case GPIOE:
246         rcu_periph_clock_enable(RCU_GPIOE);
247         break;
248     case GPIOF:
249         rcu_periph_clock_enable(RCU_GPIOF);
250         break;
251     case GPIOG:
252         rcu_periph_clock_enable(RCU_GPIOG);
253         break;
254 
255     default:
256         LOG_E("Unsport gpio port!\n");
257     }
258 }
259 
timer_clock_enable(rt_int8_t TimerIndex)260 static void timer_clock_enable(rt_int8_t TimerIndex)
261 {
262     switch (TimerIndex)
263     {
264     case 0:
265         rcu_periph_clock_enable(RCU_TIMER0);
266         break;
267     case 1:
268         rcu_periph_clock_enable(RCU_TIMER1);
269         break;
270     case 2:
271         rcu_periph_clock_enable(RCU_TIMER2);
272         break;
273     case 3:
274         rcu_periph_clock_enable(RCU_TIMER3);
275         break;
276     case 4:
277         rcu_periph_clock_enable(RCU_TIMER4);
278         break;
279     case 5:
280         rcu_periph_clock_enable(RCU_TIMER5);
281         break;
282     case 6:
283         rcu_periph_clock_enable(RCU_TIMER6);
284         break;
285     case 7:
286         rcu_periph_clock_enable(RCU_TIMER7);
287         break;
288 #ifndef GD32F30X_HD
289     case 8:
290         rcu_periph_clock_enable(RCU_TIMER8);
291         break;
292     case 9:
293         rcu_periph_clock_enable(RCU_TIMER9);
294         break;
295     case 10:
296         rcu_periph_clock_enable(RCU_TIMER10);
297         break;
298     case 11:
299         rcu_periph_clock_enable(RCU_TIMER11);
300         break;
301     case 12:
302         rcu_periph_clock_enable(RCU_TIMER12);
303         break;
304     case 13:
305         rcu_periph_clock_enable(RCU_TIMER13);
306         break;
307 #endif
308     default:
309         LOG_E("Unsport timer periph!\n");
310     }
311 }
312 
rcu_config(void)313 static void rcu_config(void)
314 {
315     rt_int16_t i;
316 
317     for (i = 0; i < sizeof(gd32_timer_periph_list.Port) / sizeof(gd32_timer_periph_list.Port[0]); ++i)
318     {
319         if (0 == gd32_timer_periph_list.Port[i])
320         {
321             break;
322         }
323 
324         /* enable GPIO clock */
325         gpio_clock_enable(gd32_timer_periph_list.Port[i]);
326     }
327 
328     rcu_periph_clock_enable(RCU_AF);
329 
330     for (i = 0; i < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++i)
331     {
332         if (-1 == gd32_timer_periph_list.TimerIndex[i])
333         {
334             break;
335         }
336 
337         /* enable timer clock */
338         timer_clock_enable(gd32_timer_periph_list.TimerIndex[i]);
339         timer_deinit(index_to_timer(gd32_timer_periph_list.TimerIndex[i]));
340     }
341 }
342 
gpio_config(void)343 static void gpio_config(void)
344 {
345     rt_int16_t i;
346 
347     /* config the GPIO as analog mode */
348     for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
349     {
350         gpio_init(gd32_pwm_obj[i].tim_handle.Port, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, gd32_pwm_obj[i].tim_handle.pin);
351     }
352 }
353 
timer_init_para(timer_parameter_struct * initpara)354 static void timer_init_para(timer_parameter_struct *initpara)
355 {
356     rt_int16_t i;
357 
358     for (i = 0; i < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++i)
359     {
360         /* config timer */
361         if (-1 != gd32_timer_periph_list.TimerIndex[i])
362         {
363             timer_init(index_to_timer(gd32_timer_periph_list.TimerIndex[i]), initpara);
364         }
365     }
366 }
367 
channel_output_config(timer_oc_parameter_struct * ocpara)368 static void channel_output_config(timer_oc_parameter_struct *ocpara)
369 {
370     rt_int16_t  i;
371     rt_uint32_t timer_periph;
372 
373     /* config the channel config */
374     for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
375     {
376         if (gd32_pwm_obj[i].tim_handle.channel < 0)
377         {
378             ocpara->outputstate                = TIMER_CCX_DISABLE;
379             ocpara->outputnstate               = TIMER_CCXN_ENABLE;
380             gd32_pwm_obj[i].tim_handle.channel = -(gd32_pwm_obj[i].tim_handle.channel + 1);
381         }
382         timer_periph = index_to_timer(gd32_pwm_obj[i].tim_handle.TimerIndex);
383         timer_channel_output_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, ocpara);
384 
385         timer_channel_output_pulse_value_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, 7999);
386         timer_channel_output_mode_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_OC_MODE_PWM0);
387         timer_channel_output_shadow_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_OC_SHADOW_DISABLE);
388         /* auto-reload preload shadow reg enable */
389         /* timer_auto_reload_shadow_enable(timer_periph); */
390         timer_channel_output_state_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_CCX_DISABLE);
391         timer_channel_complementary_output_state_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_CCXN_DISABLE);
392     }
393 
394     /* enable timer */
395     for (i = 0; i < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++i)
396     {
397         if (-1 != gd32_timer_periph_list.TimerIndex[i])
398         {
399             timer_periph = index_to_timer(gd32_timer_periph_list.TimerIndex[i]);
400             if (timer_periph == TIMER0 || timer_periph == TIMER7)
401             {
402                 timer_primary_output_config(timer_periph, ENABLE);
403             }
404             timer_enable(timer_periph);
405         }
406     }
407 }
408 
timer_config(void)409 static void timer_config(void)
410 {
411     timer_oc_parameter_struct timer_ocintpara;
412     timer_parameter_struct    timer_initpara;
413 
414     /* TIMER configuration */
415     timer_initpara.prescaler         = 119;
416     timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
417     timer_initpara.counterdirection  = TIMER_COUNTER_UP;
418     timer_initpara.period            = 15999;
419     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
420     timer_initpara.repetitioncounter = 0;
421     timer_init_para(&timer_initpara);
422 
423     /* CHX configuration in PWM mode */
424     timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
425     timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
426     timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
427     timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
428     timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
429     timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
430     channel_output_config(&timer_ocintpara);
431 }
432 
drv_pwm_enable(TIMER_PORT_CHANNEL_MAP_S * pstTimerMap,struct rt_pwm_configuration * configuration,rt_bool_t enable)433 static rt_err_t drv_pwm_enable(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm_configuration *configuration,
434                                rt_bool_t enable)
435 {
436     if (!enable)
437     {
438         timer_channel_output_state_config(index_to_timer(pstTimerMap->TimerIndex), configuration->channel,
439                                           TIMER_CCX_DISABLE);
440     }
441     else
442     {
443         if (configuration->complementary == RT_TRUE)
444         {
445             timer_channel_output_state_config(
446                 index_to_timer(pstTimerMap->TimerIndex), configuration->channel - 1, TIMER_CCXN_ENABLE);
447         }
448         else
449         {
450             timer_channel_output_state_config(
451                 index_to_timer(pstTimerMap->TimerIndex), configuration->channel, TIMER_CCX_ENABLE);
452         }
453     }
454 
455     return RT_EOK;
456 }
457 
drv_pwm_get(TIMER_PORT_CHANNEL_MAP_S * pstTimerMap,struct rt_pwm_configuration * configuration)458 static rt_err_t drv_pwm_get(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm_configuration *configuration)
459 {
460     rt_uint64_t tim_clock;
461     rt_uint16_t psc;
462     rt_uint32_t chxcv;
463 
464     tim_clock = rcu_clock_freq_get(CK_SYS);
465 
466     psc = timer_prescaler_read(index_to_timer(pstTimerMap->TimerIndex));
467     if (psc == TIMER_CKDIV_DIV2)
468     {
469         tim_clock = tim_clock / 2;
470     }
471     else if (psc == TIMER_CKDIV_DIV4)
472     {
473         tim_clock = tim_clock / 4;
474     }
475 
476     chxcv = timer_channel_capture_value_register_read(index_to_timer(pstTimerMap->TimerIndex), configuration->channel);
477     /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
478     tim_clock             /= 1000000UL;
479     configuration->period  = (TIMER_CAR(index_to_timer(pstTimerMap->TimerIndex)) + 1) * (psc + 1) * 1000UL / tim_clock;
480     configuration->pulse   = (chxcv + 1) * (psc + 1) * 1000UL / tim_clock;
481 
482     return RT_EOK;
483 }
484 
drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S * pstTimerMap,struct rt_pwm_configuration * configuration)485 static rt_err_t drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm_configuration *configuration)
486 {
487     rt_uint32_t period, pulse;
488     rt_uint64_t tim_clock, psc;
489 
490     tim_clock = rcu_clock_freq_get(CK_SYS);
491 
492     /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
493     tim_clock /= 1000000UL;
494     period     = (unsigned long long)configuration->period * tim_clock / 1000ULL;
495     psc        = period / MAX_PERIOD + 1;
496     period     = period / psc;
497 
498     timer_prescaler_config(index_to_timer(pstTimerMap->TimerIndex), psc - 1, TIMER_PSC_RELOAD_NOW);
499 
500     if (period < MIN_PERIOD)
501     {
502         period = MIN_PERIOD;
503     }
504 
505     timer_autoreload_value_config(index_to_timer(pstTimerMap->TimerIndex), period - 1);
506 
507     pulse = (unsigned long long)configuration->pulse * tim_clock / psc / 1000ULL;
508     if (pulse < MIN_PULSE)
509     {
510         pulse = MIN_PULSE;
511     }
512     else if (pulse > period)
513     {
514         pulse = period;
515     }
516 
517     timer_channel_output_pulse_value_config(index_to_timer(pstTimerMap->TimerIndex), configuration->channel, pulse);
518     timer_counter_value_config(index_to_timer(pstTimerMap->TimerIndex), 0);
519 
520     /* Update frequency value */
521     timer_event_software_generate(index_to_timer(pstTimerMap->TimerIndex), TIMER_EVENT_SRC_UPG);
522 
523     return RT_EOK;
524 }
525 
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)526 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
527 {
528     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
529     TIMER_PORT_CHANNEL_MAP_S    *pstTimerMap   = (TIMER_PORT_CHANNEL_MAP_S *)device->parent.user_data;
530 
531     switch (cmd)
532     {
533     case PWM_CMD_ENABLE:
534         return drv_pwm_enable(pstTimerMap, configuration, RT_TRUE);
535     case PWM_CMD_DISABLE:
536         return drv_pwm_enable(pstTimerMap, configuration, RT_FALSE);
537     case PWM_CMD_SET:
538         return drv_pwm_set(pstTimerMap, configuration);
539     case PWM_CMD_GET:
540         return drv_pwm_get(pstTimerMap, configuration);
541     default:
542         return -RT_EINVAL;
543     }
544 }
545 
546 static struct rt_pwm_ops drv_ops = {drv_pwm_control};
547 
gd32_hw_pwm_init(void)548 static rt_err_t gd32_hw_pwm_init(void)
549 {
550     pwm_find_timer_periph();
551     rcu_config();
552     gpio_config();
553     timer_config();
554 
555     return RT_EOK;
556 }
557 
gd32_pwm_init(void)558 static int gd32_pwm_init(void)
559 {
560     int i      = 0;
561     int result = RT_EOK;
562 
563     /* pwm init */
564     if (gd32_hw_pwm_init() != RT_EOK)
565     {
566         LOG_E("PWM init failed");
567         result = -RT_ERROR;
568         goto __exit;
569     }
570 
571     LOG_D("PWM init success");
572 
573     for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); i++)
574     {
575         /* register pwm device */
576         if (rt_device_pwm_register(&gd32_pwm_obj[i].pwm_device, gd32_pwm_obj[i].tim_handle.name, &drv_ops,
577                                    &gd32_pwm_obj[i].tim_handle)== RT_EOK )
578         {
579             LOG_D("%s register success", gd32_pwm_obj[i].tim_handle.name);
580         }
581         else
582         {
583             LOG_E("%s register failed", gd32_pwm_obj[i].tim_handle.name);
584             result = -RT_ERROR;
585         }
586     }
587 
588 __exit:
589     return result;
590 }
591 INIT_DEVICE_EXPORT(gd32_pwm_init);
592 #endif /* RT_USING_PWM */
593 
594