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.

TMS320F280039C: Glitches on HRPWM in AHC with deadband

Part Number: TMS320F280039C
Other Parts Discussed in Thread: LAUNCHXL-F280039C, SYSCONFIG, LAUNCHXL-F280049C, C2000WARE

Hey,

I am facing some problems in implementing active-high complementary PWM with dead-band and high resolution mode on TMS320F280039C. I want to use it to control a three-phase six-switch inverter with symmetrical PWM pattern or space vector modulation.

At first, everthying looks good. But by varying the duty cycle across the full range, I've detected glitches on the rising edges, as you can see on my following measurements:

CH1 (black): PWM2A output, J4 pin 38

CH2 (blue): PWM1A output, J4 pin 40

I have written small test code for use on the LAUNCHXL-F280039C with fixed duty cylces which shows the glitches from my measurements:

#include "f28x_project.h"
#include "sfo_v8.h"

#define RED_FED 42                      // t_red = t_fed = RED_FED * t_pwmclk = 42 / 120 MHz = ca. 350 ns

void init_pwm_gpio(void);
void init_pwm(void);
void update_epwm1(float dc);

volatile struct EPWM_REGS *ePWM[3] = {0, &EPwm1Regs, &EPwm2Regs};

Uint16 status = SFO_INCOMPLETE;
int MEP_ScaleFactor = 0; //scale factor value

//
// Main
//
void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    InitSysCtrl();

    //
    // Initialize GPIO
    //
    InitGpio();

    //
    // 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.
    //
    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).
    //
    InitPieVectTable();

    init_pwm_gpio();
    init_pwm();

    EPwm2Regs.CMPA.bit.CMPA = 560;
    EPwm2Regs.CMPA.bit.CMPAHR = 0;
    EPwm2Regs.CMPB.bit.CMPBHR = 0;

    update_epwm1(0.867F);

    EINT;           // Enable Global interrupt INTM
    ERTM;           // Enable Global realtime interrupt DBGM

    while(1)
    {
    }
}

void update_epwm1(float dc)
{
    uint16_t cmpa = 0;
    uint32_t cmpa_hr_temp = 0;
    uint16_t cmpa_hr = 0;

    cmpa = (uint16_t)((dc * 300) + 300);

    // Duty Cycle Range Limitation in high resolution period mode
    // which includes the up-down count mode with MEP on both rising edge and falling edge.
    // MEP is inactive in TBCTR range [0, 3[ and ]PFC_PERIOD - 3, PFC_PERIOD]
    if((cmpa >= 3) && (cmpa <= (600 - 3)))
    {
        cmpa_hr_temp = (uint32_t)((dc * ((long)(300) << 16)) + (300  << 16));
        cmpa_hr = cmpa_hr_temp - ((long)(cmpa) << 16);
    }
    else
    {
        if(cmpa < 3)
        {
            cmpa = 0;
        }
        else
        {
            cmpa = 600;
        }
        cmpa_hr = 0;
    }

    EPwm1Regs.CMPA.bit.CMPA = cmpa;
    EPwm1Regs.CMPA.bit.CMPAHR = cmpa_hr;
    EPwm1Regs.CMPB.bit.CMPBHR = cmpa_hr;
}

void init_pwm_gpio(void)
{
    EALLOW;
    GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1;      // Disable pull-up on GPIO0 (EPWM1A)
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1;      // Disable pull-up on GPIO1 (EPWM1B)

    GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1;      // Disable pull-up on GPIO2 (EPWM2A)
    GpioCtrlRegs.GPAPUD.bit.GPIO3 = 1;      // Disable pull-up on GPIO3 (EPWM2B)

    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;     // Configure GPIO0 as EPWM1A
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;     // Configure GPIO1 as EPWM1B

    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1;     // Configure GPIO2 as EPWM2A
    GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1;     // Configure GPIO3 as EPWM2B

    GpioCtrlRegs.GPALOCK.bit.GPIO0 = 1;     // lock GPIO0 configuration
    GpioCtrlRegs.GPALOCK.bit.GPIO1 = 1;     // lock GPIO1 configuration

    GpioCtrlRegs.GPALOCK.bit.GPIO2 = 1;     // lock GPIO2 configuration
    GpioCtrlRegs.GPALOCK.bit.GPIO3 = 1;     // lock GPIO3 configuration

    EDIS;
}

void init_pwm(void)
{

    uint16_t i;

    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;       // Disable EPWM Time Base Clock gating
    EDIS;

    for(i = 1; i < 3; i++)
        {
            // Time-Base Submodule
            (*ePWM[i]).TBPRD = 600;                 // Set timer period
            (*ePWM[i]).TBPRDHR = 0;                 // HR Period

            (*ePWM[i]).TBCTR = 0x0000;              // Clear counter

            (*ePWM[i]).TBCTL.bit.PRDLD = 0;         // Active Period Reg Load from Shadow
            (*ePWM[i]).TBCTL.bit.CTRMODE = 2;       // Up-Down-Count mode
            (*ePWM[i]).TBCTL.bit.FREE_SOFT = 2;     // free run in emulation mode
            (*ePWM[i]).TBCTL.bit.PHSDIR = 1;        // Count up after the synchronization event
            (*ePWM[i]).TBCTL.bit.PHSEN = 0;         // Disable load event when an EPWMxSYNCI input signal occurs
            (*ePWM[i]).TBCTL.bit.HSPCLKDIV = 0;     // Clock ratio / 1
            (*ePWM[i]).TBCTL.bit.CLKDIV = 0;        // Clock ratio / 1

            // Synchronization in- and output
            (*ePWM[i]).EPWMSYNCINSEL.bit.SEL = 0;    // Disables all inputs for this module
            (*ePWM[i]).EPWMSYNCOUTEN.bit.SWEN = 0;   // Disable EPWMxSYNCO at SWFSYNC

            // Counter-Compare Submodule
            (*ePWM[i]).CMPCTL.bit.LOADAMODE = 0;     // Load CMPA when TBCTR = 0
            (*ePWM[i]).CMPCTL.bit.SHDWAMODE = 0;     // enable CMPA shadow mode
            (*ePWM[i]).CMPA.bit.CMPA = 300;           // Set default CMPA value

            // Action-Qualifier Submodule
            // ePWMxA on-time = (1200 - 2 * CMPA) * (1 / 120 MHz)
            // ePWMxB on-time = 2* CMPA  * (1 / 120 MHz)
            (*ePWM[i]).AQCTLA.bit.ZRO = 1;           // Clear ePWMxA when TBCTR = 0
            (*ePWM[i]).AQCTLA.bit.CAU = 2;           // Set ePWMxA when TBCTR = CMPA on up-count
            (*ePWM[i]).AQCTLA.bit.CAD = 1;           // Clear ePWMxA when TBCTR = CMPA on down-count


            (*ePWM[i]).DBCTL.bit.HALFCYCLE = 1;         // clock DB counters at half TBCLK rate
            (*ePWM[i]).DBCTL.bit.DEDB_MODE = 0;         // RED to Input A, FED to Input A
            (*ePWM[i]).DBCTL.bit.IN_MODE = 0;
            (*ePWM[i]).DBCTL.bit.OUT_MODE = 3;          // RED to A path, FED to B path
            (*ePWM[i]).DBCTL.bit.POLSEL = 2;            // B path inverted
            (*ePWM[i]).DBCTL.bit.OUTSWAP = 0;           // A path to OutA, B path to OutB
            (*ePWM[i]).DBCTL.bit.SHDWDBFEDMODE = 1;     // FED shandow load mode
            (*ePWM[i]).DBCTL.bit.SHDWDBREDMODE = 1;     // RED shandow load mode
            (*ePWM[i]).DBCTL.bit.LOADFEDMODE = 2;       // Load on TBCTR = 0 or TBCTR = PRD
            (*ePWM[i]).DBCTL.bit.LOADREDMODE = 2;       // Load on TBCTR = 0 or TBCTR = PRD

            (*ePWM[i]).DBRED.bit.DBRED = 2 * RED_FED;
            (*ePWM[i]).DBFED.bit.DBFED = 2 * RED_FED;

            EALLOW;
            (*ePWM[i]).HRCNFG.all = 0x0;
            (*ePWM[i]).HRCNFG.bit.EDGMODE = 3;          // MEP control of both edges
            (*ePWM[i]).HRCNFG.bit.CTLMODE = 0;          // Duty control mode
            (*ePWM[i]).HRCNFG.bit.HRLOAD = 2;           // Load CMPAHR when TBCTR = 0 or TBCTR = PRD
            (*ePWM[i]).HRCNFG.bit.AUTOCONV = 1;         // Automatic HRMSTEP scaling is enabled

            //
            // CMPBHR is used for duty-control with dead-band in up-down-count mode and must be set to same value as CMPA
            //
            (*ePWM[i]).HRCNFG.bit.EDGMODEB = 3;          // MEP control of both edges
            (*ePWM[i]).HRCNFG.bit.CTLMODEB = 0;          // Duty control mode
            (*ePWM[i]).HRCNFG.bit.HRLOADB = 2;           // Load CMPBHR when TBCTR = 0 or TBCTR = PRD
            //

            (*ePWM[i]).HRCNFG2.bit.EDGMODEDB = 3;       // MEP control of both edges (DBREDHR and DBFEDHR)
            (*ePWM[i]).HRCNFG2.bit.CTLMODEDBRED = 2;    // load shadow register when CTR = Zero or CTR = PRD
            (*ePWM[i]).HRCNFG2.bit.CTLMODEDBFED = 2;    // load shadow register when CTR = Zero or CTR = PRD

            (*ePWM[i]).HRPWR.bit.CALPWRON = 1;          // Enables MEP calibration logic

            (*ePWM[i]).HRPCTL.bit.HRPE = 1;             // High resolution period enabled
            (*ePWM[i]).HRPCTL.bit.TBPHSHRLOADE = 1;     // Synchronize the high-resolution phase on a TBCTL[SWFSYNC] event
            EDIS;

            (*ePWM[i]).TBCTL.bit.PHSEN = 1;             // load TBPHS from shadow on a TBCTL[SWFSYNC] event
            (*ePWM[i]).TBCTL.bit.SWFSYNC = 1;           // generates a TBCTL[SWFSYNC] event

        }

        EALLOW;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;       // Enable EPWM Time Base Clock gating
        EDIS;

        while(SFO() == 0)
        {
            // Wait until SFO has finished
        }
}

With a different value of RED_FED, the duty cycle at which the glitches occurs is different. So it seems that there is a correlation between them. The problem also occurs when I use a reduced clock frequency for the ePWM modules. So maybe there is an issue in the initialization of the eWPM modules?

Best regards,

Stefan

  • Stefan,

    Thanks for posting your question and your configuration code! We will take review and get back to you with some suggestions.

    I have one question for you in the mean time, I see you are using raw bitfields, without utilizing Driver library or our GUI configuration tool (SysConfig) which can catch a lot of configuration errors for you automatically. Can you share the reason behind not using any of the additional tools provided by TI C2000 team?

    We want to make sure we know the limitations of our tools that causes users to not utilize them and make enhancements.

    Nima

  • Hi Nima,

    Thank you for your answer.

    I use bitfield because I want to learn how the controller works. By knowing all the corresponding register valuese it is also quite easy to check if the configuration was accidentally changed by other functions.

    Best regards,

    Stefan

  • Hi Stefan,

    There are some limitations to using HRPWM and deadband across the full duty cycle range. Many of these are outlined in section 20.15.1.5.3 of the TRM. Because of this you may see issues at very high or low duty cycles. Is using HRPWM at very low or high duty cycles necessary for your configuration?

    I also replicated your configuration in SysConfig, which threw the following error:

    "For High Resolution Period: CMPB/CMPA must have shadow loading enabled for when TBCTR=0 or PRD"

    Does your error persist when shadow loading CMPA and CMPB on both TBCTR=0 and TBCTR=PRD? (controlled via CMPCTL register)

  • Hi Luke,

    thank you very much for your feedback.

    I have read the chapter in TRM about the HRPWM and check the forbidden ranges [0,3] and [PERIOD-3, PERIOD] in the update_epwm1 update function.

    The limitation described in the TRM is fine for the application. However, the error occurs at CMPA = 560. This is outside the forbidden range and corresponds to turn-on times of over 300 ns in this configuration.

    I tried your suggestion to enable shadowing of CMPA and CMPB on both TBCTR=0 and TBCTR=PRD, but the error still occurs.

    I read again the ePWM chapters in the TRM and checked everything. Unfortunately, I can not find the error.

    Regards, Stefan

  • Hi Stefan,

    Thanks for checking these settings, could you elaborate on your earlier statement?

    "With a different value of RED_FED, the duty cycle at which the glitches occurs is different. So it seems that there is a correlation between them."

    Could you share which pairs of RED_FED and duty cycles caused the glitch? I tried to test the code you sent but could not replicate the issue on my end.

    Thank you,

    Luke

  • Hi Luke,

    I have found a few combinations where the glitch occurs. The glitch only occurs if the HR components (CMPAHR, CMPBHR) are not equal to zero.

    I quickly expanded the code to show multiple cases. In the "epwm_isr_0" ISR, 16 cases are run sequentially and in each the MEP of EPwm1 is varied from 0 to MEP_ScaleFactor. EPwm2 gets the same set of CMPA and DBRED / DBFED values, but with zero CMPAHR and CMPBHR values.

    #include "f28x_project.h"
    #include "sfo_v8.h"
    
    #define RED_FED 42                      // t_red = t_fed = RED_FED * t_pwmclk = 42 / 120 MHz = ca. 350 ns
    
    void init_pwm_gpio(void);
    void init_pwm(void);
    void update_epwm1(float dc);
    __interrupt void epwm_isr_0(void);
    
    float dc_fine = 0.0F;
    
    uint16_t isr_cnt = 0;
    uint16_t mep_isr_cnt = 0;
    uint16_t check_symmetry = 0;
    
    volatile struct EPWM_REGS *ePWM[3] = {0, &EPwm1Regs, &EPwm2Regs};
    
    Uint16 status = SFO_INCOMPLETE;
    int MEP_ScaleFactor = 0; //scale factor value
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        InitSysCtrl();
    
        //
        // Initialize GPIO
        //
        InitGpio();
    
        //
        // 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.
        //
        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).
        //
        InitPieVectTable();
    
        EALLOW;
        PieVectTable.EPWM1_INT = &epwm_isr_0;
        PieCtrlRegs.PIEIER3.bit.INTx1 = 1;  // EPWM1
        PieCtrlRegs.PIECTRL.bit.ENPIE = 1;  // Disable the PIE
        PieCtrlRegs.PIEACK.all = 0xFFFF;    // Enables PIE to drive a pulse into the CPU
        IFR = 0x0000;
        IER = 0x3FFF;
        EDIS;
    
        init_pwm_gpio();
        init_pwm();
    
        EINT;           // Enable Global interrupt INTM
        ERTM;           // Enable Global realtime interrupt DBGM
    
        while(1)
        {
        }
    }
    
    void update_epwm1(float dc)
    {
        uint16_t cmpa = 0;
        uint32_t cmpa_hr_temp = 0;
        uint16_t cmpa_hr = 0;
    
        cmpa = (uint16_t)((dc * 300) + 300);
    
        // Duty Cycle Range Limitation in high resolution period mode
        // which includes the up-down count mode with MEP on both rising edge and falling edge.
        // MEP is inactive in TBCTR range [0, 3[ and ]PFC_PERIOD - 3, PFC_PERIOD]
        if((cmpa >= 3) && (cmpa <= (600 - 3)))
        {
            cmpa_hr_temp = (uint32_t)((dc * ((long)(300) << 16)) + (300  << 16));
            cmpa_hr = cmpa_hr_temp - ((long)(cmpa) << 16);
        }
        else
        {
            if(cmpa < 3)
            {
                cmpa = 0;
            }
            else
            {
                cmpa = 600;
            }
            cmpa_hr = 0;
        }
    
        EPwm1Regs.CMPA.bit.CMPA = cmpa;
        EPwm1Regs.CMPA.bit.CMPAHR = cmpa_hr;
        EPwm1Regs.CMPB.bit.CMPBHR = cmpa_hr;
    }
    
    void init_pwm_gpio(void)
    {
        EALLOW;
        GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1;      // Disable pull-up on GPIO0 (EPWM1A)
        GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1;      // Disable pull-up on GPIO1 (EPWM1B)
    
        GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1;      // Disable pull-up on GPIO2 (EPWM2A)
        GpioCtrlRegs.GPAPUD.bit.GPIO3 = 1;      // Disable pull-up on GPIO3 (EPWM2B)
    
        GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;     // Configure GPIO0 as EPWM1A
        GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;     // Configure GPIO1 as EPWM1B
    
        GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1;     // Configure GPIO2 as EPWM2A
        GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1;     // Configure GPIO3 as EPWM2B
    
        GpioCtrlRegs.GPALOCK.bit.GPIO0 = 1;     // lock GPIO0 configuration
        GpioCtrlRegs.GPALOCK.bit.GPIO1 = 1;     // lock GPIO1 configuration
    
        GpioCtrlRegs.GPALOCK.bit.GPIO2 = 1;     // lock GPIO2 configuration
        GpioCtrlRegs.GPALOCK.bit.GPIO3 = 1;     // lock GPIO3 configuration
    
        EDIS;
    }
    
    void init_pwm(void)
    {
    
        uint16_t i;
    
        EALLOW;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;       // Disable EPWM Time Base Clock gating
        EDIS;
    
        for(i = 1; i < 3; i++)
            {
                // Time-Base Submodule
                (*ePWM[i]).TBPRD = 600;                 // Set timer period
                (*ePWM[i]).TBPRDHR = 0;                 // HR Period
    
                (*ePWM[i]).TBCTR = 0x0000;              // Clear counter
    
                (*ePWM[i]).TBCTL.bit.PRDLD = 0;         // Active Period Reg Load from Shadow
                (*ePWM[i]).TBCTL.bit.CTRMODE = 2;       // Up-Down-Count mode
                (*ePWM[i]).TBCTL.bit.FREE_SOFT = 2;     // free run in emulation mode
                (*ePWM[i]).TBCTL.bit.PHSDIR = 1;        // Count up after the synchronization event
                (*ePWM[i]).TBCTL.bit.PHSEN = 0;         // Disable load event when an EPWMxSYNCI input signal occurs
                (*ePWM[i]).TBCTL.bit.HSPCLKDIV = 0;     // Clock ratio / 1
                (*ePWM[i]).TBCTL.bit.CLKDIV = 0;        // Clock ratio / 1
    
                // Synchronization in- and output
                (*ePWM[i]).EPWMSYNCINSEL.bit.SEL = 0;    // Disables all inputs for this module
                (*ePWM[i]).EPWMSYNCOUTEN.bit.SWEN = 0;   // Disable EPWMxSYNCO at SWFSYNC
    
                // Counter-Compare Submodule
                (*ePWM[i]).CMPCTL.bit.LOADAMODE = 2;     // Load CMPA when TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).CMPCTL.bit.SHDWAMODE = 0;     // enable CMPA shadow mode
                (*ePWM[i]).CMPA.bit.CMPA = 300;          // Set default CMPA value
    
                (*ePWM[i]).CMPCTL.bit.LOADBMODE = 2;     // Load CMPB when TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).CMPCTL.bit.SHDWBMODE = 0;     // enable CMPB shadow mode
    
                // Action-Qualifier Submodule
                // ePWMxA on-time = (1200 - 2 * CMPA) * (1 / 120 MHz)
                // ePWMxB on-time = 2* CMPA  * (1 / 120 MHz)
                //(*ePWM[i]).AQCTLA.bit.ZRO = 0;           // Clear ePWMxA when TBCTR = 0
                (*ePWM[i]).AQCTLA.bit.CAU = 2;           // Set ePWMxA when TBCTR = CMPA on up-count
                (*ePWM[i]).AQCTLA.bit.CAD = 1;           // Clear ePWMxA when TBCTR = CMPA on down-count
    
                (*ePWM[i]).DBCTL.bit.HALFCYCLE = 1;         // clock DB counters at half TBCLK rate
                (*ePWM[i]).DBCTL.bit.DEDB_MODE = 0;         // RED to Input A, FED to Input A
                (*ePWM[i]).DBCTL.bit.IN_MODE = 0;
                (*ePWM[i]).DBCTL.bit.OUT_MODE = 3;          // RED to A path, FED to B path
                (*ePWM[i]).DBCTL.bit.POLSEL = 2;            // B path inverted
                (*ePWM[i]).DBCTL.bit.OUTSWAP = 0;           // A path to OutA, B path to OutB
                (*ePWM[i]).DBCTL.bit.SHDWDBFEDMODE = 1;     // FED shandow load mode
                (*ePWM[i]).DBCTL.bit.SHDWDBREDMODE = 1;     // RED shandow load mode
                (*ePWM[i]).DBCTL.bit.LOADFEDMODE = 2;       // Load on TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).DBCTL.bit.LOADREDMODE = 2;       // Load on TBCTR = 0 or TBCTR = PRD
    
                (*ePWM[i]).DBRED.bit.DBRED = 2 * RED_FED;
                (*ePWM[i]).DBFED.bit.DBFED = 2 * RED_FED;
                (*ePWM[i]).DBFEDHR.bit.DBFEDHR = 1;
                (*ePWM[i]).DBREDHR.bit.DBREDHR = 1;
    
                EALLOW;
                (*ePWM[i]).HRCNFG.all = 0x0;
                (*ePWM[i]).HRCNFG.bit.EDGMODE = 3;          // MEP control of both edges
                (*ePWM[i]).HRCNFG.bit.CTLMODE = 0;          // Duty control mode
                (*ePWM[i]).HRCNFG.bit.HRLOAD = 2;           // Load CMPAHR when TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).HRCNFG.bit.AUTOCONV = 1;         // Automatic HRMSTEP scaling is enabled
    
                //
                // CMPBHR is used for duty-control with dead-band in up-down-count mode and must be set to same value as CMPA
                //
                (*ePWM[i]).HRCNFG.bit.EDGMODEB = 3;          // MEP control of both edges
                (*ePWM[i]).HRCNFG.bit.CTLMODEB = 0;          // Duty control mode
                (*ePWM[i]).HRCNFG.bit.HRLOADB = 2;           // Load CMPBHR when TBCTR = 0 or TBCTR = PRD
                //
    
                (*ePWM[i]).HRCNFG2.bit.EDGMODEDB = 3;       // MEP control of both edges (DBREDHR and DBFEDHR)
                (*ePWM[i]).HRCNFG2.bit.CTLMODEDBRED = 2;    // load shadow register when CTR = Zero or CTR = PRD
                (*ePWM[i]).HRCNFG2.bit.CTLMODEDBFED = 2;    // load shadow register when CTR = Zero or CTR = PRD
    
                (*ePWM[i]).HRPWR.bit.CALPWRON = 1;          // Enables MEP calibration logic
    
                (*ePWM[i]).HRPCTL.bit.HRPE = 1;             // High resolution period enabled
                (*ePWM[i]).HRPCTL.bit.TBPHSHRLOADE = 1;     // Synchronize the high-resolution phase on a TBCTL[SWFSYNC] event
                EDIS;
    
                (*ePWM[i]).TBCTL.bit.PHSEN = 1;             // load TBPHS from shadow on a TBCTL[SWFSYNC] event
                (*ePWM[i]).TBCTL.bit.SWFSYNC = 1;           // generates a TBCTL[SWFSYNC] event
    
                if(i == 1)
                {
                    (*ePWM[i]).ETSEL.bit.INTSEL = 1;         // Enable Interrupt when TBCTR = 0
                    (*ePWM[i]).ETSEL.bit.INTEN = 1;          // Enable INT
                    (*ePWM[i]).ETPS.bit.INTPRD = 3;          // Generate INT at third event
                }
            }
    
            EALLOW;
            CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;       // Enable EPWM Time Base Clock gating
            EDIS;
    
            while(SFO() == 0)
            {
                // Wait until SFO has finished
            }
    }
    
    
    __interrupt void epwm_isr_0(void)
    {
        (*ePWM[1]).ETCLR.bit.INT = 1;
        if(check_symmetry == 1)
        {
            isr_cnt = 16;
        }
        switch(isr_cnt)
        {
            case 0:
                EPwm1Regs.DBRED.bit.DBRED = 84;
                EPwm1Regs.DBFED.bit.DBFED = 84;
                EPwm1Regs.CMPA.bit.CMPA = 560;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 84;
                EPwm2Regs.DBFED.bit.DBFED = 84;
                EPwm2Regs.CMPA.bit.CMPA = 560;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 1:
                EPwm1Regs.DBRED.bit.DBRED = 80;
                EPwm1Regs.DBFED.bit.DBFED = 80;
                EPwm1Regs.CMPA.bit.CMPA = 562;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 80;
                EPwm2Regs.DBFED.bit.DBFED = 80;
                EPwm2Regs.CMPA.bit.CMPA = 562;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 2:
                EPwm1Regs.DBRED.bit.DBRED = 78;
                EPwm1Regs.DBFED.bit.DBFED = 78;
                EPwm1Regs.CMPA.bit.CMPA = 563;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 78;
                EPwm2Regs.DBFED.bit.DBFED = 78;
                EPwm2Regs.CMPA.bit.CMPA = 563;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 3:
                EPwm1Regs.DBRED.bit.DBRED = 77;
                EPwm1Regs.DBFED.bit.DBFED = 77;
                EPwm1Regs.CMPA.bit.CMPA = 563;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 77;
                EPwm2Regs.DBFED.bit.DBFED = 77;
                EPwm2Regs.CMPA.bit.CMPA = 563;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 4:
                EPwm1Regs.DBRED.bit.DBRED = 76;
                EPwm1Regs.DBFED.bit.DBFED = 76;
                EPwm1Regs.CMPA.bit.CMPA = 564;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 76;
                EPwm2Regs.DBFED.bit.DBFED = 76;
                EPwm2Regs.CMPA.bit.CMPA = 564;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 5:
                EPwm1Regs.DBRED.bit.DBRED = 74;
                EPwm1Regs.DBFED.bit.DBFED = 74;
                EPwm1Regs.CMPA.bit.CMPA = 565;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 74;
                EPwm2Regs.DBFED.bit.DBFED = 74;
                EPwm2Regs.CMPA.bit.CMPA = 565;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 6:
                EPwm1Regs.DBRED.bit.DBRED = 72;
                EPwm1Regs.DBFED.bit.DBFED = 72;
                EPwm1Regs.CMPA.bit.CMPA = 566;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 72;
                EPwm2Regs.DBFED.bit.DBFED = 72;
                EPwm2Regs.CMPA.bit.CMPA = 566;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 7:
                EPwm1Regs.DBRED.bit.DBRED = 71;
                EPwm1Regs.DBFED.bit.DBFED = 71;
                EPwm1Regs.CMPA.bit.CMPA = 566;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 71;
                EPwm2Regs.DBFED.bit.DBFED = 71;
                EPwm2Regs.CMPA.bit.CMPA = 566;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 8:
                EPwm1Regs.DBRED.bit.DBRED = 71;
                EPwm1Regs.DBFED.bit.DBFED = 71;
                EPwm1Regs.CMPA.bit.CMPA = 566;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 71;
                EPwm2Regs.DBFED.bit.DBFED = 71;
                EPwm2Regs.CMPA.bit.CMPA = 566;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 9:
                EPwm1Regs.DBRED.bit.DBRED = 70;
                EPwm1Regs.DBFED.bit.DBFED = 70;
                EPwm1Regs.CMPA.bit.CMPA = 567;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 70;
                EPwm2Regs.DBFED.bit.DBFED = 70;
                EPwm2Regs.CMPA.bit.CMPA = 567;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 10:
                EPwm1Regs.DBRED.bit.DBRED = 68;
                EPwm1Regs.DBFED.bit.DBFED = 68;
                EPwm1Regs.CMPA.bit.CMPA = 568;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 68;
                EPwm2Regs.DBFED.bit.DBFED = 68;
                EPwm2Regs.CMPA.bit.CMPA = 568;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 11:
                EPwm1Regs.DBRED.bit.DBRED = 66;
                EPwm1Regs.DBFED.bit.DBFED = 66;
                EPwm1Regs.CMPA.bit.CMPA = 569;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 66;
                EPwm2Regs.DBFED.bit.DBFED = 66;
                EPwm2Regs.CMPA.bit.CMPA = 569;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 12:
                EPwm1Regs.DBRED.bit.DBRED = 65;
                EPwm1Regs.DBFED.bit.DBFED = 65;
                EPwm1Regs.CMPA.bit.CMPA = 569;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 65;
                EPwm2Regs.DBFED.bit.DBFED = 65;
                EPwm2Regs.CMPA.bit.CMPA = 569;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 13:
                EPwm1Regs.DBRED.bit.DBRED = 64;
                EPwm1Regs.DBFED.bit.DBFED = 64;
                EPwm1Regs.CMPA.bit.CMPA = 570;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 64;
                EPwm2Regs.DBFED.bit.DBFED = 64;
                EPwm2Regs.CMPA.bit.CMPA = 570;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 14:
                EPwm1Regs.DBRED.bit.DBRED = 62;
                EPwm1Regs.DBFED.bit.DBFED = 62;
                EPwm1Regs.CMPA.bit.CMPA = 571;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 62;
                EPwm2Regs.DBFED.bit.DBFED = 62;
                EPwm2Regs.CMPA.bit.CMPA = 571;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 15:
                EPwm1Regs.DBRED.bit.DBRED = 48;
                EPwm1Regs.DBFED.bit.DBFED = 48;
                EPwm1Regs.CMPA.bit.CMPA = 578;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 48;
                EPwm2Regs.DBFED.bit.DBFED = 48;
                EPwm2Regs.CMPA.bit.CMPA = 578;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 16:
                EPwm1Regs.DBRED.bit.DBRED = 10;
                EPwm1Regs.DBFED.bit.DBFED = 10;
                EPwm1Regs.CMPA.bit.CMPA = 595;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm2Regs.DBRED.bit.DBRED = 10;
                EPwm2Regs.DBFED.bit.DBFED = 10;
                EPwm2Regs.CMPA.bit.CMPA = 595;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
            default:
                EPwm1Regs.DBRED.bit.DBRED = 84;
                EPwm1Regs.DBFED.bit.DBFED = 84;
                EPwm1Regs.CMPA.bit.CMPA = 560;
                EPwm1Regs.CMPA.bit.CMPAHR = 6400;
                EPwm1Regs.CMPB.bit.CMPBHR = 6400;
    
                EPwm2Regs.DBRED.bit.DBRED = 84;
                EPwm2Regs.DBFED.bit.DBFED = 84;
                EPwm2Regs.CMPA.bit.CMPA = 560;
                EPwm2Regs.CMPA.bit.CMPAHR = 0;
                EPwm2Regs.CMPB.bit.CMPBHR = 0;
                break;
        }
    
        if(mep_isr_cnt < MEP_ScaleFactor)
        {
            mep_isr_cnt = mep_isr_cnt + 1;
        }
        else
        {
            mep_isr_cnt = 0;
            if(isr_cnt < 15)
            {
                isr_cnt = isr_cnt + 1;
            }
            else
            {
                isr_cnt = 0;
            }
        }
    
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    

    This setup allows to easily detect the glitches with an oscilloscope by triggering on the rising redge of EPwm1's output.

    To test the symmetry, I also created case 16. In this case statement I can easily check the symmetry of the two channels, which looks god.

    Regards,

    Stefan

  • Hi Stefan,

    Thank you very much for your detailed test code. I will test this on my end to try to determine the root cause, please expect a response back by tomorrow.

  • Hi Luke,

    Have you found out anything yet?

    Regards, Stefan

  • Hi Stefan,

    Apologies for the delayed response. I will test this tomorrow and provide you my results.

    Thank you,

    Luke

  • Hi Luke,

    what are the results of your tests?

    Regards, Stefan

  • Hi Stefan,

    I am currently testing your code but am unable to recreate this issue for some reason, I'll provide you another update tomorrow morning after I confirm everything is set up correctly on my side.

    Thank you,

    Luke

  • Hi Stefan,

    For each of the 16 configurations, does the glitch occur intermittently, or during every/most EPWM cycles? I am able to cycle through each of the different EPWM waveforms but have am unable to observe the glitch from my end. Perhaps we have some clock settings configured differently. The frequency of the EPWM output on my side is 100 kHz.

    Thank you,

    Luke

  • Hi Luke,

    I can see the glitch in every period as long as the HR fraction (CMPAHR, CMPBHR) is not zero. My frequency is also 100 kHz.

    I have taken the device initialization from a TI example. Below you can find the code from the file f28003x_sysctrl.c:

    //###########################################################################
    //
    // FILE:   f28003x_sysctrl.c
    //
    // TITLE:  f28003x Device System Control Initialization & Support Functions.
    //
    // DESCRIPTION:  Example initialization of system resources.
    //
    //###########################################################################
    //
    //
    // $Copyright:
    // Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    //
    // Included Files
    //
    #include "f28003x_device.h"     // Headerfile Include File
    #include "f28003x_examples.h"   // Examples Include File
    
    //
    // Functions that will be run from RAM need to be assigned to a different
    // section.  This section will then be mapped to a load and run address using
    // the linker cmd file.
    //
    //      *IMPORTANT*
    //
    //  IF RUNNING FROM FLASH, PLEASE COPY OVER THE SECTION ".TI.ramfunc" FROM
    //  FLASH TO RAM PRIOR TO CALLING InitSysCtrl(). THIS PREVENTS THE MCU FROM
    //  THROWING AN EXCEPTION WHEN A CALL TO DELAY_US() IS MADE.
    //
    #pragma CODE_SECTION(InitFlash, ".TI.ramfunc");
    #pragma CODE_SECTION(FlashOff, ".TI.ramfunc");
    
    
    // The following values are used to validate PLL Frequency using DCC
    //
    #define   DCC_COUNTER0_TOLERANCE   1
    
    //
    // Macro used for adding delay between 2 consecutive writes to CLKSRCCTL1
    // register.
    // Delay = 300 NOPs
    //
    #define SYSCTRL_CLKSRCCTL1_DELAY  asm(" RPT #250 || NOP \n RPT #50 || NOP")
    
    //
    // To use INTOSC as the clock source, comment the #define USE_PLL_SRC_XTAL,
    // and uncomment the #define USE_PLL_SRC_INTOSC
    //
    #define USE_PLL_SRC_XTAL
    //#define USE_PLL_SRC_INTOSC
    
    //
    // InitSysCtrl - Initialization of system resources.
    //
    void InitSysCtrl(void)
    {
        //
        // Disable the watchdog
        //
        DisableDog();
    
    #ifdef _FLASH
        //
        // Copy time critical code and Flash setup code to RAM. This includes the
        // following functions: InitFlash()
        //
        // The  RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart
        // symbols are created by the linker. Refer to the device .cmd file.
        //
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    
        //
        // Call Flash Initialization to setup flash waitstates. This function must
        // reside in RAM.
        //
        InitFlash();
    #endif
    
        //
        // Initialize the SYSPLL control  to generate a 200Mhz clock
        //
        // Defined options to be passed as arguments to this function are defined
        // in f28003x_examples.h.
        //
        // Note: The internal oscillator CANNOT be used as the PLL source if the
        // PLLSYSCLK is configured to frequencies above 194 MHz.
        //
        //  PLLSYSCLK = (XTAL_OSC) * (IMULT) /(REFDIV) * (ODIV) * (PLLSYSCLKDIV)
        //
    #if defined(USE_PLL_SRC_XTAL)
        InitSysPll(XTAL_OSC, IMULT_48, REFDIV_2, ODIV_4, PLLCLK_BY_1, SYSCTL_DCC_BASE0);
    #elif defined(USE_PLL_SRC_INTOSC)
        InitSysPll(INT_OSC2, IMULT_48, REFDIV_1, ODIV_4, PLLCLK_BY_1, SYSCTL_DCC_BASE0);
    #endif
    
    #ifndef _FLASH
        //
        // Call Device_cal function when run using debugger
        // This function is called as part of the Boot code. The function is called
        // in the InitSysCtrl function since during debug time resets, the boot code
        // will not be executed and the gel script will reinitialize all the
        // registers and the calibrated values will be lost.
        //
        Device_cal();
    #endif
    
        //
        // Turn on all peripherals
        //
        InitPeripheralClocks();
    }
    
    //
    // InitPeripheralClocks - Initializes the clocks for the peripherals.
    //
    // Note: In order to reduce power consumption, turn off the clocks to any
    // peripheral that is not specified for your part-number or is not used in the
    // application
    //
    void InitPeripheralClocks(void)
    {
        EALLOW;
    
        CpuSysRegs.PCLKCR0.bit.CLA1 = 1;
        CpuSysRegs.PCLKCR0.bit.DMA = 1;
        CpuSysRegs.PCLKCR0.bit.CPUTIMER0 = 1;
        CpuSysRegs.PCLKCR0.bit.CPUTIMER1 = 1;
        CpuSysRegs.PCLKCR0.bit.CPUTIMER2 = 1;
        CpuSysRegs.PCLKCR0.bit.CPUBGCRC = 1;
        CpuSysRegs.PCLKCR0.bit.CLA1BGCRC = 1;
        CpuSysRegs.PCLKCR0.bit.HRCAL = 1;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
        CpuSysRegs.PCLKCR0.bit.ERAD = 1;
    
        CpuSysRegs.PCLKCR2.bit.EPWM1 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM2 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM3 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM4 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM5 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM6 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM7 = 1;
        CpuSysRegs.PCLKCR2.bit.EPWM8 = 1;
    
        CpuSysRegs.PCLKCR3.bit.ECAP1 = 1;
        CpuSysRegs.PCLKCR3.bit.ECAP2 = 1;
        CpuSysRegs.PCLKCR3.bit.ECAP3 = 1;
    
        CpuSysRegs.PCLKCR4.bit.EQEP1 = 1;
        CpuSysRegs.PCLKCR4.bit.EQEP2 = 1;
    
        CpuSysRegs.PCLKCR6.bit.SD1 = 1;
        CpuSysRegs.PCLKCR6.bit.SD2 = 1;
    
        CpuSysRegs.PCLKCR7.bit.SCI_A = 1;
        CpuSysRegs.PCLKCR7.bit.SCI_B = 1;
    
        CpuSysRegs.PCLKCR8.bit.SPI_A = 1;
        CpuSysRegs.PCLKCR8.bit.SPI_B = 1;
    
        CpuSysRegs.PCLKCR9.bit.I2C_A = 1;
        CpuSysRegs.PCLKCR9.bit.I2C_B = 1;
    
        CpuSysRegs.PCLKCR10.bit.CAN_A = 1;
        CpuSysRegs.PCLKCR10.bit.MCAN_A = 1;
    
        CpuSysRegs.PCLKCR13.bit.ADC_A = 1;
        CpuSysRegs.PCLKCR13.bit.ADC_B = 1;
        CpuSysRegs.PCLKCR13.bit.ADC_C = 1;
    
        CpuSysRegs.PCLKCR14.bit.CMPSS1 = 1;
        CpuSysRegs.PCLKCR14.bit.CMPSS2 = 1;
        CpuSysRegs.PCLKCR14.bit.CMPSS3 = 1;
        CpuSysRegs.PCLKCR14.bit.CMPSS4 = 1;
    
        CpuSysRegs.PCLKCR16.bit.DAC_A = 1;
        CpuSysRegs.PCLKCR16.bit.DAC_B = 1;
    
        CpuSysRegs.PCLKCR17.bit.CLB1 = 1;
        CpuSysRegs.PCLKCR17.bit.CLB2 = 1;
        CpuSysRegs.PCLKCR17.bit.CLB3 = 1;
        CpuSysRegs.PCLKCR17.bit.CLB4 = 1;
    
        CpuSysRegs.PCLKCR18.bit.FSITX_A = 1;
        CpuSysRegs.PCLKCR18.bit.FSIRX_A = 1;
    
        CpuSysRegs.PCLKCR19.bit.LIN_A = 1;
        CpuSysRegs.PCLKCR19.bit.LIN_B = 1;
    
        CpuSysRegs.PCLKCR20.bit.PMBUS_A = 1;
    
        CpuSysRegs.PCLKCR21.bit.DCC0 = 1;
        CpuSysRegs.PCLKCR21.bit.DCC1 = 1;
    
        CpuSysRegs.PCLKCR25.bit.HICA = 1;
        CpuSysRegs.PCLKCR26.bit.AESA = 1;
        CpuSysRegs.PCLKCR27.bit.EPG1 = 1;
    
        EDIS;
    }
    
    //
    // DisablePeripheralClocks - Gates-off all peripheral clocks.
    //
    void DisablePeripheralClocks(void)
    {
        EALLOW;
    
        CpuSysRegs.PCLKCR0.all = 0;
        CpuSysRegs.PCLKCR2.all = 0;
        CpuSysRegs.PCLKCR3.all = 0;
        CpuSysRegs.PCLKCR4.all = 0;
        CpuSysRegs.PCLKCR6.all = 0;
        CpuSysRegs.PCLKCR7.all = 0;
        CpuSysRegs.PCLKCR8.all = 0;
        CpuSysRegs.PCLKCR9.all = 0;
        CpuSysRegs.PCLKCR10.all = 0;
        CpuSysRegs.PCLKCR13.all = 0;
        CpuSysRegs.PCLKCR14.all = 0;
        CpuSysRegs.PCLKCR16.all = 0;
        CpuSysRegs.PCLKCR17.all = 0;
        CpuSysRegs.PCLKCR18.all = 0;
        CpuSysRegs.PCLKCR19.all = 0;
        CpuSysRegs.PCLKCR20.all = 0;
        CpuSysRegs.PCLKCR21.all = 0;
        CpuSysRegs.PCLKCR25.all = 0;
        CpuSysRegs.PCLKCR26.all = 0;
        CpuSysRegs.PCLKCR27.all = 0;
    
        EDIS;
    }
    
    //
    // InitFlash - This function initializes the Flash Control registers.
    //
    //      *CAUTION*
    // This function MUST be executed out of RAM. Executing it out of OTP/Flash
    // will yield unpredictable results.
    //
    #ifdef __cplusplus
    #pragma CODE_SECTION(".TI.ramfunc");
    #endif
    void InitFlash(void)
    {
        EALLOW;
    
        //
        // At reset bank and pump are in sleep. A Flash access will power up the
        // bank and pump automatically.
        //
        // Power up Flash bank and pump. This also sets the fall back mode of
        // flash and pump as active.
        //
        Flash0CtrlRegs.FPAC1.bit.PMPPWR = 0x1;
        Flash0CtrlRegs.FBFALLBACK.bit.BNKPWR0 = 0x3F;
    
        //
        // Disable Cache and prefetch mechanism before changing wait states
        //
        Flash0CtrlRegs.FRD_INTF_CTRL.bit.DATA_CACHE_EN = 0;
        Flash0CtrlRegs.FRD_INTF_CTRL.bit.PREFETCH_EN = 0;
    
        //
        // Set waitstates according to frequency
        //
        //      *CAUTION*
        // Minimum waitstates required for the flash operating at a given CPU rate
        // must be characterized by TI. Refer to the datasheet for the latest
        // information.
        //
    #if CPU_FRQ_120MHZ
            Flash0CtrlRegs.FRDCNTL.bit.RWAIT = 0x5;
    #endif
    
        //
        // Enable Cache and prefetch mechanism to improve performance of code
        // executed from Flash.
        //
        Flash0CtrlRegs.FRD_INTF_CTRL.bit.DATA_CACHE_EN = 1;
        Flash0CtrlRegs.FRD_INTF_CTRL.bit.PREFETCH_EN = 1;
    
        //
        // At reset, ECC is enabled. If it is disabled by application software and
        // if application again wants to enable ECC.
        //
        Flash0EccRegs.ECC_ENABLE.bit.ENABLE = 0xA;
    
        EDIS;
    
        //
        // Force a pipeline flush to ensure that the write to the last register
        // configured occurs before returning.
        //
        __asm(" RPT #7 || NOP");
    }
    
    //
    // FlashOff - This function powers down the flash
    //
    //      *CAUTION*
    // This function MUST be executed out of RAM. Executing it out of OTP/Flash
    // will yield unpredictable results. Also you must seize the flash pump in
    // order to power it down.
    //
    #ifdef __cplusplus
    #pragma CODE_SECTION(".TI.ramfunc");
    #endif
    void FlashOff(void)
    {
        EALLOW;
    
        //
        // Power down bank
        //
        Flash0CtrlRegs.FBFALLBACK.bit.BNKPWR0 = 0;
    
        //
        // Power down pump
        //
        Flash0CtrlRegs.FPAC1.bit.PMPPWR = 0;
    
        EDIS;
    }
    
    
    //
    // ServiceDog - This function resets the watchdog timer.
    //
    // Enable this function for using ServiceDog in the application.
    //
    void ServiceDog(void)
    {
        EALLOW;
        WdRegs.WDKEY.bit.WDKEY = 0x0055;
        WdRegs.WDKEY.bit.WDKEY = 0x00AA;
        EDIS;
    }
    
    //
    // DisableDog - This function disables the watchdog timer.
    //
    void DisableDog(void)
    {
        volatile Uint16 temp;
    
        //
        // Grab the clock config first so we don't clobber it
        //
        EALLOW;
        temp = WdRegs.WDCR.all & 0x0007;
        WdRegs.WDCR.all = 0x0068 | temp;
        EDIS;
    }
    
    //
    // InitPll - This function initializes the PLL registers.
    //
    // Note: This function uses the DCC to check that the PLLRAWCLK is running at
    // the expected rate. The desirable DCC can be provided as a parameter.
    //
    void InitSysPll(Uint16 clock_source, Uint16 imult, Uint32 refdiv, Uint32 odiv,
                     Uint16 divsel, Uint32 dccbase)
    {
        Uint32 timeout,temp_syspllmult, pllLockStatus;
        bool status;
    
        if(((clock_source & 0x3) == ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL)    &&
           (((clock_source & 0x4) >> 2) == ClkCfgRegs.XTALCR.bit.SE)           &&
           (imult  == ClkCfgRegs.SYSPLLMULT.bit.IMULT)           &&
           (refdiv  == ClkCfgRegs.SYSPLLMULT.bit.REFDIV)          &&
           (odiv == ClkCfgRegs.SYSPLLMULT.bit.ODIV)               &&
           (divsel == ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV))
        {
            //
            // Everything is set as required, so just return
            //
            return;
        }
    
        EALLOW;
    
        //
        // First modify the PLL multipliers if the multipliers need an update or PLL needs
        // to be powered on / enabled
        //
        if((imult != ClkCfgRegs.SYSPLLMULT.bit.IMULT) ||
           (refdiv != ClkCfgRegs.SYSPLLMULT.bit.REFDIV)||
           (odiv != ClkCfgRegs.SYSPLLMULT.bit.ODIV) ||
           (1U != ClkCfgRegs.SYSPLLCTL1.bit.PLLEN))
        {
            //
            // Bypass PLL and set dividers to /1
            //
            ClkCfgRegs.SYSPLLCTL1.bit.PLLCLKEN = 0;
    
            //
            // Delay of at least 120 OSCCLK cycles required post PLL bypass
            //
            asm(" RPT #120 || NOP");
    
            //
            // Evaluate PLL multipliers and dividers
            //
            temp_syspllmult = ((refdiv << 24U) | (odiv << 16U)| imult);
    
            //
            // Turnoff the PLL
            //
            ClkCfgRegs.SYSPLLCTL1.bit.PLLEN = 0;
            EDIS;
    
            //
            // Delay of at least 66 OSCCLK cycles
            //
            asm(" RPT #66 || NOP");
    
            if(((clock_source & 0x3) != ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL) ||
              (((clock_source & 0x4) >> 2) != ClkCfgRegs.XTALCR.bit.SE))
            {
                switch (clock_source)
                {
                    case INT_OSC1:
                        SysIntOsc1Sel();
                        break;
    
                    case INT_OSC2:
                        SysIntOsc2Sel();
                        break;
    
                    case XTAL_OSC:
                        SysXtalOscSel();
                        break;
    
                    case XTAL_OSC_SE:
                        SysXtalOscSESel();
                        break;
                }
            }
    
            //
            // Delay of at least 60 OSCCLK cycles
            //
            asm(" RPT #60 || NOP");
    
            EALLOW;
    
            //
            // Set dividers to /1 to ensure the fastest PLL configuration
            //
            ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = 0;
    
            //
            // Program PLL multipliers
            //
            ClkCfgRegs.SYSPLLMULT.all = temp_syspllmult;
    
            //
            // Enable SYSPLL
            //
            ClkCfgRegs.SYSPLLCTL1.bit.PLLEN = 1;
    
            //
            // Lock time is 1024 OSCCLK * (REFDIV+1)
            //
            timeout = (1024U * (refdiv + 1U));
            pllLockStatus = ClkCfgRegs.SYSPLLSTS.bit.LOCKS;
    
            //
            // Wait for the SYSPLL lock
            //
            while((pllLockStatus != 1) && (timeout != 0U))
            {
                pllLockStatus = ClkCfgRegs.SYSPLLSTS.bit.LOCKS;
                timeout--;
            }
    
            EDIS;
    
            //
            // Check PLL Frequency using DCC
            //
            status = IsPLLValid(dccbase, clock_source, INT_PLL_SYSPLL,
                                imult, odiv , refdiv);
    
        }
        else
        {
            //
            // Re-Lock of PLL not needed since the multipliers
            // are not updated
            //
            status = true;
        }
    
        if(status)
        {
            EALLOW;
            //
            // Set divider to produce slower output frequency to limit current increase
            //
            if(divsel != PLLCLK_BY_126)
            {
                ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = divsel + 1;
            }
            else
            {
                ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = divsel;
            }
    
            //
            // Enable PLLSYSCLK is fed from system PLL clock
            //
            ClkCfgRegs.SYSPLLCTL1.bit.PLLCLKEN = 1;
    
            //
            // Small 100 cycle delay
            //
            asm(" RPT #100 || NOP");
    
            //
            // Set the divider to user value
            //
            ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = divsel;
            EDIS;
        }
        else
            ESTOP0; // If the frequency is out of range, stop here.
    
    }
    
    //
    // SysIntOsc1Sel - This function switches to Internal Oscillator 1.
    //
    void SysIntOsc1Sel(void)
    {
        EALLOW;
        ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 2;     // Clk Src = INTOSC1
        EDIS;
    }
    
    //
    // SysIntOsc2Sel - This function switches to Internal oscillator 2.
    //
    void SysIntOsc2Sel(void)
    {
        EALLOW;
        ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 0;     // Clk Src = INTOSC2
        EDIS;
    }
    
    //
    // PollX1Counter - Clear the X1CNT counter and then wait for it to saturate
    // four times.
    //
    static void
    PollX1Counter(void)
    {
        Uint16 loopCount = 0;
    
        //
        // Delay for 1 ms while the XTAL powers up
        //
        // 2000 loops, 5 cycles per loop + 9 cycles overhead = 10009 cycles
        //
        F28x_usDelay(2000);
    
        //
        // Clear and saturate X1CNT 4 times to guarantee operation
        //
        do
        {
            //
            // Keep clearing the counter until it is no longer saturated
            //
            while(ClkCfgRegs.X1CNT.all > 0x1FF)
            {
                ClkCfgRegs.X1CNT.bit.CLR = 1;
                ClkCfgRegs.X1CNT.bit.CLR = 0;
            }
    
            //
            // Wait for the X1 clock to saturate
            //
            while(ClkCfgRegs.X1CNT.all != 0x7FFU)
            {
                ;
            }
    
            //
            // Increment the counter
            //
            loopCount++;
        }while(loopCount < 4);
    }
    // SysXtalOscSel - This function switches to External CRYSTAL oscillator.
    //
    void SysXtalOscSel(void)
    {
        EALLOW;
        ClkCfgRegs.XTALCR.bit.OSCOFF = 0;     // Turn on XTALOSC
        ClkCfgRegs.XTALCR.bit.SE = 0;         // Select crystal mode
        EDIS;
    
        //
        // Wait for the X1 clock to saturate
        //
        PollX1Counter();
    
        //
        // Select XTAL as the oscillator source
        //
        EALLOW;
        ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 1;
        EDIS;
    
        //
        // If a missing clock failure was detected, try waiting for the X1 counter
        // to saturate again. Consider modifying this code to add a 10ms timeout.
        //
        while(ClkCfgRegs.MCDCR.bit.MCLKSTS != 0)
        {
            EALLOW;
            ClkCfgRegs.MCDCR.bit.MCLKCLR = 1;
            EDIS;
    
            //
            // Wait for the X1 clock to saturate
            //
            PollX1Counter();
    
            //
            // Select XTAL as the oscillator source
            //
            EALLOW;
            ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 1;
            EDIS;
        }
    }
    
    //
    // SysXtalOscSESel - This function switches to external oscillator in
    // single-ended mode and turns off all other clock sources to minimize power
    // consumption. This option may not be available on all device packages
    //
    void
    SysXtalOscSESel (void)
    {
        EALLOW;
        ClkCfgRegs.XTALCR.bit.OSCOFF = 0;     // Turn on XTALOSC
        ClkCfgRegs.XTALCR.bit.SE = 1;         // Select single-ended mode
        EDIS;
    
        //
        // Wait for the X1 clock to saturate
        //
        PollX1Counter();
    
        //
        // Select XTALOSC as the oscillator source
        //
        EALLOW;
        ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 1;
        EDIS;
    
        //
        // If missing clock detected, there is something wrong with the oscillator
        // module.
        //
        if(ClkCfgRegs.MCDCR.bit.MCLKSTS != 0)
        {
            ESTOP0;
        }
    }
    
    //
    // IDLE - Enter IDLE mode
    //
    void
    IDLE()
    {
        EALLOW;
        CpuSysRegs.LPMCR.bit.LPM = LPM_IDLE;
        EDIS;
        asm(" IDLE");
    }
    
    //
    // HALT - Enter HALT mode
    //
    void
    HALT()
    {
        EALLOW;
        CpuSysRegs.LPMCR.bit.LPM = LPM_HALT;
        ClkCfgRegs.SYSPLLCTL1.bit.PLLCLKEN = 0;
        ClkCfgRegs.SYSPLLCTL1.bit.PLLEN = 0;
        EDIS;
        asm(" IDLE");
    }
    
    //*****************************************************************************
    //
    // SysCtl_isPLLValid()
    //
    //*****************************************************************************
    bool
    IsPLLValid(Uint32 base, Uint16 oscSource, Uint16 pllclk, Uint16 imult,
               Uint16 odiv, Uint16 refdiv)
    {
        float fclk1_0ratio;
        volatile struct DCC_REGS *DccRegs;
    
        EALLOW;
    
        //
        // Assigning DCC for PLL validation
        // Enable Peripheral Clock Domain PCLKCR21 for DCC
        //
        if(base == SYSCTL_DCC_BASE0)
        {
                DccRegs = &Dcc0Regs;
                CpuSysRegs.PCLKCR21.bit.DCC0 = 1;
        }
        else if(base == SYSCTL_DCC_BASE1)
        {
                DccRegs = &Dcc1Regs;
                CpuSysRegs.PCLKCR21.bit.DCC1 = 1;
        }
        else
            ESTOP0; // Invalid DCC selected
    
        //
        // Clear Error & Done Flag
        //
        DccRegs->DCCSTATUS.bit.ERR = 1;
        DccRegs->DCCSTATUS.bit.DONE = 1;
    
        //
        // Disable DCC
        //
        DccRegs->DCCGCTRL.bit.DCCENA = 0x5;
    
        //
        // Disable Error Signal
        //
        DccRegs->DCCGCTRL.bit.ERRENA = 0x5;
    
        //
        // Disable Done Signal
        //
        DccRegs->DCCGCTRL.bit.DONEENA = 0x5;
    
        //
        // Configure Clock Source1 to PLL
        //
        // Clk Src1 Key 0xA to enable clock source selection
        //
        switch(pllclk)
        {
            case INT_PLL_SYSPLL:
                DccRegs->DCCCLKSRC1.all = 0xA000; // Clk Src1 = SYSPLL
                break;
    
            default:
                //
                // Code shouldn't reach here
                //
                break;
        }
    
        //
        // Configure Clock Source0 to whatever is set as a reference
        // clock source for PLL
        //
        // Clk Src0 Key 0xA to enable clock source selection
        //
        switch(oscSource)
        {
            case INT_OSC1:
                DccRegs->DCCCLKSRC0.all = 0xA001; // Clk Src0 = INTOSC1
                break;
    
            case INT_OSC2:
                DccRegs->DCCCLKSRC0.all = 0xA002; // Clk Src0 = INTOSC2
                break;
    
            case XTAL_OSC:
            case XTAL_OSC_SE:
                DccRegs->DCCCLKSRC0.all = 0xA000; // Clk Src0 = XTAL
                break;
    
            default:
                //
                // Code shouldn't reach here
                //
                break;
        }
    
        //
        // Calculating frequency ratio of output clock(f1) vs reference clock(f0)
        //
        fclk1_0ratio = (float)imult / ((odiv + 1U) * (refdiv + 1));
    
        //
        // Computing and configuring Counter0 , Counter1 & Valid Seed Values
        // with +/-1% tolerance for the desired DCC
        //
        ComputeCntrSeedValue(base, fclk1_0ratio, DCC_COUNTER0_TOLERANCE);
    
        //
        // Enable Single Shot Mode
        //
        DccRegs->DCCGCTRL.bit.SINGLESHOT = 0xA;
    
        //
        // Enable DCC to start counting
        //
        DccRegs->DCCGCTRL.bit.DCCENA = 0xA;
        EDIS;
    
        //
        // Wait until Error or Done Flag is generated
        //
        while((DccRegs->DCCSTATUS.all & 3) == 0)
        {
        }
    
        //
        // Returns true if DCC completes without error
        //
        return((DccRegs->DCCSTATUS.all & 3) == 2);
    
    }
    
    //*****************************************************************************
    //
    // ComputeCntSeedValid - Compute Counter seed values based on the frequency ratio of output
    // clock vs reference clock & tolerance expected for the desired DCC
    //
    //*****************************************************************************
    void ComputeCntrSeedValue(Uint32 base, float fclk1_0ratio, Uint32 tolerance)
    {
        Uint32 window, dccCounterSeed0, dccValidSeed0, dccCounterSeed1, total_error;
        volatile struct DCC_REGS *DccRegs;
    
        if(fclk1_0ratio >= 1U)
         {
            //
            // Setting Counter0 & Valid Seed Value with expected tolerance
            // Total error is 12
            //
            window = (12U * 100U) / tolerance;
            dccCounterSeed0 = window - 12U;
            dccValidSeed0 = 24U;
    
         }
        else
         {
            total_error = (((Uint32)2U / fclk1_0ratio) + (Uint32)10U);
    
            window = ((total_error * 100U)/ tolerance);
    
            //
            // Setting Counter0 & Valid Seed Value with expected tolerance
            //
            dccCounterSeed0 = window - total_error;
            dccValidSeed0 = (Uint32)2U * total_error;
    
         }
    
        //
        // Multiplying Counter-0 window with PLL Integer Multiplier
        //
        dccCounterSeed1 = window * fclk1_0ratio;
    
        //
        // Assigning DCC for PLL validation
        //
        if(base == SYSCTL_DCC_BASE0)
            DccRegs = &Dcc0Regs;
        else if(base == SYSCTL_DCC_BASE1)
            DccRegs = &Dcc1Regs;
        else
            ESTOP0; // Invalid DCC selected
    
        //
        // Configure COUNTER-0, COUNTER-1 & Valid Window
        //
        DccRegs->DCCCNTSEED0.bit.COUNTSEED0 = dccCounterSeed0; // Loaded Counter0 Value
        DccRegs->DCCVALIDSEED0.bit.VALIDSEED = dccValidSeed0;  // Loaded Valid Value
        DccRegs->DCCCNTSEED1.bit.COUNTSEED1 = dccCounterSeed1; // Loaded Counter1 Value
    }
    
    //
    // End of File
    //
    
    

    Regards,

    Stefan

  • Hi Stefan,

    I am able to recreate the issue on my side. This may be a common issue with HRPWM and deadband, I will consult with our other EPWM experts on what the cause of this may be and get back to you by tomorrow.

    Thank you,

    Luke

  • Hi Luke,

    did you found out anything?

    At the moment we don't use the HRPWM because of the problem. But for other projects in the near future, we think HRPWM will be necessary. So we need to know if we can use the C2000 MCUs for that.

    Regards,

    Stefan

  • Hi Stefan,

    I have been unable to find any resources in the TRM that would explain this issue. It seems the jitter does not occur when making very small adjustments to DBRED.

    I have explained this issue to the design team and asked them to provide some clarification, or if this is a known issue. I will get back to you when they provide a response.

    Thank you,

    Luke

  • Hi Stefan,

    The design team has gotten back to me, they will simulate your code and attempt to determine the cause of the jitter. Please expect a response back by Monday.

    --Luke

  • Hi Luke,

    thank you for your effort and research. Has the design team found a root cause yet?

    Regards, Stefan

  • Stefan,

    Luke is currently out of the office. 

    I'm covering his E2E while he is out, let me check with design team and get a response for you.  Please give me an additional day.

    Best,

    Matthew

  • Hi Stefan,

    The design team is still working on simulating this issue, I will provide you an update as soon as they get back to me.

    Thank you,

    Luke

  • Hi Stefan,

    I am still waiting to get feedback from the design team on this issue, apologies for the inconvenience.

    Thank you,

    Luke

  • Hi Luke,

    thank you for the information. I am very interested to see how this problem can be solved.

    Regards, Stefan

  • Hi Stefan,

    Thank you for your reply. I have contacted the design team again expressing your desire to resolve this issue. I will provide you an update as soon as they get back to me.

    --Luke

  • Hi Stefan,

    Unfortunately the design team is quite busy at the moment and may not be able to provide simulation results in the near future. However I have discussed this issue with other EPWM experts and have some suggestions.

    Is it necessary to enable high-resolution period(HRPCTL.bit.HRPE = 1)? Does the jitter still occur when disabling this?

    Could you also test removing this line of code:

    (*ePWM[i]).HRPWR.bit.CALPWRON = 1; 

    Thank you,

    Luke

  • Hi Luke,

    sorry for my late response.

    Thank you for your suggestions. I have checked these. Disabling high-resolution period (HRPCTL.bit.HRPE = 0) prevents the glitch from occuring. But with this the symmetry is lost: If I configure two ePWM modules the same and set the same CMPx values on both, but set a non-zero CMPxHR value on only one module, the switching patterns are not centered on their midpoint.

    Disabling the MEP calibration logic (HRPWR.bit.CALPWRON = 0) does not influence the glitch.

    I got a Launchpad with a F280049C from my colleague. I will try the ePWM configuration on this board. If I get the same results and you can confirm that the ePWM configuration (AHC with Deadband, High-Resolution) is correct, I suspect that it must be a problem of the ePWM module.

    Regards,

    Stefan

  • Hi,

    the glitch also occurs on the F280049C.

    Here is the code for LAUNCHXL-F280049C:

    //#############################################################################
    //
    // FILE:   empty_bitfield_driverlib_main.c
    //
    // TITLE:  Empty Example
    //
    // Empty Bit-Field & Driverlib Example
    //
    // This example is an empty project setup for Bit-Field and Driverlib 
    // development.
    //
    //#############################################################################
    //
    //
    // $Copyright:
    // Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Included Files
    //
    #include "F28x_Project.h"
    #include "driverlib.h"
    #include "device.h"
    #include "sfo_v8.h"
    
    void init_pwm_gpio(void);
    void init_pwm(void);
    __interrupt void epwm_isr_0(void);
    
    uint16_t isr_cnt = 0;
    uint16_t mep_isr_cnt = 0;
    uint16_t check_symmetry = 0;
    
    volatile struct EPWM_REGS *ePWM[3] = {0, &EPwm1Regs, &EPwm6Regs};
    
    Uint16 status = SFO_INCOMPLETE;
    int MEP_ScaleFactor = 0; //scale factor value
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        InitSysCtrl();
    
        //
        // Initialize GPIO
        //
        InitGpio();
    
        //
        // 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.
        //
        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).
        //
        InitPieVectTable();
    
        EALLOW;
        PieVectTable.EPWM1_INT = &epwm_isr_0;
        PieCtrlRegs.PIEIER3.bit.INTx1 = 1;  // EPWM1
        PieCtrlRegs.PIECTRL.bit.ENPIE = 1;  // Enable the PIE
        PieCtrlRegs.PIEACK.all = 0xFFFF;    // Enables PIE to drive a pulse into the CPU
        IFR = 0x0000;
        IER = 0x3FFF;
        EDIS;
    
        init_pwm_gpio();
        init_pwm();
    
        EINT;           // Enable Global interrupt INTM
        ERTM;           // Enable Global realtime interrupt DBGM
    
        while(1)
        {
        }
    }
    
    void init_pwm_gpio(void)
    {
        EALLOW;
        GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1;      // Disable pull-up on GPIO0 (EPWM1A)
        GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1;      // Disable pull-up on GPIO1 (EPWM1B)
    
        GpioCtrlRegs.GPAPUD.bit.GPIO10 = 1;      // Disable pull-up on GPIO10 (EPWM6A)
        GpioCtrlRegs.GPAPUD.bit.GPIO11 = 1;      // Disable pull-up on GPIO11 (EPWM6B)
    
        GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;     // Configure GPIO0 as EPWM1A
        GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;     // Configure GPIO1 as EPWM1B
    
        GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 1;     // Configure GPIO10 as EPWM6A
        GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 1;     // Configure GPIO11 as EPWM6B
    
        GpioCtrlRegs.GPALOCK.bit.GPIO0 = 1;     // lock GPIO0 configuration
        GpioCtrlRegs.GPALOCK.bit.GPIO1 = 1;     // lock GPIO1 configuration
    
        GpioCtrlRegs.GPALOCK.bit.GPIO10 = 1;     // lock GPIO10 configuration
        GpioCtrlRegs.GPALOCK.bit.GPIO11 = 1;     // lock GPIO11 configuration
    
        EDIS;
    }
    
    void init_pwm(void)
    {
    
        uint16_t i;
    
        EALLOW;
        CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;       // Disable EPWM Time Base Clock gating
        EDIS;
    
        for(i = 1; i < 3; i++)
            {
                // Time-Base Submodule
                (*ePWM[i]).TBPRD = 600;                 // Set timer period
                (*ePWM[i]).TBPRDHR = 0;                 // HR Period
    
                (*ePWM[i]).TBCTR = 0x0000;              // Clear counter
    
                (*ePWM[i]).TBCTL.bit.PRDLD = 0;         // Active Period Reg Load from Shadow
                (*ePWM[i]).TBCTL.bit.CTRMODE = 2;       // Up-Down-Count mode
                (*ePWM[i]).TBCTL.bit.FREE_SOFT = 2;     // free run in emulation mode
                (*ePWM[i]).TBCTL.bit.PHSDIR = 1;        // Count up after the synchronization event
                (*ePWM[i]).TBCTL.bit.PHSEN = 0;         // Disable load event when an EPWMxSYNCI input signal occurs
                (*ePWM[i]).TBCTL.bit.HSPCLKDIV = 0;     // Clock ratio / 1
                (*ePWM[i]).TBCTL.bit.CLKDIV = 0;        // Clock ratio / 1
    
                // Synchronization in- and output
                (*ePWM[i]).TBCTL.bit.SYNCOSEL = 0;      // EPWMxSYNCI / SWFSYNC
    
                // Counter-Compare Submodule
                (*ePWM[i]).CMPCTL.bit.LOADAMODE = 2;     // Load CMPA when TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).CMPCTL.bit.SHDWAMODE = 0;     // enable CMPA shadow mode
                (*ePWM[i]).CMPA.bit.CMPA = 595;          // Set default CMPA value
    
                (*ePWM[i]).CMPCTL.bit.LOADBMODE = 2;     // Load CMPB when TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).CMPCTL.bit.SHDWBMODE = 0;     // enable CMPB shadow mode
    
                // Action-Qualifier Submodule
                (*ePWM[i]).AQCTLA.bit.CAU = 2;           // Set ePWMxA when TBCTR = CMPA on up-count
                (*ePWM[i]).AQCTLA.bit.CAD = 1;           // Clear ePWMxA when TBCTR = CMPA on down-count
    
                (*ePWM[i]).DBCTL.bit.HALFCYCLE = 1;         // clock DB counters at half TBCLK rate
                (*ePWM[i]).DBCTL.bit.DEDB_MODE = 0;         // RED to Input A, FED to Input A
                (*ePWM[i]).DBCTL.bit.IN_MODE = 0;
                (*ePWM[i]).DBCTL.bit.OUT_MODE = 3;          // RED to A path, FED to B path
                (*ePWM[i]).DBCTL.bit.POLSEL = 2;            // B path inverted
                (*ePWM[i]).DBCTL.bit.OUTSWAP = 0;           // A path to OutA, B path to OutB
                (*ePWM[i]).DBCTL.bit.SHDWDBFEDMODE = 1;     // FED shandow load mode
                (*ePWM[i]).DBCTL.bit.SHDWDBREDMODE = 1;     // RED shandow load mode
                (*ePWM[i]).DBCTL.bit.LOADFEDMODE = 2;       // Load on TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).DBCTL.bit.LOADREDMODE = 2;       // Load on TBCTR = 0 or TBCTR = PRD
    
                (*ePWM[i]).DBRED.bit.DBRED = 5;
                (*ePWM[i]).DBFED.bit.DBFED = 5;
                (*ePWM[i]).DBFEDHR.bit.DBFEDHR = 0;
                (*ePWM[i]).DBREDHR.bit.DBREDHR = 0;
    
                EALLOW;
                (*ePWM[i]).HRCNFG.all = 0x0;
                (*ePWM[i]).HRCNFG.bit.EDGMODE = 3;          // MEP control of both edges
                (*ePWM[i]).HRCNFG.bit.CTLMODE = 0;          // Duty control mode
                (*ePWM[i]).HRCNFG.bit.HRLOAD = 2;           // Load CMPAHR when TBCTR = 0 or TBCTR = PRD
                (*ePWM[i]).HRCNFG.bit.AUTOCONV = 1;         // Automatic HRMSTEP scaling is enabled
    
                //
                // CMPBHR is used for duty-control with dead-band in up-down-count mode and must be set to same value as CMPA
                //
                (*ePWM[i]).HRCNFG.bit.EDGMODEB = 3;          // MEP control of both edges
                (*ePWM[i]).HRCNFG.bit.CTLMODEB = 0;          // Duty control mode
                (*ePWM[i]).HRCNFG.bit.HRLOADB = 2;           // Load CMPBHR when TBCTR = 0 or TBCTR = PRD
                //
    
                (*ePWM[i]).HRCNFG2.bit.EDGMODEDB = 3;       // MEP control of both edges (DBREDHR and DBFEDHR)
                (*ePWM[i]).HRCNFG2.bit.CTLMODEDBRED = 2;    // load shadow register when CTR = Zero or CTR = PRD
                (*ePWM[i]).HRCNFG2.bit.CTLMODEDBFED = 2;    // load shadow register when CTR = Zero or CTR = PRD
    
                (*ePWM[i]).HRPCTL.bit.HRPE = 1;             // High resolution period enabled
                (*ePWM[i]).HRPCTL.bit.TBPHSHRLOADE = 1;     // Synchronize the high-resolution phase on a TBCTL[SWFSYNC] event
                EDIS;
    
                (*ePWM[i]).TBCTL.bit.PHSEN = 1;             // load TBPHS from shadow on a TBCTL[SWFSYNC] event
                (*ePWM[i]).TBCTL.bit.SWFSYNC = 1;           // generates a TBCTL[SWFSYNC] event
    
                if(i == 1)
                {
                    (*ePWM[i]).ETSEL.bit.INTSEL = 1;         // Enable Interrupt when TBCTR = 0
                    (*ePWM[i]).ETSEL.bit.INTEN = 1;          // Enable INT
                    (*ePWM[i]).ETPS.bit.INTPRD = 3;          // Generate INT at third event
                    (*ePWM[i]).HRPWR.bit.CALPWRON = 1;       // Enables MEP calibration logic
                }
            }
    
            EALLOW;
            CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;       // Enable EPWM Time Base Clock gating
            EDIS;
    
            while(SFO() == 0)
            {
                // Wait until SFO has finished
            }
    }
    
    
    __interrupt void epwm_isr_0(void)
    {
        (*ePWM[1]).ETCLR.bit.INT = 1;
        if(check_symmetry == 1)
        {
            isr_cnt = 16;
        }
        switch(isr_cnt)
        {
            case 0:
                EPwm1Regs.DBRED.bit.DBRED = 5;
                EPwm1Regs.DBFED.bit.DBFED = 5;
                EPwm1Regs.CMPA.bit.CMPA = 595;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 5;
                EPwm6Regs.DBFED.bit.DBFED = 5;
                EPwm6Regs.CMPA.bit.CMPA = 595;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 1:
                EPwm1Regs.DBRED.bit.DBRED = 80;
                EPwm1Regs.DBFED.bit.DBFED = 80;
                EPwm1Regs.CMPA.bit.CMPA = 562;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 80;
                EPwm6Regs.DBFED.bit.DBFED = 80;
                EPwm6Regs.CMPA.bit.CMPA = 562;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 2:
                EPwm1Regs.DBRED.bit.DBRED = 78;
                EPwm1Regs.DBFED.bit.DBFED = 78;
                EPwm1Regs.CMPA.bit.CMPA = 563;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 78;
                EPwm6Regs.DBFED.bit.DBFED = 78;
                EPwm6Regs.CMPA.bit.CMPA = 563;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 3:
                EPwm1Regs.DBRED.bit.DBRED = 77;
                EPwm1Regs.DBFED.bit.DBFED = 77;
                EPwm1Regs.CMPA.bit.CMPA = 563;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 77;
                EPwm6Regs.DBFED.bit.DBFED = 77;
                EPwm6Regs.CMPA.bit.CMPA = 563;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 4:
                EPwm1Regs.DBRED.bit.DBRED = 76;
                EPwm1Regs.DBFED.bit.DBFED = 76;
                EPwm1Regs.CMPA.bit.CMPA = 564;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 76;
                EPwm6Regs.DBFED.bit.DBFED = 76;
                EPwm6Regs.CMPA.bit.CMPA = 564;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 5:
                EPwm1Regs.DBRED.bit.DBRED = 74;
                EPwm1Regs.DBFED.bit.DBFED = 74;
                EPwm1Regs.CMPA.bit.CMPA = 565;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 74;
                EPwm6Regs.DBFED.bit.DBFED = 74;
                EPwm6Regs.CMPA.bit.CMPA = 565;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 6:
                EPwm1Regs.DBRED.bit.DBRED = 72;
                EPwm1Regs.DBFED.bit.DBFED = 72;
                EPwm1Regs.CMPA.bit.CMPA = 566;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 72;
                EPwm6Regs.DBFED.bit.DBFED = 72;
                EPwm6Regs.CMPA.bit.CMPA = 566;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 7:
                EPwm1Regs.DBRED.bit.DBRED = 71;
                EPwm1Regs.DBFED.bit.DBFED = 71;
                EPwm1Regs.CMPA.bit.CMPA = 566;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 71;
                EPwm6Regs.DBFED.bit.DBFED = 71;
                EPwm6Regs.CMPA.bit.CMPA = 566;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 8:
                EPwm1Regs.DBRED.bit.DBRED = 71;
                EPwm1Regs.DBFED.bit.DBFED = 71;
                EPwm1Regs.CMPA.bit.CMPA = 566;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 71;
                EPwm6Regs.DBFED.bit.DBFED = 71;
                EPwm6Regs.CMPA.bit.CMPA = 566;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 9:
                EPwm1Regs.DBRED.bit.DBRED = 70;
                EPwm1Regs.DBFED.bit.DBFED = 70;
                EPwm1Regs.CMPA.bit.CMPA = 567;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 70;
                EPwm6Regs.DBFED.bit.DBFED = 70;
                EPwm6Regs.CMPA.bit.CMPA = 567;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 10:
                EPwm1Regs.DBRED.bit.DBRED = 68;
                EPwm1Regs.DBFED.bit.DBFED = 68;
                EPwm1Regs.CMPA.bit.CMPA = 568;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 68;
                EPwm6Regs.DBFED.bit.DBFED = 68;
                EPwm6Regs.CMPA.bit.CMPA = 568;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 11:
                EPwm1Regs.DBRED.bit.DBRED = 66;
                EPwm1Regs.DBFED.bit.DBFED = 66;
                EPwm1Regs.CMPA.bit.CMPA = 569;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 66;
                EPwm6Regs.DBFED.bit.DBFED = 66;
                EPwm6Regs.CMPA.bit.CMPA = 569;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 12:
                EPwm1Regs.DBRED.bit.DBRED = 65;
                EPwm1Regs.DBFED.bit.DBFED = 65;
                EPwm1Regs.CMPA.bit.CMPA = 569;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 65;
                EPwm6Regs.DBFED.bit.DBFED = 65;
                EPwm6Regs.CMPA.bit.CMPA = 569;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 13:
                EPwm1Regs.DBRED.bit.DBRED = 64;
                EPwm1Regs.DBFED.bit.DBFED = 64;
                EPwm1Regs.CMPA.bit.CMPA = 570;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 64;
                EPwm6Regs.DBFED.bit.DBFED = 64;
                EPwm6Regs.CMPA.bit.CMPA = 570;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 14:
                EPwm1Regs.DBRED.bit.DBRED = 62;
                EPwm1Regs.DBFED.bit.DBFED = 62;
                EPwm1Regs.CMPA.bit.CMPA = 571;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 62;
                EPwm6Regs.DBFED.bit.DBFED = 62;
                EPwm6Regs.CMPA.bit.CMPA = 571;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 15:
                EPwm1Regs.DBRED.bit.DBRED = 48;
                EPwm1Regs.DBFED.bit.DBFED = 48;
                EPwm1Regs.CMPA.bit.CMPA = 578;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 48;
                EPwm6Regs.DBFED.bit.DBFED = 48;
                EPwm6Regs.CMPA.bit.CMPA = 578;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            case 16:
                EPwm1Regs.DBRED.bit.DBRED = 10;
                EPwm1Regs.DBFED.bit.DBFED = 10;
                EPwm1Regs.CMPA.bit.CMPA = 595;
                EPwm1Regs.CMPA.bit.CMPAHR = mep_isr_cnt * 256;
                EPwm1Regs.CMPB.bit.CMPBHR = mep_isr_cnt * 256;
    
                EPwm6Regs.DBRED.bit.DBRED = 10;
                EPwm6Regs.DBFED.bit.DBFED = 10;
                EPwm6Regs.CMPA.bit.CMPA = 595;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
            default:
                EPwm1Regs.DBRED.bit.DBRED = 84;
                EPwm1Regs.DBFED.bit.DBFED = 84;
                EPwm1Regs.CMPA.bit.CMPA = 560;
                EPwm1Regs.CMPA.bit.CMPAHR = 6400;
                EPwm1Regs.CMPB.bit.CMPBHR = 6400;
    
                EPwm6Regs.DBRED.bit.DBRED = 84;
                EPwm6Regs.DBFED.bit.DBFED = 84;
                EPwm6Regs.CMPA.bit.CMPA = 560;
                EPwm6Regs.CMPA.bit.CMPAHR = 0;
                EPwm6Regs.CMPB.bit.CMPBHR = 0;
                break;
        }
    
        /*
        if(mep_isr_cnt < MEP_ScaleFactor)
        {
            mep_isr_cnt = mep_isr_cnt + 1;
        }
        else
        {
            mep_isr_cnt = 0;
            if(isr_cnt < 15)
            {
                isr_cnt = isr_cnt + 1;
            }
            else
            {
                isr_cnt = 0;
            }
        }
        */
    
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    
    
    //
    // End of File
    //
    

    Regards,

    Stefan

  • Hi Stefan,

    I've noticed a pattern with each of the combinations of rising edge/falling edge delay and your CMPA value. If you take the point in time that the up-count CMPA event occurs and add the rising edge delay to it, the resulting event will fall near or past the time when the down-count CMPA event should occur. Since the input to the dead-band module is first passed through the rising edge delay module before being passed to the falling edge delay module, the output of the rising edge delay module will have a have a rising edge that occurs after it's falling edge. I'm not sure how the falling edge delay module would handle this input when HR is enabled. This may be a new edge case with behavior we have not documented to customers, however it could be related to our advisory to not have an CMPA value within 3 clock cycles of TBCTR =0 when HRPWM is enabled.

    The F28003x TRM contains the following note:

    "Phase shifting B-channel with respect to the A-channel: When PWMxB is derived from PWMxA using the DEDB_MODE bit and by delaying rising edge and falling edge by the phase shift amount. When the duty cycle value on PWMxA is less than this phase shift amount, PWMxA’s falling edge has precedence over the delayed rising edge for PWMxB. It is recommended to make sure the duty cycle value of the current waveform fed to the dead-band module is greater than the required phase shift amount."

    In the cases you have created, the duty is less than the "phase shift" that is created from the rising edge and falling edge delay values. This may violate the note above.

    Is the purpose of the following code (using the same value for rising edge and falling edge delay) just to create a phase shift?

    (note that the duty in this code example would be 44 clock cycles (2*(600-578)), while the phase would be 48. This could potentially violate the note above)

    If so, have you considered using the TBPHS register to achieve this use-case?

    Thank you,

    Luke

  • Hi Luke,

    Sorry for my late response.

    I've noticed a pattern with each of the combinations of rising edge/falling edge delay and your CMPA value. If you take the point in time that the up-count CMPA event occurs and add the rising edge delay to it, the resulting event will fall near or past the time when the down-count CMPA event should occur. Since the input to the dead-band module is first passed through the rising edge delay module before being passed to the falling edge delay module, the output of the rising edge delay module will have a have a rising edge that occurs after it's falling edge. I'm not sure how the falling edge delay module would handle this input when HR is enabled. This may be a new edge case with behavior we have not documented to customers, however it could be related to our advisory to not have an CMPA value within 3 clock cycles of TBCTR =0 when HRPWM is enabled.

    Please note that Half Cycle Clocking Enable Bit of the Dead-Band Generator is enabled (DBCTL.bit.HALFCYCLE = 1) in order to use the high resolution mode.

    TRM, SPRUIW9A, Page 2191

    The F28003x TRM contains the following note:

    "Phase shifting B-channel with respect to the A-channel: When PWMxB is derived from PWMxA using the DEDB_MODE bit and by delaying rising edge and falling edge by the phase shift amount. When the duty cycle value on PWMxA is less than this phase shift amount, PWMxA’s falling edge has precedence over the delayed rising edge for PWMxB. It is recommended to make sure the duty cycle value of the current waveform fed to the dead-band module is greater than the required phase shift amount."

    In the cases you have created, the duty is less than the "phase shift" that is created from the rising edge and falling edge delay values. This may violate the note above.

    Due to the Half Cycle Clocking, in all my cases the on times or duties are longer than the delay introduced by the RED or FED.

    Even if the Dead-Band Generator does not operate in high-resolution mode by, the glitch occurs.

    Is the purpose of the following code (using the same value for rising edge and falling edge delay) just to create a phase shift?

    (note that the duty in this code example would be 44 clock cycles (2*(600-578)), while the phase would be 48. This could potentially violate the note above)

    If so, have you considered using the TBPHS register to achieve this use-case?

    As described above, this will not violate the requirements of the TRM. With the values we get:

    duty in cycles = 2 * (PRD - CMPA) =2 * (600 - 578) = 44

    RED in cycles = DBRED / 2 = 24

    This case is used to compare ePWM1 with ePWM6, both of which operate in high-resolution mode, but only ePWM1 is fed with fractional CMPA and CMPB values. I have tried many different settings to get the AHC mode to work in HR mode. This configuration I posted above seems to be the only one that works and produces balanced output pulses. Therefore, this case is for verification of the configuration.

    Regards,

    Stefan

  • Hey Stefan,

    I've discussed this issue further with the team, and I believe the most likely cause is due to an issue that is not clearly documented in the TRM but similar to the following note:

    I did not realize you were using half-cycle clocking so my previous suspicion about the delayed rising edge overlapping with the non-delayed falling edge is invalid, but another pattern I noticed about each of the cases you've created is that the delayed rising edge always falls within 7 cycles of of TBCTR=TBPRD. I will consult with the design team to determine if this is a known issue that we have not clearly documented in the TRM.

    Thank you,

    Luke

  • Hi Stefan,

    The design team does not believe this is a known issue, I am trying to recreate the issue on my side to obtain scope shots of the jitter for the design team, however I am unable to reproduce the jitter for some reason using the latest test code you have provided. What version of C2000Ware are you using? Could you send your entire F28004x project as a .zip file? What's the resolution of your scope.

    Could you verify you're seeing the jitter for all of the 16 test-cases or which test-cases in particular still produce the jitter? I only see a very small jitter for case 0 but the amplitude is less than 0.5V, unlike the 3.3V jitter you shared in your first screenshot.

    Thank you,

    Luke

  • Hi Luke,

    I have attached the project in a zip file to this post.

    The bandwith of my scope is 200 MHz. I used passive probes with 10:1 divider and a bandwidth of 250 MHz. This results in a bandwidth (3 dB) of approx. 143 MHz with an approximation as first order system. I also used a ground spring to minimize the ground inductance.

    The glitch occurs on cases 0 to 15 with an CMPAHR and CMPBHR value not equal to zero.

    I think you were correct in your assumption that there is a violation of some range restrictions that are not clearly written in the TRM. I have gone through the TRM again and made further investigations based on your assumption.

    I suspect that the glitch happens when the delayed edge of RED or FED occurs in the range of three TBCLK periods around zero or TBPRD. In my application, the CMPA values were always outside this illegal range. This range is specified in the TRM SPRUIW9A on Page 2250.  However, the delayed signals by RED and FED have violated this constraint. Since I had always set DBFEDHR and DBFEDHR to zero, I thought it would be OK. But now I suspect that the Micro Edge placing (MEP) only happens after the RED and FED and therefore the restriction also apply to the delayed signal within the dead band generator.

    Can you please check if this is the root cause of the glitch?

    Thank you very much for your efforts.

    Regards,

    StefanTest_HRPWM_DB_UPDOWN_COMPL.zip

  • Hey Stefan,

    Thanks for you detailed response, I was able to recreate the issue on my side. I was also able to create my own custom case following the rule where CMPA + DBRED =  602 with a non-zero value of CMPAHR and recreated the glitch. I'll do further testing on my side to determine the cases where the glitch does or does not occur and give my results to the design team so they can provide an explanation.

  • Hey Stefan, I've provided .out files for different cases of when the glitch does or does not occur, they've informed me they will test the .out files and get back to me with their results.

    Thank you,

    Luke

  • Hey Luke,

    Thank you for the update. I am looking forward to the results.

    Best regards, Stefan

  • Hey Stefan,

    The design team has gotten back to me, they expect to have simulation results by the end of this week or early next week, I will provide you any further updates I receive from them.

    Thank you,

    Luke

  • Hi Stefan,

    The design team provided me an update today, they are unable to recreate the issue in simulation yet but are trying a different method to recreate it.

    I will be out of office for the next two weeks but I will provide you an update once I return.

    Thank you,

    Luke

  • Hey Stefan, I am still awaiting a response from the design team. In the meantime I have a suggestion that may resolve this issue.

    Instead of varying CMPAHR and CMPBHR in your case statements, could you vary  DBREDHR and DBFEDHR to produce the same edge delay? Does the glitch still occur with the same combinations of CMPA and DBRED?

    Thank you,

    Luke