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: Dealing with variations in grid frequency in grid connected single phase inverters.

Part Number: TMS320F28379D
Other Parts Discussed in Thread: TIDM-HV-1PH-DCAC

Good day to you all.

I've got a similar question though its about the single phase inverter in TIDM-HV-1PH-DCAC grid tie inverter. In the literature, you say that you are using a modified unipolar modulation scheme where switches Q3 and Q4 switch at the grid frequency. I've studied the code and have the following questions;

1) How do you handle variations in grid frequency so as to change the frequency of Q3 and Q4 when the grid frequency varies yet you are using SPLL-SOGI? 

  • I did study the SPLL-1PH-SOGI code and the measured ac grid frequency is extracted and it can be used as the switching frequency of Q3 and Q4 (switching at grid frequency). 

    How do I set these switches to start switching at the point when the ac wave is crossing the zero point?

  • THe design bases the PWM modulation on the duty cycle commanded and not directly the AC voltage itself. 

    Please see the code, where we have updateInverterPWM 

  • Thanks for your reply Manish, though I have a few more questions. 

    In document "Grid Connected Inverter Design Guide", section 2.1 Modulation scheme, it's clearly stated that a modified unipolar modulation scheme is used in which Q1 and Q2 are switched at a high frequency and Q3 and Q4 are switched at a low frequency which is the grid frequency. Though in the code, both ePWM1 (drives Q1 and Q2) and ePWM2 (drives Q3 and Q4) have their periods set to the same value of INV_PWM_PERIOD as shown in the setupInverterPWM function code below; 

    void setupInverterPWM(uint32_t base1, uint32_t base2, uint16_t pwm_period_ticks, uint16_t pwm_dbred_ticks, uint16_t pwm_dbfed_ticks)
    {
        EALLOW;
    
        // PWM clock on F2837x is divided by 2
        // ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV=1
        // Deadband needs to be 0.5us => 10ns*50=500ns
        // Time Base SubModule Registers
        EPWM_setPeriodLoadMode(base1,EPWM_PERIOD_SHADOW_LOAD);
        EPWM_setTimeBasePeriod(base1,pwm_period_ticks >>1);
        EPWM_setTimeBaseCounter(base1,0);
        EPWM_setPhaseShift(base1,0);
        EPWM_setTimeBaseCounterMode(base1,EPWM_COUNTER_MODE_UP_DOWN);
        EPWM_setClockPrescaler(base1,EPWM_CLOCK_DIVIDER_1,EPWM_HSCLOCK_DIVIDER_1);
    
        EPWM_setPeriodLoadMode(base2,EPWM_PERIOD_SHADOW_LOAD);
        EPWM_setTimeBasePeriod(base2,pwm_period_ticks >>1);
        EPWM_setTimeBaseCounter(base2,0);
        EPWM_setPhaseShift(base2,0);
        EPWM_setTimeBaseCounterMode(base2,EPWM_COUNTER_MODE_UP_DOWN);
        EPWM_setClockPrescaler(base2,EPWM_CLOCK_DIVIDER_1,EPWM_HSCLOCK_DIVIDER_1);
    
        // Counter Compare Submodule Registers
        EPWM_setCounterCompareValue(base1,EPWM_COUNTER_COMPARE_A,0); // set duty 0% initially
        EPWM_setCounterCompareShadowLoadMode(base1,EPWM_COUNTER_COMPARE_A,EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
        EPWM_setCounterCompareValue(base2,EPWM_COUNTER_COMPARE_A,0); // set duty 0% initially
        // set as immediate mode
        EPWM_disableCounterCompareShadowLoadMode(base2,EPWM_COUNTER_COMPARE_A);
    
        // Action Qualifier SubModule Registers
        EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_TOGGLE,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
        EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        // to start don't configure the PWM to do anything
        HWREGH(base1 + EPWM_O_AQCTLA) =0 ;
        HWREGH(base2 + EPWM_O_AQCTLA) =0 ;
    
        // CTR = CMPA@Down , clear
        EPWM_setActionQualifierAction(base2, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    
        // Active high complementary PWMs - Set up the deadband
        EPWM_setDeadBandCounterClock(base1,EPWM_DB_COUNTER_CLOCK_FULL_CYCLE);
        EPWM_setRisingEdgeDelayCount(base1,pwm_dbred_ticks);
        EPWM_setFallingEdgeDelayCount(base1,pwm_dbred_ticks);
        EPWM_setDeadBandDelayMode(base1,EPWM_DB_RED,true);
        EPWM_setDeadBandDelayMode(base1,EPWM_DB_FED,true);
        EPWM_setRisingEdgeDeadBandDelayInput(base1,EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(base1,EPWM_DB_INPUT_EPWMA);
        EPWM_setDeadBandDelayPolarity(base1,EPWM_DB_FED,EPWM_DB_POLARITY_ACTIVE_LOW);
        EPWM_setDeadBandDelayPolarity(base1,EPWM_DB_RED,EPWM_DB_POLARITY_ACTIVE_HIGH);
    
        EPWM_setDeadBandCounterClock(base2,EPWM_DB_COUNTER_CLOCK_FULL_CYCLE);
        EPWM_setRisingEdgeDelayCount(base2,pwm_dbred_ticks);
        EPWM_setFallingEdgeDelayCount(base2,pwm_dbred_ticks);
        EPWM_setDeadBandDelayMode(base2,EPWM_DB_RED,true);
        EPWM_setDeadBandDelayMode(base2,EPWM_DB_FED,true);
        EPWM_setRisingEdgeDeadBandDelayInput(base2,EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(base2,EPWM_DB_INPUT_EPWMA);
        EPWM_setDeadBandDelayPolarity(base2,EPWM_DB_FED,EPWM_DB_POLARITY_ACTIVE_LOW);
        EPWM_setDeadBandDelayPolarity(base2,EPWM_DB_RED,EPWM_DB_POLARITY_ACTIVE_HIGH);
    
        // configure PWM 1 as master and Phase 2 as slaves and let it pass the sync in pulse from PWM1
        EPWM_disablePhaseShiftLoad(base1);
        EPWM_setSyncOutPulseMode(base1,EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
        EPWM_enablePhaseShiftLoad(base2);
        EPWM_setSyncOutPulseMode(base2,EPWM_SYNC_OUT_PULSE_ON_SOFTWARE);
        EPWM_setPhaseShift(base2,2);
        EPWM_setCountModeAfterSync(base2, EPWM_COUNT_MODE_UP_AFTER_SYNC);
    
        GPIO_setDirectionMode(INV_PWM1_H_GPIO,GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(INV_PWM1_H_GPIO,GPIO_PIN_TYPE_STD); // disable pull up
        GPIO_setPinConfig(INV_PWM1_H_GPIO_PIN_CONFIG);
    
        GPIO_setDirectionMode(INV_PWM1_L_GPIO,GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(INV_PWM1_L_GPIO,GPIO_PIN_TYPE_STD); // disable pull up
        GPIO_setPinConfig(INV_PWM1_L_GPIO_PIN_CONFIG);
    
        GPIO_setDirectionMode(INV_PWM2_H_GPIO,GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(INV_PWM2_H_GPIO,GPIO_PIN_TYPE_STD); // disable pull up
        GPIO_setPinConfig(INV_PWM2_H_GPIO_PIN_CONFIG);
    
        GPIO_setDirectionMode(INV_PWM2_L_GPIO,GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(INV_PWM2_L_GPIO,GPIO_PIN_TYPE_STD); // disable pull up
        GPIO_setPinConfig(INV_PWM2_L_GPIO_PIN_CONFIG);
    
    }

    How do you then get to make Q3 and Q4 then switch at the grid frequency? 

  • Please explain to me how the function updateInverterPWM makes Q3 and Q4 switch at a low frequency ( grid frequency) as is stated in document Grid Connected Inverter design guide section 2.1 Modulation scheme? Attached is the code of updateInverterPWM function.

    inline void updateInverterPWM(uint32_t base1, uint32_t base2, float32_t duty)
    {
        uint16_t invDuty;
    
        invDuty= ((float32_t)(INV_PWM_PERIOD/2.0)) * (1-fabs(duty));
    
    	if(invDuty==(EPWM_getTimeBasePeriod(base1)))
    	{
    		invDuty=invDuty-1;
    	}
    
        EPWM_setCounterCompareValue(base1,EPWM_COUNTER_COMPARE_A,invDuty);
        EPWM_setCounterCompareValue(base2,EPWM_COUNTER_COMPARE_A,1);
    
        // wait for the PWM to start counting down
        if(EPWM_getTimeBaseCounterDirection(base1)==0) // make sure the PWM is counting down
        {
            if(duty>=0)
            {
                // CTR = CMPA@UP , set to 1
                EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
                // CTR = CMPA@Down , toggle
                EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_TOGGLE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
                // CTR=0, clear to 0
                EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
                // CTR = CMPA@Down , clear
                EPWM_setActionQualifierAction(base2, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
            }
    		else
            {
                // CTR = CMPA@UP , clear to 0
                EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
                // CTR = CMPA@Down , toggle
                EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_TOGGLE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
                // CTR=0, set to 1
                EPWM_setActionQualifierAction(base1, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
                // CTR = CMPA@Down , set
                EPWM_setActionQualifierAction(base2, EPWM_AQ_OUTPUT_A ,
                        EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
            }
    	}
    
    }

  • I have studied the code of the function updateinverterPWM and I have come to the following conclusions on how to make Q3 and Q4 switch at the grid frequency, please correct me where you find me wrong;

    1) The InvDutyPU variable can take on both positive and negative value.

    2) CMPA value of INV_PWM2_BASE (ePWM2) is set to 1. This value is very small in comparison to the period count. This small CMPA value is always compared with the time base counter value, since the CMPA value of ePWM2 does not change, during the positive half cycle of the ac voltage, only Q3 will be switched on, the same argument is applied for the negative half cycle. 

    If am correct, then I get how you switch Q3 and Q4 at the grid frequency. 

  • Yes, the small value will typically be eaten by the deatime itself.