Interfacing with I2C Devices

Revision as of 12:16, 27 April 2010 by Zeta Syanthis (talk | contribs) (Basic Communication with the AD7991 ADC)
Jump to: navigation, search

This page is meant to provide some basic information about how to interface with I²C devices through the /dev/i2c interface. The I²C bus is commonly used to connect relatively low-speed sensors and other peripherals to equipment varying in complexity from a simple microcontroller to a full-on motherboard. I²C is extremely popular due to its ease-of-use and ability to control multiple peripherals while utilizing only two pins on the host controller. Although I2C has a variety of modes, this page will deal purely with communication between a Linux-based master and a slave peripheral for the time being.


Note: Examples shown on this page were developed based on a Texas Instruments BeagleBoard and some changes will be required depending on the system being utilized.

Beagleboard I2C2 Enable

The TI BeagleBoard has 3 I²C buses available, which control a variety of on-board peripherals, including the DVI display driver and power sequencing. As bus 2 is by far the easiest to connect to due to its presence on the 0.1" spaced expansion header, it is assumed the user will be controlling that bus for the purposes of this example. However, by default bus 2 is disabled due to a lack of pull-up resistors on the board, so external pull-ups to 1.8V must be added and the kernel recompiled to enable i2c2.

See BeagleBoard#Linux_kernel and BeagleBoardLinuxKernel for details on how to recompile your Linux kernel. To enable i2c2 specifically during that process, enable the setting during the "make menuconfig" step.

I2C2 is pinned out as pins 23 (SDA) and 24 (SCL) on the expansion header.

Basic Communication with the AD7991 ADC

The AD7991 has four inputs as well as the ability to use one of the input pins as a reference voltage the other inputs are measured against. If that input is not used as the reference voltage, it uses the supply voltage as the reference voltage. Because the AD7991 is 12-bit device, its outputs ranges linearly from 0 to 4096 as the voltage ranges from 0 to the reference voltage.

sensors_ADC_init(void) {
       int file;
       char filename[40];
       const gchar *buffer;
       int addr = 0b00101001;          // The I2C address of the ADC

       if ((file = open(filename,O_RDWR)) < 0) {
               printf("Failed to open the bus.");
               /* ERROR HANDLING; you can check errno to see what went wrong */

       if (ioctl(file,I2C_SLAVE,addr) < 0) {
               printf("Failed to acquire bus access and/or talk to slave.\n");
               /* ERROR HANDLING; you can check errno to see what went wrong */

       unsigned char reg = 0x10; /* Device register to access */
       char buf[10] = {0};
       float data;
       char channel;

       // Using I2C Write, equivalent of i2c_smbus_write_word_data(file,register,0x6543)
       buf[0] = reg;
       for(int i = 0; i<4; i++) {
               // Using I2C Read
               if (read(file,buf,2) != 2) {
                       /* ERROR HANDLING: i2c transaction failed */
                       printf("Failed to read from the i2c bus.\n");
                       buffer = g_strerror(errno);
               } else {
                       data = (float)((buf[0] & 0b00001111)<<8)+buf[1];
                       data = data/4096*5;
                       channel = ((buf[0] & 0b00110000)>>4);
                       printf("Channel %02d Data:  %04f\n",channel,data);

Tested Devices

External Links