Wednesday, December 19, 2012

I2C Analog to Digital Converter

The first device I hooked to my Raspberry Pi is based on the PCF8591 Analog to Digital Converter (ADC). This chip has 4 analog inputs (ADC) and one analog output or Digital to Analog Converter (DAC).

I am using a pre-assembled board from Deal Extreme which comes with the chip, a temperature sensor, light sensor, variable resistor and LED. This provides a simple showcase for the chip and more importantly, it has a light sensor which is important to my project. The board was only a few dollars http://dx.com/p/pcf8591-8-bit-a-d-d-a-converter-module-150190 there are also other similar boards on there.

PCF8591 demo board. GPIO pins are visible on the right.


The first step is to physically hook up the board. Mine came with the required cables (often called dupont cables) which is also a handy way to start. The cables must be connected to the Raspberry Pi GPIO pins nominated for I2C. These have the required 'pull up resistors' already installed. (These are what make the wires operate like a bus). The pins are
  • P1-01 +3.3v (VCC)
  • P1-03 Data (SDA)
  • P1-05 Clock (SCL)
  • P1-09 Ground (GND)
Raspberry Pi showing GPIO cables connected.


My demo board has a red power indicator LED which came on once I powered up.

The next big test is to see if the i2c driver can talk to your chip. The Raspberry Pi actually comes configured with two I2C buses and for reasons unknown, on my system the bus labelled I2C0 is allocated the Linux device i2c-1.

Scanning both buses won't hurt.

jnewbigin@raspberrypi:~$ i2cdetect 1
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-1.
I will probe address range 0x03-0x77.
Continue? [Y/n] y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --                         


You can see here that a device has been detected at address 0x48. This is the expected address for my chip so that means we are in business.

Reading and writing to the chip is quite straight forward but the chip does have a few nuances.  The first read after power on will return 0x80. The analog to digital conversion is performed when you make a read request but the read will return the previous sample so it is always one sample behind. This is not too confusing unless you are switching to read a different input.

I will show how to read the data using the command line tools i2cget and i2cset. In another blog post I will show how you can interface with the chip from c code.

All these commands take a parameter 1 to specify which i2c bus and I pass -y which skips the safety warning. (We know what we are doing so this is OK. On other hardware such as your PC, things can and do go wrong by using these commands).

The most basic read is the default channel (input 0).
jnewbigin@raspberrypi:~$ i2cget -y 1 0x48
0x80
That is the power on status code. Now we read again

jnewbigin@raspberrypi:~$ i2cget -y 1 0x48
0xd2
That is the value that was sampled when we made our first read (the one that returned 0x80).
Now cover up the light sensor and read again

jnewbigin@raspberrypi:~$ i2cget -y 1 0x48
0xd2
Yep, no change. The new value has been sampled so now we read it
jnewbigin@raspberrypi:~$ i2cget -y 1 0x48
0xeb
Now we get the new value.

Now, switch to read another input, input number 1
jnewbigin@raspberrypi:~$ i2cset -y 1 0x48 0x01
jnewbigin@raspberrypi:~$ i2cget -y 1 0x48
0xeb
First we get an old value.
jnewbigin@raspberrypi:~$ i2cget -y 1 0x48
0xcf
Then the new value

We can repeat to select channel 2 and 3.

We can enable the analog output by adding bit 0x40 to the set command and then specify a value for the DAC
jnewbigin@raspberrypi:~$ i2cset -y 1 0x48 0x41 0xff

And the indicator LED turns on

jnewbigin@raspberrypi:~$ i2cset -y 1 0x48 0x41 0x00
And the indicator LED turns off. You can of course set it to any value between 0x00 and 0xff and see the LED dim and turn off. (You can also see why LEDs don't make good analog indicators).


11 comments:

  1. I have the same board as you and trying to find out how to deal with the jumpers, LDR, thermistor and potentiometer.

    Did you figure it out?

    ReplyDelete
    Replies
    1. I found needed information at http://brainfyre.wordpress.com/2012/10/25/pcf8591-yl-40-ad-da-module-review/

      Delete
  2. "We can enable the analog output by adding bit 0x40 to the set command and then specify a value for the ADC"
    ...I think you mean setting the value for the DAC.
    Mr T.

    ReplyDelete
    Replies
    1. Yes indeed. I have updated the post.
      John.

      Delete
  3. Hi there

    I need to operate 4 DAC channels in parallel.
    Can this be done with one RasPi and 4 of the DX modules?

    Thanx -Didi

    ReplyDelete
    Replies
    1. Sure. The PCF8591 has a 3 bit address which allows you to use up to 8 of these on one bus.
      I am not sure what is required to change the address on the DX demo board. You may have to cut some tracks on the PCB. Check out the data sheet to see which pins are used for addressing.
      There may be other boards which have jumpers for addressing which might be easier.

      Delete
  4. To anyone else who has used these YL-40 modules: have you managed to get any "useful" (I know, it's only 8-bit, but still) data from the integrated thermistor?

    On mine, everything else seems to work just fine (on-board sensors as well as all using external, at least w/a trimpot wired to each, and the output seems appropriate), but the built-in thermistor doesn't seem to respond, much.

    For a ~25°F (~15°C) temperature drop, it doesn't give more than a few "bits" increase on the data channel to the RaspPi (~211 up to ~216). I've also measured the voltage through AIN1 (seems appropriate relative to Vcc), as well as the resistance while powered off (not entirely sure this measurement is "valid"): the YL-40's thermistor (same conditions as previously mentioned) only increases by about 350ohms; for comparison, an old Radio-Shack thermistor (10Kohm, also "bead" type, unfortunately no longer sold, but you could look it up #271-0110) jumps almost 15Kohms !

    So, I'm thinking I've either got a YL-40 with a "bad" thermistor, or the thermistor is just completely "not suitable" for this "application" ...

    Again, is ANYONE getting "reasonable" data from the thermistor on a YL-40 ?

    If so, am I missing something? As I mentioned, I can get "data" (such as it is, but "responsive") for everything else except the thermistor (using either the I2CTools used in John's post here, or my own Python scripts

    Thanks in advance for any help!

    Mike

    ReplyDelete
  5. If your still having trouble getting valid thermistor reading, checkout my C based helpers at https://github.com/skoona/skn_rpi-display-services. There is a client in that package that reads all the inputs with valid results.

    ReplyDelete
  6. I have the same module but the Raspberry Pi, but then I execute:
    i2cget -y 1 0x48
    or i2cget -y 1 0x48 0x01 or i2cget -y 1 0x48 0x02 or i2cget -y 1 0x48 0x03 i am always receve:
    0x00
    Why?

    ReplyDelete
  7. The datasheet for the chip provides a good reference: http://www.nxp.com/documents/data_sheet/PCF8591.pdf

    ReplyDelete