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.

Concerto F28M36 PWM7-9 on GPIO124-GPIO129

Other Parts Discussed in Thread: CONTROLSUITE

I am having some issues getting signals out of some PWMs on the F28M36.

Our custom hardware is designed with PWM7a  assigned to GPIO124, PWM7b to GPIO125, etc up to GPIO129 in order to drive a three phase inverter.

We have given the C2000 core control of the R and S GPIO ports from the M3 side and we have enabled the bits in the C2000 GPIOMUXD and GPIOMUXE registers.

We have tried enabling them according to table 4-47 in the TRM and we have also tied enabling them with a bit setting of 01b.

We are turning off protection during the IO setup with the EALLOW command however it seems no matter what we try we don’t get any signal.

One thing that scares me is table 4-58 in the TRM does not list PWMs as functions on GPIO24-GPIO29 even though table 4-47 does and they are listed as functions in the F28M36 datasheet (which we originally used to create our MAP).

Has anyone had any luck enabling PWMs on GPIO124-GPIO129?

Thanks!

  • Jerome,

    After looking through the docs, I appreciate the concerns that you have.

    PWM-7A-12B should come out of GPIO124-135 and they should come out of the C28x-side with 01b as the mux setting.  (ie the datasheet is correct)

    Hopefully, this helps clarify things some.  I haven't personally used these GPIOs as PWMs outputs and the controlCARD won't let me try this out quickly.  Let me know if you stay stuck on this and I can try to find a way to confirm.


    Thank you,
    Brett

  • Brett & Jerome,

    I tried changing up one of the epwm examples to use epwm7 and GPIO 124 and 125 and was not successful.  I think we may need to dig deeper on this.  I verified the registers (both m3 and 28x) are correct and the pwm is running in the background...just nothing on the pins.

    Trey

  • Trey & Brett,

    Thanks for the quick response on this. I want to point out that the mux settings in the TRM say that the 28x side should be set to 10b and not 01b (see first image below). The simple data sheet eludes to them being set to 01b (see second image below).

  • Jerome,

    Turns out I can't easily test this here.  The pins I was scoping were incorrect.  On the controlcard this pins aren't brought out anywhere.  If you check the schematic you'll see they are no connects.

    Are you on a custom board or controlCARD?

    Trey

  • Trey,

    We are on a custom board. My next step was to do exactly what you are doing and revert to a simple/example project. Can you send me the projects you are using and I will test them on our custom hardware? This will save me a little time having to recreate the projects from example code and at least I'll know I am using the right revision of the example code library.

    Thanks,

    Jerome

  • I used the setup_m3 and epwm_updown_aq projects from the v201 F28M36x device support.  I'll attach the source for the pwm project here as its the only thing that I changed.

    Let me know how it goes!

    //###########################################################################
    // FILE:   epwm_updown_aq_c28.c
    // TITLE:  Action Qualifier Module - Using up/down count.
    //
    //! \addtogroup control_example_list
    //! <h1> EPWM Action Qualifier (epwm_updown_aq)</h1>
    //!
    //! This example configures ePWM1, ePWM2, ePWM3 to produce an
    //! waveform with independant 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(PA0_GPIO0 & PA1_GPIO1), EPWM2A/B(PA2_GPIO2 & PA3_GPIO3)
    //! and EPWM3A/B(PA4_GPIO4 & PA5_GPIO5) waveforms via an oscilloscope.
    //
    //###########################################################################
    // $TI Release: F28M36x Support Library v201 $
    // $Release Date: Fri Jun  7 10:37:02 CDT 2013 $
    //###########################################################################
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    typedef struct
    {
        volatile struct EPWM_REGS *EPwmRegHandle;
        Uint16 EPwm_CMPA_Direction;
        Uint16 EPwm_CMPB_Direction;
        Uint16 EPwmTimerIntCount;
        Uint16 EPwmMaxCMPA;
        Uint16 EPwmMinCMPA;
        Uint16 EPwmMaxCMPB;
        Uint16 EPwmMinCMPB;
    }EPWM_INFO;
    
    // Prototype statements for functions found within this file.
    void InitEPwm1Example(void);
    void InitEPwm2Example(void);
    void InitEPwm3Example(void);
    __interrupt void epwm1_isr(void);
    __interrupt void epwm2_isr(void);
    __interrupt void epwm3_isr(void);
    void update_compare(EPWM_INFO*);
    
    // Global variables used in this example
    EPWM_INFO epwm1_info;
    EPWM_INFO epwm2_info;
    EPWM_INFO epwm3_info;
    
    // Configure the period for each timer
    #define EPWM1_TIMER_TBPRD  2000  // Period register
    #define EPWM1_MAX_CMPA     1950
    #define EPWM1_MIN_CMPA       50
    #define EPWM1_MAX_CMPB     1950
    #define EPWM1_MIN_CMPB       50
    
    #define EPWM2_TIMER_TBPRD  2000  // Period register
    #define EPWM2_MAX_CMPA     1950
    #define EPWM2_MIN_CMPA       50
    #define EPWM2_MAX_CMPB     1950
    #define EPWM2_MIN_CMPB       50
    
    #define EPWM3_TIMER_TBPRD  2000  // Period register
    #define EPWM3_MAX_CMPA      950
    #define EPWM3_MIN_CMPA       50
    #define EPWM3_MAX_CMPB     1950
    #define EPWM3_MIN_CMPB     1050
    
    // To keep track of which way the compare value is moving
    #define EPWM_CMP_UP   1
    #define EPWM_CMP_DOWN 0
    
    void main(void)
    {
    // Step 1. Initialize System Control:
    // Enable Peripheral Clocks
    // This example function is found in the F28M36x_SysCtrl.c file.
        InitSysCtrl();
    
    // Step 2. Initalize GPIO:
    // This example function is found in the F28M36x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();  // Skipped for this example
    
    // For this case just init GPIO pins for ePWM1, ePWM2, ePWM3
    // These functions are in the F28M36x_EPwm.c file
        InitEPwm1Gpio();
        InitEPwm2Gpio();
        InitEPwm3Gpio();
        EALLOW;
        GpioCtrlRegs.GPDMUX2.bit.GPIO124 = 1;   // Configure GPIO0 as EPWM1A
        GpioCtrlRegs.GPDMUX2.bit.GPIO125 = 1;   // Configure GPIO1 as EPWM1B
        EDIS;
    
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
        DINT;
    
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F28M36x_PieCtrl.c file.
        InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
        IER = 0x0000;
        IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F28M36x_DefaultIsr.c.
    // This function is found in F28M36x_PieVect.c.
        InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
        EALLOW; // This is needed to write to EALLOW protected registers
        PieVectTable.EPWM7_INT = &epwm1_isr;
        PieVectTable.EPWM2_INT = &epwm2_isr;
        PieVectTable.EPWM3_INT = &epwm3_isr;
        EDIS;   // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in F28M36x_InitPeripherals.c
    // InitPeripherals();  // Not required for this example
    
    // For this example, only initialize the ePWM
    
        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
        EDIS;
    
        InitEPwm1Example();
        InitEPwm2Example();
        InitEPwm3Example();
    
        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
        EDIS;
    
    // Step 5. User specific code, enable interrupts:
    
    // Enable CPU INT3 which is connected to EPWM1-3 INT:
        IER |= M_INT3;
    
    // Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
        PieCtrlRegs.PIEIER3.bit.INTx7 = 1;
        PieCtrlRegs.PIEIER3.bit.INTx2 = 1;
        PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
    
    // Enable global Interrupts and higher priority real-time debug events:
        EINT;  // Enable Global interrupt INTM
        ERTM;  // Enable Global realtime interrupt DBGM
    
    // Step 6. IDLE loop. Just sit and loop forever (optional):
        for(;;)
        {
            asm ("          NOP");
        }
    
    }
    
    __interrupt void epwm1_isr(void)
    {
        // Update the CMPA and CMPB values
        update_compare(&epwm1_info);
    
        // Clear INT flag for this timer
        EPwm7Regs.ETCLR.bit.INT = 1;
    
        // Acknowledge this interrupt to receive more interrupts from group 3
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    
    __interrupt void epwm2_isr(void)
    {
    
        // Update the CMPA and CMPB values
        update_compare(&epwm2_info);
    
        // Clear INT flag for this timer
        EPwm2Regs.ETCLR.bit.INT = 1;
    
        // Acknowledge this interrupt to receive more interrupts from group 3
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    
    __interrupt void epwm3_isr(void)
    {
    
        // Update the CMPA and CMPB values
        update_compare(&epwm3_info);
    
        // Clear INT flag for this timer
        EPwm3Regs.ETCLR.bit.INT = 1;
    
        // Acknowledge this interrupt to receive more interrupts from group 3
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    
    void InitEPwm1Example()
    {
    
        // Setup TBCLK
        EPwm7Regs.TBPRD = EPWM1_TIMER_TBPRD;          // Set timer period 801 TBCLKs
        EPwm7Regs.TBPHS.half.TBPHS = 0x0000;          // Phase is 0
        EPwm7Regs.TBCTR = 0x0000;                     // Clear counter
    
        // Set Compare values
        EPwm7Regs.CMPA.half.CMPA = EPWM1_MIN_CMPA;    // Set compare A value
        EPwm7Regs.CMPB = EPWM1_MAX_CMPB;              // Set Compare B value
    
        // Setup counter mode
        EPwm7Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
        EPwm7Regs.TBCTL.bit.PHSEN = TB_DISABLE;       // Disable phase loading
        EPwm7Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;      // Clock ratio to SYSCLKOUT
        EPwm7Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
        // Setup shadowing
        EPwm7Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm7Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm7Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
        EPwm7Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set actions
        EPwm7Regs.AQCTLA.bit.CAU = AQ_SET;            // Set PWM1A on event A, up
                                                     // count
        EPwm7Regs.AQCTLA.bit.CAD = AQ_CLEAR;          // Clear PWM1A on event A,
                                                      // down count
    
        EPwm7Regs.AQCTLB.bit.CBU = AQ_SET;            // Set PWM1B on event B, up
                                                      // count
        EPwm7Regs.AQCTLB.bit.CBD = AQ_CLEAR;          // Clear PWM1B on event B,
                                                      // down count
    
        // Interrupt where we will change the Compare Values
        EPwm7Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
        EPwm7Regs.ETSEL.bit.INTEN = 1;                // Enable INT
        EPwm7Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
    
        // 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
        epwm1_info.EPwm_CMPA_Direction = EPWM_CMP_UP;  // Start by increasing CMPA &
        epwm1_info.EPwm_CMPB_Direction = EPWM_CMP_DOWN; // decreasing CMPB
        epwm1_info.EPwmTimerIntCount = 0;              // Zero the interrupt counter
        epwm1_info.EPwmRegHandle = &EPwm7Regs;         // Set the pointer to the
                                                       // ePWM module
        epwm1_info.EPwmMaxCMPA = EPWM1_MAX_CMPA;       // Setup min/max CMPA/CMPB
                                                       // values
        epwm1_info.EPwmMinCMPA = EPWM1_MIN_CMPA;
        epwm1_info.EPwmMaxCMPB = EPWM1_MAX_CMPB;
        epwm1_info.EPwmMinCMPB = EPWM1_MIN_CMPB;
    
    }
    
    void InitEPwm2Example()
    {
    
        // Setup TBCLK
        EPwm2Regs.TBPRD = EPWM2_TIMER_TBPRD;          // Set timer period 801 TBCLKs
        EPwm2Regs.TBPHS.half.TBPHS = 0x0000;          // Phase is 0
        EPwm2Regs.TBCTR = 0x0000;                     // Clear counter
    
        // Set Compare values
        EPwm2Regs.CMPA.half.CMPA = EPWM2_MIN_CMPA;    // Set compare A value
        EPwm2Regs.CMPB = EPWM2_MIN_CMPB;              // Set Compare B value
    
        // Setup counter mode
        EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
        EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE;       // Disable phase loading
        EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;      // Clock ratio to SYSCLKOUT
        EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
        // Setup shadowing
        EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
        EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set actions
        EPwm2Regs.AQCTLA.bit.CAU = AQ_SET;           // Set PWM2A on event A, up
                                                     // count
        EPwm2Regs.AQCTLA.bit.CBD = AQ_CLEAR;         // Clear PWM2A on event B, down
                                                     // count
    
        EPwm2Regs.AQCTLB.bit.ZRO = AQ_CLEAR;         // Clear PWM2B on zero
        EPwm2Regs.AQCTLB.bit.PRD = AQ_SET  ;         // Set PWM2B on period
    
        // Interrupt where we will change the Compare Values
        EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;    // Select INT on Zero event
        EPwm2Regs.ETSEL.bit.INTEN = 1;               // Enable INT
        EPwm2Regs.ETPS.bit.INTPRD = ET_3RD;          // Generate INT on 3rd event
    
        // 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
        epwm2_info.EPwm_CMPA_Direction = EPWM_CMP_UP;  // Start by increasing CMPA &
        epwm2_info.EPwm_CMPB_Direction = EPWM_CMP_UP;  // increasing CMPB
        epwm2_info.EPwmTimerIntCount = 0;              // Zero the interrupt counter
        epwm2_info.EPwmRegHandle = &EPwm2Regs;         // Set the pointer to the
                                                       // ePWM module
        epwm2_info.EPwmMaxCMPA = EPWM2_MAX_CMPA;       // Setup min/max CMPA/CMPB
                                                       // values
        epwm2_info.EPwmMinCMPA = EPWM2_MIN_CMPA;
        epwm2_info.EPwmMaxCMPB = EPWM2_MAX_CMPB;
        epwm2_info.EPwmMinCMPB = EPWM2_MIN_CMPB;
    
    }
    
    void InitEPwm3Example(void)
    {
    
        // Setup TBCLK
        EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up/down
        EPwm3Regs.TBPRD = EPWM3_TIMER_TBPRD;         // Set timer period
        EPwm3Regs.TBCTL.bit.PHSEN = TB_DISABLE;      // Disable phase loading
        EPwm3Regs.TBPHS.half.TBPHS = 0x0000;         // Phase is 0
        EPwm3Regs.TBCTR = 0x0000;                    // Clear counter
        EPwm3Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;     // Clock ratio to SYSCLKOUT
        EPwm3Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
        // Setup shadow register load on ZERO
        EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
        EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set Compare values
        EPwm3Regs.CMPA.half.CMPA = EPWM3_MIN_CMPA;   // Set compare A value
        EPwm3Regs.CMPB = EPWM3_MAX_CMPB;             // Set Compare B value
    
        // Set Actions
        EPwm3Regs.AQCTLA.bit.PRD = AQ_SET;           // Set PWM3A on period
        EPwm3Regs.AQCTLA.bit.CBD = AQ_CLEAR;         // Clear PWM3A on event B, down
                                                     // count
    
        EPwm3Regs.AQCTLB.bit.PRD = AQ_CLEAR;         // Clear PWM3A on period
        EPwm3Regs.AQCTLB.bit.CAU = AQ_SET;           // Set PWM3A on event A, up
                                                     // count
    
        // Interrupt where we will change the Compare Values
        EPwm3Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;    // Select INT on Zero event
        EPwm3Regs.ETSEL.bit.INTEN = 1;               // Enable INT
        EPwm3Regs.ETPS.bit.INTPRD = ET_3RD;          // Generate INT on 3rd event
    
        // 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
        epwm3_info.EPwm_CMPA_Direction = EPWM_CMP_UP;  // Start by increasing CMPA &
        epwm3_info.EPwm_CMPB_Direction = EPWM_CMP_DOWN; // decreasing CMPB
        epwm3_info.EPwmTimerIntCount = 0;              // Zero the interrupt counter
        epwm3_info.EPwmRegHandle = &EPwm3Regs;         // Set the pointer to the
                                                       // ePWM module
        epwm3_info.EPwmMaxCMPA = EPWM3_MAX_CMPA;       // Setup min/max CMPA/CMPB
                                                       // values
        epwm3_info.EPwmMinCMPA = EPWM3_MIN_CMPA;
        epwm3_info.EPwmMaxCMPB = EPWM3_MAX_CMPB;
        epwm3_info.EPwmMinCMPB = EPWM3_MIN_CMPB;
    
    }
    
    void update_compare(EPWM_INFO *epwm_info)
    {
    
        // Every 10'th interrupt, change the CMPA/CMPB values
        if(epwm_info->EPwmTimerIntCount == 10)
        {
            epwm_info->EPwmTimerIntCount = 0;
    
            // 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->EPwm_CMPA_Direction == EPWM_CMP_UP)
            {
                if(epwm_info->EPwmRegHandle->CMPA.half.CMPA <
                   epwm_info->EPwmMaxCMPA)
                {
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA++;
                }
                else
                {
                    epwm_info->EPwm_CMPA_Direction = EPWM_CMP_DOWN;
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA--;
                }
            }
    
            // 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(epwm_info->EPwmRegHandle->CMPA.half.CMPA ==
                   epwm_info->EPwmMinCMPA)
                {
                    epwm_info->EPwm_CMPA_Direction = EPWM_CMP_UP;
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA++;
                }
                else
                {
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA--;
                }
            }
    
            // 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->EPwm_CMPB_Direction == EPWM_CMP_UP)
            {
                if(epwm_info->EPwmRegHandle->CMPB < epwm_info->EPwmMaxCMPB)
                {
                    epwm_info->EPwmRegHandle->CMPB++;
                }
                else
                {
                    epwm_info->EPwm_CMPB_Direction = EPWM_CMP_DOWN;
                    epwm_info->EPwmRegHandle->CMPB--;
                }
            }
    
            // 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(epwm_info->EPwmRegHandle->CMPB == epwm_info->EPwmMinCMPB)
                {
                    epwm_info->EPwm_CMPB_Direction = EPWM_CMP_UP;
                    epwm_info->EPwmRegHandle->CMPB++;
                }
                else
                {
                    epwm_info->EPwmRegHandle->CMPB--;
                }
            }
        }
        else
        {
            epwm_info->EPwmTimerIntCount++;
        }
    
        return;
    }
    
    
    
    

  • Any progress on this matter? We're facing the same problem on EPWM7...

  • If I remember correctly Jerome was eventually able to get these signals out of the device.

  • I was able to get all of the high number GPIO pwms working using the standard control suite project located here:

    C:\TI\controlSUITE\device_support\f28m36x\v201\F28M36x_examples_Control\epwm_updown_aq\c28

    and the attached file.

    //###########################################################################
    // FILE:   epwm_updown_aq_c28.c
    // TITLE:  Action Qualifier Module - Using up/down count.
    //
    //! \addtogroup control_example_list
    //! <h1> EPWM Action Qualifier (epwm_updown_aq)</h1>
    //!
    //! This example configures ePWM1, ePWM2, ePWM3 to produce an
    //! waveform with independant 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(PA0_GPIO0 & PA1_GPIO1), EPWM2A/B(PA2_GPIO2 & PA3_GPIO3)
    //! and EPWM3A/B(PA4_GPIO4 & PA5_GPIO5) waveforms via an oscilloscope.
    //
    //###########################################################################
    // $TI Release: F28M36x Support Library v201 $
    // $Release Date: Fri Jun  7 10:37:02 CDT 2013 $
    //###########################################################################
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    typedef struct
    {
        volatile struct EPWM_REGS *EPwmRegHandle;
        Uint16 EPwm_CMPA_Direction;
        Uint16 EPwm_CMPB_Direction;
        Uint16 EPwmTimerIntCount;
        Uint16 EPwmMaxCMPA;
        Uint16 EPwmMinCMPA;
        Uint16 EPwmMaxCMPB;
        Uint16 EPwmMinCMPB;
    }EPWM_INFO;
    
    // Prototype statements for functions found within this file.
    void InitEPwm1Example(void);
    void InitEPwm2Example(void);
    void InitEPwm3Example(void);
    __interrupt void epwm1_isr(void);
    __interrupt void epwm2_isr(void);
    __interrupt void epwm3_isr(void);
    void update_compare(EPWM_INFO*);
    
    // Global variables used in this example
    EPWM_INFO epwm1_info;
    EPWM_INFO epwm2_info;
    EPWM_INFO epwm3_info;
    
    // Configure the period for each timer
    #define EPWM1_TIMER_TBPRD  2000  // Period register
    #define EPWM1_MAX_CMPA     1950
    #define EPWM1_MIN_CMPA       50
    #define EPWM1_MAX_CMPB     1950
    #define EPWM1_MIN_CMPB       50
    
    #define EPWM2_TIMER_TBPRD  2000  // Period register
    #define EPWM2_MAX_CMPA     1950
    #define EPWM2_MIN_CMPA       50
    #define EPWM2_MAX_CMPB     1950
    #define EPWM2_MIN_CMPB       50
    
    #define EPWM3_TIMER_TBPRD  2000  // Period register
    #define EPWM3_MAX_CMPA      950
    #define EPWM3_MIN_CMPA       50
    #define EPWM3_MAX_CMPB     1950
    #define EPWM3_MIN_CMPB     1050
    
    // To keep track of which way the compare value is moving
    #define EPWM_CMP_UP   1
    #define EPWM_CMP_DOWN 0
    
    void main(void)
    {
    // Step 1. Initialize System Control:
    // Enable Peripheral Clocks
    // This example function is found in the F28M36x_SysCtrl.c file.
        InitSysCtrl();
    
    // Step 2. Initalize GPIO:
    // This example function is found in the F28M36x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();  // Skipped for this example
    
    // For this case just init GPIO pins for ePWM1, ePWM2, ePWM3
    // These functions are in the F28M36x_EPwm.c file
        //InitEPwm1Gpio();
        //InitEPwm2Gpio();
        //InitEPwm3Gpio();
        EALLOW;
        GpioCtrlRegs.GPDMUX2.bit.GPIO124 = 1;   // Configure GPIO124 as EPWM7A
        GpioCtrlRegs.GPDMUX2.bit.GPIO125 = 1;   // Configure GPIO125 as EPWM7B
        GpioCtrlRegs.GPDMUX2.bit.GPIO126 = 1;   // Configure GPIO124 as EPWM8A
        GpioCtrlRegs.GPDMUX2.bit.GPIO127 = 1;   // Configure GPIO125 as EPWM8B
        GpioCtrlRegs.GPEMUX1.bit.GPIO128 = 1;   // Configure GPIO124 as EPWM9A
        GpioCtrlRegs.GPEMUX1.bit.GPIO129 = 1;   // Configure GPIO125 as EPWM9B
        EDIS;
    
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
        DINT;
    
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F28M36x_PieCtrl.c file.
        InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
        IER = 0x0000;
        IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F28M36x_DefaultIsr.c.
    // This function is found in F28M36x_PieVect.c.
        InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
        EALLOW; // This is needed to write to EALLOW protected registers
        PieVectTable.EPWM7_INT = &epwm1_isr;
        PieVectTable.EPWM8_INT = &epwm2_isr;
        PieVectTable.EPWM9_INT = &epwm3_isr;
        EDIS;   // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in F28M36x_InitPeripherals.c
    // InitPeripherals();  // Not required for this example
    
    // For this example, only initialize the ePWM
    
        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
        EDIS;
    
        InitEPwm1Example();
        InitEPwm2Example();
        InitEPwm3Example();
    
        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
        EDIS;
    
    // Step 5. User specific code, enable interrupts:
    
    // Enable CPU INT3 which is connected to EPWM1-3 INT:
        IER |= M_INT3;
        IER |= M_INT5;
    
    // Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
        PieCtrlRegs.PIEIER3.bit.INTx7 = 1;
        PieCtrlRegs.PIEIER3.bit.INTx8 = 1;
        PieCtrlRegs.PIEIER5.bit.INTx8 = 1;
    
    // Enable global Interrupts and higher priority real-time debug events:
        EINT;  // Enable Global interrupt INTM
        ERTM;  // Enable Global realtime interrupt DBGM
    
    // Step 6. IDLE loop. Just sit and loop forever (optional):
        for(;;)
        {
            asm ("          NOP");
        }
    
    }
    
    __interrupt void epwm1_isr(void)
    {
        // Update the CMPA and CMPB values
        update_compare(&epwm1_info);
    
        // Clear INT flag for this timer
        EPwm7Regs.ETCLR.bit.INT = 1;
    
        // Acknowledge this interrupt to receive more interrupts from group 3
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    
    __interrupt void epwm2_isr(void)
    {
    
        // Update the CMPA and CMPB values
        update_compare(&epwm2_info);
    
        // Clear INT flag for this timer
        EPwm8Regs.ETCLR.bit.INT = 1;
    
        // Acknowledge this interrupt to receive more interrupts from group 3
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    }
    
    __interrupt void epwm3_isr(void)
    {
    
        // Update the CMPA and CMPB values
        update_compare(&epwm3_info);
    
        // Clear INT flag for this timer
        EPwm9Regs.ETCLR.bit.INT = 1;
    
        // Acknowledge this interrupt to receive more interrupts from group 3
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP5;
    }
    
    void InitEPwm1Example()
    {
    
        // Setup TBCLK
        EPwm7Regs.TBPRD = EPWM1_TIMER_TBPRD;          // Set timer period 801 TBCLKs
        EPwm7Regs.TBPHS.half.TBPHS = 0x0000;          // Phase is 0
        EPwm7Regs.TBCTR = 0x0000;                     // Clear counter
    
        // Set Compare values
        EPwm7Regs.CMPA.half.CMPA = EPWM1_MIN_CMPA;    // Set compare A value
        EPwm7Regs.CMPB = EPWM1_MAX_CMPB;              // Set Compare B value
    
        // Setup counter mode
        EPwm7Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
        EPwm7Regs.TBCTL.bit.PHSEN = TB_DISABLE;       // Disable phase loading
        EPwm7Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;      // Clock ratio to SYSCLKOUT
        EPwm7Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
        // Setup shadowing
        EPwm7Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm7Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm7Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
        EPwm7Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set actions
        EPwm7Regs.AQCTLA.bit.CAU = AQ_SET;            // Set PWM1A on event A, up
                                                     // count
        EPwm7Regs.AQCTLA.bit.CAD = AQ_CLEAR;          // Clear PWM1A on event A,
                                                      // down count
    
        EPwm7Regs.AQCTLB.bit.CBU = AQ_SET;            // Set PWM1B on event B, up
                                                      // count
        EPwm7Regs.AQCTLB.bit.CBD = AQ_CLEAR;          // Clear PWM1B on event B,
                                                      // down count
    
        // Interrupt where we will change the Compare Values
        EPwm7Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
        EPwm7Regs.ETSEL.bit.INTEN = 1;                // Enable INT
        EPwm7Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
    
        // 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
        epwm1_info.EPwm_CMPA_Direction = EPWM_CMP_UP;  // Start by increasing CMPA &
        epwm1_info.EPwm_CMPB_Direction = EPWM_CMP_DOWN; // decreasing CMPB
        epwm1_info.EPwmTimerIntCount = 0;              // Zero the interrupt counter
        epwm1_info.EPwmRegHandle = &EPwm7Regs;         // Set the pointer to the
                                                       // ePWM module
        epwm1_info.EPwmMaxCMPA = EPWM1_MAX_CMPA;       // Setup min/max CMPA/CMPB
                                                       // values
        epwm1_info.EPwmMinCMPA = EPWM1_MIN_CMPA;
        epwm1_info.EPwmMaxCMPB = EPWM1_MAX_CMPB;
        epwm1_info.EPwmMinCMPB = EPWM1_MIN_CMPB;
    
    }
    
    void InitEPwm2Example()
    {
    
        // Setup TBCLK
        EPwm8Regs.TBPRD = EPWM2_TIMER_TBPRD;          // Set timer period 801 TBCLKs
        EPwm8Regs.TBPHS.half.TBPHS = 0x0000;          // Phase is 0
        EPwm8Regs.TBCTR = 0x0000;                     // Clear counter
    
        // Set Compare values
        EPwm8Regs.CMPA.half.CMPA = EPWM2_MIN_CMPA;    // Set compare A value
        EPwm8Regs.CMPB = EPWM2_MIN_CMPB;              // Set Compare B value
    
        // Setup counter mode
        EPwm8Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
        EPwm8Regs.TBCTL.bit.PHSEN = TB_DISABLE;       // Disable phase loading
        EPwm8Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;      // Clock ratio to SYSCLKOUT
        EPwm8Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
        // Setup shadowing
        EPwm8Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm8Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm8Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
        EPwm8Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set actions
        EPwm8Regs.AQCTLA.bit.CAU = AQ_SET;           // Set PWM2A on event A, up
                                                     // count
        EPwm8Regs.AQCTLA.bit.CBD = AQ_CLEAR;         // Clear PWM2A on event B, down
                                                     // count
    
        EPwm8Regs.AQCTLB.bit.ZRO = AQ_CLEAR;         // Clear PWM2B on zero
        EPwm8Regs.AQCTLB.bit.PRD = AQ_SET  ;         // Set PWM2B on period
    
        // Interrupt where we will change the Compare Values
        EPwm8Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;    // Select INT on Zero event
        EPwm8Regs.ETSEL.bit.INTEN = 1;               // Enable INT
        EPwm8Regs.ETPS.bit.INTPRD = ET_3RD;          // Generate INT on 3rd event
    
        // 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
        epwm2_info.EPwm_CMPA_Direction = EPWM_CMP_UP;  // Start by increasing CMPA &
        epwm2_info.EPwm_CMPB_Direction = EPWM_CMP_UP;  // increasing CMPB
        epwm2_info.EPwmTimerIntCount = 0;              // Zero the interrupt counter
        epwm2_info.EPwmRegHandle = &EPwm8Regs;         // Set the pointer to the
                                                       // ePWM module
        epwm2_info.EPwmMaxCMPA = EPWM2_MAX_CMPA;       // Setup min/max CMPA/CMPB
                                                       // values
        epwm2_info.EPwmMinCMPA = EPWM2_MIN_CMPA;
        epwm2_info.EPwmMaxCMPB = EPWM2_MAX_CMPB;
        epwm2_info.EPwmMinCMPB = EPWM2_MIN_CMPB;
    
    }
    
    void InitEPwm3Example(void)
    {
    
        // Setup TBCLK
        EPwm9Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up/down
        EPwm9Regs.TBPRD = EPWM3_TIMER_TBPRD;         // Set timer period
        EPwm9Regs.TBCTL.bit.PHSEN = TB_DISABLE;      // Disable phase loading
        EPwm9Regs.TBPHS.half.TBPHS = 0x0000;         // Phase is 0
        EPwm9Regs.TBCTR = 0x0000;                    // Clear counter
        EPwm9Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;     // Clock ratio to SYSCLKOUT
        EPwm9Regs.TBCTL.bit.CLKDIV = TB_DIV1;
    
        // Setup shadow register load on ZERO
        EPwm9Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
        EPwm9Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
        EPwm9Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
        EPwm9Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    
        // Set Compare values
        EPwm9Regs.CMPA.half.CMPA = EPWM3_MIN_CMPA;   // Set compare A value
        EPwm9Regs.CMPB = EPWM3_MAX_CMPB;             // Set Compare B value
    
        // Set Actions
        EPwm9Regs.AQCTLA.bit.PRD = AQ_SET;           // Set PWM3A on period
        EPwm9Regs.AQCTLA.bit.CBD = AQ_CLEAR;         // Clear PWM3A on event B, down
                                                     // count
    
        EPwm9Regs.AQCTLB.bit.PRD = AQ_CLEAR;         // Clear PWM3A on period
        EPwm9Regs.AQCTLB.bit.CAU = AQ_SET;           // Set PWM3A on event A, up
                                                     // count
    
        // Interrupt where we will change the Compare Values
        EPwm9Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;    // Select INT on Zero event
        EPwm9Regs.ETSEL.bit.INTEN = 1;               // Enable INT
        EPwm9Regs.ETPS.bit.INTPRD = ET_3RD;          // Generate INT on 3rd event
    
        // 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
        epwm3_info.EPwm_CMPA_Direction = EPWM_CMP_UP;  // Start by increasing CMPA &
        epwm3_info.EPwm_CMPB_Direction = EPWM_CMP_DOWN; // decreasing CMPB
        epwm3_info.EPwmTimerIntCount = 0;              // Zero the interrupt counter
        epwm3_info.EPwmRegHandle = &EPwm9Regs;         // Set the pointer to the
                                                       // ePWM module
        epwm3_info.EPwmMaxCMPA = EPWM3_MAX_CMPA;       // Setup min/max CMPA/CMPB
                                                       // values
        epwm3_info.EPwmMinCMPA = EPWM3_MIN_CMPA;
        epwm3_info.EPwmMaxCMPB = EPWM3_MAX_CMPB;
        epwm3_info.EPwmMinCMPB = EPWM3_MIN_CMPB;
    
    }
    
    void update_compare(EPWM_INFO *epwm_info)
    {
    
        // Every 10'th interrupt, change the CMPA/CMPB values
        if(epwm_info->EPwmTimerIntCount == 10)
        {
            epwm_info->EPwmTimerIntCount = 0;
    
            // 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->EPwm_CMPA_Direction == EPWM_CMP_UP)
            {
                if(epwm_info->EPwmRegHandle->CMPA.half.CMPA <
                   epwm_info->EPwmMaxCMPA)
                {
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA++;
                }
                else
                {
                    epwm_info->EPwm_CMPA_Direction = EPWM_CMP_DOWN;
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA--;
                }
            }
    
            // 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(epwm_info->EPwmRegHandle->CMPA.half.CMPA ==
                   epwm_info->EPwmMinCMPA)
                {
                    epwm_info->EPwm_CMPA_Direction = EPWM_CMP_UP;
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA++;
                }
                else
                {
                    epwm_info->EPwmRegHandle->CMPA.half.CMPA--;
                }
            }
    
            // 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->EPwm_CMPB_Direction == EPWM_CMP_UP)
            {
                if(epwm_info->EPwmRegHandle->CMPB < epwm_info->EPwmMaxCMPB)
                {
                    epwm_info->EPwmRegHandle->CMPB++;
                }
                else
                {
                    epwm_info->EPwm_CMPB_Direction = EPWM_CMP_DOWN;
                    epwm_info->EPwmRegHandle->CMPB--;
                }
            }
    
            // 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(epwm_info->EPwmRegHandle->CMPB == epwm_info->EPwmMinCMPB)
                {
                    epwm_info->EPwm_CMPB_Direction = EPWM_CMP_UP;
                    epwm_info->EPwmRegHandle->CMPB++;
                }
                else
                {
                    epwm_info->EPwmRegHandle->CMPB--;
                }
            }
        }
        else
        {
            epwm_info->EPwmTimerIntCount++;
        }
    
        return;
    }