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]是地址,第二遍读数据时存放读的数据
-
/*
-
//作者:王磊
-
//日期:2013.11.17
-
//文件功能:实现ioctl函数调用,并操作i2c设备/dev/i2c/0进行读写数据
-
*/
-
#include<stdio.h>
-
#include<linux/types.h>
-
#include<fcntl.h>
-
#include<unistd.h>
-
#include<stdlib.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>
-
-
int main(int argc, char** argv)
-
{
-
struct i2c_rdwr_ioctl_data work_queue;
-
-
unsigned int slave_address,reg_address,dat;
-
int i,ret;
-
unsigned char val;
-
unsigned int fd;
-
-
if(argc != 3)
-
{
-
printf("usage:./eeprom_ioctl address data\n");
-
return 0;
-
}
-
fd=open("/dev/i2c/0",O_RDWR);
-
if(!fd)
-
{
-
printf("error on opening the device file\n");
-
exit(1);
-
}
-
ioctl(fd,I2C_TIMEOUT,2);//超时时间
-
ioctl(fd,I2C_RETRIES,1);//重复次数
-
-
slave_address = 0x50;//24c08的访问地址是101000b
-
reg_address = (argv[1][2]-48)<<4 | (argv[1][3]-48);
-
dat = (argv[2][2]-48)<<4 | (argv[2][3]-48);
-
-
//nmsgs决定了有多少start信号
-
//一个msgs对应一个start信号
-
//在nmsgs个信号结束后总线会产生一个stop
-
//下面因为在操作时序中最多用到2个start信号(字节读操作中)
-
-
work_queue.nmsgs = 2;
-
work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));
-
if(!work_queue.msgs)
-
{
-
printf("memory alloc failed");
-
close(fd);
-
exit(1);
-
}
-
//往i2c里面写数据,写完后产生一个stop
-
printf("began to write:\n");
-
work_queue.nmsgs = 1;
-
(work_queue.msgs[0]).len = 2;//buf的长度
-
(work_queue.msgs[0]).flags = 0;//write
-
(work_queue.msgs[0]).addr = slave_address;//设备地址
-
(work_queue.msgs[0]).buf = (unsigned char *)malloc(2);
-
(work_queue.msgs[0]).buf[0] = reg_address;//写的地址
-
(work_queue.msgs[0]).buf[1] = dat;//你要写的数据
-
-
ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
-
if(ret < 0)
-
printf("error during I2C_RDWR ioctl with error code %d\n", ret);
-
-
//从i2c里面读出数据,先写寄存器,再读数据,最后产生一个stop
-
printf("\nbegan to read:\n");
-
work_queue.nmsgs = 2;
-
//先设定一下地址
-
(work_queue.msgs[0]).len = 1;
-
(work_queue.msgs[0]).flags = 0;//write
-
(work_queue.msgs[0]).addr = slave_address;
-
(work_queue.msgs[0]).buf[0] = reg_address;//因为上面buf已经分配过了
-
//然后从刚才设定的地址处读
-
(work_queue.msgs[1]).len = 1;
-
(work_queue.msgs[1]).flags = I2C_M_RD;
-
(work_queue.msgs[1]).addr = slave_address;
-
(work_queue.msgs[1]).buf = (unsigned char *)malloc(1);
-
(work_queue.msgs[1]).buf[0] = 0;//初始化读缓冲
-
-
ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
-
if(ret < 0)
-
printf("error during I2C_RDWR ioctl with error code %d\n", ret);
-
-
close(fd);
-
return 0;
-
-
}
下面这些文章写的不错,可以参考一下:
---------------------
作者:luckywang1103
来源:CSDN
原文:https://blog.csdn.net/luckywang1103/article/details/16810833
版权声明:本文为博主原创文章,转载请附上博文链接!
阅读(4469) | 评论(0) | 转发(0) |