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.

TMS320F28069: Is it possible 100 Khz sampling 16 ADC channel ?

Part Number: TMS320F28069
Other Parts Discussed in Thread: CONTROLSUITE, C2000WARE

I am working on my rectifier project . And I am using all ADC channels. And I want to use my TMS320F28069 high performance.

So when I try sample all ADC channels at 100 khz it doesn't stable in 100 Khz. Its frequency changes. In TMS320F2806X technical reference book one sampling time is 444.44ns.

So in Simultaneous Sampling Mode 8*444.44ns = ~ 3.555 uS . So the maximum sampling frequency is 281 kHz. But I am not sampling in this rate. I am adding my adc setup code. What is the problem ??

Please help me.

    EALLOW;


    SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
     (*Device_cal)();




     AdcRegs.ADCCTL1.bit.ADCBGPWD  = 1;      // Power ADC BG
     AdcRegs.ADCCTL1.bit.ADCREFPWD = 1;      // Power reference
     AdcRegs.ADCCTL1.bit.ADCPWDN   = 1;      // Power ADC
     AdcRegs.ADCCTL1.bit.ADCENABLE = 1;      // Enable ADC
     AdcRegs.ADCCTL1.bit.ADCREFSEL = 0;      // Select interal BG



     AdcRegs.ADCCTL2.bit.CLKDIV2EN = 0;



    //ADC Selection
    GpioDataRegs.GPACLEAR.bit.GPIO29 = 1;


    AdcRegs.ADCSAMPLEMODE.all=0x00FF;

    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   = 0x0F;    // setup EOC1 to trigger ADCINT1 to fire



    AdcRegs.ADCSOC0CTL.bit.CHSEL    = 0x0;    // set SOC0 channel select to ADCINA0
   // AdcRegs.ADCSOC1CTL.bit.CHSEL    = 0x0;
    AdcRegs.ADCSOC2CTL.bit.CHSEL    = 0x1;
   // AdcRegs.ADCSOC3CTL.bit.CHSEL    = 0x1;
    AdcRegs.ADCSOC4CTL.bit.CHSEL    = 0x2;
   // AdcRegs.ADCSOC5CTL.bit.CHSEL    = 0x2;
    AdcRegs.ADCSOC6CTL.bit.CHSEL    = 0x3;
   // AdcRegs.ADCSOC7CTL.bit.CHSEL    = 0x3;
    AdcRegs.ADCSOC8CTL.bit.CHSEL    = 0x4;
   // AdcRegs.ADCSOC9CTL.bit.CHSEL    = 0x4;
    AdcRegs.ADCSOC10CTL.bit.CHSEL    = 0x5;
   // AdcRegs.ADCSOC11CTL.bit.CHSEL    = 0x5;
    AdcRegs.ADCSOC12CTL.bit.CHSEL    = 0x6;
   // AdcRegs.ADCSOC13CTL.bit.CHSEL    = 0x6;
    AdcRegs.ADCSOC14CTL.bit.CHSEL    = 0x7;
   // AdcRegs.ADCSOC15CTL.bit.CHSEL    = 0x7;

    AdcRegs.ADCSOC0CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC1CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC2CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC3CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC4CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC5CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC6CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC7CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC8CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC9CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC10CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC11CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC12CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC13CTL.bit.TRIGSEL  = 0;    // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC14CTL.bit.TRIGSEL  = 0;    // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC
    AdcRegs.ADCSOC15CTL.bit.TRIGSEL  = 0;    // 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 SOC0 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 SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC5CTL.bit.ACQPS    = 6;    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC6CTL.bit.ACQPS    = 6;    // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC7CTL.bit.ACQPS    = 6;    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC8CTL.bit.ACQPS    = 6;    // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC9CTL.bit.ACQPS    = 6;    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC10CTL.bit.ACQPS    = 6;    // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC11CTL.bit.ACQPS    = 6;    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC12CTL.bit.ACQPS    = 6;    // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC13CTL.bit.ACQPS    = 6;    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC14CTL.bit.ACQPS    = 6;    // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC15CTL.bit.ACQPS    = 6;    // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)


   // PieVectTable.ADCINT1 = &adcHwiISR;

    //PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
    IER |= M_INT1; // Enable CPU Interrupt 1

    EDIS;

  • Thanks for reaching out to the TI C2000 E2E forum.  Although your main question is how to get the ADC to sample at 100kHz in simultaneous mode, I'd like to break it up into some more fundamental questions for a better answer:

    1)Max conversion time/conversion time in general

    2)Setting up the ADC in simultaneous mode

    3)Triggering the ADC at the sampling rate needed

    I'm assuming based on the attached code snippet that you have already used one of the controlSUITE or C2000Ware examples as a starting point, that the clock tree is as follows:

    F28069 CPU clock = 90MHz

    F28069 ADC clock = 45MHz

    1)The conversion time of the on chip ADC can be broken down into two main pieces:

    a)Time of sample(controlled by the ADC_ACQPS bit field), min = 7 ADC Clocks

    b)Conversion time(always 13 ADC clocks)

    However, if we keep the ADC fully loaded then we can sample the next channel while the current conversion is ongoing. Doing this allows us to start the next sample after 6 ADC clocks into the current conversion, which means we would get an ADC result every 13 ADC Clocks

    Time for 1 ADC sample from IDLE = (7+13) * 1/45MHz = 444.44ns

    Time for subsequent ADC conversions if ADC is kept loaded = ((Sample Clocks - 7)+13) * 1/45MHz =  288.89ns (where Sample Clocks in this case = 7)

    In your case, using simultaneous sampling this would work out to a total time after trigger for all 16 channels = ((7+13) * 1/45MHz) + (15*(13*1/45MHz)) = 4.78us from trigger to ADC data for 16 channels.

    Given that you are working on a 100kHz desire control loop speed, this would mean that of the 10us you have to take data, apply your control law, almost half of it will be used just to get the ADC data, or more applicable you will have a little more than 5us to use the ADC data.  Given the CPU speed of 90MHz, this works out to ~4500 CPU cycles of work that can be done after the ADC results are in.  

    2)Setting up the ADC in simultaneous mode

    For the most part your code is correct.  As you have correctly commented out, there is no need to define any ADC parameters for the odd SOC fields, since the even SOC take care of this for the odds in this mode.  However, this also applies to the triggers, and as such you'll want to make sure that whatever trigger source is used, that it is not applied to the odd SOCTRIG fields.  In the example code you have provided all triggers are coming from SW; in which case you can write the SW so that it does not set any odd SOC FRC bits.

    3)Triggering the ADC at the sampling rate needed

    I suspect this is the part that is not working correctly, but may be influenced by #1 or #2 above, which is why I wanted to dive a little deeper.  Assuming all the above is acceptable; then to trigger the ADCs at 100kHz intervals you would just need to write to the ADCFRC bits(remember, only the odd SOCs) at 100kHz intervals.  You could use a CPU Timer and ISR to do this, or just a for loop with the correct wait time.

    I believe the easiest method would be to use a PWM to trigger the ADCs, since more than likely the PWM frequency is also 100kHz.  The base ADC example shows how to use the PWM in this manner, you would just need to tailor it to 100kHz period, as well as changing back your trigger sources to come from the PWM of your choice(and again remember to leave the odd numbered SOCs unconfigured in this case).

    Best regards,

    Matthew