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.

"Slow" AD conversions

I'm using the AD converter on a Stellaris LM4F232H5QD eval board, and I have configured a sample sequence to take a single sample with 12-bit resolution. I have been experimenting with the hardware oversampling and tried values of 0, 2, 4, 8 and 16. My problem is that when I initiate a sample sequence it takes quite a long time before I can read the result. The times are as follows:

 0 HW OS: 7,5 us
 2 HW OS: 8,8 us
 4 HW OS: 12 us 
 8 HW OS: 15 us
16 HW OS: 23 us 

I'm reading the AD value like this: (taken from the examples)

unsigned long adc_value;

/* Trigger an AD conversion */
ADCProcessorTrigger(ADC0_BASE, 3);

/* Wait until sampling is complete */
while(!ADCIntStatus(ADC0_BASE, 3, false)) { }
ADCIntClear(ADC0_BASE, 3);
ADCSequenceDataGet(ADC0_BASE, 3, &adc_value);

The sample sequence is configured like this:

ADCSequenceDisable(ADC0_BASE, 3);
ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
ADCResolutionSet(ADC0_BASE, ADC_RES_12BIT);
ADCHardwareOversampleConfigure(ADC0_BASE, 0);
ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_END | ADC_CTL_IE | ADC_CTL_CH0);

Any ideas?

  • Hi Pelle,

    A single ADC conversion takes 1uS (1MSPS max rate).  This does not include the sysclk cycles to setting up the trigger, performing the hardware averaging, storing the result in the fifo and reading it out again. 

    So just looking at the delta time between your sample list.

      

    Pelle Windestam said:
     0 HW OS: 7,5 us
     2 HW OS: 8,8 us
     4 HW OS: 12 us 
     8 HW OS: 15 us
    16 HW OS: 23 us 

    Between 2 and 4 samples you have 3.2uS (I would have expected a minimum of 2uS)

    Between 4 and 8 samples you have 3uS (I would have expected a minimum of 4uS)

    Between 8 and 16 samples you have 8uS which is what I would have expected.

    So the accuracy of the way you calculate time seems about +/- 1uS

    Given that taking a single sample by (0 HW OS: 7.5uS) it seems like the overhead from when you start counting time to when you end counting time is 7.5us - 1us = 6.5us +/- 1uS.

    How are you clocking the rest of the system? 

    Are you using the PLL at all to run the system faster to reduce the overhead?

    How are you measuring the time delta?

    - Ken

  • I'm using this code for setting the system clock:

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    I'm a bit confused on how to use the PLL instead. Would that be faster for my application? I'm also doing serial communication and PWM control, could they be affected negatively somehow by using the PLL?

    I'm measuring time delta using an oscilloscope, setting a pin high before the ADC conversion and low afterwards. This is the complete code for the ISR that does the AD conversion:

     

    unsigned long adc_value;
    TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    GPIOPinWrite(GPIO_PORTJ_BASE, GPIO_PIN_4, GPIO_PIN_4);
    /* Trigger an AD conversion */
    ADCProcessorTrigger(ADC0_BASE, 3);
    /* Wait until sampling is complete */
    while(!ADCIntStatus(ADC0_BASE, 3, false)) { }
    ADCIntClear(ADC0_BASE, 3);
    ADCSequenceDataGet(ADC0_BASE, 3, &adc_value);
    GPIOPinWrite(GPIO_PORTJ_BASE, GPIO_PIN_4, ~(GPIO_PIN_4)); 

  • Hi Pelle,

    With a clock setting of

    Pelle Windestam said:
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    you are running the system clock at 16Mhz (62ns period). 

    In my previous post I stated you seem to be measuring approximately 6.5uS of overhead.  6.5/0.062 = 105 system clock cycles.

    If you went into the debugger and stepped through the resulting assembly code code from the point of writing the GPIO pin high to the point it writes the GPIO pin low, I would expect you will find approximately 105 instruction steps. 

    If you utilized the PLL you could run the system clock faster say 32Mhz and cut your overhead time in half.  However it will have to account for the new system clock rate by initializing your serial communication and pwm code accordingly.

    Note that in many cases the StellarisWare functions are optimized for portability vs efficiency.  If efficiency is what you are after direct register writes and hard coded macros may meet your needs.

    - Ken

  • I have now made some changes to my code. I am using the PLL, and running the system clock at 66.67 MHz, initializing the clock like this:

     

    SysCtlClockSet(SYSCTL_SYSDIV_3 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

     

    I have also made some changes to my ADC sequence. Now I run a sequence of 4 samples, one for each channel that I will be using. This is my current ADC init code:
    http://susepaste.org/65976251

    and my ADC trigger code is:
    http://susepaste.org/6223425

    As you can see in the picture below the total time is ~36 us for the 4 conversions. I would expect the time to be lower, even when using 4 samples and the driver library. Or do you think that could be the cause? In that case I will try using the register access method instead.

     

  • I have done some changes in my code, and I am currently initiating my ADC conversions from a PWM trigger, and using the uDMA controller to transfer the ADC results. I'm using an ADC Sequence with a single measurement in it, and the ADC resolution is 12 bits. The PWM runs at 20 kHz, so a new conversion is triggered every 50 us. On my scope I'm watching the PWM-signal on one channel and an indication pin which I set high when the ADC interrupt handler is called on another channel (low again when the ISR is complete). The times I have measured are:

    0 HW OS: 14 us
    2 HW OS: 22 us
    4 HW OS: 38 us

    Given that a single sample should take 1 us to complete, I think it still looks like quite a lot of overhead. 4 HW oversamples should take ~4 us, which means that the trigger and uDMA transfer takes ~34us. Is that reasonable?  (I'm running my system at 80 MHz)

    Attaching an image of how it looks with 2 HW OS. PWM (active low) is blue, ADC trigger is yellow.

    .