imx257下实现I2C驱动的四种方法

发布者:HarmonyInLife最新更新时间:2024-08-13 来源: cnblogs关键字:I2C驱动  四种方法 手机看文章 扫描二维码
随时随地手机看文章

今天我们的任务是简单的入门linux内核下i2c设备驱动分离的四种写法.



一.一个简单的i2c驱动


和以前的驱动程序不同,i2c驱动分为drv驱动和dev设备驱动两个文件,不懂的可以参考我以前写的<20150313 驱动模块分离概念>以及总线设备驱动模型这些博文


地址:http://www.cnblogs.com/lihaiyan/p/4336165.html



1.首先是drv驱动的编写at24cxx_drv_1.c:


在drv驱动中,其实很简单,就是实现一个i2c_driver结构体,然后在init函数中注册i2c_driver结构体,最后自然是在exit函数中卸载i2c_driver结构体.


①定义i2c_driver结构体以及实现相应的函数


 1 //probe函数

 2 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){

 3     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

 4     return 0;

 5 }

 6 //remove函数

 7 static int __devexit at24cxx_remove(struct i2c_client *client)

 8 {

 9     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

10     return 0;

11 }

12 static const struct i2c_device_id at24cxx_id_table[] = {

13     {'at24c08', 0},      //记录了设备的名字,用于去顶后面的驱动是否匹配

14     {}

15 };    

16 static struct i2c_driver at24cxx_driver = {

17     .driver = {

18         .name = 'LoverXueEr',

19         .owner = THIS_MODULE,

20     },

21     .probe = at24cxx_probe,            //探测函数

22     .remove = at24cxx_remove,        //卸载函数

23     .id_table = at24cxx_id_table,

24 };


可以发现,在i2c_driver结构体中总共实现了探测函数probe,用于探测匹配的设备,id_table定义了设备的名字用于匹配合适的驱动.


②在init和exit对i2c_driver分别注册和卸载


 1 static int at24cxx_drv_init(void)

 2 {

 3     /* 2.注册i2c_driver*/

 4     i2c_add_driver(&at24cxx_driver);

 5     return 0;

 6 }

 7 static void at24cxx_drv_exit(void)

 8 {

 9     i2c_del_driver(&at24cxx_driver);

10 }


2.设备驱动程序编写at24cxx_dev_1.c


在设备驱动中主要是定义了一些设备的具体的信息,比如设备地址啊等等的信息.


在设备驱动中,主要就是I2C控制器(也称适配器)的使用了.


在init函数中首先创建一个i2c_adapter控制器结构体,


接着通过格泰i2c_get_adapter获取内核存在的i2c控制器号,这个在/sys/class/i2c-adapter下可以查看,


接着使用i2c_new_device直接创建一个设备,不管设备存在与否,该函数都会强制认为该设备存在.


而如果使用i2c_new_probed_device的话:它和前面不同的是,它一定要对于能够'已经识别出来的设备'(probed_device),才会去创建,否则无法创建.(见下面方法二)


理论描述总是太抽象了,我们来看看程序就懂了.


 1 //单板结构体,用于存放设备的硬件信息

 2 static struct i2c_board_info at24cxx_info = {

 3         I2C_BOARD_INFO('at24c08',0x50),        //注意这个名字 1010000

 4 };

 5 static struct i2c_client *at24cxx_client;

 6 

 7 /* 1.分配/设置i2c_driver */

 8 static int at24cxx_dev_init(void)

 9 {

10     struct i2c_adapter *i2c_adapt;

11     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

12     //创建i2c适配器

13     //直接创建设备

14     i2c_adapt = i2c_get_adapter(1);        //获得第0个适配器

15     if (!i2c_adapt) {

16         printk('can't get i2c adapter %dn',1);

17         return -EIO;

18     }

19     at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info);    //在总线下面创建一个i2c_adapt,强制认为设备存在

20     //i2c_new_probed_device:    对于能够'已经识别出来的设备'(probed_device),才会去创建

21     i2c_put_adapter(i2c_adapt);            //释放i2c_adapt

22     return 0;

23 }

24 

25 static void at24cxx_dev_exit(void)

26 {

27     if(at24cxx_client)

28         i2c_unregister_device(at24cxx_client);

29 }


3.编译测试


结果如图所示:

afe9cc762fc38f60f41c3efd04746c84_8DcWtWMqzORnEAAAAASUVORK5CYII=.png?imageView2/2/w/1000

附上drv驱动程序: at24cxx_drv_1.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 

 8 

 9 //probe函数

10 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){

11     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

12     return 0;

13 }

14 

15 //remove函数

16 static int __devexit at24cxx_remove(struct i2c_client *client)

17 {

18     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

19     return 0;

20 }

21 

22 

23 static const struct i2c_device_id at24cxx_id_table[] = {

24     {'at24c08', 0},

25     {}

26 };

27     

28 static struct i2c_driver at24cxx_driver = {

29     .driver = {

30         .name = 'LoverXueEr',

31         .owner = THIS_MODULE,

32     },

33     .probe = at24cxx_probe,

34     .remove = at24cxx_remove,

35     .id_table = at24cxx_id_table,

36 };

37 

38 

39 /* 1.分配/设置i2c_driver */

40 

41 static int at24cxx_drv_init(void)

42 {

43     /* 2.注册i2c_driver*/

44     i2c_add_driver(&at24cxx_driver);

45     return 0;

46 }

47 

48 static void at24cxx_drv_exit(void)

49 {

50     i2c_del_driver(&at24cxx_driver);

51 }

52 

53 module_init(at24cxx_drv_init);

54 module_exit(at24cxx_drv_exit);

55 MODULE_LICENSE('GPL');

56 

57 /*

58 1.左边注册一个设备 i2c_client

59 2.右边注册一个驱动 i2c_driver

60 3.比较他们的名字,如果相同,则调用probe函数

61 4.在probe函数里,register_chrdev

62 */


附上dev驱动程序: at24cxx_dev_1.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 

10 //单板结构体,用于存放设备的硬件信息

11 static struct i2c_board_info at24cxx_info = {

12         I2C_BOARD_INFO('at24c08',0x50),        //注意这个名字 1010000

13 };

14 static struct i2c_client *at24cxx_client;

15 

16 /* 1.分配/设置i2c_driver */

17 static int at24cxx_dev_init(void)

18 {

19     struct i2c_adapter *i2c_adapt;

20     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

21     //创建i2c适配器

22     //直接创建设备

23     i2c_adapt = i2c_get_adapter(1);        //获得第0个适配器

24     if (!i2c_adapt) {

25         printk('can't get i2c adapter %dn',1);

26         return -EIO;

27     }

28     at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info);    //在总线下面创建一个i2c_adapt,强制认为设备存在

29     //i2c_new_probed_device:    对于能够'已经识别出来的设备'(probed_device),才会去创建

30     i2c_put_adapter(i2c_adapt);            //释放i2c_adapt

31     return 0;

32 }

33 

34 static void at24cxx_dev_exit(void)

35 {

36     if(at24cxx_client)

37         i2c_unregister_device(at24cxx_client);

38 }

39 

40 module_init(at24cxx_dev_init);

41 module_exit(at24cxx_dev_exit);

42 MODULE_LICENSE('GPL');

43 

44 /*

45 1.左边注册一个设备 i2c_client

46 2.右边注册一个驱动 i2c_driver

47 3.比较他们的名字,如果相同,则调用probe函数

48 4.在probe函数里,register_chrdev

49 */


二.创建已经能被识别的设备



前面我们已经涉及到了,和i2c_new_device不同,使用i2c_new_probed_device的话,它会线查看设备是否存在,如果存在的话,才会创建设备.现在我们第二种方法就是使用它来实现.


再前面的程序基础上修改at24cxx_dev_1.c设备驱动程序.drv驱动不用修改.


1.定义一些用于探测的id数组


前面我们说了,它会探测id的设备是否存在,所以,意味着我们这里可以有多个id,并且id号也可以是不存在的,为了保存这些id,自然就需要一个数组来装咯.


程序如下所示:


 


1 static struct i2c_client *at24cxx_client;

2 //一些用于试探是否存在的id

3 static const unsigned short addr_list[] = {0x60,0x50,0x70,NULL};  

 


 


 


2.在init函数中


和前面第一种方法不同的是,


①我们此处是在init函数中动态的创建i2c_board_info结构体.


②接着就是初始化i2c_board_info结构体,分配设备的名字用于匹配合适的总线.


③创建适配器,获取适配器,和前面一样


④使用i2c_new_probed_device来创建设备,再i2c_new_probed_device中,首先会遍历id数组,线测试id设备是否存在,接着就是调用i2c_new_device来创建设备.


⑤动态是否i2c_adapt控制器.


程序如下:


 1 /* 1.分配/设置i2c_driver */

 2 static int at24cxx_dev_init(void)

 3 {

 4     struct i2c_adapter *i2c_adapt;

 5     struct i2c_board_info at24cxx_info;

 6     

 7     printk('%s, %s, %dnn',__FILE__,__FUNCTION__,__LINE__);

 8     

 9     //初始化i2c_board_info 结构体

10     memset(&at24cxx_info, 0, sizeof(struct i2c_board_info));

11     strlcpy(at24cxx_info.type,'at24c08',20);

12     

13     //创建i2c适配器  //直接创建设备

14     i2c_adapt = i2c_get_adapter(1);        //获得第1个i2c_bus总线

15     if (!i2c_adapt) {

16         printk('can't get i2c adapter %dn',1);

17         return -EIO;

18     }

19     //在总线下面创建一个i2c_adapt,强制认为设备存在

20     //at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info);    

21     //对于addr_list能够'已经识别出来的设备'(probed_device),才会去创建,i2c_new_device之前,先测试addr_List中的设备是否存在

22     at24cxx_client = i2c_new_probed_device(i2c_adapt, &at24cxx_info, addr_list);    

23     if(!at24cxx_client)

24         return -ENODEV;

25     if(i2c_adapt)

26         i2c_put_adapter(i2c_adapt);            //释放i2c_adapt

27     return 0;

28 }

29 

30 static void at24cxx_dev_exit(void)

31 {

32     if(at24cxx_client)

33         i2c_unregister_device(at24cxx_client);

34 }


3.编译测试


附上drv驱动程序: at24cxx_drv_2.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 

 8 

 9 //probe函数

10 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){

[1] [2] [3]
关键字:I2C驱动  四种方法 引用地址:imx257下实现I2C驱动的四种方法

上一篇:ARM基础:为何C语言(的函数调用)需要堆栈,而汇编语言却不需要堆栈
下一篇:调试分析之 使用gdb远程调试ARM开发板

推荐阅读最新更新时间:2026-03-21 06:05

S7-200 SMART CPU的四种开环运动控制方法
S7-200 SMART CPU提供了四种开环运动控制方法: 脉冲串输出(PTO):内置在CPU的速度和位置控制。此功能仅提供脉冲串输出,方向和限值控制必须通过应用程序使用PLC中集成的或由扩展模块提供。 脉宽调制(PWM):内置在CPU的速度、位置或负载循环控制。若组态PWM输出,CPU将固定输出的周期时间,通过程序控制脉冲的持续时间或负载周期。可通过脉冲持续时间的变化来控制应用的转速或位置。 运动轴:内置于CPU中,用于速度和位置控制。此功能提供了带有集成方向控制和禁用输出的单脉冲串输出,还包括可编程输入,并提供包括自动参考点搜索等多种操作模式。 运动轴组:支持基于PTO的开环轴组功能,可支持2轴或3轴的直线插补功能,并可
[嵌入式]
S7-200 SMART CPU的<font color='red'>四种</font>开环运动控制<font color='red'>方法</font>
使用频谱分析仪的四种分析方法观察信号质量
无线通信常常需要用频谱分析仪对信号进行数字解调,分析信号质量,通常的分析有四种方法——IQ星座图、IQ眼图、码元表、误码率表。今天就来介绍下这四种分析方法如何帮助我们观察信号质量。 一、IQ星座图 数字调制是将低频信息通过高频载波发射所做的必要步骤,当我们接收到信号时,首先要对信号解调。IQ星座图是一种调制映射关系,利用正交平面,把调制的所有可能性——调制后的符号数(或者叫状态空间),铺在我们构建的正交平面上。信号调制过程中从一个点跳到点(调制状态),点与点的距离叫做欧氏距离,代表能量;当我们观察迹线是否正确落在对应的格点上,可以判断信号的幅相调制是否完成。 当然,不同的调制方式星座图形态不同,比如BPSK只有两种状态,Q
[测试测量]
使用频谱分析仪的<font color='red'>四种</font>分析<font color='red'>方法</font>观察信号质量
52单片机四种方法实现流水灯
流水灯电路分析 流水灯电路图 电源→限流电阻→发光二极管→74HC573输出端→单片机P1组IO口 因为单片机的IO口输出电流非常小,无法直接用IO口驱动发光二极管,所以我们需要用到74HC573这个芯片(可以理解为电流放大的芯片)。 74HC573 芯片图 从图中可以看出74HC573有20个引脚,Vcc和GND是电源的正负极,2 ~ 9的引脚是输入端,12 ~ 19的引脚是输出端 电极特性 ①我们的电路板一般的工作电压是5V,根据表中数据可以得知,芯片高电平的输入电压为≥3.15V,低电平输入电压为0~1.35V。我们使用的单片机STC89C52输出的电压为5V或者0V,满足上面的条件。 ②再看高低电平
[单片机]
52单片机<font color='red'>四种</font><font color='red'>方法</font>实现流水灯
空调售后常见的四种故障类型及其处理方法介绍
空调在售后常见的故障主要有四种故障类型:线圈坏、不换向、串气和漏气。那么,每一种情况对应的故障原因、处理的方法是怎么?接下来我们一起讨论吧! 一、电磁线圈损坏 1、原因 由于供电电压的不稳定,或者生产中电磁线圈安装的不规范,没有对正阀芯,固定螺钉在安装或者运行过程的松弛,导致先导滑阀阀芯受力不均,同时也可能导致电磁线圈发热量过大而损坏。 2、识别方法 先查看电磁线圈端子是否与主板插接良好,然后测量主板给四通阀线圈供电是否正常,再用万用表电磁线圈的阻值、绝缘是否正常(下图)。若电阻明显偏小或者偏大,对外壳绝缘损坏表明电磁线圈坏。 3、处理方案 更换相同规格线圈。 二、不换向(机械故障) 1、原因 ①杂质进入四通阀,导致滑
[嵌入式]
空调售后常见的<font color='red'>四种</font>故障类型及其处理<font color='red'>方法</font>介绍
STM32延时函数的四种方法:普通延时(2种)、SysTick 定时器延时(2种)
STM32延时函数的三种方法:普通延时、SysTick 定时器延时(1.中断方式;2.非中断方式) 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 (1)普通延时法1 这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,不过要做的比较精准还是要下一番功夫。下面的代码是在网上搜到的,经测试延时比较精准。 //粗延时函数,微秒 void delay_us(u16 time) { u16 i=0; while(time--) { i=10; //自己定义 while(i--) ;
[单片机]
STM32延时函数的<font color='red'>四种</font><font color='red'>方法</font>:普通延时(2种)、SysTick 定时器延时(2种)
全彩led显示屏的四种有效检测方法
随着led显示屏的应用越来越多,在生活中几乎随处可见。无论是户外广告大屏、室内高清大屏、小间距led等。led显示屏无疑是目前应用最广泛的大屏幕产品之一。然而,任何产品都会有它的使用寿命和最佳使用期限,led显示屏也是如此。反复操作之后,难免会出现这样那样的问题。此时,我们需要解决和维护它,以便它能够继续正常地为我们服务。接下来,创凯光科技将与您探讨分享led显示屏的几种维护方法,希望对您有所帮助。 1、显示屏电阻检测方法 对于显示屏的电阻检测方法,我们需要将万用表调到电阻级别,先检测一个正常电路板的某一点对地的电阻值,再检测另一个相同电路板的同点测试是否与正常电阻值不同。如果是这样,我们就知道led显示屏问题的范围,否则,我
[测试测量]
电工数字万用表这四种方法太巧秒了
1、判断线路或器件带不带电 数字的交流电压挡很灵敏,哪怕周围有很小的感应电压都可以有显示。根据这一特点,可以当作测试电笔用。用法如下:将万用表打到AC20V挡,黑表笔悬空,手持红表笔与所测路线或器件相接触,这时万用表会有显示,如果显示数字在几伏到十几伏之间(不同的万用表会有不同的显示),表明该线路或器件带电,如果显示为零或很小,表明该线路或器件不带电。 2、区分供电线是火线还是零线 第一种方法: 可以用上面的方法加以判断:显示数字较大的就是火线,显示数字较小的就是零线。这种方法需要与所测量的线路或器件接触。 第二种方法: 不需要与所测量的线路或器件接触。将万用表打到AC2V挡,黑表笔悬空,手持红表笔使笔尖沿线路轻轻滑动,这
[测试测量]
电工数字万用表这<font color='red'>四种</font><font color='red'>方法</font>太巧秒了
浅析51单片机IO口的四种使用方法
传统51单片机IO接口只可以作为标准双向IO接口,如果用其来驱动LED只能用灌电流的方式或是用三极管外扩驱动电路。 灌电流方式:LED正极接VCC,负极接IO口。IO为高电平是LED两极电平相同,没有电流,LED熄灭;IO为低电平时,电流从VCC流入IO,LED点亮。但是当你吧LED正极接在IO接口,负极接GND时,将IO接口置于高电平,LED会亮,但因为IO接口上拉能力不足而使亮度不理想,可以用下面介绍的方式解决这个问题。 推挽工作方式:LED正负极分别接在两个IO口上,然后设置正极IO接口为推挽输出,负极IO接口为标准双向灌电流输入。推挽方式具有强上拉能力,可以实现高电平驱动LED。 IO口的四种使用方法 从
[单片机]
浅析51单片机IO口的<font color='red'>四种</font>使用<font color='red'>方法</font>
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved