21ic问答首页 - GD32F303芯片,需通过死区时间调整pwm输出;请各位大神支招
GD32F303芯片,需通过死区时间调整pwm输出;请各位大神支招
本帖最后由 guo159 于 2026-2-10 17:30 编辑
我在使用GD32F303芯片时,通过TIMER0实现通道0互补输出,通过设置死区时间调整占空比;
发现在设置死区时,占空比输出不理想,请问下,对于GD32F303芯片,有什么措施改善该问题吗?
为了验证该问题,我做了如下测试:
1. 在timer0初始化时,将死区设为固定的值如245,后面不设置死区时间,互补输出正常
2. 在主程序中每隔一段时间,对死区时间进行设置,设置一个固定的死区时间如245,在设置死区时,输出占空比受影响
3. 在timer0的update中断中设置死区,输出占空比相同的现象
4. 在timer0 的 TIMER_INT_FLAG_CH0 中断中设置死区,现象相同
分析主要原因是GD32F303的死区设置没有shadow寄存器,导致上面现象,初始化和设置死区程序如下,请各位大神,看看有没有什么好的措施,改善该pwm输出吗?
void timer0_config(void)
{
/* -----------------------------------------------------------------------
TIMER0 configuration:
generate 1 complementary PWM signal.
TIMER0CLK is fixed to systemcoreclock, the TIMER0 prescaler is equal to 3 so the
TIMER0 counter clock used is 40MHz.
the duty cycle is computed as the following description:
the channel 0 duty cycle is set to 25% so channel 0N is set to 75%.
insert a dead time equal to (120)/systemcoreclock = 1us
configure the break feature, active at high level, and using the automatic
output enable feature.
use the locking parameters level1.
----------------------------------------------------------------------- */
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
timer_break_parameter_struct timer_breakpara;
rcu_periph_clock_enable(RCU_TIMER0);
timer_deinit(TIMER0);
/* TIMER0 configuration */
timer_initpara.prescaler = 0;
timer_initpara.alignedmode = TIMER_COUNTER_CENTER_BOTH; //TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = TIMER0_60KHZ_PERIOD;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0, &timer_initpara);
/* CH0/CH0N configuration in PWM mode0 */
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_2, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, TIMER0_CH1_50P);
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, TIMER0_CH1_50P);
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, TIMER0_CH1_50P);
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_DISABLE);
/* automatic output enable, break, dead time and lock configuration*/
timer_breakpara.runoffstate = TIMER_ROS_STATE_DISABLE;
timer_breakpara.ideloffstate = TIMER_IOS_STATE_DISABLE ;
timer_breakpara.deadtime = 0xFF-10;//120; // 120 / 120M =1us
timer_breakpara.breakpolarity = TIMER_BREAK_POLARITY_LOW;
timer_breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
timer_breakpara.protectmode = TIMER_CCHP_PROT_OFF;//TIMER_CCHP_PROT_0;
timer_breakpara.breakstate = TIMER_BREAK_DISABLE; //TIMER_BREAK_ENABLE;
timer_break_config(TIMER0, &timer_breakpara);
/* TIMER0 primary output function enable */
timer_primary_output_config(TIMER0, ENABLE);
// timer_primary_output_config(TIMER0,DISABLE);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER0);
// timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
// timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);
// timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);
/* TIMER0 counter enable */
timer_enable(TIMER0);
// /* clear update interrupt interrupt bit */
// timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_UP);
// /* update interrupt enable */
// timer_interrupt_enable(TIMER0,TIMER_INT_UP);
// nvic_irq_enable(TIMER0_UP_IRQn, 2, 3);
/* clear update interrupt interrupt bit */
timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_CH0|TIMER_INT_FLAG_CH1|TIMER_INT_FLAG_CH2);
/* update interrupt enable */
timer_interrupt_enable(TIMER0,TIMER_INT_CH0|TIMER_INT_CH1|TIMER_INT_CH2);
nvic_irq_enable(TIMER0_Channel_IRQn, 2, 3);
}
void T0Setdeadtime(void)
{
static uint8_t softCount=50;
if(softCount>50+1)
{
softCount=50+1;
}
softCount--;
if(!softCount)
{
softCount=50+1;
FANLOG();
timer_deadtime_config(TimeInvSynT0, 245);
}
}
void TIMER0_Channel_IRQHandler(void)
{
if(SET == timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_CH0))
{
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_CH0);
T0Setdeadtime();
}
}
void TIMER0_UP_IRQHandler(void)
{
if(timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_UP))
{
timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
// T0Setdeadtime();
}
}
/*!
\brief configure TIMER deadtime function
\param[in] timer_periph: TIMERx(x=0,7)
\param[in] deadtime: 0~255
\param[out] none
\retval none
*/
void timer_deadtime_config(uint32_t timer_periph, uint8_t deadtime)
{
// DTCFG 值和死区时间的关系如下:
// DTCFG[7:5] The duration of dead-time
// 3’b0xx DTCFG[7:0] * tDTS_CK
// 3’b10x (64+ DTCFG[5:0]) * tDTS_CK *2
// 3’b110 (32+ DTCFG[4:0]) * tDTS_CK *8
// 3’b111 (32+ DTCFG[4:0]) * tDTS_CK *16
// 注意:
// 1. tDTS_CK 是 DTS_CK 的周期,由 TIMERx_CTL0 中的 CKDIC[1:0]定义。
// 2. 此位只有在 TIMERx_CCHP 寄存器的 PROT [1:0]=00 时才可修改。
TIMER_CCHP(timer_periph) &= ~((uint32_t)TIMER_CCHP_DTCFG | TIMER_CCHP_PROT);
TIMER_CCHP(timer_periph) |= (uint32_t)deadtime;
// TIMER_CCHP(timer_periph) |= (uint32_t)TIMER_CCHP_PROT_0;
}
我在使用GD32F303芯片时,通过TIMER0实现通道0互补输出,通过设置死区时间调整占空比;
发现在设置死区时,占空比输出不理想,请问下,对于GD32F303芯片,有什么措施改善该问题吗?
为了验证该问题,我做了如下测试:
1. 在timer0初始化时,将死区设为固定的值如245,后面不设置死区时间,互补输出正常
2. 在主程序中每隔一段时间,对死区时间进行设置,设置一个固定的死区时间如245,在设置死区时,输出占空比受影响
3. 在timer0的update中断中设置死区,输出占空比相同的现象
4. 在timer0 的 TIMER_INT_FLAG_CH0 中断中设置死区,现象相同
分析主要原因是GD32F303的死区设置没有shadow寄存器,导致上面现象,初始化和设置死区程序如下,请各位大神,看看有没有什么好的措施,改善该pwm输出吗?
void timer0_config(void)
{
/* -----------------------------------------------------------------------
TIMER0 configuration:
generate 1 complementary PWM signal.
TIMER0CLK is fixed to systemcoreclock, the TIMER0 prescaler is equal to 3 so the
TIMER0 counter clock used is 40MHz.
the duty cycle is computed as the following description:
the channel 0 duty cycle is set to 25% so channel 0N is set to 75%.
insert a dead time equal to (120)/systemcoreclock = 1us
configure the break feature, active at high level, and using the automatic
output enable feature.
use the locking parameters level1.
----------------------------------------------------------------------- */
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
timer_break_parameter_struct timer_breakpara;
rcu_periph_clock_enable(RCU_TIMER0);
timer_deinit(TIMER0);
/* TIMER0 configuration */
timer_initpara.prescaler = 0;
timer_initpara.alignedmode = TIMER_COUNTER_CENTER_BOTH; //TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = TIMER0_60KHZ_PERIOD;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0, &timer_initpara);
/* CH0/CH0N configuration in PWM mode0 */
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_2, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, TIMER0_CH1_50P);
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, TIMER0_CH1_50P);
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, TIMER0_CH1_50P);
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_DISABLE);
/* automatic output enable, break, dead time and lock configuration*/
timer_breakpara.runoffstate = TIMER_ROS_STATE_DISABLE;
timer_breakpara.ideloffstate = TIMER_IOS_STATE_DISABLE ;
timer_breakpara.deadtime = 0xFF-10;//120; // 120 / 120M =1us
timer_breakpara.breakpolarity = TIMER_BREAK_POLARITY_LOW;
timer_breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
timer_breakpara.protectmode = TIMER_CCHP_PROT_OFF;//TIMER_CCHP_PROT_0;
timer_breakpara.breakstate = TIMER_BREAK_DISABLE; //TIMER_BREAK_ENABLE;
timer_break_config(TIMER0, &timer_breakpara);
/* TIMER0 primary output function enable */
timer_primary_output_config(TIMER0, ENABLE);
// timer_primary_output_config(TIMER0,DISABLE);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER0);
// timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
// timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);
// timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);
/* TIMER0 counter enable */
timer_enable(TIMER0);
// /* clear update interrupt interrupt bit */
// timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_UP);
// /* update interrupt enable */
// timer_interrupt_enable(TIMER0,TIMER_INT_UP);
// nvic_irq_enable(TIMER0_UP_IRQn, 2, 3);
/* clear update interrupt interrupt bit */
timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_CH0|TIMER_INT_FLAG_CH1|TIMER_INT_FLAG_CH2);
/* update interrupt enable */
timer_interrupt_enable(TIMER0,TIMER_INT_CH0|TIMER_INT_CH1|TIMER_INT_CH2);
nvic_irq_enable(TIMER0_Channel_IRQn, 2, 3);
}
void T0Setdeadtime(void)
{
static uint8_t softCount=50;
if(softCount>50+1)
{
softCount=50+1;
}
softCount--;
if(!softCount)
{
softCount=50+1;
FANLOG();
timer_deadtime_config(TimeInvSynT0, 245);
}
}
void TIMER0_Channel_IRQHandler(void)
{
if(SET == timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_CH0))
{
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_CH0);
T0Setdeadtime();
}
}
void TIMER0_UP_IRQHandler(void)
{
if(timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_UP))
{
timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
// T0Setdeadtime();
}
}
/*!
\brief configure TIMER deadtime function
\param[in] timer_periph: TIMERx(x=0,7)
\param[in] deadtime: 0~255
\param[out] none
\retval none
*/
void timer_deadtime_config(uint32_t timer_periph, uint8_t deadtime)
{
// DTCFG 值和死区时间的关系如下:
// DTCFG[7:5] The duration of dead-time
// 3’b0xx DTCFG[7:0] * tDTS_CK
// 3’b10x (64+ DTCFG[5:0]) * tDTS_CK *2
// 3’b110 (32+ DTCFG[4:0]) * tDTS_CK *8
// 3’b111 (32+ DTCFG[4:0]) * tDTS_CK *16
// 注意:
// 1. tDTS_CK 是 DTS_CK 的周期,由 TIMERx_CTL0 中的 CKDIC[1:0]定义。
// 2. 此位只有在 TIMERx_CCHP 寄存器的 PROT [1:0]=00 时才可修改。
TIMER_CCHP(timer_periph) &= ~((uint32_t)TIMER_CCHP_DTCFG | TIMER_CCHP_PROT);
TIMER_CCHP(timer_periph) |= (uint32_t)deadtime;
// TIMER_CCHP(timer_periph) |= (uint32_t)TIMER_CCHP_PROT_0;
}

问答
赞0
评论
2026-02-11
您需要登录后才可以回复 登录 | 注册