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.

TMS320F280049: PWM startup at a defined phase angle

Genius 12760 points

Part Number: TMS320F280049

Working on a LLC converters, a question regarding the PWM peripheral on TMS320F28004x has come up.

We use burst mode to regulate our converter in operating conditions where standard PFM cannot achieve the required voltage-gains.

When starting our LLC converters, we usually work with a high frequency pulse package to initialize the resonant tank to a steady state and then run from this pre-initialized state.

Now in this new LLC converter I prefer not to go too high with the initial switching frequency during this startup pulses. In order to get the resonant tank into an equilibrium an alternative approach is to startup the PWM a predefined phase angle, thus controlling the trajectory of the resonant tank in the first pulse.

This means still preserving PFM but just starting up PWMs at a predefined counter value.

So the desired sequence would be:

  • Set TBCTR of module 0 = <some-predefined-value-of-our-choosing> (primary side FETs)
  • Set TBCTR of module 1 = <some-predefined-value-of-our-choosing> (secondary side FETs)
  • Run PWM
  • Enable PWM output

I have already tried to manually set the counter values, but unfortunately this completely screws up the synchronization between modules and the PWM produces strange waveforms. This led me to the conclusion that this is not the proper way.

We currently use TZFRC and TZCLR registers to enable/disable the PWM outputs. However, since these registers act further down the PWM generation chain, they cannot affect the phase angle at which the outputs get enabled. In our application the phase angle is simply random, which is fine most of the time.

And looking at the reference manual, I don’t really see any other way…

Some other information that might be relevant:

  • Peripheral configured in up-count mode
  • Module 0 triggers reload on Module 1
  • Each module is configured in complementary mode
  • The control loop is not run from any PWM triggers and is triggered from a CPU timer
  • All registers are shadowed
  • We use global reload

How can we solve this challange.

Regards,Bernd

  • Okay your first method should work and I think I know why its not working. The period is probably not loaded when you start at a different value than zero when you start your PWM for the first time and that is because the load occurs at zero and since you start from a non zero value, it must go all the way to 0xFFFF before it hits zero and all you configs take place. Take a look at this example, it is for F28379D but it should be identical to what you would use on F28004x. It starts from non zero values, everything syncs on SYNCIN. not only that the period is loaded at start.

    //
    //  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);
    
    __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 and GPIO6/7 as
        // ePWM1A/1B, ePWM2A/2B, ePWM3A/3B, ePWM4A/4B 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);
    
        initEPWM(EPWM2_BASE);
        EPWM_selectPeriodLoadEvent(EPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_setPhaseShift(EPWM2_BASE, 300);
        EPWM_setTimeBaseCounter(EPWM2_BASE, 300);
    
        initEPWM(EPWM3_BASE);
        EPWM_selectPeriodLoadEvent(EPWM3_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_setPhaseShift(EPWM3_BASE, 600);
        EPWM_setTimeBaseCounter(EPWM3_BASE, 600);
    
        initEPWM(EPWM4_BASE);
        EPWM_selectPeriodLoadEvent(EPWM4_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_setPhaseShift(EPWM4_BASE, 900);
        EPWM_setTimeBaseCounter(EPWM4_BASE, 900);
    
        EPWM_setSyncOutPulseMode(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
        EPWM_setSyncOutPulseMode(EPWM2_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);
        SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    
        EPWM_enablePhaseShiftLoad(EPWM2_BASE);
        EPWM_enablePhaseShiftLoad(EPWM3_BASE);
        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,
                                    EPWM_TIMER_TBPRD/2);
        EPWM_setCounterCompareValue(epwm_base,
                                    EPWM_COUNTER_COMPARE_B,
                                    EPWM_TIMER_TBPRD/4);
    
        //
        // 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);
    }