在学习了linux驱动IIC,对linux有了更深一层的了解。其中在内核drivers/i2c目录下有I2c-dev.c这么一个文件,他是一个通用的从设备驱动,一般的IIC只要使用这个驱动就能完成数据的交互,比如EEPROM、实时RTC等。
首先来介绍一下重要的结构体
struct i2c_rdwr_ioctl_data
{
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
struct i2c_msg {
__u16 addr; /* 从器件地址 */
__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 */
};
以上两个结构体在用户应用程序中进行赋值,之后调用ioctl函数直接将数据发送出去或接收。
来看一下写EEPROM的应用程序
#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>
#include <time.h>
int main()
{
int fd, ret;
unsigned char device_addr = 0x53; /*从器件的地址,这里使用EEPROM----AT24C256其中A0和A1都接高电平*/
unsigned char data=0x31; /*写入EEPROM的数据*/
unsigned short rdwr_addr; /*写入地址,在这里使用地址递增的方式写满整个EEPROM*/
struct i2c_rdwr_ioctl_data e2prom_data; /*传入驱动的结构体*/
fd= open("/dev/i2c/0", O_RDWR); /*打开IIC设备*/
if(fd < 0) {
printf("openerror");
exit(1);
}
e2prom_data.msgs= (struct i2c_msg *)malloc(e2prom_data.nmsgs * sizeof(struct i2c_msg)); /*分配结构体空间并检查*/
if(e2prom_data.msgs == NULL) {
printf("mallocerror");
exit(1);
}
ioctl(fd,I2C_TIMEOUT, 1); /*设置超时 1表示10ms*/
ioctl(fd,I2C_RETRIES, 1); /*设置重复次数*/
for(rdwr_addr=0;rdwr_addr<32768;rdwr_addr++) /*地址自增写入*/
{
e2prom_data.nmsgs= 1; /*传输数据包的数目,在这里e2prom_data.msgs[0]只有一个因此填写1*/
e2prom_data.msgs[0].len= 3; /*数据缓冲的长度3,在这里e2prom_data.msgs[0].buf是个3大小的数组因此填写3*/
e2prom_data.msgs[0].addr= device_addr; /*从器件的地址*/
e2prom_data.msgs[0].flags= 0; /*0----write\1-----read*/
e2prom_data.msgs[0].buf= (unsigned char *)malloc(3); /*分配数组大小*/
e2prom_data.msgs[0].buf[0]= (unsigned char)(rdwr_addr>>8); /* write address ,先写高位*/
e2prom_data.msgs[0].buf[1]= (unsigned char)(rdwr_addr); /* write address ,再写低位*/
e2prom_data.msgs[0].buf[2]= data; /* write data */
ret= ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data); /*执行ioctl,将数据写入并检查*/
if(ret < 0) {
printf("writedata error");
exit(1);
}
printf("writedata: %d to address: %#x\n", data, rdwr_addr); /*打印写入数据*/
usleep(10000);
}
sleep(1);
free(e2prom_data.msgs);
close(fd);
return 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>
#include <time.h>
int main()
{
int fd, ret;
unsigned short rdwr_addr;
unsigned char device_addr = 0x53;
unsigned char data;
struct i2c_rdwr_ioctl_data e2prom_data;
fd= open("/dev/i2c/0", O_RDWR);
if(fd < 0) {
printf("openerror");
exit(1);
}
e2prom_data.msgs= (struct i2c_msg *)malloc(e2prom_data.nmsgs * sizeof(struct i2c_msg));
if(e2prom_data.msgs == NULL) {
printf("mallocerror");
exit(1);
}
ioctl(fd,I2C_TIMEOUT, 1);
ioctl(fd,I2C_RETRIES, 2);
for(rdwr_addr=0;rdwr_addr<32768;rdwr_addr++)
{
e2prom_data.msgs[0].buf= (unsigned char *)malloc(5);
e2prom_data.nmsgs= 2;
e2prom_data.msgs[0].len= 2;
e2prom_data.msgs[0].addr= device_addr;
e2prom_data.msgs[0].buf[0]= (unsigned char)(rdwr_addr>>8); /* write address */
e2prom_data.msgs[0].buf[1]= (unsigned char)(rdwr_addr); /* write address */
e2prom_data.msgs[1].len= 1;
e2prom_data.msgs[1].addr= device_addr;
e2prom_data.msgs[1].flags= 1; /* read */
e2prom_data.msgs[1].buf= &data;
ret= ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
if(ret < 0) {
perror("readerror");
exit(1);
}
printf("read data: %d from address: %#x\n", data,rdwr_addr);
data = 0;
usleep(10000);
}
free(e2prom_data.msgs);
close(fd);
return 0;
}