I2C使用参考


1. 概述

表1-1

I2C Group SCL SDA DEV
HW I2C group0 PAD_I2C0_SCL PAD_I2C0_SDA /dev/i2c-0
HW I2C group1 PAD_I2C1_SCL PAD_I2C1_SDA /dev/i2c-1,

提供两组组HW I2C:

  • 第一组HW I2C 对应pad 是PAD_I2C0_SCL/ PAD_I2C0_SDA,对应节点是/dev/i2c-0;

  • 第二组HW I2C 对应pad 是PAD_I2C1_SCL/ PAD_I2C1_SDA,对应节点是/dev/i2c-1。

这是所有i2c全开的情况,如果实际情况中没有打开这么多i2c,要根据mhal_iic.h中“#define HAL_HWI2C_PORTS 2”的定义和infinity6b0.dtsi中i2c device node的定义情况,而对应的节点一般看i2c-group = <0>定义的值是多少。

图1-1

下面所有的描述都是以第一组HW I2C 为例,其他 I2C 请参照第一组的使用方法。


2. 读写I2C

通过标准的ms_i2c_xfer 函数来读写I2C,以下是一个使用的小例子。

#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#define FILE_NAME "/dev/i2c-0"

static int i2c_write(int fd,unsigned char slave_addr, unsigned char
reg_addr, unsigned char value)

{

    unsigned char outbuf[2];

    struct i2c_rdwr_ioctl_data packets;

    struct i2c_msg messages[1];

    messages[0].addr = slave_addr;

    messages[0].flags = 0;

    messages[0].len = sizeof(outbuf);

    messages[0].buf = outbuf;

    /* The first byte indicates which register we‘ll write */

    outbuf[0] = reg_addr;

    /*

    * The second byte indicates the value to write. Note that for many

    * devices, we can write multiple, sequential registers at once by

    * simply making outbuf bigger.

    */

    outbuf[1] = value;

    /* Transfer the i2c packets to the kernel and verify it worked */

    packets.msgs = messages;

    packets.nmsgs = 1;

    if(ioctl(fd, I2C_RDWR, &packets) < 0)

    {

        perror("Unable to send data");

        return 1;

    }

    return 0;

}

static int i2c_read(int fd, unsigned char slave_addr, unsigned char
reg_addr, unsigned char *value)

{

    unsigned char inbuf, outbuf;

    struct i2c_rdwr_ioctl_data packets;

    struct i2c_msg messages[2];

    /*

    * In order to read a register, we first do a "dummy write" by writing

    * 0 bytes to the register we want to read from. This is similar to

    * the packet in set_i2c_register, except it‘s 1 byte rather than 2.

    */

    outbuf = reg_addr;

    messages[0].addr = slave_addr;

    messages[0].flags = 0;

    messages[0].len = sizeof(outbuf);

    messages[0].buf = &outbuf;

    /* The data will get returned in this structure */

    messages[1].addr = slave_addr;

    messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;

    messages[1].len = sizeof(inbuf);

    messages[1].buf = &inbuf;

    /* Send the request to the kernel and get the result back */

    packets.msgs = messages;

    packets.nmsgs = 2;

    if(ioctl(fd, I2C_RDWR, &packets) < 0)

    {

        perror("Unable to send data");

        return 1;

    }

        *value = inbuf;

        return 0;

}

int main(int argc, char **argv)

{

    int fd;

    unsigned int slave_addr=0, reg_addr=0, value = 0;

    if (argc < 4){

                    printf("Usage:\n%s r[w] start_addr reg_addr [value]\n",argv[0]);

                    return 0;

                }

fd = open(FILE_NAME, O_RDWR);

if (!fd)

    {

        printf("can not open file %s\n", FILE_NAME);

        return 0;

    }

sscanf(argv[2], "%x", &slave_addr);

sscanf(argv[3], "%x", &reg_addr);

if(!strcmp(argv[1],"r"))

    {

        i2c_read(fd, slave_addr, reg_addr, (unsigned char*)&value);

    }

    else if(argc>4&&!strcmp(argv[1],"w"))

    {

        sscanf(argv[4], "%x", &value);

        i2c_write(fd, slave_addr, reg_addr, value);

    }

close(fd);

return 0;

}