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.

TMS320F28377D: EPWM模块更新比较值(CMPA)的同时开关频率上升

Part Number: TMS320F28377D

您好,我在用TMS320F28377D调试PWM过程中遇到了如下问题:

我所用PWM的功能是:将ePWM1作为主时钟(Master),ePWM2,3,10,11,12作为从时钟(Slave),输出互补死区的12路PWM波。

当我在ePWM的中断中修改PWM的占空比(dutycycle)时,原本应当只改变占空比,不改变频率。

PWM实际输出的高低电平时间和实际开关频率如下所示。实际的占空比和给定占空比不相等;当占空比上升时,实际的输出频率也会上升。只有当占空比=0时,输出频率才近似等于所需的40kHz。

其他功能,如互补死区、多路同步均表现正常。

请问我的代码存在哪些问题,应当如何修改,谢谢!

以下为我的配置函数和调用函数:

配置函数为:

// PWM MACRO DEFINE
// SYSCLK = 200MHz
// EPWMCLK = SYSCLK/2(define=2) = 100MHz
// TBCLK = EPWMCLK/(HSPCLKDIV*CLKDIV) = 100MHz
// We want 40kHz, so 2*EPWM_TIMER_TBPRD=100/40*1000=2500, thus EPWM_TIMER_TBPRD=1250
// Tdb = 1/(100MHz/40) = 400ns
#define freq_sw 40000 // Switching frequency, Hz
#define prd_sw 1.0/40000.0 // Switching period, s
#define EPWM_TIMER_TBPRD 100000000/(freq_sw*2)
#define EPWM_MIN_CMPA 50
#define EPWM_MAX_CMPB 1200
#define EPWM_DB 40

//
// InitEPwm1Gpio - Initialize EPWM1 GPIOs
//
void InitEPwm1Gpio(void)
{
    EALLOW;
    
    //
    // Disable internal pull-up for the selected output pins
    // for reduced power consumption
    // Pull-ups can be enabled or disabled by the user.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1; // Disable pull-up on GPIO0 (EPWM1A)
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1; // Disable pull-up on GPIO1 (EPWM1B)
    // GpioCtrlRegs.GPEPUD.bit.GPIO145 = 1; // Disable pull-up on GPIO145 (EPWM1A)
    // GpioCtrlRegs.GPEPUD.bit.GPIO146 = 1; // Disable pull-up on GPIO146 (EPWM1B)
    
    //
    // Configure EPWM-1 pins using GPIO regs
    // This specifies which of the possible GPIO pins will be EPWM1 functional
    // pins.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAGMUX1.bit.GPIO0 = 0; // Configure GPIO0 as EPWM1A
    GpioCtrlRegs.GPAGMUX1.bit.GPIO1 = 0; // Configure GPIO1 as EPWM1B
    
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // Configure GPIO0 as EPWM1A
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // Configure GPIO1 as EPWM1B
    // GpioCtrlRegs.GPEMUX2.bit.GPIO145 = 1; // Configure GPIO145 as EPWM1A
    // GpioCtrlRegs.GPEMUX2.bit.GPIO146 = 1; // Configure GPIO0146 as EPWM1B
    
    EDIS;
}


//
// InitEPwm2Gpio - Initialize EPWM2 GPIOs
//
void InitEPwm2Gpio(void)
{
    EALLOW;
    
    //
    // Disable internal pull-up for the selected output pins
    // for reduced power consumption
    // Pull-ups can be enabled or disabled by the user.
    // This will enable the pullups for the specified pins.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1; // Disable pull-up on GPIO2 (EPWM2A)
    GpioCtrlRegs.GPAPUD.bit.GPIO3 = 1; // Disable pull-up on GPIO3 (EPWM2B)
    // GpioCtrlRegs.GPEPUD.bit.GPIO147 = 1; // Disable pull-up on GPIO147 (EPWM2A)
    // GpioCtrlRegs.GPEPUD.bit.GPIO148 = 1; // Disable pull-up on GPIO148 (EPWM2B)
    
    //
    // Configure EPwm-2 pins using GPIO regs
    // This specifies which of the possible GPIO pins will be EPWM2 functional pins.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAGMUX1.bit.GPIO2 = 0; // Configure GPIO2 as EPWM2A
    GpioCtrlRegs.GPAGMUX1.bit.GPIO3 = 0; // Configure GPIO3 as EPWM2B
    
    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; // Configure GPIO2 as EPWM2A
    GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1; // Configure GPIO3 as EPWM2B
    // GpioCtrlRegs.GPEMUX2.bit.GPIO147 = 1; // Configure GPIO147 as EPWM2A
    // GpioCtrlRegs.GPEMUX2.bit.GPIO148 = 1; // Configure GPIO148 as EPWM2B
    
    EDIS;
}



//
// InitEPwm1Example - Initialize EPWM1 configuration
//
void InitEPwm1Example()
{
    // Setup TBCLK
    EPwm1Regs.TBPRD = EPWM_TIMER_TBPRD; // Set timer period 2*EPWM_TIMER_TBPRD TBCLKs
    EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0, change it when carrier phase-shift is used
    EPwm1Regs.TBCTR = 0x0000; // Clear counter
    
    // Set Compare values
    EPwm1Regs.CMPA.bit.CMPA = EPWM_MIN_CMPA; // Set compare A value
    EPwm1Regs.CMPB.bit.CMPB = EPWM_MAX_CMPB; // Set compare B value
    
    // Setup counter mode
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up and down
    EPwm1Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Enable phase loading
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
    EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Set synchronous bits
    EPwm1Regs.TBCTL.bit.PHSDIR = TB_DOWN; // Count down after synchronization
    
    // Setup shadowing
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
    // Set actions
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
    EPwm1Regs.AQCTLA.bit.CAD = AQ_SET; // Set PWM1A on event A, down count
    
    // Set dead-band
    EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // Enable Dead-band module
    EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Dead-band Type: AHC
    EPwm1Regs.DBFED.bit.DBFED = EPWM_DB;
    EPwm1Regs.DBRED.bit.DBRED = EPWM_DB;
    
    // Interrupt where we will change the Compare Values
    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
    EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT
    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
    
    // Assumes ePWM clock is already enabled (unknown why)
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Disable SOC on A group
    EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; //
    EPwm1Regs.ETPS.bit.SOCPSSEL = 0;
    EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // Generate pulse on 1st event
}

//
// InitEPwm2Example - Initialize EPWM2 configuration
//
void InitEPwm2Example()
{
    // Setup TBCLK
    EPwm2Regs.TBPRD = EPWM_TIMER_TBPRD; // Set timer period 2*EPWM_TIMER_TBPRD TBCLKs
    EPwm2Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0, change it when carrier phase-shift is used
    EPwm2Regs.TBCTR = 0x0000; // Clear counter
    
    // Set Compare values
    EPwm2Regs.CMPA.bit.CMPA = EPWM_MIN_CMPA; // Set compare A value
    EPwm2Regs.CMPB.bit.CMPB = EPWM_MAX_CMPB; // Set compare B value
    
    // Setup counter mode
    EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up and down
    EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Disable phase loading
    EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
    EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // Set synchronous bits
    EPwm2Regs.TBCTL.bit.PHSDIR = TB_DOWN; // Count down after synchronization
    
    // Setup shadowing
    EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
    EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
    // Set actions
    EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM2A on event A, up count
    EPwm2Regs.AQCTLA.bit.CAD = AQ_SET; // Set PWM2A on event A, down count
    
    // Set dead-band
    EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // Enable Dead-band module
    EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Dead-band Type: AHC
    EPwm2Regs.DBFED.bit.DBFED = EPWM_DB;
    EPwm2Regs.DBRED.bit.DBRED = EPWM_DB;
}

调用函数为:

//
// epwm1_isr - EPWM1 ISR
__interrupt void epwm1_isr(void)
{
    //--------------------Interrupt User Data Begin--------------------
    
    //PWM
    // int i;
    // for(i=0;i<=12;i++)
    // {
    //      (*EPWM[i]).TBPRD = MY_EPWM_TIMER_TBPRD;
    // }
    EPwm1Regs.CMPA.bit.CMPA = (dutycycle[1]*EPWM_TIMER_TBPRD);
    EPwm2Regs.CMPA.bit.CMPA = (dutycycle[2]*EPWM_TIMER_TBPRD);
    EPwm3Regs.CMPA.bit.CMPA = (dutycycle[3]*EPWM_TIMER_TBPRD);
    EPwm10Regs.CMPA.bit.CMPA = (dutycycle[1]*EPWM_TIMER_TBPRD);
    EPwm11Regs.CMPA.bit.CMPA = (dutycycle[2]*EPWM_TIMER_TBPRD);
    EPwm12Regs.CMPA.bit.CMPA = (dutycycle[3]*EPWM_TIMER_TBPRD);
    //--------------------Interrupt User Data End--------------------
    
    
    // Clear INT flag for this timer and Acknowledge this interrupt to receive more interrupts from group 3
    EPwm1Regs.ETCLR.bit.INT = 1;
    EPwm1Regs.ETCLR.bit.SOCA = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}

主函数为:

void main()
{
    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
    InitSysCtrl();
    
    //
    // Step 2. Initialize GPIO: (Cancel)
    // This example function is found in the F2837xD_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();
    //
    // EALLOW;
    // CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    //// CpuSysRegs.PCLKCR2.bit.EPWM1ENCLK = 1;
    // CpuSysRegs.PCLKCR2.bit.EPWM1=1;
    // CpuSysRegs.PCLKCR2.bit.EPWM2=1;
    // CpuSysRegs.PCLKCR2.bit.EPWM3=1;
    // EDIS;
    
    //
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;
    
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F2837xD_PieCtrl.c file.
    InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example. This is useful for debug purposes.
    // The shell ISR routines are found in F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
    InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    EALLOW; // This is needed to write to EALLOW protected registers
    PieVectTable.EPWM1_INT = &epwm1_isr;
    EDIS; // This is needed to disable write to EALLOW protected registers
    
    // Peripheral Initialization
    // PWM
    InitEPwm();
    // ADC
    InitADC();
    // Spi+VOFAplus
    InitSpi_AD5328();
    InitVOFAplus();
    // QEP
    InitEQepGpio();
    QEP_INIT_MACRO(1,qep_test);
    
    freq_speed_cal = 1000; // Frequency of speed calculation, Hz
    prd_speed_cal = 1.0/freq_speed_cal; // Period of speed calculation, s
    speed_period_cal = freq_sw/freq_speed_cal; // Interrupt intervals of speed calculation
    
    My_Filter_1st_Reset_MACRO(fil_1st_speed, 3141.59265, prd_speed_cal);
    
    // Filter
    My_Filter_1st_Reset_MACRO(fil_1st_test, 100000.0, prd_sw);
    My_Filter_2nd_Reset_MACRO(fil_2nd_test, 100000.0, prd_sw, 0.707106781);
    //
    // Step 4. User specific code, enable interrupts:
    // User specific code, initialize some key parameters
    // e.g. speed & eQEP module, ePWM module
    
    x = 6.28;
    
    //pid
    pid_test.Kp = 1.0;
    pid_test.Ki = 1.0;
    pid_test.Kd = 1.0;
    pid_test.out_max = 100.0;
    pid_test.out_min = -100.0;
    
    //qep
    qep_test.LineEncoder = line;
    qep_test.MechScaler = mech_scaler;
    qep_test.PolePairs = pole_mot;
    qep_test.CalibratedAngle = 100; // Unknown, require static positioning
    
    GpioDataRegs.GPDSET.bit.GPIO99 = 1;
    GpioDataRegs.GPCSET.bit.GPIO94 = 1;
    
    // Enable CPU INT3 which is connected to EPWM1-3 INT:
    IER |= M_INT3;
    
    // Enable EPWM INTn in the PIE: Group 3 interrupt 1
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
    
    // Enable global Interrupts and higher priority real-time debug events:
    EINT; // Enable Global interrupt INTM
    ERTM; // Enable Global real time interrupt DBGM
    
    
    //
    // Step 5. IDLE loop. Just sit and loop forever (optional):
    for(;;)
    {
        //--------------------Test Code Begin--------------------
        //Send to VOFA+
        vofa_test = vofa_test + 1;
        if(vofa_test>1500){vofa_test=0;}
        DataSend[0].DataFloat = vofa_test/1000.0;
        DataSend[1].DataFloat = 2.12;
        DataSend[2].DataFloat = 3.123;
        DataSend[3].DataFloat = 4.1234;
        BspSendFloatFifo(DataSend,4);
        
        //DAC
        //This function will easily cause endless loop, it's better to put this function at the end of for(;;)
        // DAC_AD5328(DAC_A, 2048);
        
        //--------------------Test Code End--------------------
    }
}

  • 已自己解决 错误为

     EPwm1Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Enable phase loading

    主时钟的PHSEN应设置为

     EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading

    从时钟的PHSEN应设置为

     EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Disable phase loading