Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1999292
  • 博文数量: 505
  • 博客积分: 1552
  • 博客等级: 上尉
  • 技术积分: 2524
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-23 18:24
文章分类

全部博文(505)

文章存档

2019年(12)

2018年(15)

2017年(1)

2016年(17)

2015年(14)

2014年(93)

2013年(233)

2012年(108)

2011年(1)

2009年(11)

分类: LINUX

2018-12-19 11:06:31

i2c设备驱动有两种模式:一种是用户模式设备驱动,这种驱动依赖于i2c子系统中i2c-dev驱动,这种驱动对应用程序员的要求很高,要求应用程序员了解硬件的一些东西,了解时序、地址等;另一种是普通的设备驱动,应用程序员在使用的时候就像读写文件一样。

在linux驱动中/drivers/i2c/目录下有i2c-dev.c提供了I2C设备的通用驱动,实现了read(),write(),ioctl等函数,不过这里的read()和write()函数只能对应一条消息,即如下,





但是如果碰到下面的情况:


先写一次地址,然后再开始读数据,即分为两次消息,这个时候read(),write()函数就不能正常读写了,因为先write()地址之后总线上会有stop,之后read(),就与figure 5中所示(中间没有stop)不符了,所以必须利用ioctl函数来发送两条消息,这样中间就没有stop了,发送完这两条消息才有stop。


下面就是使用ioctl函数去写和读at24c08存储器,先看下两个重要的结构体

1、struct i2c_rdwr_ioctl_data结构体

    * This is the structure as used in the I2C_RDWR ioctl call */
    struct i2c_rdwr_ioctl_data {
        struct i2c_msg __user *msgs;    /* pointers to i2c_msgs */
        __u32 nmsgs;            /* number of i2c_msgs */
    };

msgs使用前必须先分配一下内存,msgs=(struct i2c_msg *)malloc(nmsgs*sizeof(struct i2c_msg));

nmsgs是msgs的个数


2、struct i2c_msg结构体

    struct i2c_msg {
        __u16 addr;    /* slave address            */
        __u16 flags;
    #define I2C_M_TEN        0x0010    /* this is a ten bit chip address */
    #define I2C_M_RD        0x0001    /* read data, from slave to master */
    #define I2C_M_NOSTART        0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_REV_DIR_ADDR    0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_NO_RD_ACK        0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_RECV_LEN        0x0400    /* length will be first received byte */
        __u16 len;        /* msg length                */
        __u8 *buf;        /* pointer to msg data            */
    };

len是指buf的长度

buf在使用前必须先分配内存,buf=(unsigned char *)malloc(len);

一般如果写,buf[0]是写的地址,buf[1]之后都是写的数据了;如果读,第一遍写地址时buf[0]是地址,第二遍读数据时存放读的数据

点击(此处)折叠或打开

  1. /*
  2. //作者:王磊
  3. //日期:2013.11.17
  4. //文件功能:实现ioctl函数调用,并操作i2c设备/dev/i2c/0进行读写数据
  5. */
  6. #include<stdio.h>
  7. #include<linux/types.h>
  8. #include<fcntl.h>
  9. #include<unistd.h>
  10. #include<stdlib.h>
  11. #include<sys/types.h>
  12. #include<sys/ioctl.h>
  13. #include<errno.h>
  14. #include<assert.h>
  15. #include<string.h>
  16. #include<linux/i2c.h>
  17. #include<linux/i2c-dev.h>
  18.  
  19. int main(int argc, char** argv)
  20. {
  21.     struct i2c_rdwr_ioctl_data work_queue;
  22.  
  23.     unsigned int slave_address,reg_address,dat;
  24.     int i,ret;
  25.     unsigned char val;
  26.     unsigned int fd;
  27.  
  28.     if(argc != 3)
  29.     {
  30.         printf("usage:./eeprom_ioctl address data\n");
  31.         return 0;
  32.     }
  33.     fd=open("/dev/i2c/0",O_RDWR);
  34.     if(!fd)
  35.     {
  36.         printf("error on opening the device file\n");
  37.         exit(1);
  38.     }
  39.     ioctl(fd,I2C_TIMEOUT,2);//超时时间
  40.     ioctl(fd,I2C_RETRIES,1);//重复次数
  41.  
  42.     slave_address = 0x50;//24c08的访问地址是101000b
  43.     reg_address = (argv[1][2]-48)<<4 | (argv[1][3]-48);
  44.     dat = (argv[2][2]-48)<<4 | (argv[2][3]-48);

  45. //nmsgs决定了有多少start信号
  46. //一个msgs对应一个start信号
  47. //在nmsgs个信号结束后总线会产生一个stop
  48. //下面因为在操作时序中最多用到2个start信号(字节读操作中)

  49.     work_queue.nmsgs = 2;
  50.     work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));
  51.     if(!work_queue.msgs)
  52.     {
  53.         printf("memory alloc failed");
  54.         close(fd);
  55.         exit(1);
  56.     }
  57.     //往i2c里面写数据,写完后产生一个stop
  58.     printf("began to write:\n");
  59.     work_queue.nmsgs = 1;    
  60.     (work_queue.msgs[0]).len = 2;//buf的长度
  61.     (work_queue.msgs[0]).flags = 0;//write
  62.     (work_queue.msgs[0]).addr = slave_address;//设备地址
  63.     (work_queue.msgs[0]).buf = (unsigned char *)malloc(2);
  64.     (work_queue.msgs[0]).buf[0] = reg_address;//写的地址
  65.     (work_queue.msgs[0]).buf[1] = dat;//你要写的数据
  66.  
  67.     ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
  68.     if(ret < 0)
  69.         printf("error during I2C_RDWR ioctl with error code %d\n", ret);
  70.  
  71.     //从i2c里面读出数据,先写寄存器,再读数据,最后产生一个stop
  72.     printf("\nbegan to read:\n");
  73.     work_queue.nmsgs = 2;
  74.     //先设定一下地址
  75.     (work_queue.msgs[0]).len = 1;
  76.     (work_queue.msgs[0]).flags = 0;//write
  77.     (work_queue.msgs[0]).addr = slave_address;
  78.     (work_queue.msgs[0]).buf[0] = reg_address;//因为上面buf已经分配过了
  79.     //然后从刚才设定的地址处读
  80.     (work_queue.msgs[1]).len = 1;
  81.     (work_queue.msgs[1]).flags = I2C_M_RD;
  82.     (work_queue.msgs[1]).addr = slave_address;
  83.     (work_queue.msgs[1]).buf = (unsigned char *)malloc(1);
  84.     (work_queue.msgs[1]).buf[0] = 0;//初始化读缓冲
  85.  
  86.     ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
  87.     if(ret < 0)
  88.         printf("error during I2C_RDWR ioctl with error code %d\n", ret);
  89.  
  90.     close(fd);
  91.     return 0;
  92.     
  93. }

下面这些文章写的不错,可以参考一下:
http://www.21ic.com/embed/software/linuxos/201807/67526.html
http://wiki.csie.ncku.edu.tw/embedded/I2C

---------------------  
作者:luckywang1103  
来源:CSDN  
原文:https://blog.csdn.net/luckywang1103/article/details/16810833  
版权声明:本文为博主原创文章,转载请附上博文链接!
阅读(1264) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册