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.

TMS320F28379D: EPwm Sync Example Request

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE

All:

There are a lot of nuances with respect to sychronization of EPwms. Can someone create an example for C2000Ware that will set up sync of EPwm1, EPwm2, EPwm3, and EPwm4 to show how it is done?

All 4 can be the same period if that helps.Also, set up associated GPIO so the waveforms can be viewed on Oscilloscope or Logic Analyzer.

  • I am working on this for you!

  • //
    //  Nima Eskadari
    //  1/31/2019
    //
    
    
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    #define EPWM_TIMER_TBPRD    2000
    
    //
    // Function Prototypes
    //
    void initEPWM(uint32_t epwm_base);
    void initEPWMWithOffset(uint32_t epwm_base, uint16_t offset);
    
    __interrupt void epwm1ISR(void);
    __interrupt void epwm2ISR(void);
    __interrupt void epwm3ISR(void);
    __interrupt void epwm4ISR(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);
        Interrupt_register(INT_EPWM3, &epwm3ISR);
        Interrupt_register(INT_EPWM4, &epwm4ISR);
    
        //
        // Configure GPIO0/1 , GPIO2/3 and GPIO4/5 as ePWM1A/1B, ePWM2A/2B and
        // ePWM3A/3B 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(4, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_4_EPWM3A);
        GPIO_setPadConfig(5, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_5_EPWM3B);
    
        GPIO_setPadConfig(6, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_6_EPWM4A);
        GPIO_setPadConfig(7, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_7_EPWM4B);
    
    
        // CHANGE XBAR inputs from using GPIO0
        // if EPWM SYNCIN is enabled, EXTSYNCIN1 and EXTSYNCIN2 will use
        // GPIO0 (which is the output of EPWM1).
        // Pick and unused GPIO
        XBAR_setInputPin(XBAR_INPUT5, 50);
        XBAR_setInputPin(XBAR_INPUT6, 50);
    
        //
        // Disable sync(Freeze clock to PWM as well)
        //
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        initEPWM(EPWM1_BASE);
        initEPWMWithOffset(EPWM2_BASE, 300);
        initEPWMWithOffset(EPWM3_BASE, 600);
        initEPWMWithOffset(EPWM4_BASE, 900);
    
    
        EPWM_setSyncOutPulseMode(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
        EPWM_setSyncOutPulseMode(EPWM2_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);
        EPWM_enablePhaseShiftLoad(EPWM2_BASE);
        EPWM_enablePhaseShiftLoad(EPWM3_BASE);
        SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
        EPWM_enablePhaseShiftLoad(EPWM4_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);
        Interrupt_enable(INT_EPWM4);
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // IDLE loop. Just sit and loop forever (optional):
        //
    
        for(;;)
        {
    
        }
    }
    
    //
    // epwm1ISR - ePWM 1 ISR
    //
    __interrupt void epwm1ISR(void)
    {
    
        //
        // 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)
    {
        //
        // Clear INT flag for this timer
        //
        EPWM_clearEventTriggerInterruptFlag(EPWM2_BASE);
    
        //
        // Acknowledge interrupt group
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    //
    // epwm3ISR - ePWM 3 ISR
    //
    __interrupt void epwm3ISR(void)
    {
        //
        // Clear INT flag for this timer
        //
        EPWM_clearEventTriggerInterruptFlag(EPWM3_BASE);
    
        //
        // Acknowledge interrupt group
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    //
    // epwm4ISR - ePWM 4 ISR
    //
    __interrupt void epwm4ISR(void)
    {
        //
        // Clear INT flag for this timer
        //
        EPWM_clearEventTriggerInterruptFlag(EPWM4_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,
                                    2*EPWM_TIMER_TBPRD/3);
        EPWM_setCounterCompareValue(epwm_base,
                                    EPWM_COUNTER_COMPARE_B,
                                    2*EPWM_TIMER_TBPRD/3);
    
        //
        // 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_ZERO);
    
    
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    
    
        //
        // 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(epwm_base, EPWM_INT_TBCTR_ZERO);
        EPWM_enableInterrupt(epwm_base);
        EPWM_setInterruptEventCount(epwm_base, 1U);
    }
    
    
    void initEPWMWithOffset(uint32_t epwm_base, uint16_t offset)
    {
        //
        // Set-up TBCLK
        //
    
        EPWM_selectPeriodLoadEvent(epwm_base, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_setTimeBasePeriod(epwm_base, EPWM_TIMER_TBPRD);
        EPWM_setPhaseShift(epwm_base, offset);
        EPWM_setTimeBaseCounter(epwm_base, offset);
    
        //
        // Set Compare values
        //
        EPWM_setCounterCompareValue(epwm_base,
                                    EPWM_COUNTER_COMPARE_A,
                                    2*EPWM_TIMER_TBPRD/3);
        EPWM_setCounterCompareValue(epwm_base,
                                    EPWM_COUNTER_COMPARE_B,
                                    2*EPWM_TIMER_TBPRD/3);
    
        //
        // 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_ZERO);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(epwm_base,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    
    
        //
        // 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(epwm_base, EPWM_INT_TBCTR_U_CMPA);
        EPWM_enableInterrupt(epwm_base);
        EPWM_setInterruptEventCount(epwm_base, 1U);
    
    }
    

    REQUEST:

    Here you go. EPWM1 as master, EPWM2 following master and passing its sync input to its sync output. EPWM3 following EPWM2 (which is just forwarding EPWM1). EPWM4 following EPWM1 master.

    RESULT:

    Yellow EPWM1A. Green EPWM2A, PURPLE EPWM3A, PINK EPWM4A

  • Nima:
    Thanks for responding with code and with traces of the code. Do you plan to include in future C2000Ware release?

    I have been working on up-down Pwms, and it is interesting how I have been able to progress:
    I am working initially with 2 waveforms, each 8 KHz. I used code from the multi-day workshop for PWM, and it sets up the PWMs, then enables the clocks to the PWMs, so the 2 PWMs started in sync with each other. To create an offset synchronization, I needed to Enable the sync out of PWM1 (at 0 period). In PWM2, I set up the time-base control register (TBCTL): PHSDIR = 0 to count down after the sync event. I also set up PHSEN to 1 to enable phase. Finally, I loaded the TBPHS with the same number as the period. So, as PWM1 was counting up to the period match, PWM2 was initially counting down, so I was able to see that with TBPHS = TBPRD, the waveforms were 180 degrees from each other.

    We plan to have multiple PWMs, each slightly out of phase, so the associated ADCs will not all "come at once".
  • I will work with the software tean to add this to C2000WARE. If you ever have any other example code ideas you would like to see in C2000WARE, please always let me know.