This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

280049的PWM输出会有间歇性的脉冲



你好!

我在使用280049输出PWM的时候,发现当控制PWM为0输出的时候,PWM的输出会有间歇性的脉冲出现。查找程序一直找到不问题,也没有一个思路,想请教一下这是什么问题?

有关PWM的控制程序如下:

void initEPWM1()
{
    //
    // Set_up TBCLK
    //
    EPWM_setTimeBasePeriod(EPWM1_BASE, EPWM1_TIMER_TBPRD);
    EPWM_setPhaseShift(EPWM1_BASE, 0U);
    EPWM_setTimeBaseCounter(EPWM1_BASE, 0U);

    // Set up counter mode
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
    EPWM_disablePhaseShiftLoad(EPWM1_BASE);

    //
    // Set ePWM clock pre-scaler
    //
    EPWM_setClockPrescaler(EPWM1_BASE,
                           EPWM_CLOCK_DIVIDER_4,
                           EPWM_HSCLOCK_DIVIDER_4);

    //
    // Set up shadowing
    //
    EPWM_setCounterCompareShadowLoadMode(EPWM1_BASE,
                                         EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);
    EPWM_setCounterCompareShadowLoadMode(EPWM1_BASE,
                                         EPWM_COUNTER_COMPARE_B,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);


    //
    // Set-up compare
    //
    EPWM_setCounterCompareValue(EPWM1_BASE,
                                EPWM_COUNTER_COMPARE_A,
                                EPWM1_MIN_CMPA);
    EPWM_setCounterCompareValue(EPWM1_BASE,
                                EPWM_COUNTER_COMPARE_B,
                                EPWM1_MIN_CMPB);

    //
    // Set actions
    //
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);

}

void pump_ctrl(uint16_t pump, uint16_t freq, float32_t ratio)
{
    EPWM_SignalParams *signalParams;
    uint32_t base;
    float32_t tbClkInHz = 0.0F;
    uint16_t tbPrdVal = 0U, cmpAVal = 0U, cmpBVal = 0U;

    switch (pump)
    {
        case 0:
            base = EPWM1_BASE;
            signalParams = &pwmSignal1;
            signalParams->dutyValA = ratio;
            if(ratio != 0.0)
                neg_pump1_status = 1;
            else
                neg_pump1_status = 0;
            break;
        case 1:
            base = EPWM1_BASE;
            signalParams = &pwmSignal1;
            signalParams->dutyValB = ratio;
            if(ratio != 0.0)
                  neg_pump2_status = 1;
              else
                  neg_pump2_status = 0;
            break;
        case 2:
            base = EPWM2_BASE;
            signalParams = &pwmSignal2;
            signalParams->dutyValA = ratio;
            if(ratio != 0.0)
                  pos_pump_status = 1;
              else
                  pos_pump_status = 0;
            break;
    }

    signalParams->freqInHz = freq;

    //
    // Calculate TBCLK, TBPRD and CMPx values to be configured for
    // achieving desired signal
    //
    tbClkInHz = ((float32_t)signalParams->sysClkInHz /
                (1U << (uint16_t)signalParams->tbClkDiv));

    if(signalParams->tbCtrMode == EPWM_COUNTER_MODE_UP)
    {
        tbPrdVal = (uint16_t)((tbClkInHz / signalParams->freqInHz) - 1.0f);
        cmpAVal = (uint16_t)((float32_t)signalParams->dutyValA *
                             (tbPrdVal + 1U));
        cmpBVal = (uint16_t)((float32_t)signalParams->dutyValB *
                             (tbPrdVal + 1U));
    }
    else if(signalParams->tbCtrMode == EPWM_COUNTER_MODE_DOWN)
    {
        tbPrdVal = (uint16_t)((tbClkInHz / signalParams->freqInHz) - 1.0f);
        cmpAVal = (uint16_t)((tbPrdVal + 1U) -
                       ((float32_t)signalParams->dutyValA * (tbPrdVal + 1U)));
        cmpBVal = (uint16_t)((tbPrdVal + 1U) -
                       ((float32_t)signalParams->dutyValB * (tbPrdVal + 1U)));
    }
    else if((signalParams->tbCtrMode == EPWM_COUNTER_MODE_UP_DOWN))
    {

        tbPrdVal = (uint16_t)(tbClkInHz / (2.0f * signalParams->freqInHz));
            cmpBVal = (uint16_t)(((float32_t)tbPrdVal -
                                         ((float32_t)(signalParams->dutyValB *
                                          tbPrdVal))) + 0.5f);
            cmpAVal = (uint16_t)(((float32_t)tbPrdVal -
                                         ((float32_t)(signalParams->dutyValA *
                                          tbPrdVal))) + 0.5f);
    }

    //
    // Configure TBPRD value
    //
    EPWM_setTimeBasePeriod(base, tbPrdVal);

    //
    // Set Compare values
    //
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A,
                                cmpAVal);
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_B,
                                cmpBVal);



//    ++counterA;
//    if(counterA < epwm1Info.epwmMaxCompA)
//    {
//        epwm1Info.epwmCompA = counterA;
//    }
//    else
//    {
//        counterA = epwm1Info.epwmMinCompA;
//    }
//
//    ++counterB;
//    if(counterB < epwm1Info.epwmMaxCompB)
//    {
//        epwm1Info.epwmCompB = counterB;
//    }
//    else
//    {
//        counterB = epwm1Info.epwmMinCompB;
//    }
//    updataCompare(&epwm1Info);
}

void main()
{
    //
    // Disable sync(Freeze clock to PWM as well)
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    DINT;

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();
    

    //
    // Enable sync and clock to PWM
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;

    // Disable pin locks and enable internal pullups.
    Device_initGPIO();
    // Set up GPIOs
    setupGPIO();

    //
    // Configuring ePWM module for desired frequency and duty
    //
    EPWM_configureSignal(EPWM1_BASE, &pwmSignal1);
    EPWM_configureSignal(EPWM2_BASE, &pwmSignal2);


    pump_ctrl(POS_PUMP, 0, 0);
}

  • 对了,要再说一下,这个脉冲的特征跟我们CPUtimer1设置的定时时长有关系,定时器时长越长,脉冲的宽度越大。定时器的程序如下

    void initTimerInterrupt(void)
    {
        // ISRs for each CPU Timer interrupt
        // Timer0 for led
        // Timer1 for PPG ADC
        Interrupt_register(INT_TIMER0, &cpuTimer0ISR);
        Interrupt_register(INT_TIMER1, &cpuTimer1ISR);
    
    
        // Initializes the cpu timers
        initCPUTimers();
    //    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER0);
    
    
        // Configure CPU-Timer0 to interrupt every second: 1 second period(1 uSeconds)
        // Configure CPU-Timer1 to interrupt every msecond
        configCPUTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, 1000000);
        configCPUTimer(CPUTIMER1_BASE, DEVICE_SYSCLK_FREQ, 100);
    
    
        // To ensure precise timing, use write-only instruction to write to the
        // entire register, Therefore, if any of the configuration bits are changed
        // in configCPUTimer and initCPUTimers, the below settings must also be updated.
        CPUTimer_enableInterrupt(CPUTIMER0_BASE);
        CPUTimer_enableInterrupt(CPUTIMER1_BASE);
    
        // Enables CPU int1.
        // Enable TINT0 in the PIE: Group 1 interrupt 7
        Interrupt_enable(INT_TIMER0);
        Interrupt_enable(INT_TIMER1);
    
    
        //Starts CPU-Timer 0
        CPUTimer_startTimer(CPUTIMER0_BASE);
        CPUTimer_startTimer(CPUTIMER1_BASE);
    
    
    }
    
    //
    // initCPUTimers - This function initializes all three CPU timers
    // to a known state.
    //
    void initCPUTimers(void)
    {
        // Initialize timer period to maximum
        CPUTimer_setPeriod(CPUTIMER0_BASE, 0XFFFFFFFF);
        CPUTimer_setPeriod(CPUTIMER1_BASE, 0XFFFFFFFF);
    
    
        // Initialize pre-scale counter to divide by 1(SYSCLKOUT)
        CPUTimer_setPreScaler(CPUTIMER0_BASE, 0);
        CPUTimer_setPreScaler(CPUTIMER1_BASE, 0);
    
    
        // Make sure timer is stopped
        CPUTimer_stopTimer(CPUTIMER0_BASE);
        CPUTimer_stopTimer(CPUTIMER1_BASE);
    
    
        // Reload all counter register with period value
        CPUTimer_reloadTimerCounter(CPUTIMER0_BASE);
        CPUTimer_reloadTimerCounter(CPUTIMER1_BASE);
    
    
        // Reset interrupt counter
        cpuTimer0IntCount = 0;
        cpuTimer1IntCount = 0;
    
    }
    
    //
    // configCPUTimer - This function initializes the selected timer to the
    // period specified by the "freq" and "period" parameters. The "freq" is
    // entered as Hz and the period in uSeconds. The timer is held in the stopped
    // state after configuration.
    //
    void configCPUTimer(uint32_t cpuTimer, float freq, float period)
    {
        uint32_t temp;
    
        // Initialize timer period
        temp = (uint32_t)(freq / 1000000 * period);
        CPUTimer_setPeriod(cpuTimer, temp);
    
        // Set pre-scale counter to divide by 1 (SYSCLKOUT)
        CPUTimer_setPreScaler(cpuTimer, 0);
    
        // Initializes timer control register. The timer is stopped, reloaded,
        // free run disabled, and interrupt enabled.
        // Additionally, the free and soft bits are set
        CPUTimer_stopTimer(cpuTimer);
        CPUTimer_reloadTimerCounter(cpuTimer);
        CPUTimer_setEmulationMode(cpuTimer, CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT);
        CPUTimer_enableInterrupt(cpuTimer);
    
        // Resets interrupt counters for the cpuTimer
        if(cpuTimer == CPUTIMER0_BASE)
        {
            cpuTimer0IntCount = 0;
        }
        else if(cpuTimer == CPUTIMER1_BASE)
        {
            cpuTimer1IntCount = 0;
        }
    }
    //
    // cpuTimer1ISR - Counter for CpuTimer1
    //
    __interrupt void cpuTimer1ISR(void)
    {
        // Save IER register on stack
    //    volatile uint16_t tempPIEIER = HWREGH(PIECTRL_BASE + PIE_O_IER1);
    
        // Set the global and group priority to allow CPU interrupts
        // with higher priority
    //    IER |= M_INT2;
    //    IER &= MINT2;
    //    HWREGH(PIECTRL_BASE + PIE_O_IER1);
    
        // Enable Interrupts
        Interrupt_clearACKGroup(0xFFFFU);
    //    __asm(" NOP");
    //    EINT;
        cpuTimer1IntCount++;
        // Insert ISR code here
        if(IRLED_flip == 0)
        {
            IRLED_flip = 1;
            if(init_count<5000)//按照1000us定时,2000次相当于4s长度的数据
            {
                ++init_count;
            }
    //        //使IRLED关闭
    //        SPI_transmit(mySPI0_BASE, 0X0000);
    //        SPI_transmit(mySPI0_BASE, 0X3000);
    
            // 测试DAC输出与阀输出的关系
            DAC_VALVE_RELATIVE_TEST();
        }
        else
        {
            IRLED_flip = 0;
    //        //使IRLED打开
    //        SPI_transmit(mySPI0_BASE, 0X0800);
    //        SPI_transmit(mySPI0_BASE, 0X3800);
        }
    
    //    ADC_flag = 1;
    
        // Disable interrupts and restore register saved;
    //    DINT;
    //    HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER;
    
    //    // Add ISR to Trace
    //    traceISR[traceISRIndex % TRACE_SIZE] = 0x00D0;
    //    traceISRIndex++;
    }
    
    
    

  • 我们会在确认后给您回复
  • Susan,你好

    不知道问题讨论有结果了吗?

    祝好!

  • 请问这个脉冲pulse是只有当 CMPA/CMPB=PRD时发生?

  • 应该不是,这个脉冲出现的时间点比较随机
  • 在发送的代码中,您没有使用死区/ HRPWM或除CMPA / B之外可能修改PWM输出的其他任何方式。您编辑了TBPRD。那么您是什么时候调用pump_ctrl呢(除main函数之外)?
  • 我本来是在cputimer1的中断函数中调用的,pump_ctrl()在函数DAC_VALVE_RELATIVE_TEST()内,后来我为了测试,就把pump_ctrl()单独拎出来放在main里面,观察显现,同时把DAC_VALVE_RELATIVE_TEST()内的pump_ctrl()注释掉。目前就只有在main中有调用这个函数。
  • 我刚刚发现一个现象,我设置pump_ctrl(POS_PUMP, 0, 0),但是用示波器抓取波形,发现一直有一个50%占空比,频率1k的PWM输出,感觉像是没有配置上。
  • susan,
    我自己再研究一下,估计按照我现在提供的信息,你们看不出来什么,我再进一步研究一下,到时候再做进一步交流。我现在有点怀疑的是中断优先级的问题。
  • 好的,谢谢理解。期待您的反馈