Pages: 1 [2]   Go Down
Author Topic: How can I speed up the ADC?  (Read 3269 times)
0 Members and 1 Guest are viewing this topic.
United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you want to maximise the ADC conversion rate, use the conversion complete interrupt (see the atmega328p datasheet). In the interrupt service routine, read the adc result and store it in a variable appropriate to the channel you have just sampled. Then set the adc mux to the next channel (or back to the first channel, if you have done all the channels of interest) and kick off another conversion. Like this:

Code:
const byte numAdcChannels = 6;
volatile unsigned int adcResult[numAdcChannels];
volatile byte currentAdcChannel = 0;

void startConversion()
{
  ADMUX = (B01000000 | currentAdcChannel);   // Vcc reference, select current channel
  delayMicroseconds(5);    // only needed if using sensors with source resistance > 10K
  ADCSRA = B11001111;   // ADC enable, ADC start, manual trigger mode, ADC interrupt enable, prescaler = 128
}

// Interrupt service routine for ADC conversion complete
ISR(ADC_vect)
{
  // The mcu requires us to read the ADC data in the order (low byte, high byte)
  unsigned char adcl = ADCL;
  unsigned char adch = ADCH;
  adcResult[currentAdcChannel] = (adch << 8) | adcl;
  ++currentAdcChannel;
  if (currentAdcChannel == numAdcChannels)
  {
     currentAdcChannel = 0;
  }
  startConversion();
}

void setup()
{
   ...
   startConversion();
}

Then in loop() you can look at the adcResult variables and work out what needs to be done. You should disable interrupts while reading them in loop(). If you change program the ADC to use only 8-bit accuracy, then you can use a byte array instead of an unsigned int array, then you do not need to disable interrupts when reading them.

BTW using a delay inside an isr should generally be avoided, however very short delays to allow hardware to settle are OK.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

South Africa
Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

void startConversion()
{
  ADMUX = (B01000000 | currentAdcChannel);   // Vcc reference, select current channel
  delayMicroseconds(5);    // only needed if using sensors with source resistance > 10K
  ADCSRA = B11001111;   // ADC enable, ADC start, manual trigger mode, ADC interrupt enable, prescaler = 128
}
...
BTW using a delay inside an isr should generally be avoided, however very short delays to allow hardware to settle are OK.

I'm trying to understand what the delay will do to the ADC process, but my understanding of the manual isn't great. I've reread the manual on ADC several times but I cannot make sense of statements such as:
Quote
An analog source applied to ADCn is subjected to the pin capacitance and input leakage of that pin, regardless of whether that channel is selected as input for the ADC. When the channel is selected, the source must drive the S/H capacitor through the series resistance (combined resistance in the input path).

Does this imply that the ADC circuit starts charging once a channel is selected in ADMUX but before the ADCSRA ADSC bit is set?  Elsewhere the manual states that the sample & hold of a channel only starts after the ADSC bit in ADCSRA is set, so a delay before setting ADCSRA shouldn't affect the charging of the ADC cap?
« Last Edit: October 06, 2012, 12:18:23 pm by Christo » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm trying to understand what the delay will do to the ADC process, but my understanding of the manual isn't great. I've reread the manual on ADC several times but I cannot make sense of statements such as:
Quote
An analog source applied to ADCn is subjected to the pin capacitance and input leakage of that pin, regardless of whether that channel is selected as input for the ADC. When the channel is selected, the source must drive the S/H capacitor through the series resistance (combined resistance in the input path).

Does this imply that the ADC circuit starts charging once a channel is selected in ADMUX but before the ADCSRA ADSC bit is set? 

Yes. When no conversion us in progress, the sample capacitor is connected to the input channel pin selected by the mux.

Elsewhere the manual states that the sample & hold of a channel only starts after the ADSC bit in ADCSRA is set, so a delay before setting ADCSRA shouldn't affect the charging of the ADC cap?

As far as I can tell, "sample and hold" comprises waiting 1.5 ADC clocks, then disconnecting the capacitor from the selected input pin and connecting it to the converter. I have found that a delay (between setting the mux and starting the conversion) of about one microsecond per 10K source resistance is needed to achieve accurate results. There is some delay built in to the sample process already, so no delay is needed when the source resistance is 10K or less (as recommended in the datasheet).
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Ghent - Belgium
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Firemann00b,

Just a few design considerations before you max out on the ADC.
  • Do you really need to sample that fast. Controlling stuff is about controlling or changing the state they are in. Speed is a state. What is important is how fast does your robot CHANGE speed / steer. I take it it is not going to make a U-turn with a radius of 1 cm if it's doing 2 m/s. There is no point in having a very fast controller if the robot cannot comply with the commands its been given. It will cause the controller to oversteer, and can cause stability issues (oscillations)
  • Fast sampling creates noisy readings. You will have to filter the readings.
  • Fast sampling creates lots of data. Arduinos do not have lots of memory to store that information, nor do they have a lot of CPU power to process it in real time.
  • Look ahead. Knowing what's coming gives you more time to react. Faster sampling won't.
regards,

Pieter

I plan to read the interrupts on a cyclic basis. I'm not going to implement it fully, but my aim is to make my program run hard real time(for those who aren't into controller theory, this means there is no jitter on the delay between reading the input and writing the output). So it's of great importance I generate an input fast, so there's enough time left in the cycle to calculate the output. The cycle time for the whole algorithm is about 5 ms to make turns with a minimal radius of 10cm. It's calculated that if the car keeps going forward for 10 cycles, it will have lost the line. For 8 sensors, it takes about 1 ms to read them all with a division factor of 128. This means a fifth of the cycle is lost just to reading the sensors. And I have to use linear interpolation to translate the sensor values to an error and then calculate the motor speeds to compensate for the error.
Logged

Oh electronics! Thou art a fickle mistress!

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think your teacher laid out, too clearly in my view, what you needed to do.

If you really want fast adc (I don't think you need), put the adc on automatic sampling and it will perform adc non-stop. Read the adc high byte, left aligned, provided you with 8-bit resolution. Read the adc high byte, right aligned, provided you with 2-bit resolution.
Logged

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Let me just add one more bit: you may want to think about your implementation. For you to implement a PID on top of a fast adc to just follow a line, either your car is powered by a rocket or your implementation is seriously wrong.
Logged

Ghent - Belgium
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think your teacher laid out, too clearly in my view, what you needed to do.

.. Read the adc high byte, left aligned, provided you with 8-bit resolution. ..

That's what I ended up doing, as you can see in my code. The 8-bit resolution actually did the trick for me, it drastically reduces the processing time for normalizing the sensor values and translating those values into a line position.

Let me just add one more bit: you may want to think about your implementation. For you to implement a PID on top of a fast adc to just follow a line, either your car is powered by a rocket or your implementation is seriously wrong.


My car has to go 2 m/s, I really wanted some room to play in those 5 ms of cycle time. Now I've done some proper testing, apparently I've got plenty of room, even with a division factor of 128. Still, myAnalogRead is usefull, because I might want to go for fuzzy instead of PID. Once I comfortably get to those 2m/s, I might want to go even faster(but that's never going to happen in this universe smiley-wink )
Logged

Oh electronics! Thou art a fickle mistress!

Pages: 1 [2]   Go Up
Jump to: