Pages: [1]   Go Down
Author Topic: ADC conversion vs.  Interrupts  (Read 1001 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Today I noticed that my timer IRQ driven ADC polling is about 2% of the mark. That is it runs ~2-4% slower than I would expect it. The issue is not due the crystal frequency because I already checked timing if all IRQs are off, I get exactly what I expect.

Then I started analyzing and now I have some theory about what happens. I have a timer IRQ at 10 kHz (the standard times is off). Then inside the IRQ I call analogRead().

Inside the standard libraries I found out that this will block for some time due to the following loop:

      // ADSC is cleared when the conversion finishes
      while (bit_is_set(ADCSRA, ADSC));

And in wiring.c I found

      // set a2d prescale factor to 128
      // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
      // XXX: this will not work properly for other clock speeds, and
      // this code should use F_CPU to determine the prescale factor.
      sbi(ADCSRA, ADPS2);
      sbi(ADCSRA, ADPS1);
      sbi(ADCSRA, ADPS0);

According to the datasheet conversions take 13 cycles. Now 13 cycles @ 125 kHz is about 104 microseconds. So I assume that in 4% of the timer interrupts the conversion is still blocking while another interrupt is triggered. This would explain the effect perfectly well.

The obvious solution to decrease the sample frequency is not exactly what I would like to to.

Now here come my two questions:

1) Is my assesment correct?
2) What would be the highest sampling frequency that is guaranteed to give proper timings? 9kHz? Or is this to agressive?

Cheers, Udo

Logged

Check out my experiments http://blog.blinkenlight.net

Gothenburg, Sweden
Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The problem is the wait for ADC conversion completed loop. We want to be able to do other processing while the ADC conversion is taking place.

I think a usable strategy is to have a timer interrupt that does the following:

TimerInterruptHandler:
    Check, Read and store result from previous ADC conversion
   /* That is analogConversionRead() */
    Start next ADC conversion
   /* That is analogConversionStart(chn) */
   end of TimerInterruptHandler

So the ADC conversions are done between the TimerInterrupts, not within the timer interrupts.

Or you might place an interrupt on the ASDC conversion completed event.

All of this requires some low level coding, the first is easier: just take the analogRead code, reverse the read value and start conversion and place this in the TimerInterruptHandler.

    
« Last Edit: August 24, 2009, 03:25:11 pm by mlundin » Logged

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I shifted the ADC out of the timer ISR. Still I had 2% deviation. Then I figured that maybe the idea of reloading the timer in the ISR causes the deviations. I shifted to CTC mode as described here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1216085233

Now the results are much better. I now have a very different issue: how to figure out how accurate it actually is. I think it will run overnight against a stopwatch smiley

Logged

Check out my experiments http://blog.blinkenlight.net

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Finally success. After 10 hours it deviated about 40 ppm from the stopwatch --> this is within the tolerance of the crystal. Finally success smiley
Logged

Check out my experiments http://blog.blinkenlight.net

Pages: [1]   Go Up
Jump to: