LTC2309 - 8-Channel, 12-Bit SAR ADC with I2C Interface

Features

  • 12-Bit Resolution
  • Low Power: 1.5mW at 1ksps, 35μW Sleep Mode
  • 14ksps Throughput Rate
  • Low Noise: SNR = 73.4dB
  • Guaranteed No Missing Codes
  • Single 5V Supply
  • 2-Wire I2C Compatible Serial Interface with Nine Addresses Plus One Global for Synchronization
  • Fast Conversion Time: 1.3μs
  • Internal Reference
  • Internal 8-Channel Multiplexer
  • Internal Conversion Clock
  • Unipolar or Bipolar Input Ranges (Software Selectable)
  • Guaranteed Operation from –40°C to 125°C (TSSOP Package)
  • 24-Pin 4mm × 4mm QFN and 20-Pin TSSOP Packages

Typical Application

LTC2309 Typical Application
LTC2309 Typical Application

Description

The LTC2309 is a low noise, low power, 8-channel, 12-bit successive approximation ADC with an I2C compatible serial interface. This ADC includes an internal reference and a fully differential sample-and-hold circuit to reduce common mode noise. The LTC2309 operates from an internal clock to achieve a fast 1.3μs conversion time.

The LTC2309 operates from a single 5V supply and draws just 300μA at a throughput rate of 1ksps. The ADC enters nap mode when not converting, reducing the power dissipation.

The LTC2309 is available in both a small 24-pin 4mm × 4mm QFN and a 20-pin TSSOP package. The internal 2.5V reference and 8-channel multiplexer further reduce PCB board space requirements.

The low power consumption and small size make the LTC2309 ideal for battery-operated and portable applications, while the 2-wire I2C compatible serial interface makes this ADC a good match for space-constrained systems.

Packaging

For complete and up to date package information and drawings, please refer to our packaging page

QFN-24

LTC2309 Package Drawing
LTC2309 Package Drawing

Order Info

Package Variations and Pricing

Part Number Package Pins Temp Price (1-99) Price (1k)* RoHS Data
LTC2309CF#PBF TSSOP 20 C $5.27 $2.95 View
LTC2309CF#TRPBF TSSOP 20 C $3.01 View
LTC2309CUF#PBF QFN 24 C $5.27 $2.95 View
LTC2309CUF#TRPBF QFN 24 C $3.01 View
LTC2309HF#PBF TSSOP 20 H $6.07 $4.25 View
LTC2309HF#TRPBF TSSOP 20 H $4.31 View
LTC2309IF#PBF TSSOP 20 I $6.32 $3.54 View
LTC2309IF#TRPBF TSSOP 20 I $3.60 View
LTC2309IUF#PBF QFN 24 I $6.32 $3.54 View
LTC2309IUF#TRPBF QFN 24 I $3.60 View
Buy NowRequest Samples
* The USA list pricing shown is for BUDGETARY USE ONLY, shown in United States dollars (FOB USA per unit for the stated volume), and is subject to change. International prices may differ due to local duties, taxes, fees and exchange rates. For volume-specific price or delivery quotes, please contact your local Linear Technology sales office or authorized distributor.

Demo Boards

Linear Technology offers many demo boards free of charge to qualified customers. Contact your local sales office or distributor to inquire about a demo board. Certain demo boards are also available for sale via credit card on this website. Demo boards are for evaluation purposes only. It remains the customer’s responsibility to verify proper and reliable operation in the actual end application.

Part Number Description Price Documentation
DC1337A LTC2309 Demo Board | 12-bit, 8-channel SAR ADC with I2C I/F, req DC2026. $50.00
Buy Now

Companion Boards

Part Number Description Price Documentation
DC2026A Linduino One Isolated Arduino-Compatible Demonstration Board $75.00
Buy Now
Click here to view our complete list of demo boards

Applications

  • Industrial Process Control
  • Motor Control
  • Accelerometer Measurements
  • Battery-Operated Instruments
  • Isolated and/or Remote Data Acquisition
  • Power Supply Monitoring

Product Notifications

Please login to your MyLinear account for notifications of datasheet updates, new document releases and LTspice model announcements for your favorite products. If you do not have a MyLinear account you may Sign Up Now.

Forgot your password? Click here.
Need help? Email mylinear@linear.com with questions and comments.

Design Tools

Linduino

Linduino is an Arduino compatible platform for developing and distributing firmware libraries and code for SPI and I²C-compatible integrated circuits. The Linduino One board interfaces to more than 300 QuikEval demonstration cards, supporting a variety of product types including analog-to-digital converters (ADCs)digital-to-analog converters (DACs)power monitors, and more. Firmware libraries for individual devices are written in C and designed to be portable to a wide variety of processors and microcontrollers. Each library has a demonstration program that can be uploaded to the Linduino One platform to allow the circuit and software to be quickly and easily verified.

Click here for more information on Linduino

Code

Linduino is Linear Technology's Arduino compatible system for developing and distributing firmware libraries and example code for Linear Technology’s integrated circuits. The code below can be downloaded or copied and pasted into your project. Please visit the Linduino Home Page for demo board, manual and setup information.

This part is Code Supported: There is example code available for this part. The code below may rely on other drivers available in the full library.

Download LTC2309 - DC1337A Linduino .INO File

/*!
Linear Technology DC1337A Demonstration Board.
LTC2309: 8-Channel, 12-Bit SAR ADC with I2C Interface.

@verbatim

NOTES
  Setup:
   Set the terminal baud rate to 115200 and select the newline terminator. Equipment
   required is a voltage source (preferably low-noise) and a precision voltmeter. No
   external power supply is required. Ensure all jumpers on the demo board are
   installed in their default positions from the factory. Refer to Demo Manual 
   DC1337A.

  How to test Single-Ended mode:
   Ensure the voltage source is within the analog input voltage range of 0 to 
   +4.096V. The positive terminal may be connected to any channel input. The
   negative terminal must be connected to COM.

  How to test Differential Mode:
   Bipolar Mode:
     The voltage source should be connected between paired channels. Ensure both
     inputs are within their specified absolute input voltage range. (It is easiest
     to tie the voltage source negative terminal to COM or GND.) Ensure the voltage
     source is set within the range of 0 to +2.048V (differential voltage range).
     (Swapping input voltages results in a reversed polarity reading.)

   Unipolar Mode:
     The voltage source should be connected between paired channels. (It is easiest
     to tie the voltage source negative terminal to COM or GND.) Ensure both inputs
     are within their specified absolute input voltage range.  (It is easiest to tie
     the voltage source negative terminal to COM or GND.) Ensure the voltage source
     is set within the range of 0 to +4.096V (differential voltage range). (Swapping
     input voltages results in a reversed polarity reading.)

  How to calibrate:
   Apply 100mV CH0. Next, measure this voltage with a precise voltmeter and enter
   this value. (This takes the reading.) Now apply approximately 4.00 volts to CH0.
   Measure this voltage with a precise voltmeter and enter this value. Calibration
   is now stored in EEPROM. Upon startup the calibration values will be restored.

USER INPUT DATA FORMAT:
 decimal : 1024
 hex     : 0x400
 octal   : 02000  (leading 0 "zero")
 binary  : B10000000000
 float   : 1024.0

@endverbatim

http://www.linear.com/product/LTC2309

http://www.linear.com/product/LTC2309#demoboards

REVISION HISTORY
$Revision: 2032 $
$Date: 2013-10-15 13:00:53 -0700 (Tue, 15 Oct 2013) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
 */

/*! @file
    @ingroup LTC2309
*/

#include 
#include 
#include "Linduino.h"
#include "LT_I2C.h"
#include "UserInterface.h"
#include "QuikEval_EEPROM.h"
#include "LTC2309.h"
#include 

// Function Declaration
void print_title();                                     // Print the title block
void print_prompt();                                    // Prompt the user for an input command
void print_user_command_diff(uint8_t menu);             // Display selected differential channels
void store_calibration();                               // Store the ADC calibration to the EEPROM
int8_t restore_calibration();                           // Read the calibration from EEPROM return 1 if successful, 0 if not

int8_t menu_1_read_single_ended();                      // Read channels in single-ended mode
int8_t menu_2_read_differential();                      // Read differential channels
int8_t menu_3_calibrate();                              // Calibrate ADC given two known inputs
int8_t menu_4_sleep();                                  // Sets LTC2309 Sleep Mode
void menu_5_select_uni_bipolar();                       // Sets LTC2309 to Bipolar or Unipolar

// Global variables
static uint8_t demo_board_connected;                    //!< Set to 1 if the board is connected
static uint8_t uni_bi_polar = LTC2309_UNIPOLAR_MODE;    //!< LTC2309 Unipolar or Bipolar mode selection

// Calibration Variables
static float LTC2309_lsb = 1.0002442E-03;               //!< Ideal LSB voltage for a perfect part
static int16_t LTC2309_offset_code = 0;                 //!< Ideal offset for a perfect part

// Constants
// Build the command for single-ended mode
const uint8_t BUILD_COMMAND_SINGLE_ENDED[8] = {LTC2309_CH0, LTC2309_CH1, LTC2309_CH2, LTC2309_CH3,
    LTC2309_CH4, LTC2309_CH5, LTC2309_CH6, LTC2309_CH7
                                              };        //!< Builds the command for single-ended mode
// Build the command for differential mode
const uint8_t BUILD_COMMAND_DIFF[8] = {LTC2309_P0_N1, LTC2309_P2_N3, LTC2309_P4_N5, LTC2309_P6_N7,
                                       LTC2309_P1_N0, LTC2309_P3_N2, LTC2309_P5_N4, LTC2309_P7_N6
                                      };                //!< Build the command for differential mode

//! Initialize Linduino
void setup()
{
  char demo_name[]="DC1337";              // Demo board name stored in QuikEval EEPROM
  quikeval_I2C_init();                    // Enable the I2C port
  quikeval_I2C_connect();                 // Connect I2C to main data port
  Serial.begin(115200);                   // Initialize the serial port to the PC
  print_title();
  demo_board_connected = discover_demo_board(demo_name);
  if (demo_board_connected)
  {
    restore_calibration();
    print_prompt();
  }
}

//! Repeats Linduino loop
void loop()
{
  int8_t ack = 0;                       // I2C acknowledge bit

  if (demo_board_connected)
  {
    if (Serial.available())             // Check for user input
    {
      int8_t user_command;              // The user input command
      user_command = read_int();        // Read the user command
      if (user_command != 'm')
        Serial.println(user_command);   // Prints the user command to com port
      switch (user_command)
      {
        case 1:
          ack |= menu_1_read_single_ended();
          break;
        case 2:
          ack |= menu_2_read_differential();
          break;
        case 3:
          ack |= menu_3_calibrate();
          break;
        case 4:
          ack |= menu_4_sleep();
          break;
        case 5:
          menu_5_select_uni_bipolar();
          break;
        default:
          Serial.println(F("Invalid Option"));
          break;
      }
      Serial.println();
      if (ack != 0) Serial.println(F("Error: No Acknowledge. Check I2C Address."));
      Serial.println(F("*************************"));
      print_prompt();
    }
  }
}

// Function Definitions

//! Prints the title block when the program first starts.
void print_title()
{
  Serial.println();
  Serial.println(F("*****************************************************************"));
  Serial.println(F("* DC1337A Demonstration Program                                 *"));
  Serial.println(F("* This program demonstrates how to send data and receive data   *"));
  Serial.println(F("* from the 12-bit ADC.                                          *"));
  Serial.println(F("*                                                               *"));
  Serial.println(F("*                                                               *"));
  Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
  Serial.println(F("*                                                               *"));
  Serial.println(F("*****************************************************************"));
}

//! Prints main menu.
void print_prompt()
{
  Serial.println(F("1-Read Single-Ended "));
  Serial.println(F("2-Read Differential"));
  Serial.println(F("3-Calibration"));
  Serial.println(F("4-Sleep Mode"));
  Serial.println(F("5-Select Unipolar or Bipolar measurement\n"));
  Serial.print(F("Selected Uni / Bip mode:  "));
  if (uni_bi_polar == LTC2309_UNIPOLAR_MODE)
    Serial.println(F("Unipolar"));
  else
    Serial.println(F("Bipolar"));
  Serial.println();
  Serial.print(F("Enter a command:  "));
}

//! Display selected differential channels. Displaying single-ended channels is
//! straightforward; not so with differential because the inputs can take either polarity.
void print_user_command_diff(uint8_t menu)
{
  switch (menu)
  {
    case 0:
      Serial.print(F("0P-1N"));
      break;
    case 1:
      Serial.print(F("2P-3N"));
      break;
    case 2:
      Serial.print(F("4P-5N"));
      break;
    case 3:
      Serial.print(F("6P-7N"));
      break;
    case 4:
      Serial.print(F("1P-0N"));
      break;
    case 5:
      Serial.print(F("3P-2N"));
      break;
    case 6:
      Serial.print(F("5P-4N"));
      break;
    case 7:
      Serial.print(F("7P-6N"));
      break;
    default:
      Serial.println(F("Invalid Option"));
      break;
   }
  Serial.print(F(": "));
}

//! Store measured calibration parameters to nonvolatile EEPROM on demo board
void store_calibration()
// Store the ADC calibration to the EEPROM
{
  eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EEPROM_CAL_STATUS_ADDRESS);         // Cal key
  eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2309_offset_code, EEPROM_CAL_STATUS_ADDRESS+2);  // Offset
  eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2309_lsb, EEPROM_CAL_STATUS_ADDRESS+4);          // LSB
  Serial.println(F("Calibration Stored to EEPROM"));
}

//! Read stored calibration parameters from nonvolatile EEPROM on demo board
//! @return 1 if successful, 0 if not
int8_t restore_calibration()
// Read the calibration from EEPROM
{
  int16_t cal_key;
  // Read the cal key from the EEPROM
  eeprom_read_int16(EEPROM_I2C_ADDRESS, &cal_key, EEPROM_CAL_STATUS_ADDRESS);
  if (cal_key == EEPROM_CAL_KEY)
  {
    // Calibration has been stored, read offset and lsb
    eeprom_read_int16(EEPROM_I2C_ADDRESS, <C2309_offset_code, EEPROM_CAL_STATUS_ADDRESS+2);  // Offset
    eeprom_read_float(EEPROM_I2C_ADDRESS, <C2309_lsb, EEPROM_CAL_STATUS_ADDRESS+4);          // LSB
    Serial.println(F("Calibration Restored"));
    return(1);
  }
  else
  {
    Serial.println(F("Calibration not found"));
    return(0);
  }
}

//! Read channels in single-ended mode
//! @return 1 if successful, 0 if not
int8_t menu_1_read_single_ended()
{
  int8_t ack = 0;       // I2C acknowledge bit
  uint8_t user_command;
  uint16_t adc_code;    // The LTC2309 code

  while (!ack)
  {
    if (uni_bi_polar == LTC2309_UNIPOLAR_MODE)
    {
      Serial.println(F("Single-Ended, Unipolar mode:"));
      Serial.println(F("Note that in Unipolar mode, input voltages less than zero are reported as 0.0V"));
    }
    else
      Serial.println(F("Single-Ended, Bipolar mode:"));

    Serial.println(F("*************************"));                         // Display single-ended menu
    Serial.println(F("0-CH0"));
    Serial.println(F("1-CH1"));
    Serial.println(F("2-CH2"));
    Serial.println(F("3-CH3"));
    Serial.println(F("4-CH4"));
    Serial.println(F("5-CH5"));
    Serial.println(F("6-CH6"));
    Serial.println(F("7-CH7"));
    Serial.println(F("8-ALL"));
    Serial.println(F("m-Main Menu"));
    Serial.println();
    Serial.print(F("Enter a Command: "));

    user_command = read_int();                                              // Read the single-ended menu command

    if (user_command == 'm')
      return(0);
    else
      switch (user_command)
      {
         case 0:
           ;
           break;
         case 1:
            ;
           break;
         case 2:
            ;
           break;
         case 3:
             ;
           break;
         case 4:
           ;
           break;
         case 5:
           ;
           break;
         case 6:
           ;
           break;
         case 7:
           ;
           break;
         case 8:
           ;
           break;
         default:
         {
           Serial.println(F("Invalid Option"));
           return(0);
         }
           break;
   }
    Serial.println(user_command);
    
    if (user_command == 8)
    {
      uint16_t adc_command;                                                 // The LTC2309 command byte
      adc_command = BUILD_COMMAND_SINGLE_ENDED[0] | uni_bi_polar;

      ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);     // Throws out last reading and starts CH0 conversion
      for (int8_t x = 0; x <= 7; x++)
      {
        adc_command = BUILD_COMMAND_SINGLE_ENDED[(x+1) % 8] | uni_bi_polar; // Send channel config for the NEXT conversion to take place
        ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);   // Read previous channel conversion (x-1) and start next one (x)
        float adc_voltage;                                                  // The LTC2309 voltage
        adc_voltage = LTC2309_unipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);
        Serial.println();
        Serial.print(F("Voltage read on "));
        Serial.print(F("Ch"));
        Serial.print(x);
        Serial.print(F(": "));
        Serial.print(adc_voltage, 4);
        Serial.println(F("V"));
      }
    }
    else
    {
      int16_t adc_command;                                                  // The LTC2309 command byte
      adc_command = BUILD_COMMAND_SINGLE_ENDED[user_command] | uni_bi_polar;
      Serial.println();
      Serial.print(F("ADC Command: b"));
      Serial.println(adc_command, BIN);
      uint16_t adc_code;                                                    // The LTC2309 code
      ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);     // Throws out last reading and starts new conversion
      ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);
      Serial.print(F("Received Code: 0x"));
      Serial.println(adc_code, HEX);
      float adc_voltage;                                                    // The LTC2309 voltage
      adc_voltage = LTC2309_unipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);
      Serial.print(F("Voltage read on "));
      Serial.print(F("Ch"));
      Serial.print(user_command);
      Serial.print(F(": "));
      Serial.print(adc_voltage, 4);
      Serial.println(F("V"));
      Serial.println();
    }
  }
  return(ack);
}

//! Read differential channels
//! @return 1 if successful, 0 if not
int8_t menu_2_read_differential()
{
  // Read differential channels
  int8_t ack = 0;                     // I2C acknowledge bit
  uint8_t user_command;
  uint16_t adc_command;               // The LTC2309 command byte

  while (!ack)
  {
    if (uni_bi_polar == LTC2309_UNIPOLAR_MODE)
    {
      Serial.println(F("Differential, Unipolar mode:"));
      Serial.println(F("Note that in Unipolar mode, input voltages less than zero are reported as 0.0V"));
    }
    else
      Serial.println(F("Differential, Bipolar mode:"));
    // Display differential bipolar mode menu
    Serial.println(F("*************************"));
    Serial.println(F("0-0P-1N"));
    Serial.println(F("1-2P-3N"));
    Serial.println(F("2-4P-5N"));
    Serial.println(F("3-6P-7N"));
    Serial.println(F("4-1P-0N"));
    Serial.println(F("5-3P-2N"));
    Serial.println(F("6-5P_4N"));
    Serial.println(F("7-7P-6N"));
    Serial.println(F("8-ALL Even_P-Odd_N"));
    Serial.println(F("9-ALL Odd_P-Even_N"));
    Serial.println(F("m-Main Menu"));
    Serial.println();
    Serial.print(F("Enter a Command: "));

    user_command = read_int();
    if (user_command == 'm')
      return(0);
    else      
      switch (user_command)
      {
        case 0:
          ;
          break;
        case 1:
          ;
          break;
        case 2:
          ;
          break;
        case 3:
          ;
          break;
        case 4:
          ;
          break;
        case 5:
          ;
          break;
        case 6:
          ;
          break;
        case 7:
          ;
          break;       
        case 8:
          ;
          break;  
        case 9:
          ;
          break;  
        default:
        {
          Serial.println("Invalid Option");
          return(0);
        }
          break;
      }    
    Serial.println(user_command);
      
    int8_t y;

    if ((user_command == 8) || (user_command == 9))
    {
      if (user_command == 8)          // Cycles through options 0-3
      {
        Serial.println(F("ALL Even_P-Odd_N"));
        y = 0;
      }
      else
      {
        Serial.println(F("ALL Odd_P-Even_N"));
        y = 4;
      }

      adc_command = BUILD_COMMAND_DIFF[y] | uni_bi_polar;
      uint16_t adc_code;                                                 // The LTC2309 code
      ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);  // Throws out last reading and starts '0' reading
      for (int8_t x = 0; x <=3 ; x++)
      {
        adc_command = BUILD_COMMAND_DIFF[((x + 1) % 4) + y] | uni_bi_polar;
        ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);
        float adc_voltage;                                               // The LTC2309 voltage
        if (uni_bi_polar == LTC2309_UNIPOLAR_MODE)
          adc_voltage = LTC2309_unipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);
        else
          adc_voltage = LTC2309_bipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);

        Serial.println();
        Serial.print(F("Voltage read between Chs "));
        print_user_command_diff(x + y);
        Serial.print(F(": "));
        Serial.print(adc_voltage, 4);
        Serial.println(F("V"));
        Serial.println();
      }
    }

    else
    {
      // Reads and displays a selected channel
      adc_command = BUILD_COMMAND_DIFF[user_command] | uni_bi_polar;
      Serial.print(F("ADC Command: b"));
      Serial.println(adc_command, BIN);
      uint16_t adc_code;                                                 // The LTC2309 code
      ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);  // Throws out last reading and starts new conversion
      delay(100);
      ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);
      Serial.print(F("Received Code: 0x"));
      Serial.println(adc_code, HEX);
      float adc_voltage;                                                 // The LTC2309 voltage
      if (uni_bi_polar == LTC2309_UNIPOLAR_MODE)
        adc_voltage = LTC2309_unipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);
      else
        adc_voltage = LTC2309_bipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);

      Serial.print(F("Voltage read between Chs "));
      print_user_command_diff(user_command);
      Serial.print(adc_voltage, 4);
      Serial.println(F("V"));
      Serial.println();
    }
  }
  return(ack);
}

//! Calibrate ADC given two known inputs
//! @return 1 if successful, 0 if not
int8_t menu_3_calibrate()
{
  // Calibration
  int8_t ack = 0;                                                       // I2C acknowledge bit
  uint16_t user_command;
  float zero_voltage;
  
  Serial.println(F("Apply approximately 100mV to CH0 (with respect to COM) for the lower point in two point calibration."));
  Serial.print(F("Enter the measured input voltage:"));
  zero_voltage = read_float();
  Serial.println(zero_voltage, 6);
  
  int16_t adc_command;                                                  // The LTC2309 command byte
  adc_command = BUILD_COMMAND_SINGLE_ENDED[0]|LTC2309_UNIPOLAR_MODE;    // Build ADC command byte for voltage input
  uint16_t zero_code;                                                   // Cal zero code

  LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &zero_code);           // Throw away previous reading and start new conversion
  delay(200);
  LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &zero_code);           // Measure zero
  Serial.println();
  Serial.println(F("Apply approximately 4.00V to CH0 (with respect to COM)."));
  Serial.print(F("Enter the measured input voltage:  "));
  float fs_voltage;                                                     // Measured cal voltage
  fs_voltage = read_float();
  Serial.println(fs_voltage, 6);
  
  uint16_t fs_code;                                                     // Cal full scale code

  ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &fs_code);      // Throw away previous reading and start new conversion
  delay(200);
  ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &fs_code);      // Measure full scale
  
  LTC2309_cal_voltage(zero_code, fs_code, zero_voltage, fs_voltage, <C2309_lsb, <C2309_offset_code);
  
  if(ack)
    return(1);
    
  Serial.print(F("ADC offset : "));
  Serial.println(LTC2309_offset_code);
  Serial.print(F("ADC lsb : "));
  Serial.print(LTC2309_lsb * 1.0e6, 4);
  Serial.println(F("uV"));
  store_calibration();
  return(0);
}

//! Sets LTC2309 Sleep Mode
//! @return 1 if successful, 0 if not
int8_t menu_4_sleep()
{
  // Sleep Mode
  int8_t ack = 0;           // I2C acknowledge bit
  uint16_t user_command;
  uint16_t adc_code;        // The LTC2309 code
  
  ack |= LTC2309_read(LTC2309_I2C_ADDRESS, LTC2309_SLEEP_MODE, &adc_code);
  
  Serial.println();
  Serial.print(F("ADC Command: b"));
  Serial.println(LTC2309_SLEEP_MODE, BIN);
  Serial.println(F("LTC2309 is now in sleep mode"));
  Serial.println(F("Enter RETURN to exit Sleep Mode"));
  
  user_command = read_int();
  
  ack |= LTC2309_read(LTC2309_I2C_ADDRESS, LTC2309_EXIT_SLEEP_MODE, &adc_code);
  return(ack);
}

//! Sets LTC2309 to Bipolar or Unipolar
void menu_5_select_uni_bipolar()
{
  uint8_t user_command;
  Serial.println(F("\n0-Bipolar, 1=Unipolar"));
  Serial.print(F("Enter a Command: "));

  user_command = read_int();                       // Read user input for uni_bi_polar

  if (user_command == 1)
    uni_bi_polar = LTC2309_UNIPOLAR_MODE;
  else
    uni_bi_polar = LTC2309_BIPOLAR_MODE;
}

Download LTC2309 Linduino .CPP File

/*!
LTC2309: 8-channel, 12-Bit SAR ADC with I2C interface

@verbatim

The LTC2309 is a low noise, low power, 8-channel, 12-bit successive 
approximation ADC with an I2C compatible serial interface. This ADC includes an 
internal reference and a fully differential sample-and-hold circuit to reduce 
common mode noise. The LTC2309 operates from an internal clock to achieve a fast 
1.3 microsecond conversion time. 

The LTC2309 operates from a single 5V supply and draws just 300 microamps at a 
throughput rate of 1ksps. The ADC enters nap mode when not converting, reducing 
the power dissipation. 

@endverbatim

http://www.linear.com/product/LTC2309

http://www.linear.com/product/LTC2309#demoboards

REVISION HISTORY
$Revision: 2045 $
$Date: 2013-10-17 11:45:52 -0700 (Thu, 17 Oct 2013) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

//! @defgroup LTC2309 LTC2309: 8-channel, 12-Bit SAR ADC with I2C interface

/*! @file
    @ingroup LTC2309
    Library for LTC2309: 8-channel, 12-Bit SAR ADC with I2C interface
*/

#include 
#include 
#include "Linduino.h"
#include "LT_I2C.h"
#include "LTC2309.h"
#include 

// Commands
// Construct a channel / uni/bipolar by bitwise ORing one choice from the channel configuration
// and one choice from the command.

// Example - read channel 3 single-ended
// adc_command = LTC2309_CH3 | LTC2309_UNIPOLAR_MODE;

// Example - read voltage between channels 5 and 4 with 4 as positive polarity and in bipolar mode.
// adc_command = LTC2309_P4_N5 | LTC2309_BIPOLAR_MODE;

// Reads 12 bits
int8_t LTC2309_read(uint8_t i2c_address, uint8_t adc_command, uint16_t *adc_code)
{
  int8_t ack = 0;

  ack = i2c_read_word_data(i2c_address, adc_command, adc_code);
  *adc_code >>= 4;  // Shifts data 4 bits to the right. uint16 to prevent 1's from shifting in if sign bit is 1.
  return(ack);
}

// Calculates the LTC2309 input unipolar voltage.
float LTC2309_unipolar_code_to_voltage(uint16_t adc_code, float LTC2309_lsb, int16_t LTC2309_offset_code)
{
  float adc_voltage;
  adc_voltage=(float)(adc_code+LTC2309_offset_code)*LTC2309_lsb;        //! 1) Calculate voltage from ADC code, lsb, offset.
  return(adc_voltage);
}

// Calculates the LTC2309 input bipolar voltage
float LTC2309_bipolar_code_to_voltage(uint16_t adc_code, float LTC2309_lsb, int16_t LTC2309_offset_code)
{
  float adc_voltage, sign = 1.0;
  if ((adc_code & 0x800) == 0x800)
  {
    adc_code = (adc_code ^ 0xFFF)+1;                                    //! 1) Convert ADC code from two's complement to binary
    sign = -1;
  }
  adc_voltage=(float)(adc_code+LTC2309_offset_code)*LTC2309_lsb*sign;   //! 2) Calculate voltage from ADC code, lsb, offset.
  return(adc_voltage);
}

// Calibrate the lsb
void LTC2309_cal_voltage(int16_t zero_code, int16_t fs_code, float zero_voltage, float fs_voltage, float *LTC2309_lsb, int16_t *LTC2309_offset_code)
{
  float temp_offset;
  *LTC2309_lsb = (fs_voltage-zero_voltage)/((float)(fs_code - zero_code));                              //! 1) Calculate the LSB
  
  temp_offset = (zero_voltage/ *LTC2309_lsb) - zero_code;                                               //! 2) Calculate Unipolar offset
  temp_offset = (temp_offset > (floor(temp_offset) + 0.5)) ? ceil(temp_offset) : floor(temp_offset);    //! 3) Round
  *LTC2309_offset_code = (int32_t)temp_offset;                                                          //! 4) Cast as int32_t
}

Download LTC2309 Linduino Header File

/*!
LTC2309: 8-channel, 12-Bit SAR ADC with I2C interface

@verbatim

The LTC2309 is a low noise, low power, 8-channel, 12-bit successive 
approximation ADC with an I2C compatible serial interface. This ADC includes an 
internal reference and a fully differential sample-and-hold circuit to reduce 
common mode noise. The LTC2309 operates from an internal clock to achieve a fast 
1.3 microsecond conversion time. 

The LTC2309 operates from a single 5V supply and draws just 300 microamps at a 
throughput rate of 1ksps. The ADC enters nap mode when not converting, reducing 
the power dissipation. 

I2C DATA FORMAT (MSB First):


       Byte #1                             Byte #2
START  SA6 SA5 SA4 SA3 SA2 SA1 SA0 W SACK  SD OS S1 S0 UNI SLP X X SACK

             Byte #3                             Byte #4                             Byte #5
Repeat Start SA6 SA5 SA4 SA3 SA2 SA1 SA0 R SACK  D11 D10 D9  D8  D7  D6  D5 D4 MACK  D3 D2 D1 D0 X  X  X  X  MNACK  STOP

SACK  : Slave Acknowledge
MACK  : Master Acknowledge
MNACK : Master Not Acknowledge
SD    : Single, Differential# Bit
OS    : ODD, Sign# Bit
Sx    : Address Select Bit
COM   : CH7/COM Configuration Bit
UNI   : Unipolar, Bipolar# Bit
SLP   : Sleep Mode Bit
Dx    : Data Bits
X     : Don't care

Example Code:

Read Channel 0 in Single-Ended Unipolar mode

    adc_command = LTC2309_CH0 | LTC2309_UNIPOLAR_MODE;                  // Build ADC command for channel 0

    ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);   // Throws out last reading
    ack |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);   // Obtains the current reading and stores to adc_code variable

    // Convert adc_code to voltage
    adc_voltage = LTC2309_unipolar_code_to_voltage(adc_code, LTC2309_lsb, LTC2309_offset_code);

@endverbatim

http://www.linear.com/product/LTC2309

http://www.linear.com/product/LTC2309#demoboards

REVISION HISTORY
$Revision: 1883 $
$Date: 2013-08-15 09:23:36 -0700 (Thu, 15 Aug 2013) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC2309
    Header for LTC2309: 8-channel, 12-Bit SAR ADC with I2C interface
*/

#ifndef LTC2309_H
#define LTC2309_H

#include 

//! @name I2C addresses
//! @{
//! Un-comment the address corresponding to the LTC2309's address
//                                     //  Pin State
// LTC2309 I2C Address                 //  AD1       AD0

#define LTC2309_I2C_ADDRESS 0x08      //  LOW       LOW
// #define LTC2309_I2C_ADDRESS 0x09    //  LOW       Float
// #define LTC2309_I2C_ADDRESS 0x0A    //  LOW       HIGH
// #define LTC2309_I2C_ADDRESS 0x0B    //  Float     HIGH
// #define LTC2309_I2C_ADDRESS 0x18    //  Float     Float
// #define LTC2309_I2C_ADDRESS 0x19    //  Float     LOW
// #define LTC2309_I2C_ADDRESS 0x1A    //  HIGH      LOW
// #define LTC2309_I2C_ADDRESS 0x1B    //  HIGH      Float
// #define LTC2309_I2C_ADDRESS 0x14    //  High      HIGH
//!@}

//! @name Single-Ended Channel Configuration
//! @{
// Single-Ended Channel Configuration
#define LTC2309_CH0                0x80
#define LTC2309_CH1                0xC0
#define LTC2309_CH2                0x90
#define LTC2309_CH3                0xD0
#define LTC2309_CH4                0xA0
#define LTC2309_CH5                0xE0
#define LTC2309_CH6                0xB0
#define LTC2309_CH7                0xF0
//!@}

//! @name Differential Channel Configuration
//! @{
// Differential Channel Configuration
#define LTC2309_P0_N1              0x00
#define LTC2309_P1_N0              0x40

#define LTC2309_P2_N3              0x10
#define LTC2309_P3_N2              0x50

#define LTC2309_P4_N5              0x20
#define LTC2309_P5_N4              0x60

#define LTC2309_P6_N7              0x30
#define LTC2309_P7_N6              0x70
//!@}

//! @name LTC1867 Configuration Bits
//! @{
// LTC1867 Configuration Bits
#define LTC2309_SLEEP_MODE         0x04
#define LTC2309_EXIT_SLEEP_MODE    0x00
#define LTC2309_UNIPOLAR_MODE      0x08
#define LTC2309_BIPOLAR_MODE       0x00
//!@}

// Commands
// Construct a channel / uni/bipolar by bitwise ORing one choice from the channel configuration
// and one choice from the command.

// Example - read channel 3 single-ended
// adc_command = LTC2309_CH3 | LTC2309_UNIPOLAR_MODE;

// Example - read voltage between channels 5 and 4 with 4 as positive polarity and in bipolar mode.
// adc_command = LTC2309_P4_N5 | LTC2309_BIPOLAR_MODE;

//! Reads 12-bit code from LTC2309, programs channel and mode for next conversion.
//! @return Returns the state of the acknowledge bit after the I2C address write. 0=acknowledge, 1=no acknowledge.
int8_t LTC2309_read(uint8_t i2c_address,    //!< I2C address of device
                    uint8_t adc_command,    //!< ADC command / address bits
                    uint16_t *adc_code      //!< Returns code read from ADC
                   );

//! Calculates the LTC2309 input unipolar voltage.
//! @return Calculated voltage
float LTC2309_unipolar_code_to_voltage(uint16_t adc_code,           //!< Code read from ADC
                                       float LTC2309_lsb,           //!< LSB value (volts)
                                       int16_t LTC2309_offset_code  //!< Offset value (ADC counts)
                                      );

//! Calculates the LTC2309 input bipolar voltage
//! @return Calculated voltage
float LTC2309_bipolar_code_to_voltage(uint16_t adc_code,           //!< Code read from ADC
                                      float LTC2309_lsb,           //!< LSB value (volts)
                                      int16_t LTC2309_offset_code  //!< Offset value (ADC counts)
                                     );

//! Calibrate the lsb given a zero code, full-scale code, and measured full-scale voltage.
//! @return Void
void LTC2309_cal_voltage(int16_t zero_code,           //!< Code read with inputs shorted
                         int16_t fs_code,             //!< Code read with full-scale voltage applied
                         float zero_voltage,          //!< Measured zero voltage
                         float fs_voltage,            //!< Measured full-scale voltage
                         float *LTC2309_lsb,          //!< Returns  LSB value (volts)
                         int16_t *LTC2309_offset_code //!< Returns Offset value (ADC counts)
                        );

#endif  // LTC2309_H

Technical Support