Difference between revisions of "EBC Exercise 12 I2C"

From eLinux.org
Jump to: navigation, search
m (The Software: Removed opkg reference)
(20 intermediate revisions by 6 users not shown)
Line 2: Line 2:
 
[[Category:EmbeddedBeagleClass]]
 
[[Category:EmbeddedBeagleClass]]
 
{{YoderHead}}
 
{{YoderHead}}
 +
{{EBC3.8}}This page is for the 3.8 kernel. See [[EBC Exercise 12 I2C - xM]] for the 3.2 kernel.
  
[http://en.wikipedia.org/wiki/I%C2%B2C I²C] is a "two-wire interface" standard that is used to attach low-speed peripherals to an embedded system.  In this exercise we will wire up a couple of I²C temperature sensors ([http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010749 TC74]) and learn how to read their values.
+
[http://en.wikipedia.org/wiki/I%C2%B2C I²C] is a "two-wire interface" standard that is used to attach low-speed peripherals to an embedded system.  In this exercise we will wire up a couple of I²C temperature sensors ([http://www.ti.com/product/tmp101 TC74]) and learn how to read their values.
  
 
== The Hardware ==
 
== The Hardware ==
=== xM ===
+
=== bone ===
 
+
The AM3359 on the BeagleBone has three I²C controllers (Section 21 of the [http://www.ti.com/product/am3359 TRM]). You can see which ones are configured at boot time by running the following on the Beagle:
The DM3730 on the BeagleBoard-xM has four I²C controllers (Section 17 of the [http://www.ti.com/product/dm3730#technicaldocuments TRM]). You can see which ones are configured at boot time by running the following on the Beagle:
 
  
 
  beagle$ '''dmesg | grep i2c'''
 
  beagle$ '''dmesg | grep i2c'''
  [    0.000000] Beagle cameraboard: registering i2c2 bus for lbcm3m1
+
  [    0.153495] omap_i2c 44e0b000.i2c: bus 0 rev0.11 at 400 kHz
[    8.946075] i2c_omap i2c_omap.1: bus 1 rev4.0 at 2600 kHz
+
  [    0.165269] omap_i2c 44e0b000.i2c: unable to select pin group
  [    8.966064] i2c_omap i2c_omap.2: bus 2 rev4.0 at 400 kHz
+
  [    0.166036] omap_i2c 4819c000.i2c: bus 1 rev0.11 at 100 kHz
  [    8.979858] i2c_omap i2c_omap.3: bus 3 rev4.0 at 100 kHz
+
  [   0.168388] omap_i2c 4819c000.i2c: unable to select pin group
  [   10.323608] input: twl4030_pwrbutton as /devices/platform/i2c_omap.1/i2c-1/1-0049/twl4030_pwrbutton/input/input1
+
  [   0.418600] i2c /dev entries driver
  [   10.334381] i2c /dev entries driver
 
  
Here we see three buses, each running at a different speed. Bus 2 is brought out to the [[EBC_Exercise_02_Flashing_an_LED#Reading_a_gpio_pin_with_an_Oscilloscope | Expansion Header]]. These signals are 1.8V and the TC74 runs on 2.7 to 5.5VFor now I'm going to use the [[BeagleBoard Trainer]] since it brings the voltages up to 3.3V.  
+
Here we see two buses, one running at 400 kHz and the other at 100 kHz. Table 11 from the SRM shows buses 1 and 2 are brought out to the P9 Expansion Header, however what the table starts numbering with 1 and the software starts with 0, so these are really buses 0 and 1We'll use 1 (called 2 in the table).
  
I²C is a two-wire bus. The two wires are
+
You can see what's on the i2c buses with
# Serial Clock (SCLK on the data sheet, SCL on the Beagle), is an input to the TC74 and is used to clock data into and out of the TC74.
+
beagle$ '''i2cdetect -y -r 0'''
# Serial Data (SDA on both), is bidirection and carries the data to and from the TC74.
+
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 +
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
 +
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
20: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
 +
30: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
 +
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
70: UU -- -- -- -- -- -- --
 +
beagle$ '''i2cdetect -y -r 1'''
 +
      0  1  2  3  4  5  6  7  8  9  a b  c  d  e  f
 +
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
 +
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- 4f
 +
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
 +
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 +
70: 70 -- -- -- -- -- -- --  
 +
I have something at addresses 0x48, 0x4f and 0x70 on bus 1.
  
The only other two pins on the TC74 that you need to use are the Power Supply (Vdd) and Ground.
+
[[File:HeaderP9.jpg|.jpg|800px]]
  
Wire up the TC74 to the Beagle by attaching the Vdd to the 3.3V pad on the Trainer, the GND to a GND on the Trainer and SDA to SDA and SCLK to SCL. '''You will also need to attach two pull-up resistors'''.  Get two 4.7KΩ resistors. Attach one between SDA and Vdd.  Attach the other between SCL and Vdd.
+
These signals are 3.3V and the TMP101 runs on 2.7 to 5.5V so we are in luck.
  
Your TC74 should be labeled with '''TC74a''#''''' where the '''#''' is a digit. This digit tells the address of the device.  If you have another TC74 with a different address, you can wire it in parallel with the first.  That is, attach SDA to SDA and SCL to SCL, etc.  No need for additional pull up resistors.
+
I²C is a two-wire bus. The two wires are
 
+
# Serial Clock (SCL), is an input to the TMP101 and is used to clock data into and out of the TMP101.
=== bone ===
+
# Serial Data (SDA), is bidirectional and carries the data to and from the TMP101.
The DM3730 on the BeagleBoard-xM has four I²C controllers (Section 17 of the [http://www.ti.com/product/dm3730#technicaldocuments TRM]). You can see which ones are configured at boot time by running the following on the Beagle:
 
 
 
beagle$ '''dmesg | grep i2c'''
 
dmesg | grep i2c
 
[    0.102508]  omap_i2c.1: alias fck already exists
 
[    0.116668] omap_i2c omap_i2c.1: bus 1 rev2.4.0 at 100 kHz
 
[    0.241516]  omap_i2c.3: alias fck already exists
 
[    0.241790] omap_i2c omap_i2c.3: bus 3 rev2.4.0 at 100 kHz
 
[    0.532775] i2c /dev entries driver
 
 
 
Here we see two buses, each running at a different speed. Bus 3 is brought out to the P9 Expansion Header. These signals are 3.3V and the TC74 runs on 2.7 to 5.5V so we are in luck.
 
  
I²C is a two-wire bus. The two wires are
+
The only other two pins on the TMP101 that you need to use are the Power Supply (Vdd) and Ground, unless you want to use OS/ALERT, in which case you need to add a pull up resistor to Vdd, and then run another wire to a GPIO in order to properly trigger an interrupt.
# Serial Clock (SCLK on the data sheet, SCL on the Beagle), is an input to the TC74 and is used to clock data into and out of the TC74.
 
# Serial Data (SDA on both), is bidirection and carries the data to and from the TC74.
 
  
The only other two pins on the TC74 that you need to use are the Power Supply (Vdd) and Ground.
+
[[File:Bone gpio.JPG|300px]]
 +
[[File:BoneGPIO.png|300px]]
  
Wire up the TC74 to the Beagle by attaching the Vdd to the 3.3V pad on the bone, the GND to a GND on the bone and SDA to SDA and SCLK to SCL.  '''You will also need to attach two pull-up resistors'''.  Get two 4.7KΩ resistors.  Attach one between SDA and Vdd.  Attach the other between SCL and Vdd.
+
Wire up the TMP101 to the Beagle by attaching the Vdd to the 3.3V '''+''' bus, the GND to the '''-''' bus and SDA to SDA (pin 20) and SCL to SCL (pin 19).  '''You will also need to attach two pull-up resistors'''.  Get two 4.7KΩ resistors.  Attach one between SDA and Vdd.  Attach the other between SCL and Vdd.
  
Your TC74 should be labeled with '''TC74a''#''''' where the '''#''' is a digit.  This digit tells the address of the device.  If you have another TC74 with a different address, you can wire it in parallel with the first.  That is, attach SDA to SDA and SCL to SCL, etc.  No need for additional pull up resistors.
+
Your TMP101 should be labeled with '''T101'''.  If you have another TMP101 you can wire it in parallel with the first be sure to wire the '''ADD0''' pin differently.  That is, attach SDA to SDA and SCL to SCL, etc.  No need for additional pull up resistors.
  
 
== The Software ==
 
== The Software ==
 
Do this, to be sure you have all you needed installed:
 
 
beagle$ '''opkg update'''
 
beagle$ '''opkg install i2c-tools'''
 
beagle$ '''opkg install i2c-tools-dev'''
 
 
 
=== From the Shell ===
 
=== From the Shell ===
  
The Beagle brings out I²C bus 2 (bus 3 on the bone) to the Expansion Header. You can see what devices are on the bus by using the [http://www.lm-sensors.org/wiki/man/i2cdetect i2cdetect] command. On your Beagle try:
+
The Beagle brings out I²C bus 1 to the Expansion Header. You can see what devices are on the bus by using the [http://www.lm-sensors.org/wiki/man/i2cdetect i2cdetect] command. On your Beagle try:
  
  beagle$ '''i2cdetect -y -r 2''' (use '''-r 3''' on the bone)
+
  beagle$ '''i2cdetect -y -r 1'''
 
       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 
       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 
  00:          -- -- -- -- -- -- -- -- -- -- -- -- --  
 
  00:          -- -- -- -- -- -- -- -- -- -- -- -- --  
  10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
+
  10: -- -- -- -- -- -- -- -- -- -- -- UU -- -- -- --  
 
  20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
 
  20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
  30: -- -- -- -- -- -- -- -- -- -- -- -- UU -- -- --  
+
  30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
  40: -- -- -- -- -- -- -- -- 48 -- 4a -- -- -- -- --  
+
  40: -- -- -- -- -- -- -- -- 48 48 4a -- -- -- -- --  
  50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
+
  50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- --  
 
  60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
 
  60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  
  70: -- -- -- -- -- -- -- --  
+
  70: -- -- -- -- -- -- -- --   
 
 
What you see is a list of all the devices found on the bus. I've attached two TC74's, a TC74A0 and a TC74A2. Their address are <code>1001 000</code> and <code>1001 010</code> respectively.  Converting to hex you get <code>0x48</code> and <code>0x4a</code>.  You can see the two appear in the ic2detect.
 
  
Each TC74 has two registers.
+
What you see is a list of all the devices found on the bus. I've attached three TMP101's, and wired their '''ADD0''' line differently.  Their address are <code>1001 000</code>, <code>1001 010</code> and <code>1001 010</code> respectively.  Converting to hex you get <code>0x48</code>, <code>0x49</code> and <code>0x4a</code>.  You can see the three appear in the ic2detect.
{| style="color:green; background-color:#ffffcc;" cellpadding="10" cellspacing="0" border="1"
 
!scope="col"| Command
 
!scope="col"| Code
 
!scope="col"| Function
 
|-
 
| RTR
 
| 0x00
 
| Read Temperature (TEMP)
 
|-
 
| RWCR
 
| 0x01
 
| Read/Write Configuration (CONFIG}
 
|}
 
  
Check the TC74 manual for detail on the configuration register.  We're interested in the TEMP register.  You can read it with:
+
Each TMP101 has four registers. Check the TMP101 manual for details.  We're interested in the TEMP register.  You can read it with:
  
  beagle$ '''i2get -y 2 0x48 0'''
+
  beagle$ '''i2cget -y 1 0x48 0'''
0x1b
+
0x1b
  
The '''-y''' says don't ask me, just do it.  '''2''' says use bus 2.  '''0x48''' is the device address and '''0''' is the register number.  The value returned is the temperature in degrees C.   
+
The '''-y''' says don't ask me, just do it.  '''1''' says use bus 1.  '''0x48''' is the device address and '''0''' is the register number.  The value returned is the temperature in degrees C.   
 
# Convert the hex temperature to decimal.  Is the value reasonable?
 
# Convert the hex temperature to decimal.  Is the value reasonable?
 
# Write a script to run ic2get in a loop and watch the temperature.  Hold the device between your fingers.  Does the temp go up?
 
# Write a script to run ic2get in a loop and watch the temperature.  Hold the device between your fingers.  Does the temp go up?
Line 104: Line 88:
 
=== From C ===
 
=== From C ===
  
Another approach to using I²C on the Beagle is from a C program.  You can open <code>/dev/i2c-2</code> and do <code>ioctl</code> calls on it to read and write data.
+
Another approach to using I²C on the Beagle is from a C program.  You can open <code>/dev/i2c-1</code> and do <code>ioctl</code> calls on it to read and write data.
  
 
Pull the exercises
 
Pull the exercises
Line 113: Line 97:
 
Compile and run '''myi2cget.c'''.   
 
Compile and run '''myi2cget.c'''.   
  
  beagle$ '''gcc myi2cget -o myi2cget'''
+
  beagle$ '''gcc myi2cget.c -o myi2cget'''
 
  beagle$ '''./myi2cget'''
 
  beagle$ '''./myi2cget'''
 
  Usage:  ./myi2cget <i2c-bus> <i2c-address> <register>
 
  Usage:  ./myi2cget <i2c-bus> <i2c-address> <register>
  beagle$ '''./myi2cget 2 72 0'''
+
  beagle$ '''./myi2cget 1 72 0'''
 
0x1b (27)
 
0x1b (27)
  
It takes many of the arguments as '''i2cget''', but none of the flags. It's very stripped down version of i2cget.
+
It takes many of the arguments as '''i2cget''', but none of the flags. It's very stripped down version of i2cget. Note that 72 is the decimal representation of 0x48. myi2cget requires the use of decimal numbers, while the "traiditional" i2cget can use either decimal or hex representations.
  
The '''tools''' directory contains the original '''i2cget''' code.  It came from [http://www.lm-sensors.org/wiki/man/i2cget here].
+
The '''tools''' directory under '''/exercises/i2c/ic2-tools-3.1.0''' contains the original '''i2cget''' code.  It came from [http://www.lm-sensors.org/wiki/man/i2cget here].
  
== <span style="color:green">Assignment </span>==
+
== <span style="color:green">Challenge</span>==
  
 
# Look over '''myi2cget'''.
 
# Look over '''myi2cget'''.
Line 134: Line 118:
 
== References ==
 
== References ==
  
# [http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010749 TC74] information.
+
# [http://www.byteparadigm.com/applications/introduction-to-i2c-and-spi-protocols/ Introduction to i2c and SPI]
 +
# [http://www.ti.com/product/tmp101 TMP101] I2C Temperature Sensor information.
 
# I got a lot information from [[Interfacing with I2C Devices]].
 
# I got a lot information from [[Interfacing with I2C Devices]].
 
# [http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=69&Itemid=78 This] appears to have some nice I2C information for the Gumstix.  It should also work for the Beagle.
 
# [http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=69&Itemid=78 This] appears to have some nice I2C information for the Gumstix.  It should also work for the Beagle.

Revision as of 07:12, 14 September 2016

thumb‎ Embedded Linux Class by Mark A. Yoder


3.8 Kernel

This page is for the 3.8 kernel. See EBC Exercise 12 I2C - xM for the 3.2 kernel.

I²C is a "two-wire interface" standard that is used to attach low-speed peripherals to an embedded system. In this exercise we will wire up a couple of I²C temperature sensors (TC74) and learn how to read their values.

The Hardware

bone

The AM3359 on the BeagleBone has three I²C controllers (Section 21 of the TRM). You can see which ones are configured at boot time by running the following on the Beagle:

beagle$ dmesg | grep i2c
[    0.153495] omap_i2c 44e0b000.i2c: bus 0 rev0.11 at 400 kHz
[    0.165269] omap_i2c 44e0b000.i2c: unable to select pin group
[    0.166036] omap_i2c 4819c000.i2c: bus 1 rev0.11 at 100 kHz
[    0.168388] omap_i2c 4819c000.i2c: unable to select pin group
[    0.418600] i2c /dev entries driver

Here we see two buses, one running at 400 kHz and the other at 100 kHz. Table 11 from the SRM shows buses 1 and 2 are brought out to the P9 Expansion Header, however what the table starts numbering with 1 and the software starts with 0, so these are really buses 0 and 1. We'll use 1 (called 2 in the table).

You can see what's on the i2c buses with

beagle$ i2cdetect -y -r 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: UU -- -- -- -- -- -- -- 
beagle$ i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- 4f 
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: 70 -- -- -- -- -- -- -- 

I have something at addresses 0x48, 0x4f and 0x70 on bus 1.

.jpg

These signals are 3.3V and the TMP101 runs on 2.7 to 5.5V so we are in luck.

I²C is a two-wire bus. The two wires are

  1. Serial Clock (SCL), is an input to the TMP101 and is used to clock data into and out of the TMP101.
  2. Serial Data (SDA), is bidirectional and carries the data to and from the TMP101.

The only other two pins on the TMP101 that you need to use are the Power Supply (Vdd) and Ground, unless you want to use OS/ALERT, in which case you need to add a pull up resistor to Vdd, and then run another wire to a GPIO in order to properly trigger an interrupt.

Bone gpio.JPG BoneGPIO.png

Wire up the TMP101 to the Beagle by attaching the Vdd to the 3.3V + bus, the GND to the - bus and SDA to SDA (pin 20) and SCL to SCL (pin 19). You will also need to attach two pull-up resistors. Get two 4.7KΩ resistors. Attach one between SDA and Vdd. Attach the other between SCL and Vdd.

Your TMP101 should be labeled with T101. If you have another TMP101 you can wire it in parallel with the first be sure to wire the ADD0 pin differently. That is, attach SDA to SDA and SCL to SCL, etc. No need for additional pull up resistors.

The Software

From the Shell

The Beagle brings out I²C bus 1 to the Expansion Header. You can see what devices are on the bus by using the i2cdetect command. On your Beagle try:

beagle$ i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- 48 48 4a -- -- -- -- -- 
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

What you see is a list of all the devices found on the bus. I've attached three TMP101's, and wired their ADD0 line differently. Their address are 1001 000, 1001 010 and 1001 010 respectively. Converting to hex you get 0x48, 0x49 and 0x4a. You can see the three appear in the ic2detect.

Each TMP101 has four registers. Check the TMP101 manual for details. We're interested in the TEMP register. You can read it with:

beagle$ i2cget -y 1 0x48 0
0x1b

The -y says don't ask me, just do it. 1 says use bus 1. 0x48 is the device address and 0 is the register number. The value returned is the temperature in degrees C.

  1. Convert the hex temperature to decimal. Is the value reasonable?
  2. Write a script to run ic2get in a loop and watch the temperature. Hold the device between your fingers. Does the temp go up?

From C

Another approach to using I²C on the Beagle is from a C program. You can open /dev/i2c-1 and do ioctl calls on it to read and write data.

Pull the exercises

beagle$ cd exercises
beagle$ git pull
beagle$ cd i2c

Compile and run myi2cget.c.

beagle$ gcc myi2cget.c -o myi2cget
beagle$ ./myi2cget
Usage:  ./myi2cget <i2c-bus> <i2c-address> <register>
beagle$ ./myi2cget 1 72 0

0x1b (27)

It takes many of the arguments as i2cget, but none of the flags. It's very stripped down version of i2cget. Note that 72 is the decimal representation of 0x48. myi2cget requires the use of decimal numbers, while the "traiditional" i2cget can use either decimal or hex representations.

The tools directory under /exercises/i2c/ic2-tools-3.1.0 contains the original i2cget code. It came from here.

Challenge

  1. Look over myi2cget.
    1. Find the open which opens the device.
    2. Find the ioctl call that sets the address. What other values can be used instead of I2C_SLAVE? Hint: Look in the include files for the definition of I2C_SLAVE.
    3. Find the ioctl call reads the register. Hint: There are a couple of wrappers hiding it. Find where i2c_smbus_read_byte_data is defined and then keep going until you find ioctl. I2C_SLAVE is used by the previous ioctl to set the slave address. What's used at the 2nd argument to ioctl to read a byte?
  2. Challenge 1: Write a C program that will print the current temperature every time the USER button is pressed. Print the temp in F.
  3. Challenge 2: Modify your program to update the temperature every second if the USER button isn't pressed.

References

  1. Introduction to i2c and SPI
  2. TMP101 I2C Temperature Sensor information.
  3. I got a lot information from Interfacing with I2C Devices.
  4. This appears to have some nice I2C information for the Gumstix. It should also work for the Beagle.
  5. i2c via Python




thumb‎ Embedded Linux Class by Mark A. Yoder