Skip to content
Frank Bauernöppel edited this page Jan 10, 2019 · 18 revisions

Note: the Raspi chip has hardware bugs related to clock stretching and repeated start conditions. If you need those features, use a I2C implementation in software ("bit-banging"):

Sparkfun has a nice tutorial on I2C: https://learn.sparkfun.com/tutorials/i2c

You also might want to try the sense hat which contains a number of interesting i2c peripherals.

configuration

Check that local.conf contained a line

ENABLE_I2C = "1"

when the image was bitbaked. This ensures that the following settings are present. Otherwise you have to change the manually (which is okay unless you go to production)

On the running RasPi: check/enable I2C in the config.txt file (reboot needed after change)

dtparam=i2c_arm=on         
dtparam=i2c_arm_baudrate=100000

dmesg | grep -i i2c should show a line like

[    1.998278] bcm2708_i2c 3f804000.i2c: BSC1 Controller at 0x3f804000 (irq 83) (baudrate 100000)

lsmod should show that kernel module i2c_bcm2708 is loaded.

testing I2C from the command line

To use the i2c-tools, load kernel module i2c-dev:

modprobe i2c-dev

And check for i2c devices on i2c bus 1, the i2c bus available on the expansion header:

root@raspberrypi3:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

No i2c devices are connected in this example, but you may see i2c probing by using a scope.

Now, a InvenSense 9-axis sensor MPU-9250 was connected, using its default address 0x68:

root@raspberrypi3:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Dump the content of all registers:

root@raspberrypi3:~# i2cdump -y 1 0x68 b
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: bc c7 df 23 9c 02 f4 e0 07 e2 08 01 00 60 5b 67    ???#????????.`[g
10: d8 d6 d0 00 00 00 00 00 00 00 00 00 00 00 00 00    ???.............
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
30: 00 00 00 00 00 00 00 00 00 00 01 ff bc 05 00 c2    ..........?.??.?
40: 50 07 b0 fe ae 00 a7 00 75 00 00 00 00 00 00 00    P????.?.u.......
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 18 71    ...........?..?q
70: 00 00 00 00 00 71 00 e6 20 00 e6 d8 00 23 b2 00    .....q.? .??.#?.

using I2C from a C program

InvenSense MPU-9250

  • 9-axis sensor: 3-axis gyroscope, 3-axis accelerometer and 3-axis compass
  • on-chip µC capable of processing sensor fusion algorithms

Available on a convenient SparkFun IMU Breakout - MPU-9250 board: https://learn.sparkfun.com/tutorials/mpu-9250-hookup-guide

By default, the chip uses I2C address 0x68. After reset, register 0x75 ("WHO_AM_I") contains a unique value: 0x71. lets check that out: connect the breakout board to the RasPi.

edit a new file

root@raspberrypi3:~# vi mpu9250.c
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>

int main()
{

  int file = open( "/dev/i2c-1", O_RDWR);
  if (file < 0) perror("open"); //TODO: error handling

  unsigned char inbuf[1];
  unsigned char outbuf[1];
  struct i2c_rdwr_ioctl_data packets;
  struct i2c_msg msg[2];

  // prepare the first i2c request (a write)
  msg[0].addr  = 0x68; // device address
  msg[0].flags = 0;    // type of request: 0=write
  msg[0].len   = sizeof(outbuf); // number of bytes to write
  msg[0].buf   = outbuf; // pointer to the first data byte
  outbuf[0]    = 0x75; // first data byte: register to read

  msg[1].addr  = 0x68; // device address
  msg[1].flags = I2C_M_RD | I2C_M_NOSTART; // read request without an intermediate start condition
  msg[1].len   = sizeof(inbuf);  // number of bytes to read
  msg[1].buf   = inbuf; // // pointer to the first byte to read

  // send both requests to the device
  packets.msgs      = msg;
  packets.nmsgs     = 2;
  if(ioctl(file, I2C_RDWR, &packets) < 0) perror("ioctl"); //TODO: error handling

  close(file);

  printf("reg[0x%02x]=0x%02x\n", outbuf[0], inbuf[0] );

  return 0;
}

compile with

root@raspberrypi3:~# gcc -o mpu9250 mpu9250.c

and run it

root@raspberrypi3:~# ./mpu9250
reg[0x75]=0x71

DS1307 real-time-clock

see http://www.netzmafia.de/skripten/hardware/RasPi/Projekt-RTC/

using I2C from a kernel module

see Method 2: Instantiate the devices explicitly in https://www.kernel.org/doc/Documentation/i2c/instantiating-devices

minimal example

https://gist.github.com/jnewc/f8b668c41d7d4a68f6e46f46e8c559c2

PCA9685 LED (PWM) driver expander

https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/pwm/pwm-pca9685.c

DS1307 real-time-clock

driver: https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/rtc/rtc-ds1307.c