Personal tools

How to use VisionSOM-6ULL I2C interface in command line and C programs

From SomLabs Wiki

Jump to: navigation, search

How to use VisionSOM-6ULL I2C interface in command line and C programs


Configuring device tree to enable I2C interface

To enable I2C interface you may need to add (or modify) interface definition, your dts file should contain:

&i2c2 {
        clock_frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c2>;
        status = "okay";
};

In iomux section add or modify i2c pin definition:

                pinctrl_i2c2: i2c2grp {
                        fsl,pins = <
                                MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
                                MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
                        >;
                }

Those definitions may need modifications depending on which interface and pins you want to use. You can find more informations on customizing device tree in this tutorial.

In this example there is used VisionSOM-6ULL, VisionCB-STD and PModRTCC. PModRTCC module is connected to Raspberry Pi connector on VisionCB-STD:

VisionSOM-CB-STD RPi connector pin number PModRTCC pin
1 VCC
6 GND
3 SDA
5 SCL

I2C operations

By default i2c devices are controlled by a kernel driver. If your interfaces are enabled and driver is loaded then you should be able to see them in /sys/class/ directory:

root@somlabs:~# ls /sys/class/i2c-adapter
i2c-0  i2c-1

It is also possible to access i2c devices from userspace through the /dev interface. To do that you need to install some packages:

root@somlabs:~# apt install libi2c-dev i2c-tools

Now make i2c-dev module load at system boot, edit /etc/modules file:

root@somlabs:~# nano /etc/modules

At the end of the file add line:

i2c-dev

Press Ctrl+O to save then file and Ctrl+X to exit. Now reboot your system.

Using I2C interface in console

You can list i2c interfaces in /dev:

root@somlabs:~# ls /dev
autofs           loop3               ram13   tty10  tty31  tty52     vcs1

...

i2c-0            pps0                rtc     tty22  tty43  tty7      vhci
i2c-1            ptmx                rtc0    tty23  tty44  tty8      video0

...

loop2            ram12               tty1    tty30  tty51  vcs

At this point you should connect something to your boards I2C interface, after you do it you can try to detect (i2cdetect parameter is I2C interface number):

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

You can see that there are two devices detected, their addresses are 0x57 and 0x6f. In some cases you will see 'UU' instead of address in i2cdetect output, that means that device is used by some driver. In this case there is MCP78410 chip connected to I2C, it is RTC (0x6f) and EEPROM (0x57) in a single chip. The commands below will write EEPROM at address 0x00 and 0x01 and read back written values:

root@somlabs:~# i2cset -y 1 0x57 0x00 0x11
root@somlabs:~# i2cget -y 1 0x57 0x00
0x11
root@somlabs:~# i2cset -y 1 0x57 0x01 0x22
root@somlabs:~# i2cget -y 1 0x57 0x01
0x22

Using I2C interface in C program

Example below reads MCP78410 EEPROM at 0x00 address, increments read value, writes it back, all this happens in a loop.

#include <stdio.h>
#include <linux/i2c-dev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

void main() {
        char data;
        int fd = open("/dev/i2c-1", O_RDWR);

        ioctl(fd ,I2C_SLAVE, 0x57);

        while(1) {
                printf("Reading EEPROM data at 0x00.\n");
                data = i2c_smbus_read_byte_data(fd, 0x0);
                printf("Value at 0x00 is %2x.\n", data);

                usleep(100000);

                printf("Writing incremented data to EEPROM.\n");
                i2c_smbus_write_byte_data(fd, 0x0, ++data);

                usleep(100000);

                printf("Reading back incremented data.\n");
                data = i2c_smbus_read_byte_data(fd, 0x0);
                printf("EEPROM at 0x00 value is %2x.\n\n", data);

                sleep(2);
        }
}

Note that in real-life application you should check all I/O commands results to detect errors.