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: SVGEN.h function from Control Suite Outputting only integers

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