5
5
*
6
6
* Change Logs:
7
7
* 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
9
10
*/
10
11
11
12
#include <board.h>
15
16
16
17
#ifdef RT_USING_PWM
17
18
18
- // #define DRV_DEBUG
19
+ /* #define DRV_DEBUG */
19
20
#define LOG_TAG "drv.pwm"
20
21
#include <rtdbg.h>
21
22
22
23
#define MAX_PERIOD 65535
23
24
#define MIN_PERIOD 3
24
- #define MIN_PULSE 2
25
+ #define MIN_PULSE 2
25
26
26
27
typedef struct
27
28
{
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 ;
33
35
} TIMER_PORT_CHANNEL_MAP_S ;
34
36
35
37
struct gd32_pwm
36
38
{
37
- struct rt_device_pwm pwm_device ;
39
+ struct rt_device_pwm pwm_device ;
38
40
TIMER_PORT_CHANNEL_MAP_S tim_handle ;
39
41
};
40
42
@@ -99,11 +101,11 @@ static struct gd32_pwm gd32_pwm_obj[] = {
99
101
typedef struct
100
102
{
101
103
rt_uint32_t Port [7 ];
102
- rt_int8_t TimerIndex [14 ];
104
+ rt_int8_t TimerIndex [14 ];
103
105
} TIMER_PERIPH_LIST_S ;
104
106
105
107
static 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 },
107
109
.TimerIndex = {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 },
108
110
};
109
111
@@ -365,21 +367,28 @@ static void timer_init_para(timer_parameter_struct *initpara)
365
367
366
368
static void channel_output_config (timer_oc_parameter_struct * ocpara )
367
369
{
368
- rt_int16_t i ;
370
+ rt_int16_t i ;
369
371
rt_uint32_t timer_periph ;
370
372
371
373
/* config the channel config */
372
374
for (i = 0 ; i < sizeof (gd32_pwm_obj ) / sizeof (gd32_pwm_obj [0 ]); ++ i )
373
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
+ }
374
382
timer_periph = index_to_timer (gd32_pwm_obj [i ].tim_handle .TimerIndex );
375
383
timer_channel_output_config (timer_periph , gd32_pwm_obj [i ].tim_handle .channel , ocpara );
376
384
377
385
timer_channel_output_pulse_value_config (timer_periph , gd32_pwm_obj [i ].tim_handle .channel , 7999 );
378
386
timer_channel_output_mode_config (timer_periph , gd32_pwm_obj [i ].tim_handle .channel , TIMER_OC_MODE_PWM0 );
379
387
timer_channel_output_shadow_config (timer_periph , gd32_pwm_obj [i ].tim_handle .channel , TIMER_OC_SHADOW_DISABLE );
380
388
/* auto-reload preload shadow reg enable */
381
- // timer_auto_reload_shadow_enable(timer_periph);
389
+ /* timer_auto_reload_shadow_enable(timer_periph); */
382
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 );
383
392
}
384
393
385
394
/* enable timer */
@@ -388,6 +397,10 @@ static void channel_output_config(timer_oc_parameter_struct *ocpara)
388
397
if (-1 != gd32_timer_periph_list .TimerIndex [i ])
389
398
{
390
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
+ }
391
404
timer_enable (timer_periph );
392
405
}
393
406
}
@@ -396,23 +409,23 @@ static void channel_output_config(timer_oc_parameter_struct *ocpara)
396
409
static void timer_config (void )
397
410
{
398
411
timer_oc_parameter_struct timer_ocintpara ;
399
- timer_parameter_struct timer_initpara ;
412
+ timer_parameter_struct timer_initpara ;
400
413
401
414
/* 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 ;
407
420
timer_initpara .repetitioncounter = 0 ;
408
421
timer_init_para (& timer_initpara );
409
422
410
423
/* CHX configuration in PWM mode */
411
- timer_ocintpara .outputstate = TIMER_CCX_ENABLE ;
424
+ timer_ocintpara .outputstate = TIMER_CCX_ENABLE ;
412
425
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 ;
416
429
timer_ocintpara .ocnidlestate = TIMER_OCN_IDLE_STATE_LOW ;
417
430
channel_output_config (& timer_ocintpara );
418
431
}
@@ -427,8 +440,16 @@ static rt_err_t drv_pwm_enable(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_
427
440
}
428
441
else
429
442
{
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
+ }
432
453
}
433
454
434
455
return RT_EOK ;
@@ -454,9 +475,9 @@ static rt_err_t drv_pwm_get(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm
454
475
455
476
chxcv = timer_channel_capture_value_register_read (index_to_timer (pstTimerMap -> TimerIndex ), configuration -> channel );
456
477
/* 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 ;
460
481
461
482
return RT_EOK ;
462
483
}
@@ -470,9 +491,9 @@ static rt_err_t drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm
470
491
471
492
/* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
472
493
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 ;
476
497
477
498
timer_prescaler_config (index_to_timer (pstTimerMap -> TimerIndex ), psc - 1 , TIMER_PSC_RELOAD_NOW );
478
499
@@ -505,7 +526,7 @@ static rt_err_t drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm
505
526
static rt_err_t drv_pwm_control (struct rt_device_pwm * device , int cmd , void * arg )
506
527
{
507
528
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 ;
509
530
510
531
switch (cmd )
511
532
{
@@ -518,7 +539,7 @@ static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg
518
539
case PWM_CMD_GET :
519
540
return drv_pwm_get (pstTimerMap , configuration );
520
541
default :
521
- return RT_EINVAL ;
542
+ return - RT_EINVAL ;
522
543
}
523
544
}
524
545
@@ -536,7 +557,7 @@ static rt_err_t gd32_hw_pwm_init(void)
536
557
537
558
static int gd32_pwm_init (void )
538
559
{
539
- int i = 0 ;
560
+ int i = 0 ;
540
561
int result = RT_EOK ;
541
562
542
563
/* pwm init */
@@ -553,7 +574,7 @@ static int gd32_pwm_init(void)
553
574
{
554
575
/* register pwm device */
555
576
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 )== RT_EOK )
557
578
{
558
579
LOG_D ("%s register success" , gd32_pwm_obj [i ].tim_handle .name );
559
580
}
@@ -569,3 +590,4 @@ static int gd32_pwm_init(void)
569
590
}
570
591
INIT_DEVICE_EXPORT (gd32_pwm_init );
571
592
#endif /* RT_USING_PWM */
593
+
0 commit comments