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.

[FAQ] TMS320F28379D: How can I generate an ePWM interrupt on both CMPA and CMPB events?

Part Number: TMS320F28379D

QUESTION: How can I generate an interrupt for both CMPA and CMPB events? There is no option to select both CMPA AND CMPB to generate an interrupt for my ePWM module, can this be done?

  • ANSWER:

    Yes. The most efficient way of doing this is using two ePWM modules, enabling the sync between the two, and linking the CMPx and TBPRD registers.

    This allows the two ePWM modules to generate IDENTICAL waveform. Next you can set up the interrupts for the first ePWM module to occur at CMPA and the interrupts for the second ePWM module to occur at CMPB.

    The example below showcases ePWM1 and ePWM2 accomplishing this.

    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    #define EPWM_TIMER_TBPRD    1000
    
    //
    // Function Prototypes
    //
    void initEPWM(uint32_t epwm_base);
    
    __interrupt void epwm1ISR(void);
    __interrupt void epwm2ISR(void);
    
    //
    // 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);
    
        //
        // Configure GPIO0/1 , GPIO2/3 as ePWM1A/1B, ePWM2A/2B
        // pins respectively
        //
        GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_0_EPWM1A);
        GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_1_EPWM1B);
    
        GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_2_EPWM2A);
        GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_3_EPWM2B);
    
        GPIO_setPadConfig(6, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_6_GPIO6);
        GPIO_setDirectionMode(6, GPIO_DIR_MODE_OUT);
    
        GPIO_setPadConfig(7, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_7_GPIO7);
        GPIO_setDirectionMode(7, GPIO_DIR_MODE_OUT);
    
        //
        // Disable sync(Freeze clock to PWM as well)
        //
    
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC);
    
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        initEPWM(EPWM1_BASE);
        initEPWM(EPWM2_BASE);
    
        EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_U_CMPA);
        EPWM_setInterruptSource(EPWM2_BASE, EPWM_INT_TBCTR_U_CMPB);
    
        EPWM_setupEPWMLinks(EPWM2_BASE, EPWM_LINK_WITH_EPWM_1, EPWM_LINK_COMP_A);
        EPWM_setupEPWMLinks(EPWM2_BASE, EPWM_LINK_WITH_EPWM_1, EPWM_LINK_COMP_B);
        EPWM_setupEPWMLinks(EPWM2_BASE, EPWM_LINK_WITH_EPWM_1, EPWM_LINK_TBPRD);
    
        EPWM_setSyncOutPulseMode(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
        EPWM_enablePhaseShiftLoad(EPWM2_BASE);
    
    
        //
        // Enable sync and clock to PWM
        //
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
    
        // Enable ePWM interrupts
        //
        Interrupt_enable(INT_EPWM1);
        Interrupt_enable(INT_EPWM2);
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // IDLE loop. Just sit and loop forever (optional):
        //
    
        for(;;)
        {
            EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 400);
            EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_B, 800);
            SysCtl_delay(20000);
    
            EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 800);
            EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_B, 300);
            SysCtl_delay(20000);
    
        }
    }
    
    //
    // epwm1ISR - ePWM 1 ISR
    //
    __interrupt void epwm1ISR(void)
    {
        GPIO_togglePin(6);
        //
        // Clear INT flag for this timer
        //
        EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
    
        //
        // Acknowledge interrupt group
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    //
    // epwm2ISR - ePWM 2 ISR
    //
    __interrupt void epwm2ISR(void)
    {
        GPIO_togglePin(7);
        //
        // Clear INT flag for this timer
        //
        EPWM_clearEventTriggerInterruptFlag(EPWM2_BASE);
    
        //
        // Acknowledge interrupt group
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    void initEPWM(uint32_t epwm_base)
    {
        //
        // Set-up TBCLK
        //
        EPWM_setTimeBasePeriod(epwm_base, EPWM_TIMER_TBPRD);
        EPWM_setPhaseShift(epwm_base, 0U);
        EPWM_setTimeBaseCounter(epwm_base, 0U);
    
        //
        // Set Compare values
        //
        EPWM_setCounterCompareValue(epwm_base,
                                    EPWM_COUNTER_COMPARE_A,
                                    EPWM_TIMER_TBPRD/3);
        EPWM_setCounterCompareValue(epwm_base,
                                    EPWM_COUNTER_COMPARE_B,
                                    EPWM_TIMER_TBPRD/2);
    
        //
        // Set up counter mode
        //
        EPWM_setTimeBaseCounterMode(epwm_base, EPWM_COUNTER_MODE_UP);
        EPWM_disablePhaseShiftLoad(epwm_base);
        EPWM_setClockPrescaler(epwm_base,
                               EPWM_CLOCK_DIVIDER_8,
                               EPWM_HSCLOCK_DIVIDER_1);
    
        //
        // Set up shadowing
        //
        EPWM_setCounterCompareShadowLoadMode(epwm_base,
                                             EPWM_COUNTER_COMPARE_A,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
        EPWM_setCounterCompareShadowLoadMode(epwm_base,
                                             EPWM_COUNTER_COMPARE_B,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
        //
        // Set actions
        //
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    
    
        //
        // Interrupt where we will change the Compare Values
        //
        EPWM_enableInterrupt(epwm_base);
        EPWM_setInterruptEventCount(epwm_base, 1U);
    }

    Same thing can be done to generate an ePWM interrupt on both count UP and count DOWN of a CMPx. Minor changes to the code such as changing the TB mode to UP/DOWN and the interrupt source events must take place.

    The code above generates Identical waveform for ePWM1 and ePWM2. The TBPRD, CMPA and CMPB of the two modules are linked, therefor a write to CMPA of ePWM1 will also have the same effect on ePWM2.

    ePWM1 and ePWM2 Identical Outputs

    GPIO6 and GPIO7 Toggled in Interrupts