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: ePWM Variable Duty Cycle

Part Number: TMS320F280049C
Other Parts Discussed in Thread: SYSCONFIG, C2000WARE

I have a few follow up question about the properties of the ePWM.

What is the default clock speed for the ePWM interrupt routine? And could you point me towards a resource in calculating what increments of theta need to be selected to implement the 14400 Hz switching frequency?

The example 2 epwm_updown_aq updates the CMPA register with compAValue which increments to 1950 and decrements to 50. Why is it that 2000 is considered a 100% duty cycle?

I have been trying to use an array of theta values that alternated up and down every interrupt, taken the sine of them, then multiplied to the compAValue to generate varying duty cycles.

Here is the copy of my code so far, I appreciate the assistance greatly.

//#############################################################################
//
// FILE: epwm_ex2_updown_aq.c
//
// TITLE: ePWM Action Qualifier Module - Using up/down count.
//
//! \addtogroup driver_example_list
//! <h1> ePWM Up Down Count Action Qualifier</h1>
//!
//! This example configures ePWM1, ePWM2, ePWM3 to produce a 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/down count mode for this example.
//!
//! View the ePWM1A/B(GPIO0 & GPIO1), ePWM2A/B(GPIO2 &GPIO3)
//! and ePWM3A/B(GPIO4 & GPIO5) waveforms on oscilloscope.
//
//#############################################################################
//
//
// $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 "driverlib.h"
#include "device.h"
#include "board.h"


//
// Defines
//
#define EPWM1_TIMER_TBPRD 2000U
#define EPWM1_MAX_CMPA 1950U
#define EPWM1_MIN_CMPA 50U

#define EPWM2_TIMER_TBPRD 2000U
#define EPWM2_MAX_CMPA 1950U
#define EPWM2_MIN_CMPA 50U

#define EPWM3_TIMER_TBPRD 2000U
#define EPWM3_MAX_CMPA 1950U
#define EPWM3_MIN_CMPA 50U

#define EPWM_CMP_UP 1U
#define EPWM_CMP_DOWN 0U

//
// Globals
//
typedef struct
{
   uint32_t epwmModule;
   uint16_t epwmCompADirection;
   uint16_t epwmTimerIntCount;
   uint16_t epwmMaxCompA;
   uint16_t epwmMinCompA;
}epwmInformation;

//
// Globals to hold the ePWM information used in this example
//
epwmInformation epwm1Info;
epwmInformation epwm2Info;
epwmInformation epwm3Info;

//
// 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(epwmInformation *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();

//
// Assign the interrupt service routines to ePWM interrupts
//
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);

//
// Configure GPIO0/1 , GPIO2/3 and GPIO4/5 as ePWM1A/1B, ePWM2A/2B and
// ePWM3A/3B pins respectively
// Configure EPWM Modules
//
Board_init();

initEPWM1();
initEPWM2();
initEPWM3();

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

//
// Enable ePWM interrupts
//
Interrupt_enable(INT_EPWM1);
Interrupt_enable(INT_EPWM2);
Interrupt_enable(INT_EPWM3);

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

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

//
// epwm1ISR - ePWM 1 ISR
//
__interrupt void epwm1ISR(void)
{
//
// Update the CMPA and CMPB values
//
updateCompare(&epwm1Info);

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

//
// Acknowledge interrupt group
//
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// epwm2ISR - ePWM 2 ISR
//
__interrupt void epwm2ISR(void)
{
//
// Update the CMPA and CMPB values
//
updateCompare(&epwm2Info);

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

//
// Acknowledge interrupt group
//
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// epwm3ISR - ePWM 3 ISR
//
__interrupt void epwm3ISR(void)
{
//
// Update the CMPA and CMPB values
//
updateCompare(&epwm3Info);

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

//
// Acknowledge interrupt group
//
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// initEPWM1 - Configure ePWM1
//
void initEPWM1()
{
//
// 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
//
epwm1Info.epwmCompADirection = EPWM_CMP_UP;
epwm1Info.epwmTimerIntCount = 0U;
epwm1Info.epwmModule = myEPWM1_BASE;
epwm1Info.epwmMaxCompA = EPWM1_MAX_CMPA;
epwm1Info.epwmMinCompA = EPWM1_MIN_CMPA;

}

//
// initEPWM2 - Configure ePWM2
//
void initEPWM2()
{
//
// 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
//
epwm2Info.epwmCompADirection = EPWM_CMP_UP;
epwm2Info.epwmTimerIntCount = 0U;
epwm2Info.epwmModule = myEPWM2_BASE;
epwm2Info.epwmMaxCompA = EPWM2_MAX_CMPA;
epwm2Info.epwmMinCompA = EPWM2_MIN_CMPA;
}

//
// initEPWM3 - Configure ePWM3
//
void initEPWM3(void)
{
//
// 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
//
epwm3Info.epwmCompADirection = EPWM_CMP_UP;
epwm3Info.epwmTimerIntCount = 0U;
epwm3Info.epwmModule = myEPWM3_BASE;
epwm3Info.epwmMaxCompA = EPWM3_MAX_CMPA;
epwm3Info.epwmMinCompA = EPWM3_MIN_CMPA;
}

//
// updateCompare - Function to update the frequency
//
void updateCompare(epwmInformation *epwmInfo)
{
uint16_t compAValue;
float32_t theta[6] = {0, 0.314159, 0.628319, 0.942478, 1.25664, 1.5708};
float32_t x;
uint16_t count = 0;


compAValue = EPWM_getCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A);


//
// Change the CMPA/CMPB values every 10th interrupt.
//
if(epwmInfo->epwmTimerIntCount == 10U)
{
epwmInfo->epwmTimerIntCount = 0U;


//
// If we were increasing CMPA, check to see if we reached the max
// value. If not, increase CMPA else, change directions and decrease
// CMPA
//
x = sin(theta[count]);

if(epwmInfo->epwmCompADirection == EPWM_CMP_UP)
{
if(compAValue < (epwmInfo->epwmMaxCompA))
{
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
++compAValue*x);
count++;
}
else
{
epwmInfo->epwmCompADirection = EPWM_CMP_DOWN;
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
--compAValue*x);
count--;
}
}
//
// 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( compAValue == (epwmInfo->epwmMinCompA))
{
epwmInfo->epwmCompADirection = EPWM_CMP_UP;
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
++compAValue*x);
count++;
}
else
{
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
--compAValue*x);
count--;
}
}


}
else
{
epwmInfo->epwmTimerIntCount++;
}

}

  • Another thing I am confused on is how to alter the second and third epwm so their phase are 120 and 240 degrees  apart. From example 11, there is a configure signal function but I believe it will interfere with the duty cycles assigned in the updateCompare function I am currently using.

  • Hi Matthew,

    And could you point me towards a resource in calculating what increments of theta need to be selected to implement the 14400 Hz switching frequency?

    I have assigned this thread to Aditya to help continue support your initial thread, and answer the questions about the theta calculations.

    What is the default clock speed for the ePWM interrupt routine?

    The particular example you are using has the following code for setting up the EPWM interrupt:

        // Interrupt where we will change the Compare Values
        // Select INT on Time base counter zero event,
        // Enable INT, generate INT on 3rd event
        //
        EPWM_setInterruptSource(myEPWM1_BASE, EPWM_INT_TBCTR_ZERO);
        EPWM_enableInterrupt(myEPWM1_BASE);
        EPWM_setInterruptEventCount(myEPWM1_BASE, 3U);

    This means that every third time the time-base counter is equal to zero, the EPWM interrupt will occur. If you want this to happen more frequently then you can change this to be every time the time-base counter is equal to zero and therefor have your ISR frequency match the frequency of your EPWM output.

    The example 2 epwm_updown_aq updates the CMPA register with compAValue which increments to 1950 and decrements to 50. Why is it that 2000 is considered a 100% duty cycle?

    Did you run the code with the comparator value at 2000? Where you seeing 100% duty cycle?

    how to alter the second and third epwm so their phase are 120 and 240 degrees  apart. From example 11, there is a configure signal function but I believe it will interfere with the duty cycles assigned in the updateCompare function I am currently using.

    Correct, you'll want to use the functions that map to setting up the synchronization scheme and the phase shift values.

    Please take a look at this thread which has an example for how to set this up:

    https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1078925/tms320f28388d-examplw-epwm_ex3_synchronization-c/3998071?tisearch=e2e-sitesearch&keymatch=epwm_ex3_synchronization#3998071 

    We also recently released a video that talks about the steps required to setup the synchronization/phase shifts:

    https://training.ti.com/c2000-enhanced-pulse-width-modulator-epwm-time-base-submodule?context=1137766-1149551-1149545 

    Best Regards,

    Marlyn

  • And could you point me towards a resource in calculating what increments of theta need to be selected to implement the 14400 Hz switching frequency?

    Sorry for the confusion. Let me put down the calculations.

    Say, your EPWMCLK frequency is 100MHz and you need your output freq as 14400 Hz, the calculations will come down as (1M/14400) -- This value can be fed to the TBPRD register which should give you the desired switching frequency. -- This is pretty much the standard way of calculating the TBPRD value. Device Technical Reference Manual will be a good reference to check the detailed calculations.


    Theta calculations will come up only when you desire to have the output frequency of an inverter / other power module of 50/60Hz. Ignore that part if not needed.

    Thanks,

    Aditya

  • Hello Aditya,

    Thank you for your assistance. This code will be used for a 400 Hz inverter, so I will be needing to use theta to create duty cycles representing the expected sinusoidal voltage. AS of now, I have a 6 element float array containing 6 theta values, in radians, to take the sin of and multiply it by the compAValue when compAValue reaches the maximum counter value. The array indexes up to pi/2, then back down to 0 and repeats. No negative values will be used because the input voltage to the inverter is floating, so a 50% duty cycle will represent where the sin wave crosses the origin.

    I also changed the ePWMs to only be in up-count mode.

    Here is the updated 'updateCompare' function if you could let me know if this is the correct way to go about this.

    void updateCompare(epwmInformation *epwmInfo)
    {
    uint16_t compAValue;
    float32_t theta[6] = {0, 0.314159, 0.628319, 0.942478, 1.25664, 1.5708};
    float32_t x;
    uint16_t count = 0;
    bool posDirection = true;

    compAValue = EPWM_getCounterCompareValue(epwmInfo->epwmModule,
    EPWM_COUNTER_COMPARE_A);

    //
    // If we were increasing CMPA, check to see if we reached the max
    // value. If not, increase CMPA else, change directions and decrease
    // CMPA
    //
    x = sin(theta[count]);

    if(compAValue == EPWM1_MAX_CMPA)
    {

    if(posDirection)
    {
    EPWM_setCounterCompareValue(epwmInfo->epwmModule,
    EPWM_COUNTER_COMPARE_A,
    compAValue*x);
    count++;
    if(count == 6)
    {
    posDirection = false;
    count = 5;
    }
    }
    else
    {
    EPWM_setCounterCompareValue(epwmInfo->epwmModule,
    EPWM_COUNTER_COMPARE_A,
    compAValue*x);
    count--;
    if(count == 0)
    {
    posDirection = true;
    }
    }
    compAValue = 0U;
    }

    compAValue++;


    }

    Thanks,

    Matthew

  • Matthew,

    How did you come down to the array of 6 theta values within 0-90 degrees? My intuition suggests that this should be giving you an output inverter frequency of (14400/6*4) = 1440 Hz and not 400.

    For an output freq of 400, you may need the array size of (14400/400) = 36 over a full cycle of 360 degrees. i.e. array size of 9 over a quadrant.

    Otherwise, the configuration looks good.

    Thanks,

    Aditya

  • Hello Aditya,

    I have updated my program to include the 36 element array for the sinusoidal values, the previous array of 6 was for one quadrant and was based on some early calculations of sample rate per quadrant. I still have something that is confusing to me: is the ePWMCLK default set to 10MHz? I've seen in the data sheet and user manual it can be a number of values, but I am assuming that is all from using the clock dividers, so if I chose HSPCLKDIV = 4 and CLKDIV = 1, the TBCLK will be 2.5 MHz? 

    Here is my revised code, along with parameters in the sysconfig file. When the output is read on an oscilloscope, it initially shows one duty cycle of about 50% with incorrect phase spacing between the channels.

    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    #include "board.h"

    //
    // Defines
    // Calculations for TBPRD
    #define EPWM1_TIMER_TBPRD 172U //using hspclkdiv = 4, clkdiv = 1
    #define EPWM1_MAX_CMPA 170U //TBCLK = 10MHz/4*1 = 2.5MHz, T_PWM = 1/14400Hz = 69.44 usec
    //T_TBCLK = 400 nsec
    //TBPRD = (T_PWM/T_TBCLK) - 1 = 172
    #define EPWM2_TIMER_TBPRD 172U
    #define EPWM2_MAX_CMPA 170U

    #define EPWM3_TIMER_TBPRD 172U
    #define EPWM3_MAX_CMPA 170U

    #define EPWM_CMP_UP 1U


    //
    // Globals
    //
    typedef struct
    {
    uint32_t epwmModule;
    uint16_t epwmCompADirection;
    uint16_t epwmTimerIntCount;
    uint16_t epwmMaxCompA;
    }epwmInformation;

    //
    // Globals to hold the ePWM information used in this example
    //
    epwmInformation epwm1Info;
    epwmInformation epwm2Info;
    epwmInformation epwm3Info;

    //
    // 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(epwmInformation *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();

    //
    // Assign the interrupt service routines to ePWM interrupts
    //
    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);

    //
    // Configure GPIO0/1 , GPIO2/3 and GPIO4/5 as ePWM1A/1B, ePWM2A/2B and
    // ePWM3A/3B pins respectively
    // Configure EPWM Modules
    //
    Board_init();

    initEPWM1();
    initEPWM2();
    initEPWM3();


    //
    // Initialize ePWM2 with phase shift of 120 deg
    // 172*120/180 = 115
    //
    EPWM_selectPeriodLoadEvent(myEPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
    EPWM_setPhaseShift(myEPWM2_BASE, 115);


    //
    // Initialize ePWM2 with phase shift of
    //
    EPWM_selectPeriodLoadEvent(myEPWM3_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
    EPWM_setPhaseShift(myEPWM3_BASE, 230);


    //
    // ePWM1 SYNCO is generated on CTR=0
    //
    EPWM_setSyncOutPulseMode(myEPWM1_BASE,EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
    EPWM_setSyncOutPulseMode(myEPWM2_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);
    EPWM_setSyncOutPulseMode(myEPWM3_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);


    EPWM_enablePhaseShiftLoad(myEPWM2_BASE);
    EPWM_enablePhaseShiftLoad(myEPWM3_BASE);


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


    //
    // Enable ePWM interrupts
    //
    Interrupt_enable(INT_EPWM1);
    Interrupt_enable(INT_EPWM2);
    Interrupt_enable(INT_EPWM3);


    //
    //Set interrupt to occur every time TBCLK = 0
    //
    EPWM_setInterruptEventCount(myEPWM1_BASE, 1U);
    EPWM_setInterruptEventCount(myEPWM2_BASE, 1U);
    EPWM_setInterruptEventCount(myEPWM3_BASE, 1U);

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

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

    //
    // epwm1ISR - ePWM 1 ISR
    //
    __interrupt void epwm1ISR(void)
    {
    //
    // Update the CMPA and CMPB values
    //
    updateCompare(&epwm1Info);

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

    //
    // Acknowledge interrupt group
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }

    //
    // epwm2ISR - ePWM 2 ISR
    //
    __interrupt void epwm2ISR(void)
    {
    //
    // Update the CMPA and CMPB values
    //
    updateCompare(&epwm2Info);

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

    //
    // Acknowledge interrupt group
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }

    //
    // epwm3ISR - ePWM 3 ISR
    //
    __interrupt void epwm3ISR(void)
    {
    //
    // Update the CMPA and CMPB values
    //
    updateCompare(&epwm3Info);

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

    //
    // Acknowledge interrupt group
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }

    //
    // initEPWM1 - Configure ePWM1
    //
    void initEPWM1()
    {
    epwm1Info.epwmCompADirection = EPWM_CMP_UP;
    epwm1Info.epwmTimerIntCount = 0U;
    epwm1Info.epwmModule = myEPWM1_BASE;
    epwm1Info.epwmMaxCompA = EPWM1_MAX_CMPA;

    }

    //
    // initEPWM2 - Configure ePWM2
    //
    void initEPWM2()
    {
    epwm2Info.epwmCompADirection = EPWM_CMP_UP;
    epwm2Info.epwmTimerIntCount = 0U;
    epwm2Info.epwmModule = myEPWM2_BASE;
    epwm2Info.epwmMaxCompA = EPWM2_MAX_CMPA;
    }

    //
    // initEPWM3 - Configure ePWM3
    //
    void initEPWM3(void)
    {
    epwm3Info.epwmCompADirection = EPWM_CMP_UP;
    epwm3Info.epwmTimerIntCount = 0U;
    epwm3Info.epwmModule = myEPWM3_BASE;
    epwm3Info.epwmMaxCompA = EPWM3_MAX_CMPA;
    }

    //
    // updateCompare - Function to update the frequency
    //
    void updateCompare(epwmInformation *epwmInfo)
    {
    uint16_t compAValue;

    //
    //A floating voltage is being used as a power supply, so we have a 0.5 duty cycle represents AC 0 Volts
    //
    float32_t theta[36] = {0.5, 0.589278, 0.675687, 0.756449, 0.828969, 0.890915,
    0.940297, 0.975528, 0.995475, 0.999497, 0.987464, 0.959765,
    0.917288, 0.861399, 0.793895, 0.716945, 0.633022, 0.544823, 0.499497,
    0.495475, 0.475528, 0.440297, 0.390915, 0.328969, 0.256449, 0.175687,
    0.0892783, 0, 0.044823, 0.133022, 0.216945, 0.293895, 0.361399, 0.417288,
    0.459765, 0.487464};
    uint16_t count = 0U;

    compAValue = EPWM_getCounterCompareValue(epwmInfo->epwmModule,
    EPWM_COUNTER_COMPARE_A);

    //
    // Increase CMPA until Max CMPA is reached, update duty cycle, increase counter for sine value
    //


    if(compAValue == EPWM1_MAX_CMPA)
    {
    EPWM_setCounterCompareValue(epwmInfo->epwmModule,
    EPWM_COUNTER_COMPARE_A,
    EPWM1_MAX_CMPA*theta[count]);
    count++;
    if(count == 36)
    {
    count = 0;
    }
    compAValue = 0U;
    }

    compAValue++;


    }

    Thank you for all of your assistance,

    Matthew

  • I still have something that is confusing to me: is the ePWMCLK default set to 10MHz? I've seen in the data sheet and user manual it can be a number of values, but I am assuming that is all from using the clock dividers, so if I chose HSPCLKDIV = 4 and CLKDIV = 1, the TBCLK will be 2.5 MHz? 

    Depends on the clock source that you use. For default settings, you can check the Device_Init() function available under main.c or directly you can check the device.c and .h files. If the EPWMCLK is 10MHz in your case, then the settings that you've made are correct, i.e. TBCLK will be 2.5MHz. (For F28004x, the default SYSCLK/EPWMCLK frequency should be 100MHz which should give you the TBCLK of 25MHz with mentioned dividers)

    Before jumping to the phase shift part, were you able to validate whether you're getting the desired output frequency?

    Phase shift process is pretty much what you've done. I dont see any error in the calculation except the fact that you may need to validate the TBPRD value based on the sysclk. If SYSCLK is 100MHz (default) then TBPRD will come as ~1736 based on which your calculations would change.

    Also, as Marlyn pointed out earlier, there's a good video guide on setting up the TBPRD and TBPHS values available here: C2000Tm Enhanced Pulse Width Modulator (ePWM): Time-Base Submodule | TI.com Video

    I'll recommend to go through it once.

    Thanks,

    Aditya

  • Hello Aditya,

    I went through the training video and it was very helpful in calculating the TBPRD and TBPHS values. I set both of those using functions in my .c program file and the sysconfig gui (let me know if that is good practice or not). After confirming the device is default set to run on the sysclk at 100 MHz, I updated corresponding values of EPWMx_Timer_TBPRD to 1735. I removed the code and gui settings for the phase shift to focus on obtaining the desired pwm frequency first, but still read on the oscilloscope a ~1 sec pulse of a 50% duty cycle and a 4kHz frequency, and then a constant high output voltage after the 1 second pulse. Also for some reason it still seems the EPWM3 output leads by about 69 usec even after removing the phase shifts. 

    Thanks,

    Matthew

  • I set both of those using functions in my .c program file and the sysconfig gui (let me know if that is good practice or not).

    Not needed, Matthew. Sysconfig configurations are called in the main file using the Board_Init() function. If you write it again in your main code, it will simply overwrite what was there in the sysconfig file. Configure only at one instance, preferably in the sysconfig GUI to avoid any errors.

    For the code aspect, I'll recommend you to start from the available examples in C2000Ware_XX_XX/driverlib/f28004x/examples/epwm -- epwm_ex13_up_aq for up-count configuration. You can modify the TBPRD as per your need. That would be an easier way to resolve your issue. You can later compare your code with the TI provided software to check for any errors that you might have in yours.

    Thanks,
    Aditya