Skip to content

Commit 5b97ba1

Browse files
bsp:<bsp/gd32/arm/libraries/gd32_drivers/drv_pwm.c>
[Support for non-complementary PWM output with advanced timers] 1.当前结构体 TIMER_PORT_CHANNEL_MAP_Srt_int16_t 的成员channel为u16 为增加对非互补输出的支持 将uint16_t 改为int16_t /* timer channel: -2 is ch_1n, -1 is ch_0n, 0 is ch0, 1 is ch1 */ 2.对函数 channel_output_config 以及 drv_pwm_enable 进行修改,增加对非互补输出的支持 Signed-off-by: Yucai Liu <[email protected]>
1 parent 593ac8d commit 5b97ba1

File tree

1 file changed

+57
-35
lines changed

1 file changed

+57
-35
lines changed

bsp/gd32/arm/libraries/gd32_drivers/drv_pwm.c

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
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>
@@ -15,26 +16,27 @@
1516

1617
#ifdef RT_USING_PWM
1718

18-
//#define DRV_DEBUG
19+
/* #define DRV_DEBUG */
1920
#define LOG_TAG "drv.pwm"
2021
#include <rtdbg.h>
2122

2223
#define MAX_PERIOD 65535
2324
#define MIN_PERIOD 3
24-
#define MIN_PULSE 2
25+
#define MIN_PULSE 2
2526

2627
typedef 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

3537
struct 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[] = {
99101
typedef 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

105107
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},
107109
.TimerIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
108110
};
109111

@@ -365,21 +367,28 @@ static void timer_init_para(timer_parameter_struct *initpara)
365367

366368
static 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

377385
timer_channel_output_pulse_value_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, 7999);
378386
timer_channel_output_mode_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_OC_MODE_PWM0);
379387
timer_channel_output_shadow_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_OC_SHADOW_DISABLE);
380388
/* auto-reload preload shadow reg enable */
381-
// timer_auto_reload_shadow_enable(timer_periph);
389+
/* 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)
396409
static 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
505526
static 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
{
@@ -518,7 +539,7 @@ static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg
518539
case PWM_CMD_GET:
519540
return drv_pwm_get(pstTimerMap, configuration);
520541
default:
521-
return RT_EINVAL;
542+
return -RT_EINVAL;
522543
}
523544
}
524545

@@ -536,7 +557,7 @@ static rt_err_t gd32_hw_pwm_init(void)
536557

537558
static 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,7 @@ 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)== RT_EOK )
557578
{
558579
LOG_D("%s register success", gd32_pwm_obj[i].tim_handle.name);
559580
}
@@ -569,3 +590,4 @@ static int gd32_pwm_init(void)
569590
}
570591
INIT_DEVICE_EXPORT(gd32_pwm_init);
571592
#endif /* RT_USING_PWM */
593+

0 commit comments

Comments
 (0)