Słomkowski's technical musings

Playing with software, hardware and touching the sky with a paraglider.

Usual and unusual ways to connect I²C device to the PC computer


In this article, I collected some methods you can use to connect an I2C device to a computer. For the uninitiated, I²C is a low-speed serial bus commonly used in communication with small devices, such as temperature sensors, accelerometers, gyroscopes, EEPROMs, and many more. The most common clock speed is 100 kHz, resulting in a transfer rate of approximately 10 kB/s in half-duplex. Usually, there’s no need to transfer more than just a couple of bytes, so the low speed is not a problem.

I²C is the basis for SMBus, which is often used in PC motherboards for internal communication, such as with temperature sensors and fan controllers.

I²C subsystem under Linux

To understand the basics of I²C under Linux, the best resource to start with is the Kernel documentation, which is surprisingly easy to digest. You’ll also need the i2c-tools package, which contains the i2cdetect tool that scans the I²C bus for devices.

Load the kernel module first:

modprobe i2c-dev 

On my main machine, the output of i2cdetect -l shows the following:

i2c-3   i2c         AMDGPU DM i2c hw bus 0              I2C adapter
i2c-10  smbus       SMBus PIIX4 adapter port 0 at 0b00  SMBus adapter
i2c-1   i2c         AMDGPU SMU 0                        I2C adapter
i2c-8   i2c         AMDGPU DM aux hw bus 1              I2C adapter
i2c-6   i2c         AMDGPU DM i2c hw bus 3              I2C adapter
i2c-13  i2c         i2c-tiny-usb at bus 001 device 026  I2C adapter
i2c-4   i2c         AMDGPU DM i2c hw bus 1              I2C adapter
i2c-11  smbus       SMBus PIIX4 adapter port 2 at 0b00  SMBus adapter
i2c-2   i2c         AMDGPU SMU 1                        I2C adapter
i2c-0   i2c         Synopsys DesignWare I2C adapter     I2C adapter
i2c-9   i2c         AMDGPU DM aux hw bus 2              I2C adapter
i2c-7   i2c         AMDGPU DM aux hw bus 0              I2C adapter
i2c-5   i2c         AMDGPU DM i2c hw bus 2              I2C adapter
i2c-12  smbus       SMBus PIIX4 adapter port 1 at 0b20  SMBus adapter

Testing setup

To verify that the given I²C setup is practical, I used a Chinese GY-521 module, which is an accelerometer/gyroscope/thermometer based on the chip MPU6050. The device shows up under the address 0x68 by default. The Python script below reads the temperature from the chip and prints it:

import struct
import sys
import time
from timeit import default_timer

from smbus2 import SMBus

bus = SMBus(int(sys.argv[1]))
dev_address = 0x68

bus.write_byte_data(dev_address, 0x19, 7)
bus.write_byte_data(dev_address, 0x6B, 1)
bus.write_byte_data(dev_address, 0x1A, 0)
time.sleep(0.1)

while True:
    timer_start = default_timer()
    buffer = bytes(bus.read_i2c_block_data(dev_address, 65, 2))
    timer_end = default_timer()

    raw_temp = struct.unpack('>h', buffer)[0]
    temperature = (raw_temp / 340.0) + 36.53

    print("Temperature: %.1f\xb0C, time: %.1f ms" % (temperature, 1000.0 * (timer_end - timer_start)))

    time.sleep(0.1)

Calling it with python3 script.py {bus identifier} gives the following output:

Temperature: 25.0°C, time: 23.9 ms
Temperature: 25.1°C, time: 23.9 ms
Temperature: 25.0°C, time: 23.9 ms
...

External adapters

External adapters usually connect to a USB port.

Programmable modules

The most convenient method, in my opinion, is I2C-Tiny-USB — firmware for various development boards. I use it with a Digispark board, which fits directly into a USB port. The Digispark needs to be flashed with firmware, which is described on GitHub too.

Commercial USB-I²C converters

There are plenty of proprietary converters, though I haven’t used any of them yet. One of the most popular boards is based on MCP2221:

USB-I²C converter based on MCP2221.

Bus Pirate

Bus Pirate is a universal adapter that can be used for many protocols, including I²C. It’s connected via USB and exposes a virtual serial port. You can talk to I²C devices using its custom textual protocol. There is also an out-of-tree kernel driver for it, though I haven’t tested it.

Various parallel port adapters

Supported by the i2c-parport kernel module, as described in the Kernel documentation. I haven’t tested any of them.

Video interfaces: HDMI, DVI, VGA

Video interfaces: VGA, DVI and HDMI all have +5 V SDA and SCL lines for DDC communication. They are used to read the monitor’s EDID data, which contains information about the monitor’s capabilities, such as supported resolution, refresh rate, etc. DisplayPort, however, uses different signaling and does not have I²C lines.

DVI pinout.

SDA is usually marked as DDC Data, and SCL as DDC Clock. Under Linux, graphics card drivers expose these lines to the I²C subsystem. I checked the following configurations:

Some time ago, for my old computer, I made a DVI cable with exposed I²C lines for quick testing:

Directly on the motherboard

You may sometimes find the I²C lines directly on the motherboard. Look for chips in larger sockets, such as SOIC or DIP. Usually, these are EEPROMs, fan controllers, or temperature sensors. Sometimes, there are even specialized headers placed on the motherboard.

For example, I found a fan controller chip ADT7490 on my old workstation, ThinkStation C20. It operates on 3.3 V. I found some soldering pads large enough to solder the wires to. The chip is visible in the photo below:

There were many other devices on bus 0, but the GY-521 was indeed working:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- 08 -- -- -- 0c -- -- -- 
10: -- -- -- -- -- -- -- -- 18 -- 1a -- 1c -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- 2c -- 2e -- 
30: 30 -- 32 -- 34 -- -- -- -- -- -- -- -- -- 3e -- 
40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- 52 -- 54 -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 69 -- -- -- -- 6e -- 
70: -- -- -- -- -- -- -- --                         

Conclusion

If you know of any other methods, please let me know.