I2C ADC


99 posts   Page 2 of 4   1, 2, 3, 4
by rurwin » Thu Jun 28, 2012 5:06 pm
morphy_richards wrote:So, for I2C I would need to use 3 and 5.

To supply power to, say, a potentiometer and a pcf8591p 8bit I2C A-Dconverter I would take the power from 2 and ground at 6?


Yes, you have the wire numbering correct. However I would use 3.3V (wire 1) to power the ADC, not 5V (wire 2). Otherwise there may be voltages over 3.3V at the I2C input of the SoC. Always making sure to keep the current requirements low enough (the 3.3V power is only for very small currents, for anything higher you would have to use the 5V and have your own 3.3V regulator.)
User avatar
Moderator
Moderator
Posts: 2890
Joined: Mon Jan 09, 2012 3:16 pm
by davidmam » Fri Jun 29, 2012 8:17 am
I'm hoping to use some I2C ADC for a project but am a little unsure how to read the values from the ADC. The hardware side seems fine - run 5v and ground to the ADC and read the data line through a 5v/3.3v level converter.

I'm not sure which ADC to use or how to get the values. I presume I can just wire it up, modprobe i2c-dev and I should see the device(s), but then what?

And which ADC do folk reccommend? I'll be monitoring voltage levels from 0.5-4.5V

..d
Posts: 98
Joined: Tue Dec 06, 2011 4:13 pm
by morphy_richards » Fri Jun 29, 2012 12:04 pm
davidmam wrote:I'm not sure which ADC to use or how to get the values.
...


I spent a fair bit of time looking at different versions of these I2C ADC chips. Most come in surface mount packages which is fine but not easy to work with unless you want to solder them onto breakout boards. This pcf8591p 8bit I2C A-D converter comes in a classic DIP which can be poked straight into breadboard. It has 4 analogue inputs and three address pins. There are others out there with more inputs but less bits for addressing and without the DIP package, there are probably better DIP ones than the one I found out there with more inputs and more address bits but I didn't come across any.

davidmam wrote: I presume I can just wire it up, modprobe i2c-dev and I should see the device(s), but then what?
...


I'm looking into that at the minute - there are some example C programs and there are C libraries you can use for including I2C methods in your programs. Will find them again and link them in due course.
Ideally I want to use Python.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by rurwin » Fri Jun 29, 2012 12:10 pm
morphy_richards wrote:This pcf8591p 8bit I2C A-D converter comes in a classic DIP which can be poked straight into breadboard.

And it will work off 3.3V or 5V. Not a bad price either. Nice find.
User avatar
Moderator
Moderator
Posts: 2890
Joined: Mon Jan 09, 2012 3:16 pm
by davidmam » Fri Jun 29, 2012 12:54 pm
It looks like this thread has some ideas - maybe using i2cget would be the way to go? viewtopic.php?f=7&t=1434
Posts: 98
Joined: Tue Dec 06, 2011 4:13 pm
by morphy_richards » Fri Jun 29, 2012 2:17 pm
Bootc has everthing you need to get started with i2c and pi in his website (what a nice chap)

Some useful step by step setup instructions to help install your new kernel and install i2ctools.
Examples of programming and using i2C...
An example from Frannk Buss's GPIO extender thread is this code download here - http://www.frank-buss.de/io-ex.....i2c-test.c.

There should be some other examples out there, I came across a few earlier but cant find them now.

I'm on a learning curve at the moment. I'll keep updating this thread as I stumble my way through to some sort of clarity.
Last edited by morphy_richards on Fri Jun 29, 2012 2:29 pm, edited 1 time in total.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Fri Jun 29, 2012 2:26 pm
Python can be used to communicate with the I2C bus on the Raspberry Pi. With the Debian image all you need to do is "sudo apt-get install python-smbus" and then you can use e.g. http://www.frank-buss.de/io-expander/i2c-test.py with "python i2c-test.py". I've tested it and works like a charm."

... ooh hello!

From Re: Linux device drivers for Rapberry Pi on-board I/O
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by Grumpy Mike » Fri Jun 29, 2012 9:39 pm
rurwin wrote:However I would use 3.3V (wire 1) to power the ADC, not 5V (wire 2). Otherwise there may be voltages over 3.3V at the I2C input of the SoC.


I would disagree with this. The I2C lines are pull down only, implemented by open collector or open drain drivers. Therefore there is no way to get 5V onto the I2C line. I see I2C as a good bridge between the 5V world and the 3V3 world.
If you need to measure voltages up to 4.5V directly then you can't power the converter off 3V3, it has to be 5V.
User avatar
Posts: 748
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
by morphy_richards » Tue Jul 03, 2012 3:14 pm
Going to go through this step by step.

I've plugged my pcf8591p 8bit I2C A-Dconverterinto some breadboard.
Configured thusly:
Image

So... AIN0 is connected to the middle terminal of a potentiometer. The other Ain pins are left floating for now.
A0,A1,A2 are all tied to ground to set a "000" address.
VSS (pin 8) is tied to OSC (pin 11) because "an on chip oscillator generates the clock signal required for the A/D conversion and for refreshing the auto zeroed buffer amp. When using the oscillator the EXT pin has to be connected to Vss"
Pin 11 (osc) is floating currently. "at the osc pin the oscillator frequency is available" -- does that mean although it's doing it's job internally, if I wanted to, I could connect something elseto that pin that would use it's clock pulses? Should I tie this to ground if I'm not using it?
AGND is connected to ground - as supplied from the Pi's GPIO
VREF and VDD are both currently tied to 5V form the Pi's GPIO
AOUT is floating currently as I'm only interested in A to D.
SDA and SCL are both connected to relevent the I2C pins of the GPIO.
ImageImage

First - should I tie all these floating pins to ground?

Next - I should begin to construct a python program someting like ...

1) install smbus
sudo apt-get install python-smbus
(From Frank Buss's example)

Code: Select all
class i2cADCTryOut():
   # open Linux device /dev/ic2-0
   i2c = smbus.SMBus(0)

# construct a new object with the I2C address of the I2C adc
   def __init__(self, address):
      self.address = address

# create a new i2cADCTryOut object
ioExpander = i2cADCTryOut(0x20)


Not sure what the manufacturers address is at the moment , a quick scan of the datasheet doesnt reveal it straight away and I need to dash off in a moment - the value (0x20) is straigh from Frank Buss's PCA9555 example. I assume this is the i2c address. I will need to come back to this ...

self.i2c.read_byte_data(self.address, reg)
- Would this allow me quick and dirty ability to "grab" a value from an input?
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Wed Jul 04, 2012 9:37 am
More on addressing. The address for this I2CADC is one byte / eight bits. (Least significant bit is shown as bit 1 on the lists below)
The first thing that happens is that the "start condition" is sent, then the address byte...
The first byte sent is the address byte.
  1. Bit 1: R/W - this sets the direction of the data transfer.From what I can work out "1" sets this to read for A/D conversion.
  2. Bit 2: A0 - Going with the setup in my earlier post these three bits A0-A2 are all "0".
  3. Bit 3: A1- Going with the setup in my earlier post these three bits A0-A2 are all "0".
  4. Bit 4: A2 - Going with the setup in my earlier post these three bits A0-A2 are all "0".
  5. Bit 5: 1 - These four bits are the pre-set address by the manufacturer
  6. Bit 6: 0 - These four bits are the pre-set address by the manufacturer
  7. Bit 7: 0 - These four bits are the pre-set address by the manufacturer
  8. Bit 8: 1 - These four bits are the pre-set address by the manufacturer.

The second byte is the control byte.
  1. Bit 1: Used to select A/D channel number. 00 ch 0, 01 ch1, 10 ch2, 11 ch 3
  2. Bit 2: Used to select A/D channel number. 00 ch 0, 01 ch1, 10 ch2, 11 ch 3
  3. Bit 3: auto increment flag 0 = off, 1 = on.
  4. Bit 4: should be "0"
  5. Bit 5: 0 - analogue input programming allows you to select between single ended or differential inputs. I am interested in single ended... (*)
  6. Bit 6: 0 - analogue input programming allows you to select between single ended or differential inputs. I am interested in single ended... (*)
  7. Bit 7: 0 - analogue output enable. "1" to enable analogue out. I am only intersted in reading values at the moment.
  8. Bit 8: should be "0"

* Single ended is fairly straightforward. You just get a straight value based on the input (and it is accurate if every sensor shares a common ground). Differential allows you to obtain the difference between two inputs where the ground is not common and so still get meaningful results - for example a thermocouple temperature sensor has no "ground".
* After plugging in your i2c device dont forget to sudo modprobe i2c-dev, ls /dev/i2c*, chmod 666 /dev/i2c-0

Questions
1) Do you have to ...
$ sudo modprobe i2c-dev
$ sudo chmod 666 /dev/i2c-0
...every time you want to use I2C in any way at all? If yes can you write this into a startup script?
2) Auto increment - does this mean that the device will take a reading from each A0 to A3 in one cycle?
3)To use this with smbus...
Code: Select all
def __init__(self, address):
      self.address = address

... how, when using smbus does one differentiate the first address byte and the second control byte? Does one create a reference to it as in the code snippet above (dont know why I have suddenly started using the royal "one" to refer to myself in third person - scary)
Can / would / should you then write the second control byte by doing something like this?
Code: Select all
def sendControlByte(self, reg, value):
  self.i2c.write_byte_data(self.address, reg, low)


4) On a more basic level, using I2C tools, I have connected up the I2CADC and do an I2C detect as shown below. I get no values, is there anything obvious that I have missed?
Image
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Thu Jul 05, 2012 2:22 pm
This seems like a useful info source http://quick2wire.com/2012/06/i2c-python/
As my understanding gradually emerges (a bit like a very slow moving brute force driven steam roller with as much subtlety as a .. as a pneumatic sledgehammer)
I2C is not really anything like "plug and play". Even when using I2Cdetect. I assumed I2C detect sent a whole bunch of common signals to every known I2C address and then listened out for some response, and that it would be a bit like lsusb (only for things that were connected to the I2C bus as opposed to USB).

It looks like there is lots of support out there for the MCP23008 chip so that you can use an API and as long as you are using this particular chip set then it is kind of plug n play.

In some respect you do need to do a kind of "bit banging" (not exactly the case, but sort of true) in order to ensure that you can tailor the right reads or writes are sent to match whatever your device actually needs.

So, with that in mind y, you could use C and ioctl or you could use something like this quick2wire.i2c API but you still need to manually configure it.

So, the address for the pcf8591p 8bit I2C A-D converter with the three user address bits set to "0" is 10010001 = 145 = 0x91
The next control byte would be 00000000 (to use channel 0, auto increment off, single ended, analogue out off) = 0 = 0x0

The third bit which is sent to the pcf8591p is stored and then converted to a voltage by the digital to analogue converter. I dont want to do this at the moment so I assume this value would also be 0x0.

So, to read from the pcf8591p analogue input 1 I would use something like this (in quick2wire pseudo code)

Code: Select all
import quick2wire.i2c as i2c
import time

with i2c.I2CBus() as bus:
    bus.transaction(
        i2c.write_bytes(0x91, 0x0, 0x0))

 while True:
        results = bus.transaction(
               i2c.read(0x91, 1))
        gpio_state = results[0]
        print(gpio_state)

        time.sleep(1)


Am I anywhere like in the right forest before I even ask if I am near barking up the right tree?

NB. Quick2Wire references using the PCF8591, the very AD converter I am trying to use in this web page.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by davidmam » Thu Jul 05, 2012 11:16 pm
I don't know if you are in the right forest, but I am happily following your scent as you are barking int he same direction as me.. I've just ordered a different i2c ADC which claims to have kernel support, and an i2c io register so it will be interesting to see how this works out.
Posts: 98
Joined: Tue Dec 06, 2011 4:13 pm
by morphy_richards » Fri Jul 06, 2012 11:43 am
Some fairly obvious things I missed.
Add user to gpio and i2c groups
Code: Select all
sudo adduser $USER gpio
sudo adduser $USER i2c


After that I think i2cdetect should work. Except it still doesnt! My ADC seems to have a funny address which doesnt even come under the none regular addresses used by i2cdetect. I have probably bodged something somewhere. However my MMA7660FC acceclerometer uses address 1001100 (0x4C) which should be in range of i2cdetect but still it doesnt show up. :?

Anyway, install the quick2wire gpio admin api as per instructions https://github.com/quick2wire/quick2wire-gpio-admin
Next install quick2wire python api https://github.com/quick2wire/quick2wire-python-api
make sure you use virtualenv or a similar precaution as its still in development.

Some nice getting started instructions here -
https://github.com/quick2wire/quick2wir ... ith-i2c.md

I think I'm going to try buying a MCP23008 (the chip everyone seems to be using to make gpio expanders which is well supported) to help me play and learn.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Fri Jul 06, 2012 11:56 am
davidmam wrote: I've just ordered a different i2c ADC which claims to have kernel support, and an i2c io register so it will be interesting to see how this works out.

Which one did you order?
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by davidmam » Sat Jul 07, 2012 10:25 pm
http://www.ebay.com/itm/ws/eBayISAPI.dl ... 0594940129

It is an ADS7828 8 channel 12 bit ADC which should be fine to play with. There appear to be drivers in the kernel.

I've also bought a SOIC breakout board on which to put it so I can get it to behave. WHen it arrives I will be able to see if I can get it to work, and then I can develop the desired piece of kit (a multi channel monitor for the gas cylinders in the lab that can then warn us when they are needing replaced.)

At the same time I purchased some MPC 23017 I2C GPIO extenders so have those to play with as well.
Posts: 98
Joined: Tue Dec 06, 2011 4:13 pm
by morphy_richards » Tue Jul 10, 2012 12:45 pm
I am now using an MCP23008.

I have connected it up as follows:
pi gpio 3v3 (wire 1) to MCP23008 VDD (pin 18)
pi GND (wire 6) to MCP23008 VSS (pin 9)
pi SDA (wire 3) to MCP23008 SDA (pin 2)
pi SCL (wire 5) to MCP23008 SCL (pin 1)

A0, A1, A2 are connected to GND (sets user address 000)

user "pi" in groups "i2c", "gpio"

sudo modprobe i2c-dev
sudo chmod 666 /dev/i2c-0

i2cdetect 0

0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

nothing.
cur non operari ???
Before I go any further, stop me if this idea is madness ...
I will attach an LED between SDA and GND and the same with SCL. I will attempt the i2cdetect again. I should see a flicker in the LED if those pins are working?

(I have no oscilloscope to hand)

Or... slighlty more fiddly ...

I connect an arduino to those points and set the sample speed to be as fast as possible. Then watch for results.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Tue Jul 10, 2012 1:09 pm
I did it anyway with the LEDs. So, two LEDs connected between SCA and GND & SCL and GND will turn on. I think that is what is supposed to happen because I2C uses pull up resistors (which are internally provided on the pi, you usually have to add your own) to pull the supply up.

I2c then drives the voltage low on these lines to send a signal. So it's right that the LEDs should be lit / normally on but that tells me little other than that there is power getting to those points.

I can see no flicker. Like I was ever going to at 100KHz. Silly silly!

Next..?

Arduino is no good, it can only handle 10 KHz
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Tue Jul 10, 2012 1:18 pm
It works!

I originally set A0,A1,A2 to 000 by tying all three to ground.

I tied A0 (pin 5) high and suddenly I see this:

Code: Select all
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- 21 -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --   

Can anyone tell me why I cant use "000" as the hardware address input please?

Right, off to try this now using the pcf8591p 8bit I2C A-Dconverter
:D

(edit) nb. be careful when pulling micro-chips out of breadboard. The pins bend!
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Tue Jul 10, 2012 1:48 pm
Embarrassingly, the pcf8591p wasnt being picked up by i2cdetect because I had forgotten to connect Vss to ground. :oops:
This IC doesnt seem to mind A0 A1 A2 being set as "000"
Next - to see if I can read a value from the potentiometer.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Tue Jul 10, 2012 2:44 pm
For what it's worth ...
This code
Code: Select all
#!/usr/bin/env python3

import quick2wire.i2c as i2c
import time

duration = 0.2
counter = 0

address = 0x48
iodir_register = 0x00

while (counter < 120):

 with i2c.I2CBus() as bus:   
   

     read_results = bus.transaction(
         i2c.write_bytes(address, 0x0, 0x0),
         i2c.read(address, 1))

     pot_val = read_results[0][0]

     print ("%02x" % pot_val)
     time.sleep(duration)
     counter = counter + 1
     


Currently gives me as output
00
00
00
00
etc.
Regardless of what I do to the physical potentiometer. This is while using the internal oscillator for A/D conversion cycle by connecting EXT to Vss (to Gnd).
(It is a bit of progress)

Python casting question -

Why is
print int("%02x" % pot_val)
a syntax error?
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by Sjakie » Tue Jul 10, 2012 9:56 pm
I've got the pcf8591p too and i'm at a halt too with trying to read the analog inputs. I'm completely new with this low level stuff like l2c so this is a nice challenge. I've also seen the blog post about this chip over at quick2wire so it shouldn't be too far off.

I see you get NULL back while i get all sorts of values returned. Every time the registers are set to listen or read mode the value is raised by 1 bit. :?

I'm going to give it a good night's rest. :)
Posts: 15
Joined: Mon Jul 02, 2012 5:30 pm
by morphy_richards » Wed Jul 11, 2012 6:39 am
I had a similar result to what you describe before I had configured the chip to use the internal oscillator. Have you connected ext to ground?
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by morphy_richards » Wed Jul 11, 2012 12:54 pm
Sjakie wrote: Every time the registers are set to listen or read mode the value is raised by 1 bit. :?

:)

Can you specify how you are doing this? I assume you are using the Quick2wire Python API.

From the datasheet page 6 - 7.1 Addressing: "the last bit of the address byte is the read/write bit which sets the direction of the following data transfer"
Image
Image
To set the address for a read it should be
10010001 =
145 =
0x91 (???)

But i2cdetect reports the address as 0x48 which is miles away from what I get. If I do try to use 0x91 using the quick2wire
i2c.write_bytes(0x91, 0x00, 0x00) ... (*see footnote)... I just get an I/O error. I only get a result when I use the address that is reported by i2cdetect.

Reading this basic i2c tutorial
"All I2C addresses are either 7 bits [...] When sending out the 7 bit address, we still always send 8 bits. The extra bit is used to inform the slave if the master is writing to it or reading from it" which I understand.

But I cant reconcile my understanding of this with using the address thats reported by i2cdetect.

I have assumed the following:
The i2c.write_bytes function will send all the bytes enclosed in the brackets to a particular device.

i2c.write_bytes(byte1, byte2, byte3, byte4, ..., ..., byteN)

Will send that series of bytes where the first byte is the 7 bit address and read/write bit, then byte 2 and so on.

The first (address) byte will "wake up and listen" the device on that particular address.
The following bytes (byte2 to byteN) will then be recieved by that device and it will do whatever it interprets those bytes as.

Is that right?

*footnote
Which should be the (first byte) address as given in the datasheet, followed by (second byte) the control byte to specify single ended, none incremental input from channel 0 and finally the third byte which is used for Digital to Analogue conversion to set a voltage and in my case currently I dont want one so set it to 0 (0x0)) (I'm using somehting like this lookup tablefor hex values)
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London
by Sjakie » Wed Jul 11, 2012 1:33 pm
I believe the address is only 7 bits. Most significant bit would be 64, 32, 16, and so on.

The binary address would be 1001000, dec=72, hex=0x48. I believe we have to write this to the chip, plus the 8th bit at 1 for read/input operation.
Posts: 15
Joined: Mon Jul 02, 2012 5:30 pm
by morphy_richards » Wed Jul 11, 2012 2:06 pm
Sjakie wrote:I believe the address is only 7 bits. Most significant bit would be 64, 32, 16, and so on.

The binary address would be 1001000, dec=72, hex=0x48. I believe we have to write this to the chip, plus the 8th bit at zero for read/input operation.

That makes sense and expains things. 0x48 is the 7 bit address!

So I'm a bit closer to understanding this but I still dont understand (call me "Mister Slow") how...

If the address is 7 bits and the eighth bit is used to dictate read or write from the master ...
And the address part is 72 (hex = 0x48) (made up from the 7 bits)...
And that 7 bit address is written to the device as in i2c.write_bytes(0x91, ...)

How then do you refer to the eigth/ extra bit?

Also - my understanding of the datasheet and this diagram Image was that the eighth (LSB) would be "1" for a 'master read' - analogue to digital.

Hmmm ... :?

Gotta go, bbs.
User avatar
Posts: 852
Joined: Mon Mar 05, 2012 3:26 pm
Location: London