Logging 100 ksps with the Arduino internal ADC
Moderators: adafruit_support_bill, adafruit

Logging 100 ksps with the Arduino internal ADC

by fat16lib on Wed Jul 11, 2012 3:24 pm

I have been experimenting with a fast logger using the Data Logging Shield and a sketch to log 8-bit data from an Arduino analog pin. I have been able to log data to an SD card at 100,000 samples per second.

If there is any interest in this sketch I will polish it a bit and post it.

Here is a sample of a 5 kHz Sine Wave.
data.png
data.png (38.32 KiB) Viewed 6055 times

Here is a FFT of logged data to see how much noise is at other frequencies.
fft.png
fft.png (26.52 KiB) Viewed 6055 times


Amazingly I was able to log the data to a new version of this cheap SD card, $4.99 with shipping on Amazon. This card is not fast in random access mode but works extremely well in the special streaming mode that I use.
sd-card.jpg
sd-card.jpg (12.19 KiB) Viewed 6055 times
fat16lib
 
Posts: 593
Joined: Wed Dec 24, 2008 1:54 pm

Re: Logging 100 ksps with the Arduino internal ADC

by adafruit_support_bill on Wed Jul 11, 2012 4:03 pm

Very impressive. Customers often ask "how fast can I log". Now I have a new post to point them to :D
User avatar
adafruit_support_bill
 
Posts: 30824
Joined: Sat Feb 07, 2009 10:11 am

Re: Logging 100 ksps with the Arduino internal ADC

by fat16lib on Fri Aug 10, 2012 8:15 pm

I have posted a sketch that can log data from the internal Arduino ADC at very high sample rates using an ISR to capture ADC values.

The sketch is posted as AnalogIsrLogger20120810.zip here http://code.google.com/p/beta-lib/downloads/list.

The sketch can log 8-bit ADC values at 100,000 samples per second. The estimated accuracy is 7.3 ENOB.

The sketch can also log 10-bit ADC values at over 30,000 samples per second with a reasonable accuracy (Estimated ENOB 9.3). It can log 10-bit data at up to 60,000 samples per second with an estimated accuracy of 8.5 ENOB.

Very high quality SD cards with low write latency are required to achieve these rates. Three SanDisk cards that work are shown in a photo included with the sketch.

Here is the readme file:
The AnalogIsrLogger.ino program demonstrates techniques for logging data to
an SD card at high rates by capturing data in a timer driven interrupt routine.

I have been able to log data at up to 100,000 samples per second using
AnalogIsrLogger.ino. This requires an excellent SD card. See SD_CARDS.JPG
for photos of cards that have worked at 100,000 8-bit samples per second.

Example data is shown in DATA.PNG and it's FFT is in FFT.PNG. See ExcelFFT.pdf
in the ADCdocs folder.

The accuracy of the ADC samples depends on the ADC clock rate. See the
ADC_ENOB.PNG file for a plot of accuracy vs ADC clock frequency.

See files in ADCdocs folder for more information on ADC accuracy.

To modify this program you will need a good knowledge of the Arduino
ADC, timer1 and C++ programming. This is not for the newbie.

You may need to increase the time between samples if your card has higher
latency. Using a Mega Arduino can help since it has more buffering.

I have an LED and resistor connected to pin 3 to signal data overruns.
You can disable this feature by setting the pin number negative:

// led to indicate overrun occurred, set to -1 if no led.
const int8_t RED_LED_PIN = 3;

These programs must be used with a recent version of SdFat. The program
was developed using sdfatlib20120719.zip from:

http://code.google.com/p/sdfatlib/downloads/list

You also need to install the included BufferedWriter library. It provides
fast text formatting.

Place these three folders in your sketchbook libraries folder.

Place the AnalogIsrLogger folder in your sketchbook.

The program has four commands:

c to check for overruns
d to dump data to Serial
r to record ADC data
t to convert file to text

All commands can be terminated by entering a character from the serial monitor.

The r command will record ADC data to a binary file. It will terminate
when a character is entered on the serial monitor or the the maximum file
block count has been reached.

The d command converts the binary file to text and displays it on the serial
monitor. Entering a character on the serial monitor terminates the command.

The t command converts the binary file to a text file. Entering a character
on the serial monitor terminates the command.

The c commands checks the binary file for overruns. Data overruns happen when
data samples are lost due to long write latency of the SD.

A number of program options can be set by changing constants at the beginning
of the program. Key settings include:

// set RECORD_EIGHT_BITS nonzero to only record high 8-bits
#define RECORD_EIGHT_BITS 1

// Sample rate in samples per second.
const uint32_t SAMPLE_RATE = 100000;

// Analog pin number
const uint8_t ANALOG_PIN = 0;

// digital pin to indicate overrun, set to -1 if not used
const int8_t RED_LED_PIN = 3;

// SD chip select pin
const uint8_t chipSelect = SS;

// max file size in blocks
const uint32_t FILE_BLOCK_COUNT = 256000;

// log file name
#define FILE_NAME "LOGFILE.BIN"

// Reference voltage
uint8_t const ADC_REF_AVCC = (1 << REFS0);
fat16lib
 
Posts: 593
Joined: Wed Dec 24, 2008 1:54 pm

Re: Logging 100 ksps with the Arduino internal ADC

by wikkit on Mon Oct 15, 2012 1:05 am

If you are reading six analog signals at ten bits, how fast could it run?

For comparison, how fast will the demo sketch that is on the data logger page run? Can it get to 1khz, or does it need a msec number greater than 1 for the "LOG_INTERVAL" definition?
wikkit
 
Posts: 1
Joined: Mon Oct 15, 2012 12:59 am

Re: Logging 100 ksps with the Arduino internal ADC

by adafruit_support_bill on Mon Oct 15, 2012 6:32 am

For 6 readings, the limiting factor would be settling time for the ADC multiplexer. High impedance sensors can take some milliseconds to settle.

The limiting factor on the demo sketch will likely be all the serial output it does. If you strip that out, you could probably do better than 1KHz.
User avatar
adafruit_support_bill
 
Posts: 30824
Joined: Sat Feb 07, 2009 10:11 am

Re: Logging 100 ksps with the Arduino internal ADC

by adafruit_support_mike on Tue Oct 16, 2012 5:31 pm

adafruit_support wrote:For 6 readings, the limiting factor would be settling time for the ADC multiplexer. High impedance sensors can take some milliseconds to settle.

It's also worth remembering that multiplexing an ADC gives you the effect of negative phase shift.

For the sake of argument, let's say we have all six analog inputs connected to the same signal (a sine wave), and call a set of readings on all six pins a 'frame'. All six values in a frame will be different since they're snapshots of the same signal at different times. Given the timing, the sixth reading of frame 1 will be closer to the first value of frame 2 than the first value of frame 1. If you treated all the values in a frame as though they happened simultaneously, you'd see the later readings effectively shifted backwards in time.

That isn't a big deal when you're measuring slow-moving signals, but when the delay between readings becomes a large fraction of the signal period, you get problems.

Taking 100ksps as a baseline, one frame of six readings would take .00006 seconds, and the lag between the first and last readings would be .00005s. You'd see 180 degrees of phase shift for a signal whose period is twice that long (.0001s), or 10kHz. You'd see 90 degrees of phase shift between the first and last readings in a frame for signals moving at 5kHz.
When you void a product warranty, you give up your right to sue the manufacturer if something goes wrong and accept full responsibility for whatever happens next. And then you truly own the product.
User avatar
adafruit_support_mike
 
Posts: 10084
Joined: Thu Feb 11, 2010 2:51 pm

Re: Logging 100 ksps with the Arduino internal ADC

by rubenk1 on Mon Apr 15, 2013 10:42 pm

Apologies for digging up an old post. Can I use parts of this fast logging sketch to make my logging system faster?

I am using the datalogging shield to log rainfall. The problem I have is that I am losing a little bit of data capture time I log. Let me explain:

In the loop: I am summing ticks each time my sensor senses rainfall. I want this loops to run as fast as possible.
When 10 seconds has passed I call a function for datalogging.
This function then checks to see if at least 60 seconds has passed. If not, then it keeps that summed 10 second value in memory. If 60 seconds has passed, then it writes all 6 summed readings that have been for the minute.
This is all standard, as the refrigerator and light code was well constructed (yay).
The issue I have it that the time in between each 10 second value is drifting by anywhere from a few milliseconds and sometimes about 40 milliseconds or possibly more. Those milliseconds are time that my main loop isn't adding up ticks.

I am trying to decide if I need to use a pseudo RTOS or scheduler type system (chime in with your favorite) OR if I can reduce the amount of time it takes to record the data to the card. I assume that the 5 or 10 millisecond "delays" are due to populating registers and I don't know if there is anything I can do about that. I assume the 30-40 msec delays are due to writing to the card. I can check to see if this occurs every 60 seconds to verify. Is this the wrong tool for my problem?
Thank you very much.
rubenk1
 
Posts: 10
Joined: Tue Mar 26, 2013 1:48 pm

Re: Logging 100 ksps with the Arduino internal ADC

by adafruit_support_bill on Tue Apr 16, 2013 6:56 am

It is hard to say without seeing how your code is structured, but it sounds like you should be using interrupts to count these raindrop events.
User avatar
adafruit_support_bill
 
Posts: 30824
Joined: Sat Feb 07, 2009 10:11 am