Adafruit_ADS1x15 library update for python

by Pedvide on Thu Mar 28, 2013 1:59 pm

Hello!

I have updated the python library for the ADS1115 and ADS1015 (ADS1x15, https://github.com/adafruit/Adafruit-Ra ... it_ADS1x15).
The original code didn't include differential measurements nor the comparator function, I have added those following the lines in the C++ code.
I have implemented more functions, I'll describe them in a moment. Also, now it is possible to select the gain and sample speed for every function, and more options for the comparator. All functions that return a measurement do so in mV.
There is a mistake in the original code for the ADS1015, in the register part at the beginning, it says __ADS1015_REG_CONFIG_DR_920SPS = 0x0050 but it should be __ADS1015_REG_CONFIG_DR_920SPS = 0x0060, as you can check in the datasheet.

Functions:

readADCSingleEnded(channel=0, pga=6144, sps=250)
Gets a single-ended ADC reading from the specified channel in mV.
The sample rate for this mode (single-shot) can be used to lower the noise (low sps) or to lower the power consumption (high sps) by duty cycling, see datasheet page 14 for more info.
The pga must be given in mV, see page 13 for the supported values.

readADCDifferential(chP=0, chN=1, pga=6144, sps=250)
Gets a differential ADC reading from channels chP and chN in mV.
The sample rate for this mode (single-shot) can be used to lower the noise (low sps) or to lower the power consumption (high sps) by duty cycling, see data sheet page 14 for more info.
The pga must be given in mV, see page 13 for the supported values.

eadADCDifferential01(pga=6144, sps=250)
Gets a differential ADC reading from channels 0 and 1 in mV.
The sample rate for this mode (single-shot) can be used to lower the noise (low sps) or to lower the power consumption (high sps) by duty cycling, see data sheet page 14 for more info.
The pga must be given in mV, see page 13 for the supported values.

Similar functions: readADCDifferential03, readADCDifferential13 and readADCDifferential23.

startContinuousConversion(channel=0, pga=6144, sps=250)
Starts the continuous conversion mode and returns the first ADC reading in mV from the specified channel.
The sps controls the sample rate. The pga must be given in mV, see datasheet page 13 for the supported values.
Use getLastConversionResults() to read the next values and stopContinuousConversion() to stop converting."

stopContinuousConversion()
Stops the ADC's conversions when in continuous mode and resets the configuration to its default value.

getLastConversionResults()
Returns the last ADC conversion result in mV.

startSingleEndedComparator(channel, thresholdHigh, thresholdLow, pga=6144, sps=250,
activeLow=True, traditionalMode=True, latching=False, numReadings=1)

Starts the comparator mode on the specified channel, see datasheet pg. 15.
In traditional mode it alerts (ALERT pin will go low) when voltage exceeds thresholdHigh until it falls below thresholdLow (both given in mV).
In window mode (traditionalMode=False) it alerts when voltage doesn't lie between both thresholds.
In latching mode the alert will continue until the conversion value is read.
numReadings controls how many readings are necessary to trigger an alert: 1, 2 or 4.
Use getLastConversionResults() to read the current value (which may differ from the one that triggered the alert) and clear the alert pin in latching mode.
This function starts the continuous conversion mode. The sps controls the sample rate and the pga the gain, see datasheet page 13.

This last function is by far the most complex, but you can just call it with the channel number and the thresholds and see how it works, then change the options and play! Don't forget to read the datasheet for more information, skip the graphs, and i2c info and you'll be fine.

The rest of the functions are pretty straightforward, single of differential functions return the voltage and set the ADC to "sleep", the data rate is used to control the duration of the measurement, the longer the less noisy. If the voltage is 256, 1024 or 2048, change the gain to be sure that you're not at the maximum of the scale.
Continuous mode makes the ADC convert all the time at the selected rate, call this function and the use getLastConversionResults() to read the values, when you're done make sure to call stopContinuousConversion(). Choosing between single-shot or continuous mode is a matter of the application. Single-shot mode consumes very little power but you need to call it all the time to get a value, continuous mode "wastes" a lot of energy but you can always get a reading as fast as the i2c bus and the raspberry (or arduino when somebody translates this code to C++) are able.
The comparator is very useful, but it has a lot of modes, read the datasheet and play with it and you'll understand everything. I'll include the comparator for the differential inputs as soon as I can (a couple of days) .

The only feature of the chips that I'm not going to implement is the READY pin. This allows the ALERT/READY pin to go low (or high) whenever a conversion has taken place, but when you set the data conversion rate you already know how long the conversions take, and you can wait for that amount. If somebody needs this I can implement it, I just don't see the point.

It seems that I can't upload a .py file, so it's a .zip with just the file Adafruit_ADS1x15
Attachments
Adafruit_ADS1x15.zip
(4.44 KiB) Downloaded 108 times
Pedvide
 
Posts: 6
Joined: Thu Feb 21, 2013 12:59 pm

Re: Adafruit_ADS1x15 library update for python

by Pedvide on Fri Mar 29, 2013 10:19 am

I have fully tested the library with the ADS1115 (I don't have a ADS1015).
You can find some images here http://imgur.com/a/crJhF

The first two show the voltage drop in a red or blue LED, using two single-ended inputs (and subtracting one from the other, V1-V2) or the differential inputs mode (DeltaV):
Image
Image

The continuous mode: two different data rates. The 860sps rate is very noisy, but also fast, so we get a new measurement every time we check. The slow rate (8sps) is more precise, but we get the same value when we check for some time.
Image

Two pga settings: 1024mV and 6144mV. The 6144mV gain can't see the little ripples in the voltage.
Image

Two data rates: 8sps and 860sps: The fast rate has less detail and more noise, it's also shifted downwards, which could be due to a change in the resistance of the led because it warmed up between the two series of measurements or because this rate is too fast and the accuracy is low. See that the 8sps series take 2m8s and the 860sps only 4s.
Image

If we repeat the example above but after every reading we sleep for 0.5s both series will take the same time, but the when the rate is 860sps the ADC will be in power-off mode for a lot of the time, saving energy, although the noise is larger.
Image
Pedvide
 
Posts: 6
Joined: Thu Feb 21, 2013 12:59 pm

Re: Adafruit_ADS1x15 library update for python

by ktownsend on Sat Mar 30, 2013 7:02 am

Hi Pedvide:

Thanks for looking at this. Is the .zip file above still the latest code? I'll be happy to integrate any changes, but just wanted to make sure I'm looking at the final code first.

The charts are fairly useful as well and it's interesting to see a bit of characterization work on these sensors since I haven't looked at the output in as much detail myself. If you wouldn't mind sharing the setup for how you generated them I think other people may find that useful as well compared to pasting stuff into Excel or whatever else.

Kevin
User avatar
ktownsend
 
Posts: 278
Joined: Thu Nov 05, 2009 1:18 am

Re: Adafruit_ADS1x15 library update for python

by Pedvide on Sat Mar 30, 2013 6:50 pm

Hi, I have added the differential input mode with the comparator, so the .zip in the first post is NOT the latest code, use the one in this post.
Also included in the file (and here) are the scripts I've used to measure the data, and some pictures of the setup:
For single-ended, differential and continuous measurements:
Image

For comparator mode:
Image

The scripts are very easy.

For the single-ended measurements, and for the comparisons between different pga and sps:
Code: Select all
#!/usr/bin/python

import time, signal, sys
from Adafruit_ADS1x15 import ADS1x15

def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

#print 'Press Ctrl+C to exit'

ADS1115 = 0x01   # 16-bit ADC

# Initialise the ADC using the default mode (use default I2C address)
adc = ADS1x15(ic=ADS1115)

i=0
while i!=1000:
   # Read channel 2 in single-ended mode with pga=4096 and sps=250
   volts = adc.readADCSingleEnded(2, 4096, 250)/1000
   i+=1
   print "%d %.6f" % (i, volts)
   #time.sleep(0.1)


For the differential inputs:
Code: Select all
#!/usr/bin/python

import time, signal, sys
from Adafruit_ADS1x15 import ADS1x15

def signal_handler(signal, frame):
        #print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
#print 'Press Ctrl+C to exit'

ADS1115 = 0x01   # 16-bit ADC

# Initialise the ADC using the default mode (use default I2C address)
adc = ADS1x15(ic=ADS1115, debug=True)

i=0
while i!=1000:
   # Read channel 2 and 3 in single-ended mode, at range (+/-4.096V) and data rate 250sps
   volts2 = adc.readADCSingleEnded(2, 4096, 250)/1000.0
   volts3 = adc.readADCSingleEnded(3, 4096, 250)/1000.0
   # Read the difference between channels 2 and 3 with the same properties
   voltsdiff = adc.readADCDifferential23(4096, 250)/1000.0
   print "%d %.8f %.8f %.8f %.8f" % (i, volts2, volts3, volts3-volts2, -voltsdiff)
   time.sleep(0.01)
   i+=1


For the continuous mode (single-ended and differential)
Code: Select all
#!/usr/bin/python

import time, signal, sys
from Adafruit_ADS1x15 import ADS1x15

def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
   # Stop continuous mode even if we press Ctrl+C, otherwise the ADC will keep on converting!
        adc.stopContinuousConversion()
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
#print 'Press Ctrl+C to exit'

ADS1115 = 0x01   # 16-bit ADC

# Initialise the ADC using the default mode (use default I2C address)
adc = ADS1x15(ic=ADS1115)

i=0
# Start the continuous mode for channel 2 at range 2048mV and rate 8sps
volts=adc.startContinuousConversion(2, 2048, 8)
# Start the continuous mode for the difference between channels 2 and 3 at range 2048mV and rate 8sps
#volts=adc.startContinuousDifferentialConversion(2, 3,  2048, 8)

# Allow some time for the first conversion, otherwise the first value will be zero.
time.sleep(1/8+0.01)
while i!=5000:
   # Read conversion as fast as we can
   volts = adc.getLastConversionResults()/1000.0
   i+=1
   print "%d %.6f" % (i, volts)

# Stop continuous mode when we're done
adc.stopContinuousConversion()


And for the comparator:
Code: Select all
#!/usr/bin/python

import time, signal, sys
from Adafruit_ADS1x15 import ADS1x15

def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        print adc.getLastConversionResults()/1000.0
        adc.stopContinuousConversion()
        sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
#print 'Press Ctrl+C to exit'

ADS1115 = 0x01   # 16-bit ADC

# Initialise the ADC using the default mode (use default I2C address)
adc = ADS1x15(ic=ADS1115, debug=True)


# start comparator on channel 2 with a thresholdHigh=200mV and low=100mV
# in traditional mode, non-latching
adc.startSingleEndedComparator(2, 200, 100, pga=1024, sps=250, activeLow=True, traditionalMode=True, latching=False, numReadings=1)

# comparator for differential inputs, same as before (thresholds change accordingly).
#adc.startSingleEndedComparator(2, 3, 3000, 3100, pga=1024, sps=250, activeLow=True, traditionalMode=True, latching=False, numReadings=1)

while True:
        # It doesn't matter what we do here, the ALERT pin will go low as soon as the voltage increases to 200mV
        # We might even exit the script and the ADS would keep working until further order!
        # See that if you press Ctrl+C stopContinuousConversion() will be called,
        # You can comment it and see that it indeed works when you exit the script,
        print adc.getLastConversionResults()/1000.0
        time.sleep(0.25)



I've made a video of the comparator, substituting the pot with a force sensor, when I press the sensor the red led lights up, and the voltage changes, with the correct thresholds the green led (that it's connected to the alert pin) stops shining!
http://gifninja.com/animatedgifs/564052/comparator.gif
Sorry for the bad quality, I don't have time to find a better video to gif online conversor.
Attachments
Adafruit_ADS1x15.zip
(7.41 KiB) Downloaded 113 times
Pedvide
 
Posts: 6
Joined: Thu Feb 21, 2013 12:59 pm

Re: Adafruit_ADS1x15 library update for python

by Pedvide on Sun Mar 31, 2013 1:04 pm

Yesterday I forgot to write about the two new functions implemented in the code:

startContinuousDifferentialConversion(chP=0, chN=1, pga=6144, sps=250)
"Starts the continuous differential conversion mode and returns the first ADC reading \
in mV as the difference from the specified channels. \
The sps controls the sample rate. \
The pga must be given in mV, see datasheet page 13 for the supported values. \
Use getLastConversionResults() to read the next values and \
stopContinuousConversion() to stop converting."

startDifferentialComparator(chP, chN, thresholdHigh, thresholdLow, pga=6144, sps=250, activeLow=True, traditionalMode=True, latching=False, numReadings=1)
"Starts the comparator mode on the difference of the specified channels, \
see datasheet pg. 15. \
In traditional mode it alerts (ALERT pin will go low) when voltage exceeds \
thresholdHigh until it falls below thresholdLow (both given in mV). \
In window mode (traditionalMode=False) it alerts when voltage doesn't lie\
between both thresholds.\
In latching mode the alert will continue until the conversion value is read. \
numReadings controls how many readings are necessary to trigger an alert: 1, 2 or 4.\
Use getLastConversionResults() to read the current value (which may differ \
from the one that triggered the alert) and clear the alert pin in latching mode. \
This function starts the continuous conversion mode. The sps controls \
the sample rate and the pga the gain, see datasheet page 13. "


Also I've made some more measurements on the continuous mode for three data rates and for single-ended and differential inputs:
Single-ended:
Image
Differential inputs, the green data is behind the blue one, I've added it with paint, it's constant except for the first measurement:
Image

The last thing to discuss is the naming of the functions, I'm not entirely sure this is the best one, because for the comparator we say "startDifferentialComparator" but for the continuous mode "startContinuousDifferentialConversion", so the differential or single-ended word is first item in the former expression but the second in the later. Also, we could add a function named "stopComparator()", that calls "stopContinuousConversion()" so that "start...Comparator" is finnished by "stopComparator", not by "stopContinuousConversion". Maybe I'm overthinking it anyway...
Pedvide
 
Posts: 6
Joined: Thu Feb 21, 2013 12:59 pm

Re: Adafruit_ADS1x15 library update for python

by ktownsend on Tue Apr 09, 2013 5:06 am

Hi Pedro:

Your additions are now live. Thanks for taking the time to contribute these great additions.
User avatar
ktownsend
 
Posts: 278
Joined: Thu Nov 05, 2009 1:18 am

Re: Adafruit_ADS1x15 library update for python

by Pedvide on Tue Apr 09, 2013 6:08 am

No problem, thanks to you and your co-workers for you great job!
Pedvide
 
Posts: 6
Joined: Thu Feb 21, 2013 12:59 pm

Re: Adafruit_ADS1x15 library update for python

by Tonk on Wed Jun 05, 2013 11:49 am

In using the ADS_1x15.py library with a ADS_1015 I ran into a few minor problems anda questions.

1. The differential readings did not account for the sign bit. Since there was already logic for the 1115 that did, it was easy to fix. I also factored the code so that the same logic did not have to be repeated in several places.

2. I would like to be able to initiate a conversion without it blocking to wait for the result. Perhaps there should be, e.g., both a readADCSingleEnded and startADCSingleEnded where readADCSingleEnded would be a start, sleep and getLastConversionResults.

3. I'm not sure if you intented the method to be spelled getLastConversionResults of getLastConversionResult. In the definition it is spelled as the former, in a comment as the latter. Since it returns a single value, the latter makes a bit more sense.

4. It seems like support for the alert pin is necessary if you want to capture every conversion or if you want to do other work while the conversions take place. I'm not sure what code you would have to add since the GPIO library already supports rising and falling edges.

- tonk

p.s., let me know if you want me to submit my bug fixes.
Tonk
 
Posts: 1
Joined: Sat Jun 01, 2013 1:04 pm

Re: Adafruit_ADS1x15 library update for python

by Pedvide on Tue Jul 30, 2013 3:51 am

Hello,

I'm, sorry that I didn't replay sooner!
I actually ended up implementing the alert pin, as it is useful using interrupts. I'll post the code later today.
Could you post your modifications to the code, I'm interested!
Pedvide
 
Posts: 6
Joined: Thu Feb 21, 2013 12:59 pm

Re: Adafruit_ADS1x15 library update for python

by tasrock on Mon Sep 16, 2013 8:35 pm

My ADS1015 is being powered by the 5V GPIO header and I am applying 2.5V to the first input via a voltage divider.
Using ads1x15_ex_singleended.py, I modified the code to ADS1015 and channel 1 I get:
8.190000
I changed to the +/-6.144V gain mode and I get:
12.285000

That seemed strange so I made a modified version of the example program:
Code: Select all
#!/usr/bin/python

import time, signal, sys
from Adafruit_ADS1x15 import ADS1x15

def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
#print 'Press Ctrl+C to exit'

ADS1015 = 0x00  # 12-bit ADC
ADS1115 = 0x01 # 16-bit ADC

# Initialise the ADC using the default mode (use default I2C address)
# Set this to ADS1015 or ADS1115 depending on the ADC you are using!
adc = ADS1x15(ic=ADS1015)

# DataRate options: 128, 250, 490, 920, 1600, 2400, 3300 samples per second
DataRate = 3300

# Gain options: 0256(+/-0.256V), 0512(+/-0.512V), 1024(+/-1.024V), 2048(+/-2.048V), 4096(+/-4.096V), 6144(+/-6.144V)
Gain = 6144

#while True:
for z in xrange(0,3):
   for x in xrange(0,4):
      print x,': ',adc.readADCSingleEnded(x, Gain, DataRate)/1000
      time.sleep(.02)


Channel 0 : 0.54 V
Channel 1 : 12.285 V
Channel 2 : 0.534 V
Channel 3 : 0.567 V
Channel 0 : 0.543 V
Channel 1 : 12.285 V
Channel 2 : 0.525 V
Channel 3 : 0.546 V
Channel 0 : 0.606 V
Channel 1 : 12.285 V
Channel 2 : 0.549 V
Channel 3 : 0.528 V

What am I doing wrong that is leading to erroneous voltages? I would think that the unused channels should be reading 0V and the used channel should be reading 2.5V.
tasrock
 
Posts: 1
Joined: Mon Sep 16, 2013 5:00 pm