I2C使用参考

Version 1.0


1. 概述

目前开发板上支持2组I2C controller。


2. Dts配置


2.1. Demo板支持的I2C padmux

表1-1

I2C Group Mode SCL SDA DEV
HW I2C group0 10 PAD_KEY6 PAD_KEY7 /dev/i2c-0
11 PAD_KEY12 PAD_KEY13
12 PAD_GPIO1 PAD_GPIO2
13 PAD_GPIO3 PAD_GPIO4
HW I2C group1 8 PAD_KEY8 PAD_KEY9 /dev/i2c-1
9 PAD_GPIO1 PAD_GPIO2

提供两组HW I2C,第一组HW I2C group0的配置可选择如上4种其中一种, 对应节点是/dev/i2c-0;第二组HW I2C group1的配置可选择如上2种其中一种, 对应节点是/dev/i2c-1


2.2. I2C的dts配置,以mode11为例

  1. 如下红色方框i2c-padmux = \<Mode>,参数Mode要设为11,修改pioneer3 -demo.dtsi:

  1. 添加I2C0 padmux复用

    修改pioneer3-ssc020a-s01a-demo-padmux.dtsi

    I2C0选择Mode 11(PAD_KEY12/PAD_KEY13)进行输出,没有在其他组输出的话,需要将其他组注释掉。


2.3. I2C的dts配置,以mode8为例

  1. 如下红色方框i2c-padmux = \<Mode>,参数Mode要设为8

    修改pioneer3 -demo.dtsi

  2. 添加I2C1 padmux复用

    修改pioneer3-ssc020a-s01a-demo-padmux.dtsi

    I2C1选择Mode 8(PAD_KEY8/PAD_KEY9)进行输出,没有在其他组输出的话,需要将其他组注释掉。


3. Kernel配置

  1. 打开kernel对I2C的配置

  2. 打开SStar I2C驱动配置


4. 使用I2C


4.1. 使用i2c_read_write验证

Ex:

往slave addr为0x54的reg 0x24写入0x30,cmd如下:

./i2c_read_write b 0 a 0x54 f A16D16 w 0x24 0x30

![](mymedia/P3_i2c_7.png)

4.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;
}