Part Number: TMS320F28335
Other Parts Discussed in Thread: CONTROLSUITE
Tool/software: Code Composer Studio
Hello,
I am attempting to implement SVM on my custom made control board which has the TMS320F28335 DSP. I am setting Vd and Vq as arbitrarily values as if I am receiving them as a PI controller (because I have not yet configured this part yet) and then doing the inverse Park Transformation to get my Valpha and Vbeta values which are my inputs for the SVM. When I get an output from the SVGENDQ(svgen1) function I am only reading the Ta, Tb, Tc fields as either -1, 0, or 1 instead of a range of decimals between [-1,1]. I am aware the struct data type in the svgen header file uses _iq which are of type long which would explain why I am only getting integers, however (correct me if I'm wrong) isn't the point of the function to get a range of values between [-1,1].
Here is the code I am using:
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#include "math.h"
#include "IQmathLib.h"
//#include "pi.h"
#include "svgen.h"
#define EPWM2_TIMER_TBPRD 10000 // period of the SPWM counter
#define Vdc 800 //DC Link Voltage
#define dead_time 500// dead_time of the switch
#define PI 3.14159265358979323846
Uint16 LoopCount;
Uint16 ConversionCount;
Uint16 ADCIN3[256];
Uint16 ADCIN4[256];
Uint16 ADCIN5[256];
float max = 4095.0, min = 1220.0, a=0.250, b=3.90; //conversion parameters used for converting 12 bit to digital range
float VoltageA, VoltageB, ialpha, ibeta, id, iq, Vd, Vq, Valpha, Vbeta; //Variables for Transformations
float dutyA, dutyB, dutyC, Theta;
float Vref_angle, Vref_magn, M, Sector, T1, T2, T0, Ta ,Tb, Tc; //M is modulation index
const float Ts = 1.0/7500.0;
//PI_CONTROLLER pi1 = PI_CONTROLLER_DEFAULTS, pi2 = PI_CONTROLLER_DEFAULTS;
SVGEN svgen1 = SVGEN_DEFAULTS;
// Prototype statements for functions found within this file.
void InitEPwm4Trigger(void);
void InitEPwm2Example(void);
void InitEPwm3Example(void);
void InitEPwm1Example(void);
void ConfigureADC(void);
float Calc_Sector(float angle);
void dutyCycle(float PerA, float PerB, float Per0, float sector, float* da, float* db, float* dc);
__interrupt void adc_isr(void);
void main(void)
{
/*The following configure the paramters for the PI Controller. This will be used later*/
// pi1.Kp = _iq(1);
// pi1.Ki = _iq(0);
// pi1.Umax = _iq(0.9);
// pi1.Umin = _iq(-0.9);
// pi2.Kp = _iq(1);
// pi2.Ki = _iq(0);
// pi2.Umax = _iq(0.9);
// pi2.Umin = _iq(-0.9);
/*Arbitrary values set for values 'obtained' from PI Controller*/
Vd = 10.0;
Vq = 10.5;
InitSysCtrl();
EALLOW;
#if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT
#define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz
#endif
#if (CPU_FRQ_100MHZ)
#define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2) = 25.0 MHz
#endif
EDIS;
EALLOW;
SysCtrlRegs.HISPCP.all = 0x3; // 150MHz / (HISPCP*2) == HSPCLK
EDIS;
InitEPwm1Gpio();
InitEPwm2Gpio();
InitEPwm3Gpio();
InitEPwm4Gpio();
DINT; // DISABLE cpu interrupts
InitPieCtrl();
IER = 0X0000;
IFR = 0X0000;
InitPieVectTable();
EALLOW;
PieVectTable.ADCINT = &adc_isr;
EDIS;
InitAdc();
LoopCount = 0;
ConversionCount = 0;
Theta = 0;
ConfigureADC();
InitEPwm4Trigger();
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS;
InitEPwm1Example();
InitEPwm2Example();
InitEPwm3Example();
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx6=1;
//Enable global interrupt
EINT;
ERTM;
for(;;)
{
LoopCount++;
}
}
__interrupt void adc_isr(void)
{
/*Shifting the ADC values so they are on a 12 bit range*/
ADCIN3[ConversionCount] = AdcRegs.ADCRESULT0 >>4;
ADCIN4[ConversionCount] = AdcRegs.ADCRESULT1 >>4;
ADCIN5[ConversionCount] = AdcRegs.ADCRESULT2 >>4;
/* The following three lines are for basic duty cycle functionality, nothing else*/
// EPwm2Regs.CMPA.half.CMPA = EPwm2Regs.TBPRD - ((EPwm2Regs.TBPRD)*(ADCIN3[ConversionCount]-min)/(max-min));
// EPwm3Regs.CMPA.half.CMPA = EPwm3Regs.TBPRD - ((EPwm3Regs.TBPRD)*(ADCIN4[ConversionCount]-min)/(max-min));
// EPwm4Regs.CMPA.half.CMPA = EPwm4Regs.TBPRD - ((EPwm4Regs.TBPRD)*(ADCIN5[ConversionCount]-min)/(max-min));
/*Converting the 12 bit ADC values to the readable voltage range (digital)*/
// VoltageA = (b-a)*(ADCIN3[ConversionCount]-min)/(max-min) + a;
// VoltageB = (b-a)*(ADCIN4[ConversionCount]-min)/(max-min) + a;
/*Clarke Transform*/
// ialpha = VoltageA;
// ibeta = (1/sqrt(3))*(VoltageA + 2*VoltageB);
/*Park Transform*/
// id = ialpha*cos(Theta) + ibeta*sin(Theta);
// iq = -1*ialpha*sin(Theta) + ibeta*cos(Theta);
/*Inverse Park Transform*/
Valpha = Vd*cos(Theta*PI/180.0) - Vq*sin(Theta*PI/180.0);
Vbeta = Vq*cos(Theta*PI/180.0) + Vd*sin(Theta*PI/180.0);
/*SVM Duty Cycles Input*/
svgen1.Ualpha = Valpha;
svgen1.Ubeta = Vbeta;
/*SVM Function Call*/
SVGENDQ_MACRO(svgen1);
/*SVM Duty Cycles Output*/
dutyA = svgen1.Ta;
dutyB = svgen1.Tb;
dutyC = svgen1.Tc;
EPwm1Regs.CMPA.half.CMPA = (EPWM2_TIMER_TBPRD - 0)*(dutyA - (-1))/(1-(-1)) + 0;
EPwm2Regs.CMPA.half.CMPA = (EPWM2_TIMER_TBPRD - 0)*(dutyB - (-1))/(1-(-1)) + 0;
EPwm3Regs.CMPA.half.CMPA = (EPWM2_TIMER_TBPRD - 0)*(dutyC - (-1))/(1-(-1)) + 0;
// Vref_angle = atan(Vbeta/Valpha)*180.0/PI; //converting from radians to degrees
//
// if(Valpha<0)
// Vref_angle = 180 + Vref_angle;
// if(Valpha>0 && Vbeta<0)
// Vref_angle = 360 + Vref_angle;
// Vref_magn = sqrt(pow(Valpha,2)+pow(Vbeta,2));
// Vref_magn = 415.6922;
// Vref_angle = Theta;
// Sector = Calc_Sector(Vref_angle);
// M = sqrt(3)*Vref_magn/Vdc;
//
// T1 = Ts*M*sin(Sector*PI/3 - (Vref_angle*PI/180.0));
// T2 = Ts*M*sin(-(Sector-1)*PI/3 + (Vref_angle*PI/180.0));
// T0 = (Ts - T1 - T2)/2;
//
// dutyCycle(T1, T2, T0, Sector, &Ta, &Tb, &Tc);
// EPwm1Regs.CMPA.half.CMPA = (Ta/Ts)*EPWM2_TIMER_TBPRD;
// EPwm2Regs.CMPA.half.CMPA = (Tb/Ts)*EPWM2_TIMER_TBPRD;
// EPwm3Regs.CMPA.half.CMPA = (Tc/Ts)*EPWM2_TIMER_TBPRD;
if(Theta == 360)
Theta = 0;
else {
Theta++; }
// If 256 conversions have been logged, start over
if(ConversionCount == 255)
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 ConfigureADC(){
//Following two lines finalize the ADC Clock Frequency
AdcRegs.ADCTRL3.bit.ADCCLKPS = 0x0000; // Divider = HSPCLK / (x*2) --> this bit is the x
AdcRegs.ADCTRL1.bit.CPS = 0; // ADC CLOCK FREQ = Divider / (y*2) --> This bit is the y
AdcRegs.ADCTRL1.bit.ACQ_PS = 0; //Acquisition Window bit: S/H period is (1 + Acqps) * tc(ADCCLK) * 2 --> This is the sampling period!
//Sampling freq is: Freq(ADC CLK) / [2*(1 + ACQ_PS)]
AdcRegs.ADCTRL3.bit.SMODE_SEL = 0; // Sequential Sampling mode is selected
AdcRegs.ADCTRL1.bit.SEQ_CASC = 0; //Dual Sequencer Mode
AdcRegs.ADCMAXCONV.all = 0x0002; // Setup 3 conv's on SEQ1
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // Setup ADCINA3 as 1st SEQ1 conv.
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x4; // Setup ADCINA4 as 1st SEQ1 conv.
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x5; // Setup ADCINA5 as 1st SEQ1 conv.
AdcRegs.ADCTRL1.bit.CONT_RUN = 1;
AdcRegs.ADCTRL1.bit.SEQ_OVRD = 0;
AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;// Enable SOCA from ePWM to start SEQ1
AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Enable SEQ1 interrupt (every EOS)
}
void InitEPwm4Trigger(){
// Assumes ePWM1 clock is already enabled in InitSysCtrl();
EPwm4Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
EPwm4Regs.ETSEL.bit.SOCASEL = 1; // Select SOC when TBCTR=0
EPwm4Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event
EPwm4Regs.CMPA.half.CMPA = 0x0080; // Set compare A value
EPwm4Regs.TBPRD = 0xFFFF; // Set period for ePWM1
EPwm4Regs.TBCTL.bit.HSPCLKDIV = 1; //divider of 2
EPwm4Regs.TBCTL.bit.CLKDIV = 0; //divider of 1
EPwm4Regs.TBCTL.bit.CTRMODE = 0x2; // count up down mode and start
}
void InitEPwm1Example()
{
EPwm1Regs.TBPRD = EPWM2_TIMER_TBPRD; // Set timer period
EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
EPwm1Regs.TBCTR = 0x0000; // Clear counter
// Setup TBCLK
EPwm1Regs.TBCTL.bit.CTRMODE = 0x2; // Count up and down mode
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // Clock ratio to SYSCLKOUT
EPwm1Regs.TBCTL.bit.CLKDIV = 0;
EPwm1Regs.TBCTL.bit.SYNCOSEL = 0x01; // SYNC output at CTR=0
EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0; // Load registers every ZERO
EPwm1Regs.CMPCTL.bit.SHDWBMODE = 0;
EPwm1Regs.CMPCTL.bit.LOADAMODE = 0;
EPwm1Regs.CMPCTL.bit.LOADBMODE = 0;
// Set actions
EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
// Active Low PWMs - Setup Deadband
EPwm1Regs.DBCTL.bit.OUT_MODE = 0x3; // rising edge delay on EPWMxA and falling edge delay on EPWMxB
EPwm1Regs.DBCTL.bit.POLSEL = 0x2; // EPWMxB is inverted
EPwm1Regs.DBCTL.bit.IN_MODE = 0x0; // EPWMxA is the source for both falling and rising edge delay
EPwm1Regs.DBRED = dead_time;
EPwm1Regs.DBFED = dead_time;
}
void InitEPwm2Example()
{
EPwm2Regs.TBPRD = EPWM2_TIMER_TBPRD; // Set timer period
EPwm2Regs.TBCTR = 0x0000; // Clear counter
// Interrupt where we will change the Deadband
// EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
// EPwm2Regs.ETSEL.bit.INTEN = 1; // Enable INT
// EPwm2Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
// Setup TBCLK
EPwm2Regs.TBCTL.bit.CTRMODE = 0x2; // Count up and down mode
EPwm2Regs.TBCTL.bit.PHSEN = 0x01; // enable phase loading, SYNC to EPWM1
EPwm2Regs.TBPHS.half.TBPHS = 0; // Phase shift
EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0; // Clock ratio to SYSCLKOUT
EPwm2Regs.TBCTL.bit.CLKDIV = 0;
EPwm2Regs.CMPCTL.bit.SHDWAMODE = 0; // Load registers every ZERO
EPwm2Regs.CMPCTL.bit.SHDWBMODE = 0;
EPwm2Regs.CMPCTL.bit.LOADAMODE = 0;
EPwm2Regs.CMPCTL.bit.LOADBMODE = 0;
// Set actions
EPwm2Regs.AQCTLA.bit.CAD = AQ_SET;
EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
// Active Low PWMs - Setup Deadband
EPwm2Regs.DBCTL.bit.OUT_MODE = 0x3; // rising edge delay on EPWMxA and falling edge delay on EPWMxB
EPwm2Regs.DBCTL.bit.POLSEL = 0x2; // EPWMxB is inverted
EPwm2Regs.DBCTL.bit.IN_MODE = 0x0; // EPWMxA is the source for both falling and rising edge delay
EPwm2Regs.DBRED = dead_time;
EPwm2Regs.DBFED = dead_time;
}
void InitEPwm3Example()
{
EPwm3Regs.TBPRD = EPWM2_TIMER_TBPRD; // Set timer period
EPwm3Regs.TBCTR = 0x0000; // Clear counter
// Setup TBCLK
EPwm3Regs.TBCTL.bit.CTRMODE = 0x2; // Count up and down mode
EPwm3Regs.TBCTL.bit.PHSEN = 0x01; // enable phase loading, SYNC to EPWM1
EPwm3Regs.TBPHS.half.TBPHS = 0; // Phase shift
EPwm3Regs.TBCTL.bit.HSPCLKDIV = 0; // Clock ratio to SYSCLKOUT
EPwm3Regs.TBCTL.bit.CLKDIV = 0;
EPwm3Regs.CMPCTL.bit.SHDWAMODE = 0; // Load registers every ZERO
EPwm3Regs.CMPCTL.bit.SHDWBMODE = 0;
EPwm3Regs.CMPCTL.bit.LOADAMODE = 0;
EPwm3Regs.CMPCTL.bit.LOADBMODE = 0;
// Set actions
EPwm3Regs.AQCTLA.bit.CAD = AQ_SET;
EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
// Active Low PWMs - Setup Deadband
EPwm3Regs.DBCTL.bit.OUT_MODE = 0x3; // rising edge delay on EPWMxA and falling edge delay on EPWMxB
EPwm3Regs.DBCTL.bit.POLSEL = 0x2; // EPWMxB is inverted
EPwm3Regs.DBCTL.bit.IN_MODE = 0x0; // EPWMxA is the source for both falling and rising edge delay
EPwm3Regs.DBRED = dead_time;
EPwm3Regs.DBFED = dead_time;
}
Thanks,
Kyle