LTC2440 Output question

Thread Starter

Metalfan1185

Joined Sep 12, 2008
170
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)?

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);
    }
 

OBW0549

Joined Mar 2, 2015
3,566
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)?
Well... sort of.

One thing to keep in mind about sigma-delta ADCs is that unlike successive-approximation ADCs, they can NOT produce a single output code for a particular input voltage; rather, they produce a range of codes centered around the "correct" value, with a distribution that closely follows a Gaussian curve. For example, the following histogram is from page 6 of the LTC2380-24 data sheet and is typical of most Σ-Δ converters:

Untitled.png
The "spread" of the output codes depends on the kind of digital filtering used on the ADC and how it's configured, but in general the slower you set the sample rate, the narrower the spread of codes.
 
Top