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.

TMS320F280049: Jitter of HRPWM phase shift

Part Number: TMS320F280049

Hello everyone,

I'm just implementing a few optimizations of my code of the dual active bridge power converter.

To calculate the HRPWM TBPHS register values, I'm using the following example code:

    PHSFine = -(long)controlvalue; //controlvalue is negativ

    
    PHS_reg_val = (long)(PHSFine * (EPwm3Regs.TBPRD*2 + 2))>>15;
    tempPHS = (long)(PHSFine * (EPwm3Regs.TBPRD*2 + 2)) ;
    tempPHS = tempPHS - ((long)PHS_reg_val << 15);
    PHSHR_reg_val = tempPHS << 1; // convert to Q16

    EPwm3Regs.TBPHS.all = (((long)PHS_reg_val) << 16) |
                  PHSHR_reg_val; // loses lower 8-bits 
    EPwm4Regs.TBPHS.all = (((long)PHS_reg_val) << 16) |
                  PHSHR_reg_val; // loses lower 8-bits

I have the following issue:

during the control phase, the PHSHR_reg_val is always near the maximum value and jumps between ~65000 and ~200. The PHS_reg_val value jumps also between two values.

This results in jitter on the PWM signal and is no smooth transition. 

If I add 16384 to PHSFine and subtract 100 from the register value PHS_reg_val , the jitter disappears. The code follows.

PHSFine = 16384 +(long)controlvalue;

//Phase Shift Mode


PHS_reg_val = (long)(PHSFine * (EPwm3Regs.TBPRD*2 + 2))>>15;
tempPHS = (long)(PHSFine * (EPwm3Regs.TBPRD*2 + 2)) ;
tempPHS = tempPHS - ((long)PHS_reg_val << 15);
PHSHR_reg_val = tempPHS << 1; // convert to Q16

EPwm3Regs.TBPHS.all = (100-((long)PHS_reg_val) << 16) |
      PHSHR_reg_val; // loses lower 8-bits 
EPwm4Regs.TBPHS.all = (100-((long)PHS_reg_val) << 16) |
      PHSHR_reg_val; // loses lower 8-bits 

I cannot understand why there is a difference because normally the control loop should generate the same phase shift value.

Thanks for your help.

  • Hi Patrick,

    f I add 16384 to PHSFine and subtract 100 from the register value PHS_reg_val , the jitter disappears. The code follows.

    This is strange. Would it be possible to see how you have configured the EPWM module?

    Are you applying a synchronization pulse at every EPWM period or once on initialization?

    Best Regards,

    Marlyn

  • Thanks for your quick answer.

    The subroutines are called one after the other. Firstly, I call initEPWMstartup_project(void) and then initEPWM_project(void). 

    void initEPWMstartup_project(void)
    {
       volatile struct EPWM_REGS *ePWM[] = {0, &EPwm1Regs, &EPwm2Regs, &EPwm3Regs, &EPwm4Regs, &EPwm7Regs, &EPwm8Regs};
       volatile struct EPWM_REGS *ePWM_LV[] = {0, &EPwm1Regs, &EPwm2Regs, &EPwm7Regs, &EPwm8Regs};
    
       EALLOW;
       //stops the clock within the enabled EPWMs
       CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;                		// Disable TBCLK within the EPWM
       SyncSocRegs.SYNCSELECT.bit.EPWM4SYNCIN = 0x0;           		//EPWM4 is also synchronized with the clock of EPWM1
       SyncSocRegs.SYNCSELECT.bit.EPWM7SYNCIN = 0x0;           		//EPWM4 is also synchronized with the clock of EPWM1
       int j = 0;
       for(j=1; j<=PWM_CH; j++)
       {
           (*ePWM[j]).TBCTL.bit.HSPCLKDIV = 0;                      // Change clock divider to /1
           (*ePWM[j]).TBPRD = SWPERIOD;                             // Period = (fSYSCLK/fs)/2 - 1 = 100e6/250e3 - 1 = 199
           (*ePWM[j]).TBPHS.bit.TBPHS = 0;                          // Set Phase register to 50% period
           (*ePWM[j]).TBCTR = 0;                                    // clear TB counter
           (*ePWM[j]).TBCTL.bit.SYNCOSEL = TB_SYNC_IN;              // Master: sync out pulse at counter zero - all other PWM TB_SYNC_IN (slave)
           (*ePWM[j]).TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;          // Sawtooth carrier
           (*ePWM[j]).TBCTL.bit.PHSEN = TB_ENABLE;                  // Phase loading enable
           (*ePWM[j]).TBCTL.bit.PRDLD = TB_SHADOW;                  // use shadow register for TBPRD (synchronized pulses)
           (*ePWM[j]).TBCTL.bit.HSPCLKDIV = TB_DIV1;                // TBCLK = SYSCLKOUT (two registers, same functionality-history)
           (*ePWM[j]).TBCTL.bit.CLKDIV = TB_DIV1;                   // TBCLK = SYSCLKOUT (two registers, same functionality-history)
           (*ePWM[j]).TBCTL.bit.PHSDIR = 0;
           (*ePWM[j]).CMPCTL.bit.SHDWAMODE = CC_SHADOW;             // use shadow register for compare value A
           (*ePWM[j]).CMPCTL.bit.SHDWBMODE = CC_SHADOW;             // use shadow register for compare value B
           (*ePWM[j]).CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;           // load on CTR = TBPRD and ZRO. Shadow Mode (Ref Manuel S.1833)
                                                                    // (definition when the content is transferred from shadow to active register)
                                                                    // Time-base counter equal to the period (TBCTR = TBPRD)
                                                                    // Time-base counter equal to zero (TBCTR = 0x00)
                                                                    // Both CTR = PRD and CTR = Zero
           (*ePWM[j]).CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;           // load on CTR = TBPRD and ZRO
           (*ePWM[j]).DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;         	// Deadband enabled
           (*ePWM[j]).DBCTL.bit.POLSEL = DB_ACTV_HIC;
           (*ePWM[j]).DBCTL.bit.IN_MODE = DBA_ALL;
           (*ePWM[j]).TZCTL.bit.TZA = TZ_FORCE_LO;                 	// Force to low at trip (fault condition)
           (*ePWM[j]).TZCTL.bit.TZB = TZ_FORCE_LO;                 	// Force to low at trip (fault condition)
           (*ePWM[j]).TZFRC.bit.OST = 1;                           	// Enable TZ interrupt on any TZ event
    
    
           //HRPWM
           (*ePWM[j]).HRCNFG.all = 0x0;                        		// clear all bits first
           (*ePWM[j]).HRCNFG.bit.EDGMODE = HR_BEP;                  // Control both Edge Position
           (*ePWM[j]).HRCNFG.bit.CTLMODE = HR_PHS;                  // Phasecontrol controls the MEP
           (*ePWM[j]).HRCNFG.bit.HRLOAD = HR_CTR_PRD;               // Shadow load on CTR=PRD
    
           (*ePWM[j]).HRCNFG.bit.EDGMODEB = HR_BEP;            		// Control both Edge Position
           (*ePWM[j]).HRCNFG.bit.CTLMODEB = HR_PHS;          		// Phasecontrol controls the MEP
           (*ePWM[j]).HRCNFG.bit.HRLOADB = HR_CTR_PRD;       		// Shadow load on CTR=PRD
    
           (*ePWM[j]).TBPHS.bit.TBPHSHR = (1 << 8);                 //init HRPWM
           (*ePWM[j]).HRPCTL.bit.HRPE = 0;
    
           (*ePWM[j]).CMPA.bit.CMPA = 20 ;                         
           (*ePWM[j]).CMPB.bit.CMPB = SWPERIOD - 20 ;               
    
           (*ePWM[j]).TBPRDHR = SWPERIOD;
    
           (*ePWM[j]).HRCNFG.bit.AUTOCONV = 1;                     // Enable auto-conversion
    
           (*ePWM[j]).DBFED.all = 3;                               // Dead Time Xns  Deadband Generator Falling
           (*ePWM[j]).DBRED.all = 3;                               // Dead Time Xns  Deadband Generator rising
           (*ePWM[j]).HRPCTL.bit.TBPHSHRLOADE = 1;                 // Enable TBPHSHR sync
                                                                   // (required for updwn count HR control)
       }
    
       for(j=1; j<=4; j++)
       {
           (*ePWM_LV[j]).AQCTLA.bit.CAU = AQ_CLEAR;                 //Counter equals zero
           (*ePWM_LV[j]).AQCTLA.bit.CBD = AQ_SET;                   //Counter equals CMPA on up-count (CAU)
           (*ePWM_LV[j]).AQCSFRC.bit.CSFB = AQ_CLEAR;               //force output B low
       }
       //Setup PWM1 (DSP_DO_LV1_PWM_2L(B),DSP_DO_LV1_PWM_2H(A))
    
       // Set up Action Qualifier regs (AQ)                    -- what happens on the output pin
       EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO;   // Master: sync out pulse at counter zero - all other PWM TB_SYNC_IN (slave)
    
       // Set up event trigger for ADC conversion start at max. and 0
       EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO;                   // SOCA at counter zero WAS ZERO
       EPwm1Regs.ETSEL.bit.SOCAEN = 0;                              // Enable SOCA
       EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST;                         // SOCA on every event
    
       /***************************************************************************************************************************************/
       //Setup PWM2 (DSP_DO_LV1_PWM_1L(B),DSP_DO_LV1_PWM_1H(A))
    
       // Set up Action Qualifier regs (AQ)                    		-- what happens on the output pin
       EPwm2Regs.AQCTLA.bit.CAU = AQ_SET;                           
       EPwm2Regs.AQCTLA.bit.CBD = AQ_CLEAR;                         
       EPwm2Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;                       //force output B low
    
       /***************************************************************************************************************************************/
       //Setup PWM7 (DSP_DO_LV2_PWM_2L(B),DSP_DO_LV2_PWM_2H(A))
    
       EPwm7Regs.AQCTLA.bit.CAU = AQ_SET;                           
       EPwm7Regs.AQCTLA.bit.CBD = AQ_CLEAR;                         
       EPwm7Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;                       
    
       /****************************************************************************************************************************/
       //Setup PWM3 (DSP_DO_HV_PWM_1L(A),DSP_DO_HV_PWM_1H(B)) -- caution: pinning swapped compared to LV
    
       EPwm3Regs.DBFED.all = 13;                                    // Dead Time X0ns Deadband Generator Falling 
       EPwm3Regs.DBRED.all = 15;                                    // Dead Time Xns Deadband Generator rising 
       
       EPwm3Regs.AQCTLA.bit.ZRO = AQ_SET;                           //Counter equals zero
       EPwm3Regs.AQCTLA.bit.PRD = AQ_CLEAR;                         //Counter equals CMPA on up-count (CAU)
       EPwm3Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;                       //force output B low
    
       /**************************************************************************************************************************/
       //Setup PWM4 (DSP_DO_HV_PWM_2L(A),DSP_DO_HV_PWM_2H(B))-- caution: pinning swapped compared to LV
    
       // Set up Dead Band regs (DB)
    
       EPwm4Regs.DBFED.all = 13;                                    
       EPwm4Regs.DBRED.all = 15;
    
       EPwm4Regs.AQCTLA.bit.ZRO = AQ_SET;                           //Counter equals zero
       EPwm4Regs.AQCTLA.bit.PRD = AQ_CLEAR;                         //Counter equals CMPA on up-count (CAU)
       EPwm4Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;                       //force output B low
    
        //start the clocks again, all timers are synchronized
    
       /**************************************************************************************************************************/
       CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    EDIS;
    
    }
       
       void initEPWM_project(void)
    {
        volatile struct EPWM_REGS *ePWM[] = {0, &EPwm1Regs, &EPwm2Regs, &EPwm3Regs, &EPwm4Regs, &EPwm7Regs, &EPwm8Regs};
        EALLOW;
    
    
        EPwm3Regs.EPWMXLINK.bit.TBPRDLINK = 0b0011;          		//Link EPWM3 to EPWM4
    
        int j = 0;
        for(j=1; j<=PWM_CH; j++)
        {
            (*ePWM[j]).CMPA.bit.CMPA = ((SWPERIOD+1)/2)-1 ;     	
            (*ePWM[j]).AQCTLA.bit.CAU = AQ_CLEAR;              		
            (*ePWM[j]).AQCTLA.bit.CAD = AQ_SET;                     
            (*ePWM[j]).AQCSFRC.bit.CSFB = AQ_CLEAR;              	//force output B low
            (*ePWM[j]).AQCTLA.bit.CBD = 0;
            (*ePWM[j]).AQCTLA.bit.ZRO = 0;
            (*ePWM[j]).AQCTLA.bit.PRD = 0;
        }
    
        /***************************************************************************************************************************************/
        //Setup PWM2 (DSP_DO_LV1_PWM_1L(B),DSP_DO_LV1_PWM_1H(A))
    
        // Set up Action Qualifier regs (AQ)                    
        EPwm2Regs.AQCTLA.bit.CAU = AQ_SET;                    		
        EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;                     	
        EPwm2Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;                  	
    
        /***************************************************************************************************************************************/
        //Setup PWM7 (DSP_DO_LV2_PWM_2L(B),DSP_DO_LV2_PWM_2H(A))
    
        EPwm7Regs.AQCTLA.bit.CAU = AQ_SET;                    		
        EPwm7Regs.AQCTLA.bit.CAD = AQ_CLEAR;                  		
        EPwm7Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;                		
    
        /****************************************************************************************************************************/
        EPwm4Regs.AQCTLA.bit.CAU = AQ_SET;                     		
        EPwm4Regs.AQCTLA.bit.CAD = AQ_CLEAR;                     	
        EPwm4Regs.AQCSFRC.bit.CSFB = AQ_CLEAR;              		
    	
    	EPwm3Regs.TBCTL.bit.PHSDIR = 1;
    	EPwm4Regs.TBCTL.bit.PHSDIR = 1;
    		  
        EDIS;
    }

  • Hi Patrick,

    Thank you for sharing your code. I will take a look through it and provide any feedback by tomorrow.

    Best Regards,

    Marlyn

  • Hi Patrick,

    If in up & down count mode, and doing both edge control then in this case you need to have action qualifier settings as follows: CMPxU = set, CMPxD = clear, no actions on TBCTR= PRD or ZRO. For AQCTLA registers, set on CAU and clear on CAD, for AQCLTB, set on CBU and clear on CBD

    The SYNCOSEL for EPWM1 is set as "TB_CTR_ZERO", which will send a sync pulse to the slave modules every time EPWM1's TBCTR counter is equal to 0. Note that when high-resolution period mode is enabled, an EPWMxSYNC pulse will introduce +/- 1 - 2 cycle jitter to the PWM (+/- 1 cycle in up-count mode and +/- 2 cycle in up-down count mode).

    You should set the  'Sync Out Pulse' to be configured to software, a software synchronization pulse should be issued only once during initialization and then only when the phase or period is changed. If a software sync pulse is applied while the PWM is running, the jitter will appear on the PWM output at the time of the sync pulse.

    Best Regards,

    Marlyn