55 *
66 * Change Logs:
77 * Date Author Notes
8- * 2023-06-05 zengjianwei first version
8+ * 2023-06-05 zengjianwei first version
9+ * 2025-06-23 Yucai Liu Support for non-complementary PWM output with advanced timers
910 */
1011
1112#include <board.h>
2122
2223#define MAX_PERIOD 65535
2324#define MIN_PERIOD 3
24- #define MIN_PULSE 2
25+ #define MIN_PULSE 2
2526
2627typedef struct
2728{
28- rt_int8_t TimerIndex ; // timer index:0~13
29- rt_uint32_t Port ; // gpio port:GPIOA/GPIOB/GPIOC/...
30- rt_uint32_t pin ; // gpio pin:GPIO_PIN_0~GPIO_PIN_15
31- rt_uint16_t channel ; // timer channel
32- char * name ;
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 ;
3335} TIMER_PORT_CHANNEL_MAP_S ;
3436
3537struct gd32_pwm
3638{
37- struct rt_device_pwm pwm_device ;
39+ struct rt_device_pwm pwm_device ;
3840 TIMER_PORT_CHANNEL_MAP_S tim_handle ;
3941};
4042
@@ -99,11 +101,11 @@ static struct gd32_pwm gd32_pwm_obj[] = {
99101typedef struct
100102{
101103 rt_uint32_t Port [7 ];
102- rt_int8_t TimerIndex [14 ];
104+ rt_int8_t TimerIndex [14 ];
103105} TIMER_PERIPH_LIST_S ;
104106
105107static TIMER_PERIPH_LIST_S gd32_timer_periph_list = {
106- .Port = {0 , 0 , 0 , 0 , 0 , 0 , 0 },
108+ .Port = {0 , 0 , 0 , 0 , 0 , 0 , 0 },
107109 .TimerIndex = {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 },
108110};
109111
@@ -365,12 +367,18 @@ static void timer_init_para(timer_parameter_struct *initpara)
365367
366368static void channel_output_config (timer_oc_parameter_struct * ocpara )
367369{
368- rt_int16_t i ;
370+ rt_int16_t i ;
369371 rt_uint32_t timer_periph ;
370372
371373 /* config the channel config */
372374 for (i = 0 ; i < sizeof (gd32_pwm_obj ) / sizeof (gd32_pwm_obj [0 ]); ++ i )
373375 {
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+ }
374382 timer_periph = index_to_timer (gd32_pwm_obj [i ].tim_handle .TimerIndex );
375383 timer_channel_output_config (timer_periph , gd32_pwm_obj [i ].tim_handle .channel , ocpara );
376384
@@ -380,6 +388,7 @@ static void channel_output_config(timer_oc_parameter_struct *ocpara)
380388 /* auto-reload preload shadow reg enable */
381389 // timer_auto_reload_shadow_enable(timer_periph);
382390 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 );
383392 }
384393
385394 /* enable timer */
@@ -388,6 +397,10 @@ static void channel_output_config(timer_oc_parameter_struct *ocpara)
388397 if (-1 != gd32_timer_periph_list .TimerIndex [i ])
389398 {
390399 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+ }
391404 timer_enable (timer_periph );
392405 }
393406 }
@@ -396,23 +409,23 @@ static void channel_output_config(timer_oc_parameter_struct *ocpara)
396409static void timer_config (void )
397410{
398411 timer_oc_parameter_struct timer_ocintpara ;
399- timer_parameter_struct timer_initpara ;
412+ timer_parameter_struct timer_initpara ;
400413
401414 /* TIMER configuration */
402- timer_initpara .prescaler = 119 ;
403- timer_initpara .alignedmode = TIMER_COUNTER_EDGE ;
404- timer_initpara .counterdirection = TIMER_COUNTER_UP ;
405- timer_initpara .period = 15999 ;
406- timer_initpara .clockdivision = TIMER_CKDIV_DIV1 ;
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 ;
407420 timer_initpara .repetitioncounter = 0 ;
408421 timer_init_para (& timer_initpara );
409422
410423 /* CHX configuration in PWM mode */
411- timer_ocintpara .outputstate = TIMER_CCX_ENABLE ;
424+ timer_ocintpara .outputstate = TIMER_CCX_ENABLE ;
412425 timer_ocintpara .outputnstate = TIMER_CCXN_DISABLE ;
413- timer_ocintpara .ocpolarity = TIMER_OC_POLARITY_HIGH ;
414- timer_ocintpara .ocnpolarity = TIMER_OCN_POLARITY_HIGH ;
415- timer_ocintpara .ocidlestate = TIMER_OC_IDLE_STATE_LOW ;
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 ;
416429 timer_ocintpara .ocnidlestate = TIMER_OCN_IDLE_STATE_LOW ;
417430 channel_output_config (& timer_ocintpara );
418431}
@@ -427,8 +440,16 @@ static rt_err_t drv_pwm_enable(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_
427440 }
428441 else
429442 {
430- timer_channel_output_state_config (index_to_timer (pstTimerMap -> TimerIndex ), configuration -> channel ,
431- TIMER_CCX_ENABLE );
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+ }
432453 }
433454
434455 return RT_EOK ;
@@ -454,9 +475,9 @@ static rt_err_t drv_pwm_get(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm
454475
455476 chxcv = timer_channel_capture_value_register_read (index_to_timer (pstTimerMap -> TimerIndex ), configuration -> channel );
456477 /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
457- tim_clock /= 1000000UL ;
458- configuration -> period = (TIMER_CAR (index_to_timer (pstTimerMap -> TimerIndex )) + 1 ) * (psc + 1 ) * 1000UL / tim_clock ;
459- configuration -> pulse = (chxcv + 1 ) * (psc + 1 ) * 1000UL / tim_clock ;
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 ;
460481
461482 return RT_EOK ;
462483}
@@ -470,9 +491,9 @@ static rt_err_t drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm
470491
471492 /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
472493 tim_clock /= 1000000UL ;
473- period = (unsigned long long )configuration -> period * tim_clock / 1000ULL ;
474- psc = period / MAX_PERIOD + 1 ;
475- period = period / psc ;
494+ period = (unsigned long long )configuration -> period * tim_clock / 1000ULL ;
495+ psc = period / MAX_PERIOD + 1 ;
496+ period = period / psc ;
476497
477498 timer_prescaler_config (index_to_timer (pstTimerMap -> TimerIndex ), psc - 1 , TIMER_PSC_RELOAD_NOW );
478499
@@ -505,7 +526,7 @@ static rt_err_t drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm
505526static rt_err_t drv_pwm_control (struct rt_device_pwm * device , int cmd , void * arg )
506527{
507528 struct rt_pwm_configuration * configuration = (struct rt_pwm_configuration * )arg ;
508- TIMER_PORT_CHANNEL_MAP_S * pstTimerMap = (TIMER_PORT_CHANNEL_MAP_S * )device -> parent .user_data ;
529+ TIMER_PORT_CHANNEL_MAP_S * pstTimerMap = (TIMER_PORT_CHANNEL_MAP_S * )device -> parent .user_data ;
509530
510531 switch (cmd )
511532 {
@@ -536,7 +557,7 @@ static rt_err_t gd32_hw_pwm_init(void)
536557
537558static int gd32_pwm_init (void )
538559{
539- int i = 0 ;
560+ int i = 0 ;
540561 int result = RT_EOK ;
541562
542563 /* pwm init */
@@ -553,7 +574,8 @@ static int gd32_pwm_init(void)
553574 {
554575 /* register pwm device */
555576 if (rt_device_pwm_register (& gd32_pwm_obj [i ].pwm_device , gd32_pwm_obj [i ].tim_handle .name , & drv_ops ,
556- & gd32_pwm_obj [i ].tim_handle ) == RT_EOK )
577+ & gd32_pwm_obj [i ].tim_handle )
578+ == RT_EOK )
557579 {
558580 LOG_D ("%s register success" , gd32_pwm_obj [i ].tim_handle .name );
559581 }
0 commit comments