I've been learning about ADCs and analog circuits in general (you may have seen other posts from me along these lines).
One of the resources i found extremely informative is from John Beale from Dangerousprototypes forum on some of his work with the LTC2400 and LTC2440 24-bit ADC's.
My setup is an Arduino connected to 12V. The same 12V supplies a typical LM7805 regulator circuit that is the Vcc and +Ref for the ADC (and other opamps that are not connected right now, im just testing the ADC. I have a more simplified version of his code here that I have adapted to my abus- err, I mean "experimentation".
My two questions are as follows:
1) When this is running and the +IN simply has a 1k ohm R to GND, the ADC output value still seems to float a bit. Strange?
More importantly:
2) It seems that the actual voltage range that I can measure seems to cap at 2.5v (2500000 is the output sent over serial). The datasheet tells me the +IN pin can work within GND and Vcc (But don't even THINK about going overrange in either direction!). Is this the code that is giving me this result? In a perfect world, in theory shouldn't I get 16777216 'steps' between 0V and +REF (which is connected to Vcc)?
One of the resources i found extremely informative is from John Beale from Dangerousprototypes forum on some of his work with the LTC2400 and LTC2440 24-bit ADC's.
My setup is an Arduino connected to 12V. The same 12V supplies a typical LM7805 regulator circuit that is the Vcc and +Ref for the ADC (and other opamps that are not connected right now, im just testing the ADC. I have a more simplified version of his code here that I have adapted to my abus- err, I mean "experimentation".
My two questions are as follows:
1) When this is running and the +IN simply has a 1k ohm R to GND, the ADC output value still seems to float a bit. Strange?
More importantly:
2) It seems that the actual voltage range that I can measure seems to cap at 2.5v (2500000 is the output sent over serial). The datasheet tells me the +IN pin can work within GND and Vcc (But don't even THINK about going overrange in either direction!). Is this the code that is giving me this result? In a perfect world, in theory shouldn't I get 16777216 'steps' between 0V and +REF (which is connected to Vcc)?
Code:
/*
Interface between Arduino DM board and Linear Tech LTC2440 24-bit ADC
Oct. 24 2012 John Beale
LTC2440 <----------> Arduino
10: /EXT : ground (use external serial clock)
11: /CS <- to digital pin 10 (SS pin)
12: MISO -> to digital pin 12 (MISO pin)
13: SCLK <- to digital pin 13 (SCK pin)
15: BUSY -> to digital pin 9 (low when result ready)
1,8,9,16: GND : all grounds must be connected
2: Vcc : +5V supply
3: REF+ : +5V reference
4: REF- : GND
5: IN+ : Input+
6: IN- : Input-
7: SDI : +5V (select 6.9 Hz output rate, or GND for 880 Hz rate)
14: Fo : GND (select internal 9 MHz oscillator)
http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
*/
#include <SPI.h> // include the SPI library
#include <digitalWriteFast.h> // from http://code.google.com/p/digitalwritefast/downloads/list
// I had to update the WriteFast library for Arduino 1.0.1: replace "#include wiring.h" and "#include WProgram.h"
// with "#include <Arduino.h>" in libraries/digitalwritefast/digitalWriteFast.h
#define VREF (5.0) // ADC voltage reference
#define PWAIT (198) // milliseconds delay between readings
#define SLAVESELECT 10 // digital pin 10 for CS/
#define BUSYPIN 9 // digital pin 9 for BUSY or READY/
const int nsamples = 10; // how many ADC readings to average together (original was 50, changed to 10 jfn)
int SpedOUT = 8;
int SpedIN = 7;
boolean CurrentState = LOW;
boolean SpedState = LOW;
//---Smoothing variables
const int numReadings = 7;
float readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
float total = 0; // the running total
float average = 0; // the average
// SPI_CLOCK_DIV16 gives me a 1.0 MHz SPI clock, with 16 MHz crystal on Arduino
void setup() {
Serial.begin(115200); // set up serial comm to PC at this baud rate
pinMode (SLAVESELECT, OUTPUT);
pinMode (BUSYPIN, INPUT);
pinMode (SpedOUT, OUTPUT);
pinMode (SpedIN, INPUT);
digitalWriteFast(SLAVESELECT,LOW); // take the SS pin low to select the chip
delayMicroseconds(1);
digitalWriteFast(SLAVESELECT,HIGH); // take the SS pin high to start new ADC conversion
digitalWrite(SpedOUT, HIGH); //Start in low speed high accuracy mode. (6.9Hz samples)
SPI.begin(); // initialize SPI, covering MOSI,MISO,SCK signals
SPI.setBitOrder(MSBFIRST); // data is clocked in MSB first
SPI.setDataMode(SPI_MODE0); // SCLK idle low (CPOL=0), MOSI read on rising edge (CPHI=0)
SPI.setClockDivider(SPI_CLOCK_DIV16); // set SPI clock at 1 MHz. Arduino xtal = 16 MHz, LTC2440 max = 20 MHz
//---Reset smoothing vars to 0
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
// throw away the first few readings, which seem to be way off
for (int i=0;i<2;i++) {
SpiRead();
}
}
void loop() {
int i;
int uVolts; // average reading in microvolts
long n; // count of how many readings so far
float x;
CurrentState = digitalRead(SpedIN);
if (CurrentState == HIGH){
digitalWrite(SpedOUT, LOW); //LOW enables high speed samples on ADC
SpedState = HIGH;
}
else {
digitalWrite(SpedOUT, HIGH);//HIGH enables low speed, more accurate samples on ADC
SpedState = LOW;
}
n = 0; // have not made any ADC readings yet
//for (i=0; i<nsamples; i++) {
x = SpiRead();
//}
//smooth before sending result
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = x;
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
Serial.println(average, 6);
//Serial.println(x,6); //removed ,3
}
float SpiRead(void) {
long result = 0;
byte sig = 0; // sign bit
byte b;
float v;
while (digitalReadFast(BUSYPIN)==HIGH) {} // wait until ADC result is ready
digitalWriteFast(SLAVESELECT,LOW); // take the SS pin low to select the chip
delayMicroseconds(1); // probably not needed, only need 25 nsec delay
b = SPI.transfer(0xff); // B3
if ((b & 0x20) ==0) sig=1; // is input negative ?
b &=0x1f; // discard bits 25..31
result = b;
result <<= 8;
b = SPI.transfer(0xff); // B2
result |= b;
result = result<<8;
b = SPI.transfer(0xff); // B1
result |= b;
result = result<<8;
b = SPI.transfer(0xff); // B0
result |= b;
digitalWriteFast(SLAVESELECT,HIGH); // take the SS pin high to bring MISO to hi-Z and start new conversion
if (sig) result |= 0xf0000000; // if input is negative, insert sign bit (0xf0.. or 0xe0... ?)
v = result;
v = v / 16; // scale result down , last 4 bits are "sub-LSBs"
v = v * VREF / (2 * 16777216); // +Vfullscale = +Vref/2, max scale (2^24 = 16777216)
return(v);
}