Mar 232014
 

The hardware I’m using here is a Raspberry Pi Type A, described in detail here. The aim in this post is to connect to the I2C interface.

1. Configuring the Raspberry Pi to use I2C

First things first, set up the Raspberry Pi to use I2C. Here’s a good guide: Configuring Your Pi for I2C. (And another.)

1. Start by installing some extra packages (developer page here):

sudo apt-get install python-smbus
sudo apt-get install i2c-tools
sudo apt-get install libi2c-dev

2. Check the blacklist:

~ $ cat /etc/modprobe.d/raspi-blacklist.conf 
# blacklist spi and i2c by default (many users don't need them)

blacklist spi-bcm2708
blacklist i2c-bcm2708

and disable those two last lines (edit with nano):

~ $ cat /etc/modprobe.d/raspi-blacklist.conf 
# blacklist spi and i2c by default (many users don't need them)

#blacklist spi-bcm2708
#blacklist i2c-bcm2708

3. Check the list of modules:

~ $ cat /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

snd-bcm2835

and add two more modules to the list there:

~ $ cat /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

snd-bcm2835
i2c-dev 
i2c-bcm2708

4. (Optional) To allow non-administrator users to use I2C, you can use this handy trick (thanks here to Raspberry Pi I2C udev rules).

Create a file /etc/udev/rules.d/90-i2c.rules and add the line:

KERNEL=="i2c-[0-7]",MODE="0666"

5. (Optional) To adjust the clock speed of the I2C (the default is 100kHz but many I2C devices can operates at 400kHz), then here’s another handy trick (thanks here to Setting the Raspberry Pi I2C ports to operate at 400kHz). Create a file /etc/modprobe.d/i2c.conf and add the line:

options i2c_bcm2708 baudrate=400000

6. Reboot.

7. One final step if you skipped Step 4 and if you don’t want to use I2C as an administrator – give everyone read-write access to the devices:

~ $ sudo chmod o+rw /dev/i2c-*

It will be necessary to do this after every reboot.

2. Testing the I2C Connection

Linux has I2C support in the kernel (see kernel documentation for details of the interface), and here’s a nice tutorial explaining the simplest way to use it.

I’m going to cheat and use a test program – check_I2C.c by Vincenzo Villa:

// Rapsberry Pi: I2C in C - Versione 0.61 - Luglio 2013
// Copyright (c) 2013, Vincenzo Villa (http://www.vincenzov.net)
// Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported.
// Creative Commons | Attribution-Share Alike 3.0 Unported
// http://www.vincenzov.net/tutorial/elettronica-di-base/RaspberryPi/i2c-c.htm

// Compile:  gcc check_I2C.c -std=c99 -o check_I2C
// Run as user with R&W right on /dev/i2c-* (NOT ROOT!)
// vv@vvrpi ~ $ ./check_I2C 
// Check whether some i2c functionality are present

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>

#define I2C_ADDR 0x4B				// Device adress

#define LM92_TEMP 0                             // Temperature register (see data sheet)
#define LM92_RES 0.0625                         // Resolution (see data sheet)

static const char *device = "/dev/i2c-1";	// I2C bus

static void exit_on_error (const char *s)	// Exit and print error code
{ 	perror(s);
  	abort();
} 

int main(int argc, char *argv[])
{
	int fd;
	
	int32_t functionality;
	uint8_t  buffer[2];
        int16_t  data;
        double   temperature;
        
        printf("Rapsberry Pi: I2C in C - Versione 0.61 - Luglio 2013\n");
        printf("Copyright (c) 2013, Vincenzo Villa (http://www.vincenzov.net)\n");
        printf("Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported.\n");
        printf("Creative Commons | Attribution-Share Alike 3.0 Unported\n");
        printf("http://www.vincenzov.net/tutorial/elettronica-di-base/RaspberryPi/i2c-c.htm\n\n");                                       

       	// Open I2C device
       	if ((fd = open(device, O_RDWR)) < 0) exit_on_error ("Can't open I2C device");

        if (ioctl(fd, I2C_FUNCS, &functionality) < 0)  exit_on_error ("Can't use I2C_FUNCS ioctl");
        
        printf("Raw data from driver (I2C_FUNCS): 0x%.8X\n", functionality);        
        
        printf("\nI2C_FUNC_I2C ");
        if ( I2C_FUNC_I2C & functionality) printf("\t\t\t\tOK");      

        printf("\nI2C_FUNC_10BIT_ADDR ");
        if ( I2C_FUNC_10BIT_ADDR & functionality)  printf("\t\t\tOK");
                                                                                                        
        printf("\nI2C_FUNC_PROTOCOL_MANGLING ");                 
        if ( I2C_FUNC_PROTOCOL_MANGLING & functionality) printf("\tOK");                   

//        printf("\nI2C_FUNC_NOSTART ");
//        if ( I2C_FUNC_NOSTART & functionality) printf("\tOK");
                
        printf("\nI2C_FUNC_SMBUS_QUICK ");
        if ( I2C_FUNC_SMBUS_QUICK & functionality) printf("\t\t\tOK");
                
        printf("\nI2C_FUNC_SMBUS_READ_BYTE ");
        if ( I2C_FUNC_SMBUS_READ_BYTE & functionality) printf("\t\tOK");
                
        printf("\nI2C_FUNC_SMBUS_WRITE_BYTE ");
        if ( I2C_FUNC_SMBUS_WRITE_BYTE & functionality) printf("\t\tOK");
                                                               
        printf("\nI2C_FUNC_SMBUS_READ_BYTE_DATA ");
        if ( I2C_FUNC_SMBUS_READ_BYTE_DATA & functionality) printf("\t\tOK");
                
        printf("\nI2C_FUNC_SMBUS_WRITE_BYTE_DATA ");
        if ( I2C_FUNC_SMBUS_WRITE_BYTE_DATA & functionality) printf("\t\tOK");
                
        printf("\nI2C_FUNC_SMBUS_READ_WORD_DATA ");
        if ( I2C_FUNC_SMBUS_READ_WORD_DATA & functionality) printf("\t\tOK");

        printf("\nI2C_FUNC_SMBUS_WRITE_WORD_DATA ");
        if ( I2C_FUNC_SMBUS_WRITE_WORD_DATA & functionality) printf("\t\tOK");

        printf("\nI2C_FUNC_SMBUS_PROC_CALL ");  
        if ( I2C_FUNC_SMBUS_PROC_CALL & functionality) printf("\t\tOK"); 
                
        printf("\nI2C_FUNC_SMBUS_READ_BLOCK_DATA ");  
        if ( I2C_FUNC_SMBUS_READ_BLOCK_DATA & functionality) printf("\t\tOK");                                                                                                                 

        printf("\nI2C_FUNC_SMBUS_WRITE_BLOCK_DATA ");  
        if ( I2C_FUNC_SMBUS_WRITE_BLOCK_DATA & functionality) printf("\tOK");                                                
 
        printf("\nI2C_FUNC_SMBUS_READ_I2C_BLOCK ");  
        if ( I2C_FUNC_SMBUS_READ_I2C_BLOCK & functionality) printf("\t\tOK"); 
 
        printf("\nI2C_FUNC_SMBUS_WRITE_I2C_BLOCK ");  
        if ( I2C_FUNC_SMBUS_WRITE_I2C_BLOCK & functionality) printf("\t\tOK");         
        
        printf("\n\n");

        if (ioctl( fd, I2C_PEC, 1) < 0) printf("Failed to enable PEC\n");
        else printf("PEC enabled\n\n"); 

        data = i2c_smbus_read_byte_data ( fd , 0x0a );

        close(fd);

	return (0);
}

Compile & run:

~ $ gcc check_I2C.c -std=c99 -o check_I2C
~ $ ./check_I2C 
Rapsberry Pi: I2C in C - Versione 0.61 - Luglio 2013
Copyright (c) 2013, Vincenzo Villa (http://www.vincenzov.net)
Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported.
Creative Commons | Attribution-Share Alike 3.0 Unported
http://www.vincenzov.net/tutorial/elettronica-di-base/RaspberryPi/i2c-c.htm

Raw data from driver (I2C_FUNCS): 0x0EFF0009

I2C_FUNC_I2C 				OK
I2C_FUNC_10BIT_ADDR 
I2C_FUNC_PROTOCOL_MANGLING 
I2C_FUNC_SMBUS_QUICK 			OK
I2C_FUNC_SMBUS_READ_BYTE 		OK
I2C_FUNC_SMBUS_WRITE_BYTE 		OK
I2C_FUNC_SMBUS_READ_BYTE_DATA 		OK
I2C_FUNC_SMBUS_WRITE_BYTE_DATA 		OK
I2C_FUNC_SMBUS_READ_WORD_DATA 		OK
I2C_FUNC_SMBUS_WRITE_WORD_DATA 		OK
I2C_FUNC_SMBUS_PROC_CALL 		OK
I2C_FUNC_SMBUS_READ_BLOCK_DATA 
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 	OK
I2C_FUNC_SMBUS_READ_I2C_BLOCK 		OK
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 		OK

PEC enabled

All I need now are some I2C sensors to play with…