Using devices with the I2C bus

The Raspberry Pi can support several higher-level protocols that a wider range of devices can easily be connected to. In this chapter, we shall focus on the most common bus, called I2C (I-squared-C). It provides a medium-speed bus for communicating with devices over two wires. In this section, we shall use I2C to interface with an 8-bit ADC. This device will measure an analog signal, convert it to a relative value between 0 and 255, and send the value as a digital signal (represented by 8 bits) over the I2C bus to the Raspberry Pi.

Getting ready

The I2C bus is not enabled in all Raspberry Pi images; therefore, we need to enable the module and install some supporting tools. Newer versions of Raspbian use Device Trees to handle hardware peripherals and drivers.

In order to make use of the I2C bus, we need to enable the ARM I2C in the ootconfig.txt file.

You can do this automatically using the following command:

sudo raspi-config

As shown in the following screenshot, select Advanced Options from the menu and then I2C. When asked, select Yes to enable the interface and Yes to load the module by default.

Getting ready

From the menu select I2C and select Yes to enable the interface and to load the module by default.

Tip

The raspi-config program enables the I2C_ARM interface by altering /boot/config.txt to include dtparam=i2c_arm=on. The other bus (I2C_VC) is typically reserved for interfacing with Raspberry Pi HAT add-on boards (to read the configuration information from the on-board memory devices); however, you can enable this using dtparam=i2c_vc=on.

You can also enable the SPI using raspi-config list if you wish, which is another type of bus that can be seen in Chapter 10, Interfacing with Technology.

Next, we should include the I2C module to be loaded on power up, as follows:

sudo nano /etc/modules

Add the following on separate lines and save (Ctrl + X, Y, Enter):

i2c-dev
i2c-bcm2708

Similarly, we can also enable the SPI module by adding spi-bcm2708.

Next, we will install some tools to use I2C devices directly from the command line, as follows:

sudo apt-get update
sudo apt-get install i2c-tools

Finally, shut down the Raspberry Pi before attaching the hardware in order to allow the changes to be applied, as follows:

sudo halt

You will need a PCF8591 module (retailers of these are listed in Appendix, Hardware and Software List) or you can obtain the PCF8591 chip separately and build your own circuit (see the There's more… section for details of the circuit).

Getting ready

The PCF8591 ADC and sensor module from dx.com

Connect the GND, VCC, SDA, and SCL pins to the Raspberry Pi GPIO header as follows:

Getting ready

I2C connections on the Raspberry Pi GPIO header

Note

You can use the same I2C tools/code with other I2C devices by studying the datasheet of the device to find out what messages to send/read and which registers are used to control your device.

How to do it...

Detect the I2C device by using i2cdetect (the --y option skips any warnings about possible interference with other hardware that could be connected to the I2C bus) using the following commands to scan both buses:

sudo i2cdetect -y 0
sudo i2cdetect -y 1

Depending on your Raspberry Pi board revision, the address of the device should be listed on bus 0 (for Model B Rev1 boards) or bus 1 (for Raspberry Pi 2 & 3, Raspberry Pi 1 Model A and Model B Rev 2). By default, the PCF8591 address is 0x48.

I2C bus number to use

Bus 00

Bus 11

Raspberry Pi 2 & 3

HAT ID (I2C_VC)

GPIO (I2C_ARM)

Model A and Model B Revision 2

P5

GPIO

Model B Revision 1

GPIOGPIO

n/a

The following screenshot shows the output of i2cdetect:

How to do it...

The PCF8591 address (48) is displayed here on bus 1

If nothing is listed, shut down and double-check your connections (the ADC module from www.dx.com will have a red LED showing when powered).

Note

If you receive an error that the /dev/i2c1 bus doesn't exist, you can perform the following checks.

Ensure that the /etc/modprobe.d/raspi-blacklist.conf file is empty (that is, the modules haven't been blacklisted), using the following command to view the file:

sudo nano /etc/modprobe.d/raspi-blacklist.conf

If there is anything in the file (such as blacklist i2c-bcm2708), remove it and save.

Check /boot/config and ensure there isn't a line that has device_tree_param= (this will disable support for the new device tree configurations and disable support for some Raspberry Pi HAT add-on boards).

Check whether the modules have been loaded by using lsmod and look for i2c-bcm2708 and i2c_dev.

Using the detected bus number (0 or 1) and the device address (0x48) use i2cget to read from the device (after a power up or channel change you will need to read the device twice to see the latest value), as follows:

sudo i2cget -y 1 0x48
sudo i2cget -y 1 0x48

To read from channel 1 (this is the temperature sensor on the module), we can use i2cset to write 0x01 to the PCF8591 control register. Again, use two reads to get a new sample from channel 1, as follows:

sudo i2cset -y 1 0x48 0x01
sudo i2cget -y 1 0x48
sudo i2cget -y 1 0x48

To cycle through each of the input channels, use i2cset to set the control register to 0x04, as follows:

sudo i2cset -y 1 0x48 0x04

We can also control the AOUT pin using the following command to set it fully on (lighting up the LED D1):

sudo i2cset -y 1 0x48 0x40 0xff

Finally, we can use the following command to set it fully off (switching off the LED D1):

sudo i2cset -y 1 0x48 0x40 0x00

How it works...

The first read from the device after power on will return 0x80 and will also trigger the new sample from channel 0. If you read a second time, it will return the sample previously read and generate a fresh sample. Each reading will be an 8-bit value (ranging from 0 to 255), representing the voltage 0 to VCC (in this case, 0V to 3.3V). On the www.dx.com module, channel 0 is connected to a light sensor, so if you cover up the module with your hand and resend the command, you will observe a change in the values (darker means a higher value and lighter means a lower one). You will find the readings are always one behind; this is because as it returns the previous sample, it captures the next sample.

We use the following command to specify a particular channel to read:

sudo i2cset -y 1 0x48 0x01

This changes the channel that is read to channel 1 (this is marked as AIN1 on the module). Remember, you will need to perform two reads before you will see data from the newly selected channel. The following table shows the channels and pin names as well as which jumper connectors enable/disable each of the sensors:

Channel

0

1

2

3

Pin Name

AIN0

AIN1

AIN2

AIN3

Sensor

Light Dependent Resistor

Thermistor

External Pin

Potentiometer

Jumper

P5

P4

 

P6

Next, we control the AOUT pin by setting the analog output enable flag (bit 6) of the control register and use the next value to set the analog voltage (0V-3.3V 0x00-0xFF), as follows:

sudo i2cset -y 1 0x48 0x40 0xff 

Finally, you can set bit 2 (0x04) to auto-increment and cycle through the input channels as follows:

sudo i2cset -y 1 0x48 0x04

Each time you run i2cget -y 1 0x48, the next channel will be selected, starting with channel AIN0, then AIN1 through to AIN3, and back to AIN0 again.

Note

To understand how to set a particular bit in a value, it helps to look at the binary representation of a number. The 8-bit value 0x04 can be written as b0000 0100 in binary (0x indicates the value is written in hexadecimal or hex, and b indicates a binary number).

Bits within binary numbers are counted from right to left, starting with 0, that is, MSB 7 6 5 4 3 2 1 0 LSB.

Bit 7 is known as the Most Significant Bit (MSB) and bit 0 as the Least Significant Bit (LSB). Therefore, by setting bit 2, we end up with b0000 0100 (which is 0x04).

There's more...

The I2C bus allows us to easily connect multiple devices using only a few wires. The PCF8591 chip can be used to connect your own sensors to the module or just the chip.

Using multiple I2C devices

All commands on the I2C bus are addressed to a specific I2C device (many have the option to set some pins high or low to select additional addresses and allow multiple devices to exist on the same bus). Each device must have a unique address so that only one device will respond at any one time. The PCF8591 starting address is 0x48, with additional addresses selectable by the three address pins to 0x4F. This allows up to eight PCF8591 devices to be used on the same bus.

Note

If you decide to use the I2C_VC bus that is located on GPIO pins 27 and 2828 (or on the P5 header on Model A and Rev2 Model B devices), you may need to add a 1k8 ohm pull-up resistor between the I2C lines and 3.3V. These resistors are already present on the I2C bus on the GPIO connector. However, some I2C modules, including the PCF8591 module, have their own resistors fitted, so it will work without the extra resistors.

I2C bus and level shifting

The I2C bus consists of two wires, one data (SDA) and one clock (SCL). Both are passively pulled to VCC (on the Raspberry Pi, this is 3.3V) with pull-up resistors. The Raspberry Pi will control the clock by pulling it low every cycle and the data line can be pulled low by Raspberry Pi to send commands or by the connected device to respond with data.

I2C bus and level shifting

The Raspberry Pi I2C pins include pull-up resistors on SDA and SCL

Since the slave devices can only pull the data line to GND, the device may be powered by 3.3V or even 5V without the risk of driving the GPIO pins too high (remember that the Raspberry Pi GPIO is not able to handle voltages over 3.3V). This should work as long as the I2C bus of the device will recognize logic high at 3.3V instead of 5V. The I2C device must not have its own pull-up resistors fitted, as this will cause the GPIO pins to be pulled to the supply voltage of the I2C device.

Note the PCF8591 module used in this chapter has resistors fitted; therefore, we must only use VCC=3V3. A bidirectional logic level converter can be used to overcome any issues with logic levels. One such device is the Adafruit I2C bidirectional logic level translator, shown in the following image:

I2C bus and level shifting

Adafruit I2C Bi-directional logic level translator module

In addition to ensuring that any logic voltages are at suitable levels for the device you are using, it will allow the bus to be extended over longer wires (the level shifter will also act as a bus repeater).

Using just the PCF8591 chip or adding alternative sensors

A circuit diagram of the PCF8591 module without the sensors attached is shown in the following diagram:

Using just the PCF8591 chip or adding alternative sensors

The PCF8591 ADC circuit – VCC, GND, SCL, and SDA are connected to the Raspberry Pi as before

As you can see, excluding the sensors, there are only five additional components. We have a power-filtering capacitor (C1) and the power-indicating LED (D2) with a current-limiting resistor (R5), all of which are optional.

It should be noted that the module includes two 10k pull-up resistors (R8 and R9) for SCL and SDA signals. However, since the GPIO I2C connections on the Raspberry Pi also include pull-up resistors, these are not needed on the module (and could be removed). It also means we should only connect this module to VCC=3.3V (if we use 5V, then voltages on SCL and SDA will be around 3.56V, which is too high for the Raspberry Pi GPIO pins).

The sensors on the PCF891 module are all resistive, so the voltage level that is present on analog input will change between GND and VCC as the resistance of the sensor changes.

Using just the PCF8591 chip or adding alternative sensors

A potential divider circuit is used to provide a voltage proportional to the sensor's resistance

The module uses a circuit known as a potential divider. The resistor at the top balances the resistance provided by the sensor at the bottom to provide a voltage that is somewhere between VCC and GND.

The output voltage (Vout) of the potential divider can be calculated as follows:

Using just the PCF8591 chip or adding alternative sensors

The Rt and Rb are the resistance values at the top and bottom respectively, and VCC is the supply voltage.

The potentiometer in the module has the 10k ohm resistance split between top and bottom depending on the position of the adjuster. So, halfway, we have 5k ohm on each side and an output voltage of 1.65V; a quarter of the way (clockwise), we have 2.5k ohm and 7.5k ohm, producing 0.825V.

Note

I've not shown the AOUT circuit, which is a resistor and LED. However, as you will find, an LED isn't suited to indicate an analog output (except to show the on/off states).

For more sensitive circuits, you can use more complex circuits such as a Wheatstone bridge (which allows the detection of very small changes in resistance), or you can use dedicated sensors that output an analog voltage based on their readings (such as a TMP36 temperature sensor). The PCF891 also supports the differential input mode, where one channel can be compared to the input of another (the resultant reading will be the difference between the two).

For more information on the PCF8591 chip, refer to the datasheet at http://www.nxp.com/documents/data_sheet/PCF8591.pdf.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.222.12