I think the key is whether you need continuous data for long periods of time and how precisely the data has to be sampled. I currently have a system with a SPI ADC from Analog Devices. It is an 8 channel device and is capable of 250,000 samples per second. I don’t need to sample that fast and neither do you so that makes our job much easier. You can use the SPI chip select (CS) line as the convert signal for most SPI ADCs. As long as you can set up your ADC to output data on the SPI MISO line every time it sees a convert signal, you shouldn’t need the data ready interrupt. Every SPI transfer toggles the CS so you get one conversion per transfer. I have a timer that kicks off my readADC method. I have to write one word over the SPI to configure the ADC and I get one sample back. I do this in a loop for each channel I need to convert and I’m done for that cycle The timer is pretty repeatable even with all the other stuff I have going on in my app. You should be able to get timing accuracy of +/- a couple of milliseconds.
One complication is my understanding is you don’t want to spend a lot of time in your event handlers, like a timer handler. All my timer handler does is stick a message to sample the ADC on a queue I have in implemented in my program. When the method that handles the queue sees the ADC message, it does the ADC read.
This approach works and is really simple if you don’t need long blocks of precisely timed samples. I’ve done that in the past but I’m a little hazy on how I did it. Seems like all did was set up my SPI transfer to read multiple bytes for as many samples as I needed. My recollection is the whole SPI transfer happened without significant jitter in the ADC conversion pulse timing.
If you tell me what ADC you’re using I can take a quick look and see if it should work this way.
Here’s my method
using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;
//using GHI.Hardware.EMX;
using GHI.Hardware.G400;
namespace miniCPF
{
class CN0254
{
// private static SPI.Configuration CN2054Config = new SPI.Configuration((Cpu.Pin)GHI.Hardware.EMX.Pin.IO18, false, 100, 100, false, true, 1000, SPI.SPI_module.SPI1);
private static SPI.Configuration CN0254Config = new SPI.Configuration(Pin.PC29, false, 0, 0, false, true, 100, SPI.SPI_module.SPI2);
private static SPI CN2054spi = new SPI(CN0254Config);
private static ushort[] txData = new ushort[1];
private static ushort[] rxData = new ushort[1];
private static ushort[] configWord = new ushort[8];
private static double[] voltage = new double[8];
private static int[] rxShort = new int[8];
private static double voltAccum = 0.0;
private static int shortAccum = 0;
//It take 2 samples before config word takes effect, see AD7689 data sheet timing diagrams
private static int numBogusChannels = 2;
private static int numAverages = 10; //seems to be a problem with averaging on the Raptor
private static int numChannels = 8;
private static int startCh = 0;
public static double[] scanAll()
{
double volts = 0.0;
//txData[0] = 0x3FFF; //Default
configWord[0] = 0xF004; //sequencer disabled, ch0 only. 1/4 BW filter
configWord[1] = 0xF204; //sequencer disabled, ch1 only. 1/4 BW filter
configWord[2] = 0xF404; //sequencer disabled, ch2 only. 1/4 BW filter
configWord[3] = 0xF604; //sequencer disabled, ch3 only. 1/4 BW filter
configWord[4] = 0xF804; //sequencer disabled, ch4 only. 1/4 BW filter
configWord[5] = 0xFA04; //sequencer disabled, ch5 only. 1/4 BW filter
configWord[6] = 0xFC04; //sequencer disabled, ch6 only. 1/4 BW filter
configWord[7] = 0xFE04; //sequencer disabled, ch7 only. 1/4 BW filter
for (int chNum = startCh; chNum < (startCh + numChannels); chNum++)
{
volts = 0.0;
voltAccum = 0.0;
shortAccum = 0;
txData[0] = configWord[chNum];
for (int sampleNum = 0; sampleNum < numAverages + numBogusChannels; sampleNum++)
{
CN2054spi.WriteRead(txData, rxData);
if (sampleNum > (numBogusChannels - 1))
{
//This converts the ADC output to voltage at the input to the ADC
volts = (3.81476E-05 * rxData[0]) + -6.35783E-06;
//This converts the voltage at the input to the ADC to the voltage at the input to the ADC buffer
volts = (volts - 1.251586) * -4.99;
voltAccum = voltAccum + volts;
shortAccum = shortAccum + rxData[0];
}
}
voltage[chNum] = voltAccum / numAverages;
rxShort[chNum] = shortAccum / numAverages;
//Debug.Print("CH " + chNum.ToString() + " " + rxShort[chNum].ToString() + " " + voltage[chNum].ToString("F3"));
//Debug.Print(" ");
}
return (voltage);
}
}
}