问答

汇集网友智慧,解决技术难题

21ic问答首页 - GD32F303芯片,需通过死区时间调整pwm输出;请各位大神支招

TI

GD32F303芯片,需通过死区时间调整pwm输出;请各位大神支招

guo1592026-02-09
本帖最后由 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;
}





回答 +关注 0
651人浏览 1人回答问题 分享 举报
1 个回答

您需要登录后才可以回复 登录 | 注册