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/TMS320F28069M: ADC+PWM

Part Number: TMS320F28069M

Tool/software: Code Composer Studio

Hi 

I'm having problems with my PWM and ADC configuration using the C2000 - F28069M. I need to apply a current PI controller to some values read by the ADC and send the controller output trough ePWM. There is something wrong, it seems the clock? The controlled values are changing too much and i have a simulation with same values and controller gains working properly. I put my code Below. I think the problem might be with the Clock for ADC and PWM or related. I need to read 5 ADC channes.

Thanks in advance for the help, please find below the code

#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
//#include <sgen.h>
#include <math.h>

__interrupt void adc_isr(void);
void Adc_Config(void);
void InitEPwm1Example(void);

Uint32 EPwm1TimerIntCount;
Uint16 EPwm1_DB_Direction;

//Initial Values
#define initial_CMPA 2250;
#define Epwm1_TBPRD 2250; //


// Global variables used in this example:
Uint16 LoopCount;
Uint16 ConversionCount;
Uint16 I_count=0;
Uint16 I_val=0;
Uint16 adc_sample;
Uint16 Voltage1[10];
float32 iboost = 0;
Uint16 iboost_dsp = 0;
float32 vin = 0;
Uint16 vin_dsp = 0;
float32 Ipv = 0;
Uint16 Ipv_dsp = 0;
float32 vout = 0;
Uint16 vout_dsp = 0;
Uint16 k;

//Controller settings
float32 Kp = 5.78;
float32 Ki = 33.333;
float32 integral=0;
float32 error=0;
float32 v_inductor=0;
float32 PI=0;
float32 vcdc=0;
float32 m=0;
Uint16 m_CMPA=0;
float32 dt = 1/10e3;
float32 iboost_sp = 0; //1755 - almost 30 Amps


//Controller inner loop
float32 e_new = 0;
float32 e_old = 0;
float32 y_new = 0;
float32 y_old = 0;
float32 delta_y = 0;

//Controller outer loop
float32 vin_sp = 100;

float32 e_new_o = 0;
float32 e_old_o = 0;
float32 y_new_o = 0;
float32 y_old_o = 0;
float32 delta_y_o = 0;

float32 tot_time = 0;
float32 sine_50Hz = 0;
float32 f = 50;
Uint16 sine_CMPA =0;

float32 Icpv = 0;
float32 Kp_o = 0.066667;
float32 Ki_o = 25.641;

#define ADC_MODCLK 0x96 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz

main()
{

// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
InitSysCtrl();

// Step 2. Initialize GPIO:
InitEPwm1Gpio();

// 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.
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
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.ADCINT1 = &adc_isr;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS; // This is needed to disable write to EALLOW protected registers

// Step 4. Initialize all the Device Peripherals:

for (i = 0; i< ADC_BUF_LEN; i++)
{
AdcBuf[i] = 0x0000;
AdcFiltBuf[i] = 0x0000;
}

// init_cla();
init_adc();


InitEPwm1Example();
InitAdc(); // For this example, init the ADC
AdcOffsetSelfCal();

EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;

// Step 5. User specific code, enable interrupts:
EPwm1TimerIntCount = 0;
// Enable ADCINT1 in PIE Enable the interrupt

PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable INT 1.1 in the PIE
IER |= M_INT1; // Enable CPU Interrupt 1
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM

LoopCount = 0;
ConversionCount = 0;

// Configure ADC
EALLOW;
AdcRegs.ADCCTL2.bit.ADCNONOVERLAP = 1; // Enable non-overlap mode
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; // ADCINT1 trips after AdcResults latch
AdcRegs.INTSEL1N2.bit.INT1E = 1; // Enabled ADCINT1
AdcRegs.INTSEL1N2.bit.INT1CONT = 0; // Disable ADCINT1 Continuous mode
AdcRegs.INTSEL1N2.bit.INT1SEL = 1; // setup EOC1 to trigger ADCINT1 to fire
AdcRegs.ADCSOC0CTL.bit.CHSEL = 11; // set SOC0 channel select to ADCINB3
AdcRegs.ADCSOC1CTL.bit.CHSEL = 2; // set SOC1 channel select to ADCINA2
AdcRegs.ADCSOC2CTL.bit.CHSEL = 9; // set SOC1 channel select to ADCINB1
AdcRegs.ADCSOC3CTL.bit.CHSEL = 10; // set SOC1 channel select to ADCINB2
//AdcRegs.ADCSOC4CTL.bit.CHSEL = 12; // set SOC1 channel select to ADCINB14
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5; // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
AdcRegs.ADCSOC2CTL.bit.TRIGSEL = 5; // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
AdcRegs.ADCSOC3CTL.bit.TRIGSEL = 5; // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
//AdcRegs.ADCSOC4CTL.bit.TRIGSEL = 5; // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
AdcRegs.ADCSOC1CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
AdcRegs.ADCSOC2CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
AdcRegs.ADCSOC3CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
//AdcRegs.ADCSOC4CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)

EDIS;

// Assumes ePWM1 clock is already enabled in InitSysCtrl();
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
EPwm1Regs.ETSEL.bit.SOCASEL = 2; // Select SOC from CMPA on upcount ----- in middle
EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event

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

}


__interrupt void adc_isr(void)
{
if ((m<-0.5) || (m>1.5))
{
m = 0; e_new_o=0; delta_y_o=0; y_new_o=0; Icpv=0; iboost_sp=0; y_old_o=0; e_old_o=0;
e_new=0; delta_y=0; y_new=0; v_inductor=0; vcdc=0; m_CMPA=0; y_old=0; e_old=0;
}

I_count = I_count+1;
tot_time = tot_time + dt;
sine_50Hz = 2250*sin(2*3.14*f*tot_time)+2250;
sine_CMPA = sine_50Hz;
//After reading the values of the boost we need to scale them with oposite values used in the switching model
//ADC converter reads alue from 0 to 4096, and that means a scale from 0 to 3.3 Volts from the boost
//Depending on each value we have a scaling factor
iboost_dsp = AdcResult.ADCRESULT0;
iboost = (unsigned int) (((float)iboost_dsp) /4096*3.3* 700/33); //Scaling factor 33/700 to achieve 3.3 Volts at the output of boost
vin_dsp = AdcResult.ADCRESULT1;
vin = (unsigned int) (((float)vin_dsp) /4096*3.3* 5000/33); //Scaling factor 33/5000 to achieve 3.3 Volts at the output of boost
vout_dsp = AdcResult.ADCRESULT2;
vout= (unsigned int) (((float)vout_dsp) /4096*3.3* 9000/11); //Scaling factor 11/9000 to achieve 3.3 Volts at the output of boost
Ipv_dsp = AdcResult.ADCRESULT3;
Ipv = (unsigned int) (((float)Ipv_dsp) /4096*3.3* 700/33); //Scaling factor 33/700 to achieve 3.3 Volts at the output of boost

Voltage1[ConversionCount] = AdcResult.ADCRESULT0;

//CONTROLLER FF
//error = iboost_sp - iboost;
//integral = integral+Ki*error*dt;
//PI = Kp*error+integral;
//v_inductor = PI;

//New controller outer loop
//e_new_o = vin_sp - vin; //new error (actual)
//delta_y_o = Kp_o*(e_new_o-e_old_o)+dt*Ki_o*e_old_o;
//y_new_o = y_old_o + delta_y_o;
//Icpv = y_new_o;

//vcdc = vin-v_inductor;
//iboost_sp = Ipv - Icpv;
//m = 1- vcdc/vout;
//m_CMPA = (unsigned int)(m*4500);

y_old_o = y_new_o;
e_old_o = e_new_o;

iboost_sp = 30;

//New controller inner loop
e_new = (iboost_sp - iboost); //new error (actual)
delta_y = Kp*(e_new-e_old)+dt*Ki*e_old;
y_new = y_old + delta_y;
v_inductor = y_new;

vcdc = vin-v_inductor;
m = 1- vcdc/vout;
m_CMPA = (unsigned int)(m*2250);

y_old = y_new;
e_old = e_new;


// If 10 conversions have been logged, start over
if(ConversionCount == 9)
{
ConversionCount = 0;
}
else ConversionCount++;

EPwm1Regs.CMPA.half.CMPA = m_CMPA; //(unsigned int) (((float)adc_sample)*1.095); //140; Or 280/2=0.5 dutycycle for checking that is 10K exactly FFT
//I use the division by 15 as a scaling factor!!! (PWM carrier is almost 15 of my wave)


EPwm1TimerIntCount++;

// Clear INT flag for this timer
EPwm1Regs.ETCLR.bit.INT = 1;


AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //Clear ADCINT1 flag reinitialize for next SOC
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE

return;
}

void InitEPwm1Example()
{

EPwm1Regs.TBPRD = Epwm1_TBPRD; //10 Kz - para 1KHz funciona muy bien poner 2750
EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
EPwm1Regs.TBCTR = 0x0000; // Clear counter

// Setup TBCLK
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;

EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; // Load registers every ZERO
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

// Setup compare
EPwm1Regs.CMPA.half.CMPA = initial_CMPA;

// Set actions
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // Set PWM1A on CAU
EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // Clear PWM1A on CAD


EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR; // Clear PWM1B on CAU
EPwm1Regs.AQCTLB.bit.CAD = AQ_SET; // Set PWM1B on CAD

// Active Low PWMs - Setup Deadband
EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_LO;
EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL;
// EPwm1Regs.DBRED = EPWM1_MIN_DB;
// EPwm1Regs.DBFED = EPWM1_MIN_DB;

// Interrupt where we will change the Deadband
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT
EPwm1Regs.ETPS.bit.INTPRD = ET_3RD; // Generate INT on 3rd event


}

Best Regards 

Maria