How to use I²C over USB

Several routers and embedded devices with OpenWRT-support are equipped with one or more USB ports. In order not to risk your warranty by opening your device and soldering an I²C bus to the GPIOs, you can use an USB-I²C adapter to connect to your I²C-devices (e.g. temperature sensors, RTCs, AD-converters, GPIO-expanders, LCD-Drivers). One of those adapters is called i2c-tiny-usb, developed by Till Harbaum. Biggest advantage is the low price (though not as cheap as the GPIO mod) and the support in the Linux kernel (thus making it possible to connect it to your computer running a recent Linux distribution and test it). Though you need some basic soldering skills, and at the moment you need to build OpenWRT from source.

Note: This module is now in trunk, called kmod-i2c-tiny-usb. You can use a snapshot and install this kernel module with opkg.

Follow the build instructions until you reach the topic building images. At that point you have to edit you kernel configuration:

make kernel_menuconfig

Make sure the following items are selected:

  • Device Drivers > I2C support > I2C device interface <*> (to get access through /dev/i2c-X)
  • Device Drivers > I2C support > I2C Hardware Bus support > Tiny-USB adapter <*>

Continue with the build instructions.

Since the module is compiled into the kernel, the I2C-Tiny-USB adapter can be plugged in. The successful registration can be tested:

dmesg | tail

usb 1-3.3: new low speed USB device using ehci_hcd and address 5
usb 1-3.3: New USB device found, idVendor=0403, idProduct=c631
usb 1-3.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-3.3: Product: i2c-tiny-usb
usb 1-3.3: Manufacturer: Till Harbaum
usb 1-3.3: configuration #1 chosen from 1 choice
i2c-tiny-usb 1-3.3:1.0: version 1.05 found at bus 001 address 005
i2c-adapter i2c-0: connected i2c-tiny-usb device
usbcore: registered new interface driver i2c-tiny-usb

The same results are achieved by loading the kernel module by insmod. The current trunk module within kmod-i2c-tiny-usb package works just fine (requiring also kmod-i2c-core package).

First install the i2c-tools package. This will provide all necessary tools for you to work with the bus.

As you already can see in the dmesg listing, the i2c-0 device was created. The device node is visible under /dev/i2c-0. First of all, check the device is also visible for i2c tools. Running

i2cdetect -l

should print something like

i2c-0 i2c i2c-tiny-usb at bus 001 device 004 I2C adapter

This is a good sign. We can show the implemented functions by running

i2cdetect -F 0

and it will print something like

Functionalities implemented by /dev/i2c-0: I2C yes SMBus Quick Command yes SMBus Send Byte yes SMBus Receive Byte yes SMBus Write Byte yes SMBus Read Byte yes SMBus Write Word yes SMBus Read Word yes SMBus Process Call yes SMBus Block Write yes SMBus Block Read no SMBus Block Process Call no SMBus PEC no I2C Block Write yes I2C Block Read yes

Now, we can search for devices, connected to the bus:

i2cdetect 0

will scan the bus and show available devices, similar to this:

WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-0. I will probe address range 0x03-0x77. Continue? [Y/n] 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

Should you be anoyed by the Y/n question, you can use the -y switch to avoid it ;)

As you can see, I have an i2c device accessible on address 0x20 on the bus number 0.

My device is actually a MCP23017 - 16 port GPIO expander. First I have to set the directions of the inputs and outputs - as this device possess 2 ports (A and B), I have to set the direction for both of them - setting a bit to 0 will cause it to switch to output, setting the bit to 1 will cause to switch to input. The address to set the direction for port A is 0x00, for port B it's 0x01. Therefore to set the first 8 channels (port A) to output, I'd run

i2cset -y 0 0x20 0x00 0

That means use the device at the address 0x20 on the bus /dev/i2c-0, set its address 0x00 to zero value. The -y switch is there just to avoid the Y/n question. Also, to set the port B to input, I'd issue following command:

i2cset -y 0 0x20 0x01 0xff

This will set all the pins for port B to input. To set the actual value for port A, the address 0x12 is utilized. Similar, for port B, the address is 0x13. Therefore to set first bit to logical 1, I'd issue (assuming I already set the port's bit for output):

i2cset -y 0 0x20 0x12 1

Should you have some LED connected to the port, it will shine bright now. To turn it off, simply issue the following:

i2cset -y 0 0x20 0x12 0

Should some input be set on the port B, one can read its value by using following command:

i2cget -y 0 0x20 0x13

The result will be something like 0x00 (corresponding to the logical values presented to the actual pins).

Using this approach, you can enrich the OpenWRT device with multiple I/O channels.

I've already tested MCP23017, MCP23008, some i2c temperature sensors and EEPROM - all working just fine.

This I²C bus operates at 5V. Make sure not to connect I²C devices incompatible with this voltage level!

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2021/10/15 08:26
  • by bobafetthotmail