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.

Close loop in H bridge buck boost DC/DC converter using TMS320F28027(c2000 LP), PWM ON/OFF frequently

Other Parts Discussed in Thread: TMS320F28027

Hello,

I am using TMS320F28027 LP for close loop control and PWM generation of H-bridge buck boost converter. It is a bit modified design of buck-boost having One Mosfet and One Diode in each leg.

Above image depicts the topology. With below ratings:

Vin: 19-100V

Vout: 72V

Power: 500W

Fsw: 75 kHz

I am using TMS320F28027 launchpad for close loop control and PWM generation. Both the pulses for top and bottom mosfet are same (ton and toff are same). The issue is, it works fine in complete range till 200 Ohm load, but as I reduce the load (increase the current level) PWM starts to ON/OFF frequently. This may be due to Noise, but controller pulses also turns on and off frequntly on low load. Currently I am only taking the output voltage feedback and changing the pulse width as the the feedback voltage. I seen and used some example and forum code and modified it a bit.

Can someone look at the code and let me know the issue with it..?

Thanks.

// Code for H bridge buck boost converter PWM 

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

#include "f2802x_common/include/adc.h"
#include "f2802x_common/include/clk.h"
#include "f2802x_common/include/flash.h"
#include "f2802x_common/include/gpio.h"
#include "f2802x_common/include/pie.h"
#include "f2802x_common/include/pll.h"
#include "f2802x_common/include/pwm.h"
#include "f2802x_common/include/wdog.h"

// Prototype statements for functions found within this file.
#define PWM1_TIMER_TBPRD   0x0190		//TBPRD = 400 == 75Khz
__interrupt void adc_isr(void);
void InitEPwm1(void);
// Global variables used in this example:
uint16_t LoopCount;
uint16_t ConversionCount;
//uint16_t V1, V2, V3;
uint16_t V4, V5, V6;
uint16_t Voltage1[20];
 float Vout_count,Va,sum = 0;
 float err_5, A_5=0,B_5=0, v_5=0, Vpi_5 = 0;
static float in_A = 0.0, k_5 = 0.0;
float V_duty;
float comp_value, Duty;
/*** PI controller **/


	float Kp = 0.1;		// [0] proportional gain
 	float Ki = 0.05;		// [2] integral gain
 	float i10;		        // [4] I storage
	float Umax = 0.99;		// [6] upper saturation limit
	float Umin = -0.99;		// [8] lower saturation limit
	float i6;		        // [A] saturation storage

ADC_Handle myAdc;
CLK_Handle myClk;
FLASH_Handle myFlash;
GPIO_Handle myGpio;
PIE_Handle myPie;
PWM_Handle myPwm1, myPwm2;

void main(void)

{

    CPU_Handle myCpu;
    PLL_Handle myPll;
    WDOG_Handle myWDog;

    // Initialize all the handles needed for this application
    myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));
    myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
    myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));
    myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
    myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
    myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
    myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
    myPwm2 = PWM_init((void *)PWM_ePWM2_BASE_ADDR, sizeof(PWM_Obj));
    myPwm1 = PWM_init((void *)PWM_ePWM1_BASE_ADDR, sizeof(PWM_Obj));
    myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));

    // Perform basic system initialization
    WDOG_disable(myWDog);
    CLK_enableAdcClock(myClk);
    (*Device_cal)();

    //Select the internal oscillator 1 as the clock source
    CLK_setOscSrc(myClk, CLK_OscSrc_Internal);

    // Setup the PLL for x12 /2 which will yield 60Mhz = 10Mhz * 12 / 2
    PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

    // Disable the PIE and all interrupts
    PIE_disable(myPie);
    PIE_disableAllInts(myPie);
    CPU_disableGlobalInts(myCpu);
    CPU_clearIntFlags(myCpu);

// If running from flash copy RAM only functions to RAM
#ifdef _FLASH
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif

    // Setup a debug vector table and enable the PIE
    PIE_setDebugIntVectorTable(myPie);
    PIE_enable(myPie);
    PIE_registerPieIntHandler(myPie, PIE_GroupNumber_10, PIE_SubGroupNumber_1,
                                    (intVec_t)&adc_isr);
    InitEPwm1();

    // Initialize the ADC
    ADC_enableBandGap(myAdc);
    ADC_enableRefBuffers(myAdc);
    ADC_powerUp(myAdc);
    ADC_enable(myAdc);
    ADC_setVoltRefSrc(myAdc, ADC_VoltageRefSrc_Int);

    // Enable ADCINT1 in PIE
         PIE_enableAdcInt(myPie, ADC_IntNumber_1);
         // Enable CPU Interrupt 1
         CPU_enableInt(myCpu, CPU_IntNumber_10);
         // Enable Global interrupt INTM
         CPU_enableGlobalInts(myCpu);
         // Enable Global real time interrupt DBGM
         CPU_enableDebugInt(myCpu);

    LoopCount = 0;
    ConversionCount = 0;
  
        ADC_setIntPulseGenMode(myAdc, ADC_IntPulseGenMode_Prior);               //ADCINT1 trips after AdcResults latch
   	    ADC_enableInt(myAdc, ADC_IntNumber_1);                                  //Enabled ADCINT1
   	    ADC_setIntMode(myAdc, ADC_IntNumber_1, ADC_IntMode_ClearFlag);          //Disable ADCINT1 Continuous mode
   	    ADC_setIntSrc(myAdc, ADC_IntNumber_1, ADC_IntSrc_EOC2);                 //setup EOC2 to trigger ADCINT1 to fire
   	    ADC_setSocChanNumber (myAdc, ADC_SocNumber_0, ADC_SocChanNumber_A4);    //set SOC0 channel select to ADCINA4
   	    ADC_setSocChanNumber (myAdc, ADC_SocNumber_1, ADC_SocChanNumber_A4);    //set SOC1 channel select to ADCINA4
   	    ADC_setSocChanNumber (myAdc, ADC_SocNumber_2, ADC_SocChanNumber_A2);    //set SOC2 channel select to ADCINA2
   	    ADC_setSocTrigSrc(myAdc, ADC_SocNumber_0, ADC_SocTrigSrc_EPWM2_ADCSOCA);    //set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
   	    ADC_setSocTrigSrc(myAdc, ADC_SocNumber_1, ADC_SocTrigSrc_EPWM2_ADCSOCA);    //set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
   	    ADC_setSocTrigSrc(myAdc, ADC_SocNumber_2, ADC_SocTrigSrc_EPWM2_ADCSOCA);    //set SOC2 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1, then SOC2

   	    ADC_setSocSampleWindow(myAdc, ADC_SocNumber_0, ADC_SocSampleWindow_12_cycles);   //set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
   	    ADC_setSocSampleWindow(myAdc, ADC_SocNumber_1, ADC_SocSampleWindow_12_cycles);   //set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
   	    ADC_setSocSampleWindow(myAdc, ADC_SocNumber_2, ADC_SocSampleWindow_12_cycles);   //set SOC2 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

    // Enable PWM clock
    CLK_enablePwmClock(myClk, PWM_Number_2);

    // Setup PWM
    PWM_enableSocAPulse(myPwm2);                                         // Enable SOC on A group
    PWM_setSocAPulseSrc(myPwm2, PWM_SocPulseSrc_CounterEqualCmpAIncr);   // Select SOC from from CPMA on upcount
    PWM_setSocAPeriod(myPwm2, PWM_SocPeriod_FirstEvent);                 // Generate pulse on 1st event
    PWM_setCmpA(myPwm2, 0x0000);                                         // Set compare A value
    PWM_setPeriod(myPwm2, 0x05DC);                                       // Period = 1388 for 5Khz Sampling Frequency
    PWM_setCounterMode(myPwm2, PWM_CounterMode_Up);                      // count up and start
    CLK_enableTbClockSync(myClk);

    // Wait for ADC interrupt
    for(;;)
    {
    	PWM_setCmpA(myPwm1,Vpi_5);					//TBPRD = 200
    }
}

void InitEPwm1()
{
    CLK_disableTbClockSync(myClk);
    CLK_enablePwmClock(myClk, PWM_Number_1);
    GPIO_setPullUp(myGpio, GPIO_Number_0, GPIO_PullUp_Disable);
    GPIO_setPullUp(myGpio, GPIO_Number_1, GPIO_PullUp_Disable);
    GPIO_setMode(myGpio, GPIO_Number_0, GPIO_0_Mode_EPWM1A);
    GPIO_setMode(myGpio, GPIO_Number_1, GPIO_1_Mode_EPWM1B);
     // Setup Sync
    PWM_setSyncMode(myPwm1, PWM_SyncMode_EPWMxSYNC);
  //  PWM_setSyncMode(myPwm2, PWM_SyncMode_EPWMxSYNC);
    // Allow each timer to be sync'ed
    PWM_enableCounterLoad(myPwm1);
    PWM_setPeriod(myPwm1, PWM1_TIMER_TBPRD);
    PWM_setCounterMode(myPwm1, PWM_CounterMode_Up);         // Count up
    PWM_setIntMode(myPwm1, PWM_IntMode_CounterEqualZero);   // Select INT on Zero event
    PWM_enableInt(myPwm1);                                  // Enable INT
    PWM_setIntPeriod(myPwm1, PWM_IntPeriod_FirstEvent);     // Generate INT on 1st event

    PWM_setActionQual_Period_PwmA(myPwm1, PWM_ActionQual_Set);
    PWM_setActionQual_CntUp_CmpA_PwmA(myPwm1, PWM_ActionQual_Clear);


    PWM_setActionQual_Period_PwmB(myPwm1, PWM_ActionQual_Clear);
    PWM_setActionQual_CntUp_CmpA_PwmB(myPwm1, PWM_ActionQual_Set);

    CLK_enableTbClockSync(myClk);

}

__interrupt void adc_isr(void)

 {
	 Voltage1[ConversionCount] = ADC_readResult(myAdc, ADC_ResultNumber_1);
	 sum += Voltage1[ConversionCount];
	  if(ConversionCount == 19)
	  {
	    Vout_count = sum/ConversionCount;  // average count
	    Va = (Vout_count * 3.3)/(4096) ;  // sensed voltage in 3.3V format
	    err_5 = 3.0 - Va;

	    A_5 = (err_5 * Kp); // kp multiplication
	    B_5 = (err_5 * Ki); // Ki multiplication
	    v_5 = k_5 + (B_5 + in_A);
	    if (v_5 >= 300) v_5 = 300;  // maximum duty cycle limit
	   	if (v_5 <= 00) v_5 = 00;
	    k_5 = v_5;
	    in_A = B_5;
	    Vpi_5 = A_5 + v_5;
	    if (Vpi_5 >= 300) Vpi_5 = 300;
	    if (Vpi_5 <= 01)  Vpi_5 = 01;                 // minimum duty cycle limit
        if (Va > 3.0) Vpi_5 = 01;
    //    if (err_5< 0) Vpi_5= 0;
		ConversionCount = 0;
		sum=0;
	  }
	  else ConversionCount++;
    // Clear ADCINT1 flag reinitialize for next SOC
    ADC_clearIntFlag(myAdc, ADC_IntNumber_1);
    // Acknowledge interrupt to PIE
    PIE_clearInt(myPie, PIE_GroupNumber_10);

  //  return;
}



  • Dear anup,

    i checked your code and found some thing.

    A_5 = (err_5 * Kp); // kp multiplication
    B_5 = (err_5 * Ki); // Ki multiplication
    v_5 = k_5 + (B_5 + in_A);
    if (v_5 >= 300) v_5 = 300;  // maximum duty cycle limit
    if (v_5 <= 00) v_5 = 00;
    k_5 = v_5;
    in_A = B_5;
    

    as your system starts, eventually your target would be to make error -> 0.

    as in your equation if error = 0

    A_5 and B_5 will be zero in present iteration.

    thus in_A and k_5 will become zero in next iteration.

    So in the second iteration after error becomes zero your v_5 term will become zero.

    Vpi_5 = A_5 + v_5;

    now if both of them are zero your Vpi_5 will become zero.

    That is the ultimate variable which is responsible for duty.

    anupsingh chandel said:
    The issue is, it works fine in complete range till 200 Ohm load, but as I reduce the load (increase the current level) PWM starts to ON/OFF frequently.

    So if Vpi_5 becomes zero your duty becomes zero and pwm appears off, and after that again PI loop comes in picture and duty increases.

    And the process goes on and on.

    So to solve you problem you need to write Pi equatin properly

    error = ref-fb;
    up = error * kp;
    ui = ui + (up * ki);
    if (ui > max_lim) ui = max_lim
    if (ui<min_lim) ui = min_lim
    out = up + ui; 
    if(out > max_lim) out = max_lim;
    if (out< min_lim) out = min_lim;

    in this code ui term will sustain value even if your error becomes zero.

     Hope this helps.

    With regards,

    Keyur

  • Hi Keyur,

    Thanks for your reply.
    I will impliment it and test it. But one more doubt is this code is working fine with 200 Ohm (Minumum load) but as I increase the load (current), this PWM ON/OFF starts to apear.

    Let me try and put some waveforms .

    Thank you once again.
  • Hi anup,

    err_5 = 3.0 - Va;
    

    Generally the feedback oscillates around set value

    (typical response of system)

    in that case va can be greater than 3.0

    when the va > 3.0

    if (Va > 3.0) Vpi_5 = 01;
    

    will make your duty near to zero.

  • Hi Keyur,

    Thanks for the prompt reply.
    Just the doubt is when the system is on No load condition a small pulse is also increasing it's output voltage. So to control that I have kept this condition to check if output voltage is increasing from maximum limit turn off/minimize the pulses.

    Actually for H bridge related topology the value of duty cycle comes to

    D = Vout/(Vin+Vout)

    But on no load condition if a constant pulse (even if of low Ton) comes voltage keeps on increasing.

    Hope I am making sense.