i2c的设备驱动可以直接利用内核提供的i2c-dev.c文件提供的ioctl函数接口在应用层实现对i2c设备的读写,
但是在应用层使用ioctl函数对应用程序员要求较高,需要自行构建msg结构体,必须了解设备的操作流程,时序之类的。
另外i2c设备的驱动也可以通过普通的设备驱动实现,像往常的驱动一样实现,然后在应用层就可以像读取普通文件
一样操作,无需再考虑读写时序。其实普通的设备驱动也可以用两种方法实现,
1)构建字符设备驱动,在open,read,write等函数中直接操作i2c总线的相关寄存器来读写i2c设备,但是这种方法因平台不同,
设备不同都要重新写驱动,
2)在设备驱动中调用i2c-core.c提供的i2c_transfer函数来实现和i2c设备的通信,这样只要对不同的设备写不同的驱动就行了。
下面就分别对i2c-dev驱动、普通设备驱动方法1和普通设备驱动方法2来介绍一下,共分为博客的三篇文章:
1)i2c驱动之i2c-dev驱动,
2)普通设备驱动1,
3)普通设备驱动方法2(推荐方法)。
关于i2c设备驱动,自己在理解的过程中感觉比较好的资料的连接:
linux下I2C驱动架构全面分析 、 、
在/linux-2.6.32.2/drivers/i2c目录下
----Algos/ 一些i2c总线适配器通信的算法,个人感觉是用I/O口模拟实现i2c通信的算法
----Busses/ I2C总线驱动的方法,对应于s3c2440适配器驱动的文件是I2c-s3c2410.c
----Chips/ I2C设备驱动,具体到某个设备,比如at24c08等
----I2c-boardinfo.c
----I2c-core.c I2C核心文件,用于联系设备驱动和总线驱动,作为一个桥梁,有用的函数i2c_add_addapter
i2c_add_driver,和i2c_transfer函数
----I2c-dev.c 通用的i2c设备驱动
----Kconfig
----Makefile
开始在内核编译i2c-dev通用驱动
1)在linux-2.6.32.2/内核目录下make menuconfig,选择如下Device Drivers
2)进入Device Drivers目录,选择I2C Support,表示编译I2C驱动模块,会将i2c-core.c编译成模块文件i2c-core.ko
3)进入I2C support
4)选择模块化编译I2C device interface "M",则会将i2c-dev.c编译成i2c-dev.ko
5)选择I2C Hardware Bus support,并进入
选择s3c2410 I2c Driver则会将i2c-s3c2410.c编译成i2c-s3c2410.ko驱动模块
6)选择Miscellaneous I2c Chip Support,并进入
会提示让你选择编译具体的设备驱动,因为这里我们采用内核提供的通用设备驱动i2c-dev,所以这里的驱动就暂时不编译了
以上编译总共得到了3个驱动文件i2c-core.ko,i2c-dev.ko,i2c-s3c2410.ko
将这三个模块insmod到内核中,顺序是i2c-core.ko,i2c-s3c2410.ko,i2c-dev.ko,会自动创建/dev/i2c/0设备节点,然后就可以直接调用/dev/i2c/0文件节点进行访问设备了
之后应用程序员可以利用下面两种ioctl函数
ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);或者
ioctl(file,I2C_SMBUS,&args);
进行与i2c设备通信了。
验证i2c应用程序:
-
-
-
-
-
-
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
int main(int argc, char** argv)
-
{
-
struct i2c_rdwr_ioctl_data work_queue;
-
-
unsigned int slave_address,reg_address,dat;
-
unsigned int fd;
-
int ret;
-
char select;
-
-
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);
-
-
-
-
work_queue.nmsgs = 1;
-
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);
-
}
-
-
slave_address = 0x50;
-
printf("please select:w or r?\n");
-
scanf("%c", &select);
-
if('w' == select)
-
{
-
printf("please input:address,dat?(example:0x00,0x00)\n");
-
scanf("%x,%x", ®_address, &dat);
-
-
printf("began to write\n");
-
work_queue.nmsgs = 1;
-
(work_queue.msgs[0]).len = 2;
-
(work_queue.msgs[0]).flags = 0;
-
(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);
-
}
-
else if('r' == select)
-
{
-
printf("please input:address?(example:0x00)\n");
-
scanf("%x", ®_address);
-
-
printf("began to read:");
-
work_queue.nmsgs = 1;
-
-
(work_queue.msgs[0]).flags = 0;
-
(work_queue.msgs[0]).addr = slave_address;
-
(work_queue.msgs[0]).len = 1;
-
(work_queue.msgs[0]).buf = (unsigned char *)malloc(1);
-
(work_queue.msgs[0]).buf[0] = reg_address;
-
ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
-
if(ret < 0)
-
printf("error during I2C_RDWR ioctl with error code %d\n", ret);
-
-
-
-
work_queue.nmsgs = 1;
-
(work_queue.msgs[0]).flags = I2C_M_RD;
-
(work_queue.msgs[0]).addr = slave_address;
-
(work_queue.msgs[0]).len = 1;
-
(work_queue.msgs[0]).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);
-
printf("reg_address=0x%2x,dat=0x%2x\n", reg_address, work_queue.msgs[0].buf[0]);
-
}
-
close(fd);
-
free((work_queue.msgs[0]).buf);
-
free(work_queue.msgs);
-
return 0;
-
-
}
-
转载地址 :http://blog.csdn.net/luckywang1103/article/details/16834519
阅读(3530) | 评论(0) | 转发(0) |