Linux驱动之i2c用户态函数调用

一、概述

I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.


二、用户态实现设备驱动

  Linux内核代码文件i2c-dev.c中实现了I2C适配器设备文件的功能,针对每个适配器生成一个主设备号为89的设备节点(次设备号为0-255),I2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read(),write(),ioctl()等文件操作接口,在用户空间的应用层就可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。

i2c适配器的设备节点是/dev/i2c-x,其中x是数字。由于适配器编号是动态分配的(和注册次序有关),所以想了解哪一个适配器对应什么编号,可以查看/sys/class/i2c-dev/目录下的文件内容。


三、用户态调用

3.1i2c-dev

  用户空间操作i2c,需要包含以下头文件


 打开适配器对应的设备节点

Linux驱动之i2c用户态函数调用_第1张图片

i2c-dev为打开的线程建立一个i2c_client但是这个i2c_client并不加到i2c_adapterclient链表当中。他是一个虚拟的临时client,当用户打开设备节点时,它自动产生,当用户关闭设备节点时,它自动被释放。

3.2ioctl()

查看include/linux/i2c-dev.h文件,可以看到i2c支持的IOCTL命令

1.     #define I2C_RETRIES                    0x0701     /*设置收不到ACK时的重试次数*/  

2.     #define I2C_TIMEOUT                 0x0702 /* 设置超时时限的jiffies */  

3.     #define I2C_SLAVE                       0x0703 /*设置从机地址 */  

4.     #define I2C_SLAVE_FORCE        0x0706  /* 强制设置从机地址 */  

5.     #define I2C_TENBIT                      0x0704 /*选择地址位长:=0 for 7bit , != 0 for 10 bit */  

6.     #define I2C_FUNCS                      0x0705 /*获取适配器支持的功能 */  

7.     #define I2C_RDWR                        0x0707                                 /*Combined R/W transfer (one STOP only)  */  

8.     #define I2C_PEC                            0x0708                                  /* != 0 to use PEC with SMBus */  

9.     #define I2C_SMBUS                      0x0720                                   /*SMBus transfer  */  

 

例如:

1、设置重试次数:

ioctl(fd, I2C_RETRIES,m);

设置适配器收不到ACK时重试的次数为m。默认的重试次数为1

2、设置超时
ioctl(fd, I2C_TIMEOUT,m);
设置SMBus的超时时间为m,单位为jiffies

3、设置从机地址
ioctl(fd, I2C_SLAVE,addr);
ioctl(fd, I2C_SLAVE_FORCE, addr);
在调用read()write()函数之前必须设置从机地址。这两行都可以设置从机的地址,区别是第二行无论内核中是否已有驱动在使用这个地址都会成功,第一行则只在该地址空闲的情况下成功。由于i2c-dev创建的i2c_client不加入i2c_adapterclient列表,所以不能防止其它线程使用同一地址,也不能防止驱动模块占用同一地址。

 4、设置地址模式
ioctl(file,I2C_TENBIT,select)
如果select不等于0选择10bit地址模式,如果等于0选择7bit模式,默认7位模式。

 

3.3数据包

i2c发送或者接收一次数据都以数据包( struct i2c_msg )封装

Linux驱动之i2c用户态函数调用_第2张图片

addr是设备从地址。

flags通信标志,发送数据为0接收数据为I2C_M_RD

len是数据长度

buf是传输数据

 

3.4、接受数据

设备驱动中我们通常调用 /driver/i2c/i2c-core.c 定义的接口i2c_master_recv 来接收一次数据。通过i2c_transfer调用数据包。

int i2c_master_recv(structi2c_client *client, char *buf ,int count)  
{
 
   structi2c_adapter *adap=client->adapter; // 获取adapter信息 
   struct i2c_msgmsg;                  // 定义一个临时的数据包 
   int ret;  

   msg.addr =client->addr;              // 将从机地址写入数据包 
   msg.flags =client->flags & I2C_M_TEN;  // 将从机标志并入数据包 
   msg.flags |=I2C_M_RD;       // 将此次通信的标志并入数据包 
   msg.len = count;            // 将此次接收的数据字节数写入数据包 
   msg.buf = buf;              

   ret =i2c_transfer(adap, &msg, 1); // 调用平台接口接收数据 

   /* If everythingwent ok (i.e. 1 msg transmitted), return #bytes 
    transmitted, elseerror code. */  
   return (ret == 1)? count : ret; // 如果接收成功就返回字节数 
}
 
EXPORT_SYMBOL(i2c_master_recv);
 

 

参考驱动i2c_master_recv()函数封装属于自己用户态的接受函数。用户态是通过ioctl(handle->fd, I2C_RDWR, &data)函数与i2c从设备进行数据交互。主要有2个步骤:首先是写入需要读取的寄存器的地址,然后从寄存器中读取数据。需要2个数据包。如下:

 Linux驱动之i2c用户态函数调用_第3张图片

3.5、发送数据

设备驱动中我们通常调用 /driver/i2c/i2c-core.c 定义的接口 i2c_master_send来发送一次数据。通过i2c_transfer调用数据包

 

inti2c_master_send(struct i2c_client *client,const char *buf ,int count)  
{
 
   int ret;  
   structi2c_adapter *adap=client->adapter; // 获取adapter信息 
   struct i2c_msgmsg;                  // 定义一个临时的数据包 

   msg.addr =client->addr;             // 将从机地址写入数据包 
   msg.flags =client->flags & I2C_M_TEN; // 将从机标志并入数据包 
   msg.len = count;            // 将此次发送的数据字节数写入数据包 
   msg.buf = (char*)buf;         // 将发送数据写入数据包 

   ret =i2c_transfer(adap, &msg, 1); // 调用平台接口发送数据 

   /* If everythingwent ok (i.e. 1 msg transmitted), return #bytes 
    transmitted, elseerror code. */  
   return (ret == 1)? count : ret; // 如果发送成功就返回字节数 
}
 
EXPORT_SYMBOL(i2c_master_send);
 

 

参考驱动i2c_master_send()函数封装属于自己用户态的接受函数。用户态是通过ioctl(handle->fd, I2C_RDWR, &data)函数与i2c从设备进行数据交互。每次要写入两个字节数据主要包括写入的寄存器地址和要写入的数据。只需发送一次数据包。如下:

 Linux驱动之i2c用户态函数调用_第4张图片


3.6、使用案例

1.     #include

2.     #include

3.     #include

4.     #include

5.     #include

6.     #include

7.     #include

8.     #include

9.     #include

10.   

11.  #defineI2C_FILE_NAME   "/dev/i2c-1"

12.  #defineI2C_ADDR    0x40

13.   

14.  intfd;

15.   

16.  inti2c_open()

17.  {

18.      fd = open(I2C_FILE_NAME, O_RDWR);

19.      if(fd < 0){

20.          perror("Unable to open i2c controlfile");

21.          return 1;

22.      }

23.  }

24.   

25.  inti2c_write(int fd, unsigned char dev_addr, unsigned char reg_addr, unsigned charval)

26.  {

27.      int ret;

28.      unsigned char buf[2];

29.      struct i2c_rdwr_ioctl_data data;

30.      struct i2c_msg messages;

31.   

32.      buf[0] = reg_addr;

33.      buf[1] = val;

34.      messages.addr = dev_addr;  //device address

35.      messages.flags = 0;    //write

36.      messages.len = 2;

37.      messages.buf = buf;  //data address

38.   

39.      data.msgs = &messages;

40.      data.nmsgs = 1;

41.      if(ioctl(fd, I2C_RDWR, &data) < 0){

42.          printf("write ioctl err\n");

43.          return 1;

44.      }

45.      usleep(1000);

46.   

47.      return 1;

48.  }

49.   

50.  inti2c_read(int fd, unsigned char addr, unsigned char reg, unsigned char *val)

51.  {

52.      int ret;

53.      struct i2c_rdwr_ioctl_data data;

54.      struct i2c_msg messages[2];

55.   

56.      messages[0].addr = addr;  //device address

57.      messages[0].flags = 0;    //write

58.      messages[0].len = sizeof(reg);

59.      messages[0].buf = ®  //data address

60.   

61.      messages[1].addr = addr;       //device address

62.      messages[1].flags = I2C_M_RD;  //read

63.      messages[1].len = sizeof(val);

64.      messages[1].buf = val; 

65.   

66.      data.msgs = messages;

67.      data.nmsgs = 2;

68.      if(ioctl(fd, I2C_RDWR, &data) < 0){

69.          printf("read ioctlerr\n");   

70.          return 1;

71.      }

72.   

73.      return 0;

74.  }

75.   

76.  intmain()

77.  {

78.      int i;

79.      unsigned char buf[4];

80.      unsigned char val[] = {0x04, 0x05, 0x06,0x07};

81.   

82.      i2c_open();

83.      

84.   

85.      for(i =0; i< 4; i++)

86.        i2c_write(fd, I2C_ADDR, i, val[i]);

87.   

88.   

89.      memset(buf, 0x00, sizeof(buf));

90.      for(i = 0; i < sizeof(buf); i++){

91.          if(i2c_read(fd, I2C_ADDR, i,&buf[i])){

92.              printf("Unable to getregister!\n");

93.          }

94.      }

95.   

96.      for(i=0; i< 4;i++)

97.          printf("buf[%d]=%d\n",i,buf[i]);

98.   

99.  }

 

 

你可能感兴趣的:(LInux)