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.

TMS320F280049C: TMS320F280049C

Part Number: TMS320F280049C
Other Parts Discussed in Thread: C2000WARE

Hello All,

I am using the code, epwm_ex13_up_aq.c .I have attached the code here. 

The objective is:

1) To vary the duty cycle upto 50% and fix it at 50%.

2) give a phase shift defined by the variable "Ph" in watchdog

To achieve this, I have two flags: AshikFlag and loop_counter in watchdog. To enable the phase shift, the loop_counter should be equal to AshikFlag.

There are some challenges I am facing:

1) At higher frequencies, when I change the loop_counter to AshikFlag, EPWM2 becomes unstable. I think its' because I put a hardcode in isr function of EPWM2. Is there any smarter way to do it?

The code is added.

Thanks.

Ashik

//###########################################################################
//
// FILE:   epwm_ex13_up_aq.c
//
// TITLE:  Action Qualifier Module - Using up count.
//
//! \addtogroup driver_example_list
//! <h1> EPWM Action Qualifier (epwm_up_aq)</h1>
//!
//! This example configures ePWM1, ePWM2, ePWM3 to produce an
//! waveform with independent modulation on EPWMxA and
//! EPWMxB.
//!
//! The compare values CMPA and CMPB are modified within the ePWM's ISR.
//!
//! The TB counter is in up count mode for this example.
//!
//! View the EPWM1A/B(GPIO0 & GPIO1), EPWM2A/B(GPIO2 & GPIO3)
//! and EPWM3A/B(GPIO4 & GPIO5) waveforms via an oscilloscope.
//!
//
//###########################################################################
//
//
// $Copyright:
// Copyright (C) 2021 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 "driverlib.h"
#include "device.h"
#include "board.h"
//
// Defines
//
#define EPWM1_TIMER_TBPRD  100  // Period register //2000
#define EPWM1_MAX_CMPA     50   //1000
#define EPWM1_MIN_CMPA       0
#define EPWM1_MAX_CMPB     50     //1000
#define EPWM1_MIN_CMPB       0

#define EPWM2_TIMER_TBPRD  100  // Period register
#define EPWM2_MAX_CMPA     50  //1950
#define EPWM2_MIN_CMPA      0   //50
#define EPWM2_MAX_CMPB     50  //1950
#define EPWM2_MIN_CMPB      0   //50

#define EPWM3_TIMER_TBPRD  100  // Period register
#define EPWM3_MAX_CMPA      50
#define EPWM3_MIN_CMPA       0
#define EPWM3_MAX_CMPB      50
#define EPWM3_MIN_CMPB       0

#define EPWM_CMP_UP           1
#define EPWM_CMP_DOWN         0

//
// Globals
//
typedef struct
{
    uint32_t epwmModule;
    uint16_t epwmCompADirection;
    uint16_t epwmCompBDirection;
    uint16_t epwmTimerIntCount;
    uint16_t ePWMDone;
    uint16_t epwmMaxCompA;
    uint16_t epwmMinCompA;
    uint16_t epwmMaxCompB;
    uint16_t epwmMinCompB;
} epwmInfo;

epwmInfo epwm1Info;
epwmInfo epwm2Info;
epwmInfo epwm3Info;
uint16_t AshikFlag = 0 ; //Ashik Added
uint16_t Ph = 0 ; //Ashik Added
uint16_t loop_counter = 0 ; //Ashik Added

volatile uint16_t compAVal, compBVal;

//
//  Function Prototypes
//
void initEPWM1(void);
void initEPWM2(void);
void initEPWM3(void);
__interrupt void epwm1ISR(void);
__interrupt void epwm2ISR(void);
__interrupt void epwm3ISR(void);
void updateCompare(epwmInfo*);

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

    //
    // Disable pin locks and enable internal pull-ups.
    //
    Device_initGPIO();

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

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

    //
    // For this case just init GPIO pins for ePWM1, ePWM2, ePWM3
    //
    Board_init();

    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
    Interrupt_register(INT_EPWM1, &epwm1ISR);
    Interrupt_register(INT_EPWM2, &epwm2ISR);
    Interrupt_register(INT_EPWM3, &epwm3ISR);

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

    // Initialize PWM1 without phase shift as master
    initEPWM1();

    // Initialize PWM2 with phase shift of X
    initEPWM2();
    //EPWM_selectPeriodLoadEvent(myEPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
    //EPWM_setPhaseShift(myEPWM2_BASE, Ph); //ashik added Ph
   // EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph

    initEPWM3();

    EPWM_setSyncOutPulseMode(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);

    //
    // ePWM2 uses the ePWM 1 SYNCO as its SYNCIN.
    // ePWM2 SYNCO is generated from its SYNCIN, which is ePWM1 SYNCO
    //
    EPWM_setSyncOutPulseMode(myEPWM2_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);

    //
    // ePWM4 uses the ePWM 1 SYNCO as its SYNCIN.
    //
    //SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    //
    // Enable all phase shifts.
    //
    EPWM_enablePhaseShiftLoad(myEPWM2_BASE);

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

    //
    // Enable interrupts required for this example
    //
    Interrupt_enable(INT_EPWM1);
    Interrupt_enable(INT_EPWM2);
    Interrupt_enable(INT_EPWM3);

    //
    // Enable global Interrupts and higher priority real-time debug events:
    //
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

    //
    // IDLE loop. Just sit and loop forever (optional):
    //
    for(;;)
    {
        asm ("  NOP");
    }
}

//
// epwm1ISR - EPWM1 ISR to update compare values
//
__interrupt void epwm1ISR(void)
{
    //
    // Update the CMPA and CMPB values
    //
    updateCompare(&epwm1Info);

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM1_BASE);

    //
    // Acknowledge this interrupt to receive more interrupts from group 3
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// epwm2ISR - EPWM2 ISR to update compare values
//
__interrupt void epwm2ISR(void)
{
    //
    // Update the CMPA and CMPB values
    //
    if (loop_counter!=AshikFlag)
    {
    updateCompare(&epwm2Info);
    }
    else
    {

        //Ph=300;
        EPWM_selectPeriodLoadEvent(myEPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_setPhaseShift(myEPWM2_BASE, Ph); //ashik added Ph
        EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph

    }
    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM2_BASE);

    //
    // Acknowledge this interrupt to receive more interrupts from group 3
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// epwm3ISR - EPWM3 ISR to update compare values
//
__interrupt void epwm3ISR(void)
{
    //
    // Update the CMPA and CMPB values
    //
    updateCompare(&epwm3Info);

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM3_BASE);

    //
    // Acknowledge this interrupt to receive more interrupts from group 3
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// initEPWM1 - Initialize EPWM1 values
//
void initEPWM1()
{
    //
    // Setup TBCLK
    //
    EPWM_setTimeBaseCounterMode(myEPWM1_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBasePeriod(myEPWM1_BASE, EPWM1_TIMER_TBPRD);
    EPWM_disablePhaseShiftLoad(myEPWM1_BASE);
    EPWM_setPhaseShift(myEPWM1_BASE, 0U);
    EPWM_setTimeBaseCounter(myEPWM1_BASE, 0U);

    //
    // Set ePWM clock pre-scaler
    //
    EPWM_setClockPrescaler(myEPWM1_BASE,
                           EPWM_CLOCK_DIVIDER_2,
                           EPWM_HSCLOCK_DIVIDER_2);

    //
    // Setup shadow register load on ZERO
    //
    EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE,
                                         EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);
    EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE,
                                         EPWM_COUNTER_COMPARE_B,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);

    //
    // Set Compare values
    //
    EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_A,
                                EPWM1_MIN_CMPA);
    EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_B,
                                EPWM1_MIN_CMPB);

    //
    // Set actions for ePWM1A & ePWM1B
    //
    // Set PWM1A on Zero
    EPWM_setActionQualifierAction(myEPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    // Clear PWM1A on event A, up count
    EPWM_setActionQualifierAction(myEPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);

    // Set PWM1B on Zero
    EPWM_setActionQualifierAction(myEPWM1_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    // Clear PWM1B on event B, up count
    EPWM_setActionQualifierAction(myEPWM1_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);

//    // Set PWM1B on Zero
//    EPWM_setActionQualifierAction(myEPWM1_BASE,
//                                  EPWM_AQ_OUTPUT_B,
//                                  EPWM_AQ_OUTPUT_HIGH,
//                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
//    // Clear PWM1B on event B, up count
//    EPWM_setActionQualifierAction(myEPWM1_BASE,
//                                  EPWM_AQ_OUTPUT_B,
//                                  EPWM_AQ_OUTPUT_LOW,
//                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);

    //
    // Interrupt where we will change the Compare Values
    //
    EPWM_setInterruptSource(myEPWM1_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(myEPWM1_BASE);
    EPWM_setInterruptEventCount(myEPWM1_BASE, 3U);

   //
   // Information this example uses to keep track
   // of the direction the CMPA/CMPB values are
   // moving, the min and max allowed values and
   // a pointer to the correct ePWM registers
   //

    // Start by increasing CMPA & CMPB
    epwm1Info.epwmCompADirection = EPWM_CMP_UP;
    epwm1Info.epwmCompBDirection = EPWM_CMP_UP;

    // Clear interrupt counter
    epwm1Info.epwmTimerIntCount = 0;
    epwm1Info.ePWMDone = 0;

    // Set base as ePWM1
    epwm1Info.epwmModule = myEPWM1_BASE;

    // Setup min/max CMPA/CMP values
    epwm1Info.epwmMaxCompA = EPWM1_MAX_CMPA;
    epwm1Info.epwmMinCompA = EPWM1_MIN_CMPA;
    epwm1Info.epwmMaxCompB = EPWM1_MAX_CMPB;
    epwm1Info.epwmMinCompB = EPWM1_MIN_CMPB;
}

//
// initEPWM2 - Initialize EPWM2 values
//
void initEPWM2()
{
    //
    // Setup TBCLK
    //
    EPWM_setTimeBaseCounterMode(myEPWM2_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBasePeriod(myEPWM2_BASE, EPWM2_TIMER_TBPRD);
    EPWM_disablePhaseShiftLoad(myEPWM2_BASE);
    EPWM_setPhaseShift(myEPWM2_BASE, 0U);
    EPWM_setTimeBaseCounter(myEPWM2_BASE, 0U);

    //
    // Set ePWM clock pre-scaler
    //
    EPWM_setClockPrescaler(myEPWM2_BASE,
                           EPWM_CLOCK_DIVIDER_2,
                           EPWM_HSCLOCK_DIVIDER_2);

    //
    // Setup shadow register load on ZERO
    //
    EPWM_setCounterCompareShadowLoadMode(myEPWM2_BASE,
                                         EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);
    EPWM_setCounterCompareShadowLoadMode(myEPWM2_BASE,
                                         EPWM_COUNTER_COMPARE_B,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);

    //
    // Set Compare values
    //
    EPWM_setCounterCompareValue(myEPWM2_BASE, EPWM_COUNTER_COMPARE_A,
                                EPWM2_MIN_CMPA);
    EPWM_setCounterCompareValue(myEPWM2_BASE, EPWM_COUNTER_COMPARE_B,
                                EPWM2_MIN_CMPB); //EPWM2_MAX_CMPB

    //
    // Set actions for ePWM1A & ePWM1B
    //
    // Clear PWM2A on period and set on event A, up-count
//    EPWM_setActionQualifierAction(myEPWM2_BASE,
//                                  EPWM_AQ_OUTPUT_A,
//                                  EPWM_AQ_OUTPUT_LOW,
//                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
//    EPWM_setActionQualifierAction(myEPWM2_BASE,
//                                  EPWM_AQ_OUTPUT_A,
//                                  EPWM_AQ_OUTPUT_HIGH,
//                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);

    // Clear PWM2A on period and set on event A, up-count
    EPWM_setActionQualifierAction(myEPWM2_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);// EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD
    EPWM_setActionQualifierAction(myEPWM2_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);

    // Clear PWM2B on Period & set on event B, up-count
    EPWM_setActionQualifierAction(myEPWM2_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);// EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD
    EPWM_setActionQualifierAction(myEPWM2_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);

    //
    // Interrupt where we will change the Compare Values
    //
    EPWM_setInterruptSource(myEPWM2_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(myEPWM2_BASE);
    EPWM_setInterruptEventCount(myEPWM2_BASE, 3U);

    //
    // Information this example uses to keep track
    // of the direction the CMPA/CMPB values are
    // moving, the min and max allowed values and
    // a pointer to the correct ePWM registers
    //

    // Start by increasing CMPA & decreasing CMPB
    epwm2Info.epwmCompADirection = EPWM_CMP_UP;
    epwm2Info.epwmCompBDirection = EPWM_CMP_DOWN;

    // Clear interrupt counter
    epwm2Info.epwmTimerIntCount = 0;

    // Set base as ePWM2
    epwm2Info.epwmModule = myEPWM2_BASE;

    // Setup min/max CMPA/CMP values
    epwm2Info.epwmMaxCompA = EPWM2_MAX_CMPA;
    epwm2Info.epwmMinCompA = EPWM2_MIN_CMPA;
    epwm2Info.epwmMaxCompB = EPWM2_MAX_CMPB;
    epwm2Info.epwmMinCompB = EPWM2_MIN_CMPB;
}

//
// initEPWM3 - Initialize EPWM3 values
//
void initEPWM3(void)
{
    //
    // Setup TBCLK
    //
    EPWM_setTimeBaseCounterMode(myEPWM3_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBasePeriod(myEPWM3_BASE, EPWM3_TIMER_TBPRD);
    EPWM_disablePhaseShiftLoad(myEPWM3_BASE);
    EPWM_setPhaseShift(myEPWM3_BASE, 0U);
    EPWM_setTimeBaseCounter(myEPWM3_BASE, 0U);

    //
    // Set ePWM clock pre-scaler
    //
    EPWM_setClockPrescaler(myEPWM3_BASE,
                           EPWM_CLOCK_DIVIDER_1,
                           EPWM_HSCLOCK_DIVIDER_1);

    //
    // Setup shadow register load on ZERO
    //
    EPWM_setCounterCompareShadowLoadMode(myEPWM3_BASE,
                                         EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);
    EPWM_setCounterCompareShadowLoadMode(myEPWM3_BASE,
                                         EPWM_COUNTER_COMPARE_B,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);

    //
    // Set Compare values
    //
    EPWM_setCounterCompareValue(myEPWM3_BASE, EPWM_COUNTER_COMPARE_A,
                                EPWM3_MIN_CMPA);
    EPWM_setCounterCompareValue(myEPWM3_BASE, EPWM_COUNTER_COMPARE_B,
                                EPWM3_MAX_CMPB);

    //
    // Set actions for ePWM1A & ePWM1B
    //
    // Set PWM3A on event B, up-count & clear on event B, up-count
    EPWM_setActionQualifierAction(myEPWM3_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(myEPWM3_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);

    // Toggle EPWM3B on counter = zero
    EPWM_setActionQualifierAction(myEPWM3_BASE,
                                  EPWM_AQ_OUTPUT_B,
                                  EPWM_AQ_OUTPUT_TOGGLE,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);

    //
    // Interrupt where we will change the Compare Values
    //
    EPWM_setInterruptSource(myEPWM3_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(myEPWM3_BASE);
    EPWM_setInterruptEventCount(myEPWM3_BASE, 3U);

   //
   // Information this example uses to keep track
   // of the direction the CMPA/CMPB values are
   // moving, the min and max allowed values and
   // a pointer to the correct ePWM registers
   //

    // Start by increasing CMPA & decreasing CMPB
    epwm3Info.epwmCompADirection = EPWM_CMP_UP;
    epwm3Info.epwmCompBDirection = EPWM_CMP_UP;

    // Start the count at 0
    epwm3Info.epwmTimerIntCount = 0;

    // Set base as ePWM1
    epwm3Info.epwmModule = myEPWM3_BASE;

    // Setup min/max CMPA/CMP values
    epwm3Info.epwmMaxCompA = EPWM3_MAX_CMPA;
    epwm3Info.epwmMinCompA = EPWM3_MIN_CMPA;
    epwm3Info.epwmMaxCompB = EPWM3_MAX_CMPB;
    epwm3Info.epwmMinCompB = EPWM3_MIN_CMPB;
}

//
// updateCompare - Update the compare values for the specified EPWM
//
void updateCompare(epwmInfo *epwm_info)
{
   //
   // Every 10'th interrupt, change the CMPA/CMPB values
   //
   if(epwm_info->epwmTimerIntCount == 10)
   {
       epwm_info->epwmTimerIntCount = 0;
       compAVal = EPWM_getCounterCompareValue(epwm_info->epwmModule,
                                              EPWM_COUNTER_COMPARE_A);
       compBVal = EPWM_getCounterCompareValue(epwm_info->epwmModule,
                                              EPWM_COUNTER_COMPARE_B);
//       if (compAVal==epwm_info->epwmMaxCompA) {epwm1Info.ePWMDone = 1;}
       //
       // If we were increasing CMPA, check to see if
       // we reached the max value.  If not, increase CMPA
       // else, change directions and decrease CMPA
       //
       if(epwm_info->epwmCompADirection == EPWM_CMP_UP)
       {
           if(compAVal < epwm_info->epwmMaxCompA)
           {
               EPWM_setCounterCompareValue(epwm_info->epwmModule,
                                           EPWM_COUNTER_COMPARE_A, ++compAVal);
               AshikFlag = AshikFlag+1;
           }
           else
           {
//               epwm_info->epwmCompADirection = EPWM_CMP_DOWN;
//               EPWM_setCounterCompareValue(epwm_info->epwmModule,
//                                           EPWM_COUNTER_COMPARE_A, --compAVal);
//               epwm1Info.ePWMDone = 1;

           }

       }

       //
       // If we were decreasing CMPA, check to see if
       // we reached the min value.  If not, decrease CMPA
       // else, change directions and increase CMPA
       //
       else
       {
           if(compAVal == epwm_info->epwmMinCompA)
           {
               epwm_info->epwmCompADirection = EPWM_CMP_UP;
               EPWM_setCounterCompareValue(epwm_info->epwmModule,
                                           EPWM_COUNTER_COMPARE_A, ++compAVal);

           }
           else
           {
               EPWM_setCounterCompareValue(epwm_info->epwmModule,
                                           EPWM_COUNTER_COMPARE_A, --compAVal);
           }
       }

       //
       // If we were increasing CMPB, check to see if
       // we reached the max value.  If not, increase CMPB
       // else, change directions and decrease CMPB
       //
       if(epwm_info->epwmCompBDirection == EPWM_CMP_UP)
       {
           if(compBVal < epwm_info->epwmMaxCompB)
           {
               EPWM_setCounterCompareValue(epwm_info->epwmModule,
                                           EPWM_COUNTER_COMPARE_B, ++compBVal);
           }
           else
           {
//               epwm_info->epwmCompBDirection = EPWM_CMP_DOWN;
//               EPWM_setCounterCompareValue(epwm_info->epwmModule,
//                                           EPWM_COUNTER_COMPARE_B, --compBVal);

           }
       }

       //
       // If we were decreasing CMPB, check to see if
       // we reached the min value.  If not, decrease CMPB
       // else, change directions and increase CMPB
       //
       else
       {
           if(compBVal == epwm_info->epwmMinCompB)
           {
               epwm_info->epwmCompBDirection = EPWM_CMP_UP;
               EPWM_setCounterCompareValue(epwm_info->epwmModule,
                                           EPWM_COUNTER_COMPARE_B, ++compBVal);
           }
           else
           {
               EPWM_setCounterCompareValue(epwm_info->epwmModule,
                                           EPWM_COUNTER_COMPARE_B, --compBVal);
           }
       }
   }

   //
   // Increment interrupt count if < 10
   //
   else
   {
      epwm_info->epwmTimerIntCount++;
   }

   return;

}
//
// End of file
//

  • Hi Ashik,

    Apologies for the delayed response.

    This code snippet is very long, could you identify the specific location in your code that you are concerned about? What is the purpose of loop_counter and AshikFlag? Could you provide a scope shot of EPWM2 at both lower and higher frequencies?

    Thank you,

    Luke

  • Hi Luke,

    I have added the code where i am concerned.

    I want to assign a phase shift (Ph) from watchdog after the PWM reaches 50% duty cycle. I don't know much intuitive method to find when the duty cycle will reach 50%. That's why in updateCompare(), I put a flag in line 623. In the interrupt epwm2ISR() function, I have put a check (code given in snippet). From watchdog I can initiate the else loop while putting final value of AshikFlag to loop_counter.

    __interrupt void epwm2ISR(void)
    {
        //
        // Update the CMPA and CMPB values
        //
        if (loop_counter!=AshikFlag)
        {
        updateCompare(&epwm2Info);
        }
        else
        {
    
            //Ph=300;
            EPWM_selectPeriodLoadEvent(myEPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
            EPWM_setPhaseShift(myEPWM2_BASE, Ph); //ashik added Ph
            EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph
    
        }
     

    Watchdog

    Before the loop_counter==AshikFlag

    After the loop_counter==AshikFlag

    Your help will be appreciated.

    Ashik

  • Hi Luke, any update on this?

  • Hi Ashik,

    I'm assuming this scope shot is showing EPWM1A, EPWM1B, EPWM2A, EPWM2B from top to bottom. Let me know if this is incorrect.

    Is Ph supposed to be 300? I see in the top of your code your EPWM2_TIMER_TBPRD is 100. Is this intentional? I don't see any code that is modifying Ph, how is this being modified?

    If your phase shift is larger than your CMPA value, there will be a missed action qualifier event, since the TBCTR will skip over CMPA when the phase shift occurs.

    How large of a phase shift are you expecting for EPWM2 when the duty cycle reaches 50%?

    The glitch in your output may be due to you hard-coding the EPWM TBCTR in line 262 of your original code snippet. What is the purpose of this code? Is it not sufficient to program the phase shift value so that the phase shift takes effect in the next EPWM cycle? There will be some delay between when the EPWM2 interrupt is triggered and when this code is executed due to the overhead from the previous driverlib functions being called in your ISR, so the effective phase shift between EPWM1 and EPWM2 will not actually be Ph after this code is executed.

  • Thanks for the reply Luke.

    "I'm assuming this scope shot is showing EPWM1A, EPWM1B, EPWM2A, EPWM2B from top to bottom. Let me know if this is incorrect."

    -Yes you are correct. Although in the code there is EPWM3 which I am not considering at this moment.

    "Is Ph supposed to be 300? I see in the top of your code your EPWM2_TIMER_TBPRD is 100. Is this intentional? I don't see any code that is modifying Ph, how is this being modified"

    "If your phase shift is larger than your CMPA value, there will be a missed action qualifier event, since the TBCTR will skip over CMPA when the phase shift occurs."

    - Thanks for pointing this out. I was wrong. When EPWM2_TIMER_TBPRD is 100, for a 30 degree shift Ph value should be ~8.

    - I have put the logic of applying Ph in __interrupt void epwm2ISR(void). 

    __interrupt void epwm2ISR(void)
    {
        //
        // Update the CMPA and CMPB values
        //
        if (loop_counter!=AshikFlag)
        {
        updateCompare(&epwm2Info);
        }
        else
        {
    
            //Ph=300;
            EPWM_selectPeriodLoadEvent(myEPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
            EPWM_setPhaseShift(myEPWM2_BASE, Ph); //ashik added Ph
            EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph
    
        }
        //
        // Clear INT flag for this timer
        //
        EPWM_clearEventTriggerInterruptFlag(myEPWM2_BASE);
    
        //
        // Acknowledge this interrupt to receive more interrupts from group 3
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    

    -I am updating the Ph value in watchdog. To enable any phase shift the loop_counter variable needs to be same as AshikFlag as in the image below.

    "How large of a phase shift are you expecting for EPWM2 when the duty cycle reaches 50%?"

    - Now I am expecting it to vary from 10-30 degree

    Now the major problem is when I enable the logic in __interrupt void epwm2ISR(void) by making loop_counter==150 from watchdog the epwm becomes unstable. 

    The purpose of this code is to apply pwm in a halfbridge where there will be no phase shift initially and after attaining 50% duty cycle it will give a certain phase shift. It was working in low frequencies (i.e., 12.5 kHz). But at higher frequencies the epwm2 has become unstable.

    I would appreciate your comment in these. Thanks

    Ashik

  • Hi Ashik,

    To clarify, the purpose of this entire code block is to apply a phase shift when EPWM2 attains a 50% duty cycle:

    EPWM_selectPeriodLoadEvent(myEPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
    EPWM_setPhaseShift(myEPWM2_BASE, Ph); //ashik added Ph
    EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph

    Maybe I'm misunderstanding your previous reply, but I still don't understand why the following line of code is necessary:

    EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph

    If you call EPWM_setPhaseShift, the phase shift will take effect the next time EPWM1 TBCTR = 0, so calling EPWM_setTimeBaseCounter to manually set EPWM2 TBCTR to the same value as the phase shift seems unnecessary, and will probably muck up your synchronization, especially at higher PWM frequencies where the execution time of the ISR is constant.

    Let me know if I'm misunderstanding something or why it's necessary to call EPWM_setTimeBaseCounter in your ISR.

    Thank you,

    Luke

  • Wow, great... It fixed the issue of instability in EPWM2.. I have disabled below line

    //EPWM_setTimeBaseCounter(myEPWM2_BASE, Ph); //ashik added Ph.

    Just another query.

    Now EPWM2B is shifting left from the rising edge of EPWM2A. I want to make the shift bidirectional. If I want to shift the EPWM2B right from the rising edge of EPWM2A, can you suggest in which function I should bring changes?

    Thanks and my sincerest appreciation to pointing the fault in my code.

    Ashik

  • Hey Ashik,

    Very glad to hear this resolved the instability issue. If you want to induce a delay on one of the edges of your output, you can utilize the dead-band module. We have a very helpful video on the dead-band module here if you need a general background information on it:

    https://www.ti.com/video/6304743885001?keyMatch=EPWM%20DEADBAND

    This module can delay the rising edge or falling edge on either one of your EPWM outputs, essentially shifting them to the right on your oscilloscope.

    Let me know if you have any further questions.

    Thank you,

    Luke

  • Hello Luke,

    It seems giving a negative value in the Ph variable from watchdog shifts the EPWM2 at right. the negative value is converted into unsigned integer.

    Can you let me know what is the maximum frequency F280049C can operate? How can I check it from code?

    Can I apply HRPWM in the code that I am using?

    Thanks for your support.

     Ashik

  • Hi Luke,

    Is there any reference you can give me so that I can integrate HRPWM in current code?

    Ashik

  • Hi Ashik,

    We have examples in C2000Ware for using HRPWM, let me know if you have any trouble using these as a reference to add HRPWM capability in your system.

    The data sheet contains the maximum clock values for various clocks in the system including EPWM clock, on F28004x this is 100 Mhz