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.

CCS/TMS320F28335: PI controller on TMS320f28335

Part Number: TMS320F28335


Tool/software: Code Composer Studio

I am trying to implement PI controller for Boost dc -dc converter. I tested boost converter in open loop with 0.5 duty cycle is working fine with ccs code. I kept Maximum and minimum duty ratios as 0.8 and 0.2.

The input dc voltage is 10V, the sensor gain is 100:3,  so the reference voltage is I need is 0.6V(reference 20V). I gave this reference voltage, adc voltage to the controller it is always settling at 0.2 duty cycle and I am getting over current indication in my source.   I am attaching my code please help somebody.

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
#include "DCL.h"
#include "DCLF32.h"
#include "DCL_fdlog.h"
#include "DCLC28.h"
//
// Function Prototypes
//
__interrupt void adc_isr(void);

float summ=0.0f;

DCL_PI pi1 = PI_DEFAULTS;
//
// Globals
//
Uint16 LoopCount;
Uint16 ConversionCount;
Uint16 Voltage1[10];
Uint16 Voltage2[10];
float a[10];
long b[10];
float U=0.5f;
float rk=0.6f;
float yk;
float uk=0.5f;
void InitEPwm1(void);
void gpio_select(void);
//
// Main
//
void main(void)
{
    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
    //
    InitSysCtrl();

    EALLOW;
    #if (CPU_FRQ_150MHZ)     // Default - 150 MHz SYSCLKOUT
        //
        // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz
        //
        #define ADC_MODCLK 0x3
    #endif
    #if (CPU_FRQ_100MHZ)
        //
        // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2)   = 25.0 MHz
        //
        #define ADC_MODCLK 0x2
    #endif
    EDIS;

    //
    // Define ADCCLK clock frequency ( less than or equal to 25 MHz )
    // Assuming InitSysCtrl() has set SYSCLKOUT to 150 MHz
    //
    EALLOW;
    SysCtrlRegs.HISPCP.all = ADC_MODCLK;
    EDIS;


    //
    // Step 2. Initialize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    //
    // InitGpio();  // Skipped for this example

    //
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    //
    DINT;

    //
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
    //
    InitPieCtrl();

    //
    // Disable CPU interrupts and clear all CPU interrupt flags:
    //
    IER = 0x0000;
    IFR = 0x0000;

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
    //
    InitPieVectTable();

    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
    EALLOW;  // This is needed to write to EALLOW protected register
    PieVectTable.ADCINT = &adc_isr;
    EDIS;    // This is needed to disable write to EALLOW protected registers

    //
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    //
    // InitPeripherals(); // Not required for this example
    InitAdc();  // For this example, init the ADC

    //
    // Step 5. User specific code, enable interrupts:
    //

    //
    // Enable ADCINT in PIE
    //
    PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
    IER |= M_INT1;      // Enable CPU Interrupt 1
    EINT;               // Enable Global interrupt INTM
    ERTM;               // Enable Global realtime interrupt DBGM

    LoopCount = 0;
    ConversionCount = 0;
    gpio_select();
    InitEPwm1();
           pi1.Kp=1.0f;
           pi1.Ki=0.1f;
           pi1.Umax=0.8f;
           pi1.Umin=0.2f;
           pi1.Imax=0.8f;
           pi1.Imin=0.2f;
           pi1.i10=0.0f;
           pi1.i6=0.0f;

    //
    // Configure ADC
    //
    AdcRegs.ADCMAXCONV.all = 0x0001;       // Setup 2 conv's on SEQ1
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // Setup ADCINA3 as 1st SEQ1 conv.
    AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x2; // Setup ADCINA2 as 2nd SEQ1 conv.
    
    //
    // Enable SOCA from ePWM to start SEQ1
    //
    AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;
    
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;  // Enable SEQ1 interrupt (every EOS)

    //
    // Assumes ePWM1 clock is already enabled in InitSysCtrl();
    //
    /*EPwm1Regs.ETSEL.bit.SOCAEN = 1;     // Enable SOC on A group
    EPwm1Regs.ETSEL.bit.SOCASEL = 4;    // Select SOC from from CPMA on upcount
    EPwm1Regs.ETPS.bit.SOCAPRD = 1;     // Generate pulse on 1st event
    EPwm1Regs.CMPA.half.CMPA = 1875;	// Set compare A value
    EPwm1Regs.TBPRD = 3750;           // Set period for ePWM1
    EPwm1Regs.TBCTL.bit.CTRMODE = 0;	// count up and start
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading
    EPwm1Regs.TBPHS.half.TBPHS = 0x0000;       // Phase is 0
    EPwm1Regs.TBCTR = 0x0000;                  // Clear counter
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 001;   // Clock ratio to SYSCLKOUT
    EPwm1Regs.TBCTL.bit.CLKDIV = 000;
    EPwm1Regs.TBCTL.bit.SYNCOSEL=1;
    EPwm1Regs.AQCTLA.bit.CAU=2;    // Set PWM1A on Zero
    EPwm1Regs.AQCTLA.bit.CAD=1;*/

        //
        // Setup shadow register load on ZERO
        //


        //
        // Set Compare values
        //
        //EPwm1Regs.PCCTL.bit.CHPEN=1;
        //EPwm1Regs.PCCTL.bit.CHPFREQ=0x111;
        //EPwm1Regs.PCCTL.bit.OSHTWTH=0x1111;
        //EPwm1Regs.PCCTL.bit.CHPDUTY=0x011;
        //
        // Set actions
        //


    //
    // Wait for ADC interrupt
    //
    for(;;)
    {
        LoopCount++;
    }
}

//
// adc_isr - 
//
__interrupt void  
adc_isr(void)
{
    Voltage1[ConversionCount] = AdcRegs.ADCRESULT0 >>4;
    Voltage2[ConversionCount] = AdcRegs.ADCRESULT1 >>4;
    a[ConversionCount]=(float) Voltage1[ConversionCount]*0.000732600f;
    //
    // If 40 conversions have been logged, start over
    //
    summ=summ+a[ConversionCount];

    if(ConversionCount == 9)
    {
        yk=summ*0.1f;
        uk = DCL_runPI_C1(&pi1, rk, yk);
        EPwm1Regs.CMPA.half.CMPA = (EPwm1Regs.TBPRD)*uk;
        ConversionCount = 0;
    }
    else
    {
        ConversionCount++;
    }

    //
    // Reinitialize for next ADC sequence
    //
    AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;         // Reset SEQ1
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;       // Clear INT SEQ1 bit
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE

    return;
}

void InitEPwm1(){
        EPwm1Regs.TBCTL.bit.CTRMODE = 0; // Count up down
        EPwm1Regs.TBPRD = 3750;       // Set timer period
        EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading
        EPwm1Regs.TBPHS.half.TBPHS = 0x0000;       // Phase is 0
        EPwm1Regs.TBCTR = 0x0000;                  // Clear counter
        EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0x001;   // Clock ratio to SYSCLKOUT
        EPwm1Regs.TBCTL.bit.CLKDIV = 000;
        EPwm1Regs.TBCTL.bit.SYNCOSEL=1;
        EPwm1Regs.CMPA.half.CMPA =1000;    // Set compare A value
        EPwm1Regs.CMPB = 1000;              // Set Compare B value
        EPwm1Regs.DBCTL.bit.OUT_MODE=3;
        EPwm1Regs.DBCTL.bit.POLSEL=2;
        EPwm1Regs.DBCTL.bit.IN_MODE=0;
        EPwm1Regs.DBRED=100;
        EPwm1Regs.DBFED=100;
        EPwm1Regs.ETSEL.bit.SOCAEN = 1;     // Enable SOC on A group
        EPwm1Regs.ETSEL.bit.SOCASEL = 4;    // Select SOC from from CPMA on upcount
        EPwm1Regs.ETPS.bit.SOCAPRD = 1;     // Generate pulse on 1st event
        //EPwm1Regs.PCCTL.bit.CHPEN=1;
        //EPwm1Regs.PCCTL.bit.CHPFREQ=0x111;
        //EPwm1Regs.PCCTL.bit.OSHTWTH=0x1111;
        //EPwm1Regs.PCCTL.bit.CHPDUTY=0x011;
        //
        // Set actions
        //
        EPwm1Regs.AQCTLA.bit.ZRO=2;    // Set PWM1A on Zero
        EPwm1Regs.AQCTLA.bit.CAU=1;

}
void gpio_select(){
        EALLOW;
        GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;   // Enable pullup on GPIO0
        GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;   // Enable pullup on GPIO0
        GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;  // GPIO0 = PWM1A
        GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;  // GPIO0 = PWM1A
        EDIS;

}

  • Firstly, you need to think carefully about the structure of the program. Look at the flow from the start of main(). You are partially configuring the peripherals, then enabling interrupts; then you complete ADC and controller configuration. As soon as interrupts are enabled in line 126 you will start running ISRs even before the ADC and controllers are set up. Do this: move the EINT and ERTM instructions to just before the for(;;) loop so the ISR will run with everything set up.

    Secondly, I am not following the logic behind your use of the "summ" variable. This seems to be accumulating successive feedback measurements:

    summ=summ+a[ConversionCount];
    ...
    yk=summ*0.1f;

    "Voltage1[]" is always positive and "summ" is never reset, so looking at this I would expect "yk" to become large and for the controller to saturate. You can monitor these variables in a CCS watch window to check what is going on. In general, whenever you develop a feedback control loop, always monitor the reference and feedback to ensure they are in the expected range.

    Regards,

    Richard
  • Thank you sir,

    I did modifications as you said. I am thinking to average every ten adc values and give to the controller, of course I forgot to reset 'summ' variable . Thank you for reminding me. But still my controller output 'uk' is always setting to its maximum value 0.8. I am trying to change the PI gains but it is effecting the output. Is it problem with number system, initialization of adc or initialization of epwm.
    Please help me in this connection.
  • You should not set i6 to zero unless you want to disable the integrator. Please change that to 1.0f in line 140.

    It may be a gain selection issue. You're going to have to experiment to see if that's the case. Start with some conservative values and concentrate on making incremental changes to one gain at a time. There are few general guidelines, but power systems are often not very sensitive to changes in Ki, so you may need to increase that. You'll have to experiment.

    What may help you is to log the variables as you start the system up to see what's going out of range. There is a data logger utility in the DCL you can use to monitor the floating point variables yk & uk.

    What are rk and yk when it saturates?

    Regards,

    Richard
  • Thnank you Sir,
    Instead of adc average value I gave instantaneous value to the PI controller and I tuned the gains. It is working fine now. Thanking you for your support.
  • Glad to know you found the problem. Thanks for letting us know.

    Regards,

    Richard