[CODE][C]Scanning, "free running" ADC. Version 2

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know it's been a while but I wanted to finally post this. This is an updated version of my previous "tutorial". That thread however has gotten too long and I don't want to go and completely change my original post. I'm hoping to address all the concerns that came up there...

Notice
While this is posted in the "AVR Tutorials" forum, it is not a tutorial on using this code. This, as was the previous version, is a description of a more advanced way to scan all of the ADC inputs in the background and I have included my implementation only as an example. I cannot make any commitment to maintain or help anyone with this software.

Disclaimer
This software is provided completely without warranty. It is an example implementation of an advanced A/D converter scanner. I take no responsibility for it's function or helping other use it.

Changes
- 10 bit!
- not pointer based
- "complete"

Design
I originally used pointers to variables from the main loop to combine the need for marking which lines were enabled (non-null ptr) and to get the data out. This however led to needing a second variable to hold a latched value for the main loop because otherwise it would change during the loop.

So when I extended this to 10-bit I decided to change the structure. Now I store a byte who's bits are the enabled lines and then an array of current values.

Usage

// Initialization
ADC_init();
ADC_setEnabled(0xff); // Enable all the pins
sei();
ADC_startScan();

uint16_t motorPosition, armPosition;

// Retrieve values
motorPosition = ADC_get(0); // returns most recent value of ADC0
armPosition   = ADC_get(1); // returns "                  " ADC1
...

Improved resolution
I have not written the software for this yet but there is a simple way to virtually increase the ADC's resolution:
I noticed while using this code that the ADC is actually taking ~80 measurements per 100Hz main loop (128 ADC prescaler, 16Mhz F_CPU). If instead of always storing the last read value, we stored the sum of the last 8 values read. Then, you effectively get a 13-bit ADC! :-D

A similar implementation stores the current sum and then returns the count with the sum for variable (maximum) resolution every main loop.

Local approximations
A more advanced implementation of the above that we've been playing with in excel is to store a running weighted average. Then you don't need to store the last eight values. It would also be simple to implement a velocity estimate at this low level.

Future
I have since re-written these as a c++ class based adc, similar to the classes used in Arduino but for "power users". I don't like the complete abstraction from the underlying hardware (ie. pin #0-32 over PORT[A-G][0-7]) but I do like the c++ syntax and abstraction. It is not complete and completely untested. I hope to release is on AVRFreaks eventually.

Another place for expansion is to support more MUX settings. We currently only support individual reading of the inputs. It would be nice to support differential measurements, the internal bandgap, etc.

Attachment(s): 

Pushing AVRs to their limits

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If instead of always storing the last read value, we stored the sum of the last 8 values read. Then, you effectively get a 13-bit ADC!

This is not true. Though you might have a 13 bit number, you do not have 13 bit accuracy. You need 4^n oversampling to get n extra bits accuracy, so to get 13 bits you need 64 samples. It also requires that the sample have noise in the range of those bits.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It never occurred to me that you might not get the full improved accuracy! A quick search and hurray for wikipedia!
Oversampling

Describing the three things oversampling is used for: Anti-aliasing, increasing resolution, and reducing noise.

I don't see the math for how accuracy goes as 4^n (=2^2n), but I believe it.

At a minimum however, oversampling can be used to reduce the noise by simply dividing our 13-bit "improved" accuracy by 8.

Another possible future enhancement would be to distribute the sampling un-evenly, getting a large number of readings for the lines that we want the improved accuracy on and less on ones we don't care about. (ie, sample the high resolution roll rate gyro 16 times for 12-bit accuracy and the steering wheel input only once per main loop for the normal 10-bit accuracy)

Pushing AVRs to their limits

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is an Atmel paper describing how to apply oversampling.
http://atmel.com/dyn/resources/prod_documents/doc8003.pdf

Basically in order to increase the resolution by one bit from 10 to 11bit you need to sum four samples and then shift right by 1 (divide by 2)

In order to go from 10 to 12bit you need to add 16 samples and then shift the result right by 2 (divide by 4).

The effective sampling rate drops accordingly so when you have 1000 samples/sec and you apply a 16x oversampling then the effective sampling rate drops to 1000/16 and the resolution increases to 12bit.

There is also the need to have some noise in the source that you measure, for details check the paper mentioned above.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alexan_e wrote:
The effective sampling rate drops accordingly so when you have 1000 samples/sec and you apply a 16x oversampling then the effective sampling rate drops to 1000/16 and the resolution increases to 12bit.

There is also the need to have some noise in the source that you measure, for details check the paper mentioned above.

Yeah this is exactly true - if ADC value 15 corresponded to voltage of 0.130 volts and 16 was 0.135 volts, if you have a noiseless signal at 0.132 volts the ADC would return 15 all the time. However, if you have uniform, somewhat gaussian noise (normal deviation), multiple samples would return more 15's than 16's and oversampling would work (on average, single periods could still have the "wrong" ratio of 15s and 16s).

To actually get additional resolution, one could have two ADC units side by side with the other having a circuit to drop the voltage 0.005 relative to the other, so you'd get 1 bit of extra resolution without any impact on sampling rate. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could you dither the aref by 5mv using an output and a resistor?

Imagecraft compiler user