Below is a slightly modified version of Martin Nawrath's LTC2400 ADC code, which I am using with a LTC2410 (a fully-differential version of the 2400). This code should work as-is with a LTC2400 as well, except the output will be half the correct value, due to the difference in full-scale value and output normalization between the two chips.
The differential input is taken from a 4x10k full bridge using simple 1/4 watt resistors. My circuit has both Vcc and +Vref connected to +5V from a LM7805. The 2410 has an input range of -(Vref/2) to +(Vref/2) or in my case, -2.5 to +2.5V for a full-scale span of 5V.
I have Fo (pin 14) connected to GND for 60 Hz noise rejection, giving me a 134 msec output rate. Obtaining 100 samples takes about 134 seconds. The datasheet claims 0.8 uV(rms) noise for the LTC2410, and in my case I am seeing 1.3 uV(rms). With the full scale span being 5V, that means the RMS noise is 2.6E-7 of full scale, giving me 21.9 bits (rms) of resolution. The datasheet claim is 22.6 bits (rms) so I'm not too far off.
The circuit was in a plastic box to shield from drafts, but a metal shielding box might reduce noise further. I mounted the SSOP-16 chip on an ebay adaptor I had handy, which turned out to have pins 1-8 some non-100-mil-multiple spacing from pins 9-16, so I had to use it SIP-style on the breadboard, as you see below. I used copper foil under the chip to try for a solid ground (pins 1,7,8,9,10,15,16 are all ground pins on this device).
Photos: LTC2410 on adaptor and
adaptor assy in breadboard.
Note: I saw 3 uV(rms) noise when Vcc came from a noisy 5V USB rail, even though +Vref was still using the cleaner LM7805 output, so there is some noise coupling from the Vcc supply.
Sample output from program (last column is the standard deviation of 100 readings, in microvolts).
- Code: Select all
count,sec,value,stdev
# LTC2410 v0.1 Oct.23 2012 jpb
0,13.59,0.0063365,1.29
1,26.98,0.0063367,1.38
2,40.38,0.0063368,1.35
3,53.77,0.0063368,1.30
4,67.16,0.0063368,1.46
5,80.55,0.0063369,1.36
6,93.94,0.0063368,1.25
7,107.33,0.0063368,1.28
8,120.72,0.0063372,1.32
9,134.12,0.0063372,1.18
10,147.51,0.0063371,1.14
11,160.90,0.0063369,1.24
12,174.29,0.0063371,1.30
Arduino code which generated above output:- Code: Select all
/* *********** LTC2410 24 Bit ADC Test *************
* Connect an LTC2410 24 Bit ADC to the Arduino Board in SPI Mode
* by John Beale, Oct. 23 2012
* based on code for LTC2400 by KHM 2009 / Martin Nawrath
* from http://interface.khm.de/index.php/lab/experiments/
*/
// define clear-bit and set-bit macros
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// Setup SPI pins at standard Arduino locations (specific to ATmega328p chip)
#define LTC_CS 2 // LTC2410 Chip Select Pin on PortB.2 (pin16: D10, CS)
#define LTC_MISO 4 // LTC2410 SDO Select Pin on PortB.4 (pin18: D12, MISO)
#define LTC_SCK 5 // LTC2410 SCK Select Pin on PortB.5 (pin19: D13, SCK)
// ADC-related constants
#define VREF (5.0) // ADC Reference, Volts
#define SAMPLES (100) // how many readings to combine for average and standard deviation
void setup() {
cbi(PORTB,LTC_SCK); // LTC2410 SCK low
sbi (DDRB,LTC_CS); // LTC2410 CS HIGH
cbi (DDRB,LTC_MISO);
sbi (DDRB,LTC_SCK);
Serial.begin(115200); // serial port baud rate
// init SPI Hardware
sbi(SPCR,MSTR) ; // SPI master mode
sbi(SPCR,SPR0) ; // SPI speed
sbi(SPCR,SPR1); // SPI speed
sbi(SPCR,SPE); //SPI enable
Serial.println("count,sec,value,stdev");
Serial.println("# LTC2410 v0.1 Oct.23 2012 jpb");
cbi(PORTB,LTC_CS); // LTC2410 CS Low
delay(200); // acquire first reading
SPI_read(); // throw it away (1st one has big offset)
sbi(PORTB,LTC_CS); // LTC2410 CS High
delay(1);
cbi(PORTB,LTC_CS); // LTC2410 CS Low
} // end setup()
/********************************************************************/
int cnt; // ADC reading counter
void loop() { // **** main loop
float datSum = 0; // reset our accumulated sum of input values to zero
float sMax;
float sMin;
long n; // count of how many readings so far
float x,mean,delta,sumsq,m2,variance,stdev; // to calculate standard deviation
sMax = -VREF; // set max to minimum possible reading
sMin = VREF; // set min to max possible reading
sumsq = 0; // initialize running squared sum of differences
n = 0; // have not made any ADC readings yet
mean = 0; // start off with running mean at zero
m2 = 0;
for (int i=0;i<SAMPLES;i++) {
while (PINB & (1 << PORTB4)) {} // busy loop waiting for ADC to be ready
x = readADC(); // get analog reading in units of volts
// Serial.println(x,6);
datSum += x;
if (x > sMax) sMax = x;
if (x < sMin) sMin = x;
// from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
n++;
delta = x - mean;
mean += delta/n;
m2 += (delta * (x - mean));
}
variance = m2/(n-1); // (n-1):Sample Variance (n): Population Variance
stdev = 1E6*sqrt(variance); // Calculate standard deviation in microvolts
float tsec = millis()/1000.0; // elapsed time in seconds
Serial.print(cnt++);
Serial.print(",");
Serial.print(tsec,2); // elapsed time, seconds
Serial.print(",");
Serial.print(mean,7); // average reading, volts
Serial.print(",");
Serial.print(stdev,2); // standard deviation, microvolts
Serial.println();
} // end loop()
// ******************************************************************************
// readADC(): read 32-bit word from Linear Tech LTC2410 and return volts
// currently ignoring the "overrange" and "underrange" condition flags
float readADC(void) {
float volt; // ADC reading in real-world units (volts)
long int ltw = 0; // full 32-bit ADC data word
byte b0; // one byte in ADC data word
byte sig; // sign bit flag
ltw=0; // 32-bit data word
sig=0; // sign bit
b0 = SPI_read(); // read 4 bytes adc raw data with SPI
if ((b0 & 0x20) ==0) sig=1; // is input negative ?
b0 &=0x1F; // discard bit 25..31
ltw |= b0;
ltw <<= 8;
b0 = SPI_read();
ltw |= b0;
ltw <<= 8;
b0 = SPI_read();
ltw |= b0;
ltw <<= 8;
b0 = SPI_read();
ltw |= b0;
sbi(PORTB,LTC_CS); // LTC2410 CS hi: start of new ADC conversion
delayMicroseconds(5);
cbi(PORTB,LTC_CS); // LTC2410 CS Low: allow detection of "conversion done" bit on MISO pin
if (sig) ltw |= 0xf0000000; // if input is negative, insert sign bit
ltw=ltw/16; // scale result down , last 4 bits have no information
volt = ltw * VREF / (2 * 16777216); // +Vfullscale = +Vref/2, max scale (2^24 = 16777216)
return(volt);
} // end readADC()
/********************************************************************/
byte SPI_read()
{
SPDR = 0;
while (!(SPSR & (1 << SPIF))) ; /* Wait for SPI shift out done */
return SPDR;
}