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.

WEBENCH® Tools: ADC sampling

Other Parts Discussed in Thread: TLV6001

Tool/software: WEBENCH® Design Tools

hi,

I am designing isolated AC voltage sensor using ISO244 using (TMSF28377D0.i have used voltage divider to scale down voltage va=vo(R2/R1+R2) is within range of ISO244 further ISO244 has gain of 1/3 V/V so  differential output of ISO244 is va*1/3 with 2.5 V common mode voltage and my ADC range is 0-3V so I used TLV6001 with gain of 0.75 and offset voltage is 1.65.so output voltage is vo= va*1/3*0.75. my question is how can I make output voltage equal to real voltage inside DSP.

v1=(((AdcaResultRegs.ADCRESULT5)*3/9046-1.65)*outputfactor); //  outputfactor is (R2/R1+2)*1/3*0.75

but when I write this inside CCS and check value of v1 its not correct.

  • Hi Shah,

    It looks to me like you're following this cookbook circuit: http://www.ti.com/lit/an/sbaa317/sbaa317.pdf

    and are having trouble with converting your ADC codes back to volts? 

    What code format does the TMSF28377D0 output? 2's complement, or something else? 

    Output factor should be: outputfactor is (R2/(R1+R2))*1/3*0.75

    Where is the 3/9046 term coming from in v1=(((AdcaResultRegs.ADCRESULT5)*3/9046-1.65)*outputfactor); ?

    What is va? 

  • yes i am following this cookbook. yes i have trouble converting ADC code back to volts. ADC output code format is like that if I have 30V  AC voltage then i use divider circuit to scale down 30 AC voltage in range of ISO244, and this divider voltage could be any voltage less than 12V. so Va is that divider voltage  i multiply that divider voltage with factor and subtract DC OFFSETwhich is 1.65. 

     The relationship between the analogue input -voltage (Vin), the number of binary digits to represent the digital number  and the digital number (D) is
    given by 

                                    Vin=D*3.0V/4095

    so D is AdcaResultRegs.ADCRESULT5 multiplied with 3/4095 so the whole output is (((AdcaResultRegs.ADCRESULT5)*3/9046-1.65)*outputfactor).

    is it right or wrong? could you please explain the right way how to convert ADC code back to voltage. Output of ADC is then compared with reference voltage then it is given to PI controller for PWM generation.

  • Hi Shah,

    First it was 3/9046, now it's 3/4095, so which one are you using in your code? 

    How is your ADC configured? 

    It is measuring in a psuedo-differential configuration or something else? 

    What is the output code format? 

  • thanks you very much i have solved ADC sampling correctly. now i have written C code. i am using 50Hz fundamental frequency and 50KHz switching frequency so 50KHz/50Hz= 1000, i need 1000 points to sine wave generation, I want SPWM for single phase half bridge. i wanted to see SPWM waveform from TMSf28377D board without turning on DC source. but SPWM looks not right. i am attaching figure and below is my code thanks

    #include "F28x_Project.h"

    #include "F28377D_ADC.h"

    #include "F28377D_ePWM.h"

    #include "F28377D_GpioSetup.h"

    #include "math.h"

    #include "string.h"

    #include "Solar_F.h"

    typedef struct

    {

    volatile struct EPWM_REGS *EPwmRegHandle;

    Uint16 EPwm_CMPA_Direction;

    Uint16 EPwm_CMPB_Direction;

    Uint16 EPwmTimerIntCount;

    Uint16 EPwmMaxCMPA;

    Uint16 EPwmMinCMPA;

    Uint16 EPwmMaxCMPB;

    Uint16 EPwmMinCMPB;

    }EPWM_INFO;

     

    interrupt void epwm1_isr(void);

    interrupt void cpu_timer0_isr(void);

    #define pi 3.1415926

    #define PERIOD 1000

    #define HALF_PERIOD PERIOD*0.5

    float mag,ua,a=0,z,d,num,CMP;

    float v1,i1;

    int16 VC1,IL1;

    Uint32 i,j,k;

    CNTL_PI_F VC,IL;

    void main(void)

    {

     

    // Step 1. Initialize System Control:

    InitSysCtrl();

    InitEPwm1Gpio();

     

    DINT;

    InitPieCtrl();

    IER = 0x0000;

    IFR = 0x0000;

    InitPieVectTable();

    EALLOW; // This is needed to write to EALLOW protected registers

    PieVectTable.EPWM1_INT = &epwm1_isr;

    PieVectTable.TIMER0_INT = &cpu_timer0_isr;

    EDIS;

    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0;

    EDIS;

    InitEPwm1Example();

    ConfigureADC();

    SetupADCEpwm();

    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;

    EDIS;

    IER |= M_INT3;

    // Enable EPWM INTn in the PIE: Group 3 interrupt 1-3

    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;

    PieCtrlRegs.PIEIER2.bit.INTx1 = 1;

    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;

    PieCtrlRegs.PIEIER3.bit.INTx2 = 1;

    PieCtrlRegs.PIEIER3.bit.INTx3 = 1;

    IER |= M_INT1;

    IER |= M_INT2;

    InitCpuTimers();

    ConfigCpuTimer(&CpuTimer0, 200, 20000);

    CpuTimer0Regs.TCR.all = 0x4000;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;

    EINT; // Enable Global interrupt INTM

    ERTM; // Enable Global realtime interrupt DBGM

     

    /******Voltage PI Regulator*****/

    CNTL_PI_F_init(&VC);

    VC.Ki = (500);

    VC.Kp = (5);

    VC.Umax= 10;

    VC.Umin= -10;

    /******Current PI Regulator*****/

    CNTL_PI_F_init(&IL);

    IL.Ki = (6000);

    IL.Kp = (0.005);

    IL.Umax= 30;

    IL.Umin= -30;

    i = 0;

    j = 0;

    k = 0;

    }

    interrupt void epwm1_isr(void)

    {

     

    //Samlped voltage and current

    i1=((float)(AdcaResultRegs.ADCRESULT1)-2210)*0.01;

    v1=((float)(AdcaResultRegs.ADCRESULT3)-2192)*0.0364;

    IL1=i1;

    VC1= v1;

     

    /*****voltage PI Regulator*****/

    VC.Ref=a;

    VC.Fbk=v1;;

    CNTL_PI_F_FUNC(&VC);

    /*****Current PI Regulator*****/

    IL.Ref=VC.Out;

     

    IL.Fbk=i1;

    CNTL_PI_F_FUNC(&IL);

    d=IL.Out;

     

     

    mag=PERIOD/100;

    ua=d*mag;

    CMP=0.5*PERIOD+ua;

    EPwm1Regs.CMPA.bit.CMPA =(Uint16)CMP;

    EPwm1Regs.ETCLR.bit.INT = 1;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;

    }

    void InitEPwm1Example()

    {

    // Setup TBCLK

    EPwm1Regs.TBPRD = PERIOD ; // Set timer period

    EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0

    EPwm1Regs.TBCTR = 0x0000; // Clear counter

     

    // Setup counter mode

    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;

    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.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync output is equal to zero

     

    // Setup shadowing

    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;

    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;

    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero

    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    //

    // Setup compare

    //

    EPwm1Regs.CMPA.bit.CMPA = 0; //

    // EPwm1Regs.CMPB.bit.CMPB = 0;

    // Set actions

    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Set PWM1A on High

    EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;

     

    EPwm1Regs.AQCTLB.bit.CAU = AQ_SET; // Set PWM1B on LOW

    EPwm1Regs.AQCTLB.bit.CAD = AQ_CLEAR;

     

    //

    // Interrupt where we will change the Compare Values

    //

    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event INTSEL= interrupt selection

    EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT

    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event

    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group

    EPwm1Regs.ETSEL.bit.SOCASEL = 2;

    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;

    }

    void ConfigureADC(void)

    {

    EALLOW;

     

    AdcaRegs.ADCCTL2.bit.PRESCALE = 2; //set ADCCLK divider to /2

    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);

    //

    //Set pulse positions to late

    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;

     

    //power up the ADC

    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;

    //

    //delay for 1ms to allow ADC time to power up

    //

    DELAY_US(1000);

    EDIS;

    }

     

     

    void SetupADCEpwm(void)

    {

    //

    //Select the channels to convert and end of conversion flag

    //

    EALLOW;

    AdcaRegs.ADCSOC1CTL.bit.CHSEL = 1; //SOC0 will convert pin ADCINA0 and ADCRESULT0

    AdcaRegs.ADCSOC1CTL.bit.ACQPS = 28; //sample window is XX SYSCLK cycles

    AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C

     

    AdcaRegs.ADCSOC3CTL.bit.CHSEL = 3; //SOC3 will convert pin ADCINA3 and A1 ADCRESULT3

    AdcaRegs.ADCSOC3CTL.bit.ACQPS = 28; //sample window is XX SYSCLK cycles

    AdcaRegs.ADCSOC3CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C

    //

    //Intrupt

    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 4; //end of SOC4 will set INT1 flag

    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; //enable INT1 flag

    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared

     

    EDIS;

    }

     

     

    interrupt void cpu_timer0_isr(void)

    {

    if(num<1000)

    {num++;}

    else

    {num=0;}

    z=2*3.14*num/1000;

    a=30*sinf(z);

     

    CpuTimer0Regs.TCR.bit.TIF = 1;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    }

    // Step 1. Initialize System Control:

    InitSysCtrl();

    InitEPwm1Gpio();

     

    DINT;

    InitPieCtrl();

    IER = 0x0000;

    IFR = 0x0000;

    InitPieVectTable();

    EALLOW; // This is needed to write to EALLOW protected registers

    PieVectTable.EPWM1_INT = &epwm1_isr;

    PieVectTable.TIMER0_INT = &cpu_timer0_isr;

    EDIS;

    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0;

    EDIS;

    InitEPwm1Example();

    ConfigureADC();

    SetupADCEpwm();

    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;

    EDIS;

    IER |= M_INT3;

    // Enable EPWM INTn in the PIE: Group 3 interrupt 1-3

    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;

    PieCtrlRegs.PIEIER2.bit.INTx1 = 1;

    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;

    PieCtrlRegs.PIEIER3.bit.INTx2 = 1;

    PieCtrlRegs.PIEIER3.bit.INTx3 = 1;

    IER |= M_INT1;

    IER |= M_INT2;

    InitCpuTimers();

    ConfigCpuTimer(&CpuTimer0, 200, 20000);

    CpuTimer0Regs.TCR.all = 0x4000;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;

    EINT; // Enable Global interrupt INTM

    ERTM; // Enable Global realtime interrupt DBGM

    /******Voltage PI Regulator*****/

    CNTL_PI_F_init(&VC);

    VC.Ki = (500);

    VC.Kp = (5);

    VC.Umax= 10;

    VC.Umin= -10;

    /******Current PI Regulator*****/

    CNTL_PI_F_init(&IL);

    IL.Ki = (6000);

    IL.Kp = (0.005);

    IL.Umax= 30;

    IL.Umin= -30;

    i = 0;

    j = 0;

    k = 0;

    }

    interrupt void epwm1_isr(void)

    {

    //Samlped voltage and current

    i1=((float)(AdcaResultRegs.ADCRESULT1)-2210)*0.01;

    v1=((float)(AdcaResultRegs.ADCRESULT3)-2192)*0.0364;

    IL1=i1;

    VC1= v1;

    /*****voltage PI Regulator*****/

    VC.Ref=a;

    VC.Fbk=v1;;

    CNTL_PI_F_FUNC(&VC);

    /*****Current PI Regulator*****/

    IL.Ref=VC.Out;

    IL.Fbk=i1;

    CNTL_PI_F_FUNC(&IL);

    d=IL.Out;

    mag=PERIOD/100;

    ua=d*mag;

    CMP=0.5*PERIOD+ua;

    EPwm1Regs.CMPA.bit.CMPA =(Uint16)CMP;

    EPwm1Regs.ETCLR.bit.INT = 1;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;

    }

    void InitEPwm1Example()

    {

    // Setup TBCLK

    EPwm1Regs.TBPRD = PERIOD ; // Set timer period

    EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0

    EPwm1Regs.TBCTR = 0x0000; // Clear counter

    // Setup counter mode

    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;

    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.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync output is equal to zero

     

    // Setup shadowing

    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;

    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;

    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero

    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    // Setup compare

    EPwm1Regs.CMPA.bit.CMPA = 0; //

     

    // Set actions

    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Set PWM1A on High

    EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;

    EPwm1Regs.AQCTLB.bit.CAU = AQ_SET; // Set PWM1B on LOW

    EPwm1Regs.AQCTLB.bit.CAD = AQ_CLEAR;

      // Interrupt where we will change the Compare Values

     

    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event INTSEL= interrupt selection

    EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT

    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event

    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group

    EPwm1Regs.ETSEL.bit.SOCASEL = 2;

    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;

    }

    void ConfigureADC(void)

    {

    EALLOW;

    AdcaRegs.ADCCTL2.bit.PRESCALE = 2; //set ADCCLK divider to /2

    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);

    //

    //Set pulse positions to late

    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;

    //power up the ADC

    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;

    //delay for 1ms to allow ADC time to power up

    DELAY_US(1000);

    EDIS;

    }

    void SetupADCEpwm(void)

    {

    //Select the channels to convert and end of conversion flag

    //

    EALLOW;

    AdcaRegs.ADCSOC1CTL.bit.CHSEL = 1; //SOC0 will convert pin ADCINA0 and ADCRESULT0

    AdcaRegs.ADCSOC1CTL.bit.ACQPS = 28; //sample window is XX SYSCLK cycles

    AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C

    AdcaRegs.ADCSOC3CTL.bit.CHSEL = 3; //SOC3 will convert pin ADCINA3 and A1 ADCRESULT3

    AdcaRegs.ADCSOC3CTL.bit.ACQPS = 28; //sample window is XX SYSCLK cycles

    AdcaRegs.ADCSOC3CTL.bit.TRIGSEL = 5; //trigger on ePWM1 SOCA/C

    //Intrupt

    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 4; //end of SOC4 will set INT1 flag

    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; //enable INT1 flag

    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared

    EDIS;

    }

    interrupt void cpu_timer0_isr(void)

    {

    if(num<1000)

    {num++;}

    else

    {num=0;}

    z=2*3.14*num/1000;

    a=30*sinf(z);

    CpuTimer0Regs.TCR.bit.TIF = 1;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    }

  • Hi Shah,

    Happy to hear that the ADC issue is resolved! 

    Please create a new thread for new questions.