Originally designed for controlling consumer electronics, the I2C bus is easily adapted to working with Linux to control a variety of devices using the I2C bus standard.
The I2C bus is a two-wire serial bus for connecting a wide range of ICs to a computer or micro-controller. It was originally developed by Phillips in the early ’80s, but is now supported by a wide range of companies.
I first stumbled over this bus when I still had my old Commodore C64, while looking over some hardware books. I never built an adapter, so I forgot about it, until I started to hack around in the Linux kernel. Then I thought building an adapter and writing a corresponding kernel module to access the bus a character device would be a promising goal.
Description of the Bus
The I2C bus consists of two lines, one for the data and one for the clock. The chips connect to the bus via open collector input/output stages, which cause the lines to be high when idle.
Transmission is initiated via a start condition, after which an address byte is transmitted. The byte consists of a 7-bit device address and a direction bit. If a slave recognizes its own address, it acknowledges the transmission. Then, any number of bytes can be transmitted to the slave, until the last byte is not acknowledged. Transmission ends with a stop condition.
The data is transferred synchronously with the high state of the clock line, when the state of the data signal has to be stable. This rule is broken only for the generation of the start and stop conditions, which encapsulate a transmission. Transfer speed is not fixed, but specifications guarantee speeds up to 100 kHz. If a device cannot cope with the transmission speed it may hold down the clock line, and thus slow the process.
When considering the data transmission rate, we can thus only assume the best case, as there are no lower limits. With 100 kHz (i.e., 100 kbps), we need 2 bits for start and stop, 9 bits for the address (including the acknowledge bit), and 18 bits for the data if we want to read two bytes. All in all, with an inter-transmission gap of an additional bit, we have an effective data acquisition rate of 100 k/30 bps, or 3333 samples per second. Therefore, one can see the I2C bus cannot be used for audio data, or other high-speed applications, but it is still fast enough to easily survey an array of sensor devices and react in under a millisecond.
Also, several extensions exist to the basic specification of the bus. One extension is a fast mode which allows transmission of data at rates up to 400 kHz. Another extension in the address space supports 10-bit wide identifiers. The Access.bus implements a software protocol on top of the I2C-bus hardware in order to communicate with computer peripherals.
From Consumer Electronics to Radio Communications
The chips available for the bus cover a wide range of needs. Originally the bus was designed for computer-controlled TV sets, resulting in a wide range of tuning circuits, colour controllers and video-text controllers.
Nowadays several micro-controller families are also on the market offering direct I2C-bus support, with A/D-D/A converters, power switches, electronic potentiometers and LCD-display drivers. These micro-controllers allow the connection of slower peripherals to the bus.
I2C bus-controlled ICs are also available for telecommunication services ranging from pagers to GSM telephones. Using these services would make it easy to start actions via a pager call to your computer.
Putting the I2C Bus and Linux Together
When I started to experiment with the I2C bus, I had to build an adapter for my PC. The simplest solution to connect them involved a TTL chip and several resistors. This adaptor occupies my second parallel port and has served me well for a long time.
In essence, transmission of data is accomplished by control of the states of the lines. This type of device is also common to many types of commercial products, such as TV-cards with teletext receivers.
More sophisticated solutions involve a dedicated adapter chip, called the PCF 8584. This chip implements most of the needed protocol, and offers some nice extras, like interrupt generation, bus monitoring and a long distance mode.
Originally, I supported only my own adapter, but I am currently implementing drivers for others.
Controlling the bus via Linux is simple. As usual with character devices, you have only to open the device file, set the slave address (via an ioctl call) and read or write data. Depending on the adapter, you can set different options.
If you don’t like C, I have written a little extension to Tcl/Tk which gives direct control over the I2C bus, allowing a comfortable way to visualize acquired information. The extension is also a convenient interface to the bus for debugging.