I’m looking into combining the Healthy pH and EC Shields into one shield.  This means 2 differential and 1 single ended ADC channel will be needed.  One for pH, EC, and thermistor voltage readings.  This post investigates using the ADS1015 to handle all three Analog to Digital conversions.  When I was discussing combining the shields with  Chris, I thought by best option was to use the ADS1015 for pH and EC voltage measurements and one of the analog channels on the Arduino to handle the voltage values from the thermistor.  Chris brilliantly pointed out there was a pretty good chance the ADS1015 could handle 2 differential and 1 single ADC readings on one chip.  Up until now, I had thought the ADS1015 could handle EITHER 2 differential OR 4 single-ended ADC readings.  In fact, I took this for granted after reading Adafruit’s ADS1015 product page. Then I went back to the ADS1015 datasheet:

Either four single-ended or two differential signals can be measured. Additionally, AIN0 and AIN1 may be measured differentially to AIN3.

So if AIN0, AIN1, and AIN3 are participating in two differential signals, what the heck is the AIN2 pin up to?  When the two differential signals are being read, can’t AIN2 be used to read a single-ended signal?  Well…can it?

The Goal

The goal of this post is to determine if the ADS1015 can handle all three analog to digital conversion needs of a combined Healthy pH and EC shield.  

Thanks To Those That Went Before

On top of learning a lot in Chris Gammell’s Contextual Electronics course, Chris has been a terrific mentor.  It was Chris who pushed me in the direction of configuring the ADS1015 in a way that works for all three signals.  

Adafruit has done an excellent job providing the ADS1015 breadboard and Arduino library.  I highly recommend and am thankful for the great products and learning opportunities Adafruit has enabled.

The Test

To test two differential and one single-ended signal being read at the same time by the ADS1015, I populated a breadboard with Adafruit’s ADS1015 breakout board and four voltage dividers.  I used my bench power supply set to +5V.  I put four voltage dividers on the breadboard:



AIN0 and AIN1 are relative to VGND.  AIN2 is relative to the power supply’s GND.  If this configuration works, the Arduino sketch should return voltage values close to those listed on the image.

The Sketch

Because Adafruit has open sourced their library for the ADS1015 (available at this GitHub repository), all I had to do was add in a routine to the library that used AIN3 as VGND for AIN0 and AIN1.  I copy/pasted another routine and change setting to the config based on a switch statement.  If the Arduino Sketch passes a 0 or 1 or 2 as the P input, the ADS1015 expects a differential reading where AIN0 or AIN1 or AIN2 is the voltage to be read (say a pH voltage value) and AIN3 is VGND.



 @brief  Margaret Johnson Added on 12/09/2014…same as other routines for differential readings except

 sets the N to AIN3.  This way, three readings can be made – 2 differential and 1 single.

 Reads the conversion results, measuring the voltage

 difference between the P (AIN0 or AIN1 or AIN2) and N (AIN3) input.  Generates

 a signed value since the difference can be either

 positive or negative.




int16_t Adafruit_ADS1015::readADC_Differential_VGND(int P){

    // Start with default values

    uint16_t config = ADS1015_REG_CONFIG_CQUE_NONE    | // Disable the comparator (default val)

    ADS1015_REG_CONFIG_CLAT_NONLAT  | // Non-latching (default val)

    ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low   (default val)

    ADS1015_REG_CONFIG_CMODE_TRAD   | // Traditional comparator (default val)

    ADS1015_REG_CONFIG_DR_1600SPS   | // 1600 samples per second (default)

    ADS1015_REG_CONFIG_MODE_SINGLE;   // Single-shot mode (default)


    // Set PGA/voltage range

    config |= m_gain;


    // Set channels

    switch (P) {

        case 0:

            config |= ADS1015_REG_CONFIG_MUX_DIFF_0_3;


        case 1:

            config |= ADS1015_REG_CONFIG_MUX_DIFF_1_3;


        case 2:

            config |= ADS1015_REG_CONFIG_MUX_DIFF_2_3;





    // Set ‘start single-conversion’ bit

    config |= ADS1015_REG_CONFIG_OS_SINGLE;


    // Write config register to the ADC

    writeRegister(m_i2cAddress, ADS1015_REG_POINTER_CONFIG, config);


    // Wait for the conversion to complete



    // Read the conversion results

    uint16_t res = readRegister(m_i2cAddress, ADS1015_REG_POINTER_CONVERT) >> m_bitShift;

    if (m_bitShift == 0)


        return (int16_t)res;




        // Shift 12-bit results right 4 bits for the ADS1015,

        // making sure we keep the sign bit intact

        if (res > 0x07FF)


            // negative number – extend the sign to 16th bit

            res |= 0xF000;


        return (int16_t)res;



I modified the ADC differential sketch provided by Adafruit to do a AIN0/AIN3 differential read, a AIN1/AIN3 differential read, and a AIN2

results = ads1015.readADC_Differential_VGND(0);
Serial.print(“Differential AIN0: “); Serial.print(results); Serial.print(“(“); Serial.print(results * 3); Serial.println(“mV)”);

results = ads1015.readADC_Differential_VGND(1);
Serial.print(“Differential AIN1: “); Serial.print(results); Serial.print(“(“); Serial.print(results * 3); Serial.println(“mV)”);

results = ads1015.readADC_SingleEnded(2);
Serial.print(“Single-ended AIN2: “); Serial.print(results); Serial.print(“(“); Serial.print(results * 3); Serial.println(“mV)”);

 and as one of the outputs show:

Differential AIN0: 34(102mV)
Differential AIN1: 71(213mV)
Single-ended AIN2: 526(1578mV)

YES INDEEDY….It is possible to have a circuit in which one ADS1015 reads two differential and one single-ended signal.

Definitely a YIPPEE MOMENT!!!!



That’s it for now.  (oh…I’m kind of excited…excuse me…IT WORKS!  IT WORKS!)  

Thanks for reading this far.  Please find many things to smile about.