为什么I2C上接了多个光交接设备上的模块,就不能工作

& & I2C总线定义I2C(&intel&&-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。在主从通信中,可以有多个I2C总线器件同时接到I2C总线上,通过地址来识别通信对象。
& & I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既可以是主控器(或被控器),又可以是发送器(或接收器),这取决于它所要完成的功能。
& & Arduino通讯命令见网址:,我通过这次IIC通讯实验把这10个I2C通讯命令全部应用到了。
& & 我现在采用老版本A rduino-0018编程,老版本I2C通讯的发送数据命令是send(),接受数据命令是receive(),最新版本Arduino 1.0的发送数据的命令是write(),接受数据的命令是read(),这一点要注意啊,看清楚自己下载应用的是什么版本的Arduino编程软件。Arduino程序下载地址:
& & &I2C实验说明:&主机向从机循环发送字符串&light is &和字节x,x为1或0,从机接收后,把数据显示在它的串口监视器中,如上图。然后当主机通知从机向它上传数据时,会把x值再上传回主机,然后赋值给变量c。当主机程序判断c为1,则点亮主机数字端口13相连的LED,否则熄灭LED。
& & 通过这个实验把主从机之间的双向通讯都诠释出来了。
实验全景图:
& & 把双Arduino控制器的SCL和SDA以及GND三根引脚用杜邦线相连,如果不是两个Arduino分别独立供电,您就要把双Arduino控制器的VCC也连一起,它们共用一个电源。这次实验就是把这四根线SCL和SDA以及GND、VCC都互连起来了。Arduino的SCL引脚位于模拟端口5,SDA引脚位于模拟端口4。
& &Arduino控制器源于DFRobot官方网址:
注意:由于&单三角括号&里的内容,博客里显示不出来,所以我把头文件声明命令&被迫&进行了修改,以便在博客里看到头文件,例如改成&#include 《Wire.h&&。
Arduino主机程序:(与I2C通讯相关的命令用蓝色标注)
&/*主机向从机循环发送字符串&light is &和字节x,x为1或0
从机接收到主机发来的数据后,当主机通知从机向它上传数据时
会把x值再上传回主机,然后赋值给变量c。
当主机程序判断c为1,则点亮LED,否则熄灭LED。*/
#include 《Wire.h&//声明I2C库文件
#define LED 13
byte x = 0;//变量x决定LED的亮灭
void setup()
& Wire.begin(); // 加入 i2c 总线,作为主机
&&pinMode(LED,OUTPUT);//设置数字端口13为输出
void loop()
& Wire.beginTransmission(4); //发送数据到设备号为4的从机
& Wire.send(&light is &); & & & &// 发送字符串&light is &
& Wire.send(x); & & & & & & &// 发送变量x中的一个字节 &
& Wire.endTransmission(); & &// 停止发送
& x++;//变量x加1
& if(x==2)//如果变量x的值为2,则把x值转为0
& delay(1000);//延时1s
& Wire.requestFrom(4, 1); & &//通知4号从机上传1个字节
& while(Wire.available()&0) & &// 当主机接收到从机数据时
& & byte c = Wire.receive(); //接收一个字节赋值给c
& & //判断c为1,则点亮LED,否则熄灭LED。
& & if(c==1)
& & {digitalWrite(LED,LOW);}
& & &{digitalWrite(LED,HIGH);}
& delay(1000);//延时1s
Arduino从机程序:(与I2C通讯相关的命令用蓝色标注)
/*循环接收主机发送来的数据包,同时显示在串口监视器上
把数据包的最后一个字节,再上传回主机
#include 《Wire.h&//声明I2C库文件
//变量x值决定主机的LED是否点亮
void setup()
& Wire.begin(4); & & & & & & & &// 加入 i2c 总线,设置从机地址为 #4
& Wire.onReceive(receiveEvent); //注册接收到主机字符的事件
& Wire.onRequest(requestEvent); // 注册主机通知从机上传数据的事件
& Serial.begin(9600); & & & & & //设置串口波特率
void loop()
& delay(100);//延时
// 当从机接收到主机字符,执行该事件
void receiveEvent(int howMany)
& while( Wire.available()&1) // 循环执行,直到数据包只剩下最后一个字符
& & char c = Wire.receive(); // 作为字符接收字节
& & Serial.print(c); & & & & // 把字符打印到串口监视器中
& &//接收主机发送的数据包中的最后一个字节
& x = Wire.receive(); & &// 作为整数接收字节
& Serial.println(x); & &//把整数打印到串口监视器中,并回车&
//当主机通知从机上传数据,执行该事件
void requestEvent()
& //把接收主机发送的数据包中的最后一个字节再上传给主机
& Wire.send( x); // 响应主机的通知,向主机发送一个字节数据
& &我通过这次I2C通讯实验把这10个Arduino的I2C通讯命令全部应用到了,仔细看实验程序注释,并实践一次,就可以了解这Arduino控制器的I2C命令如何应用了。
源程序请下载:
& &&在数字通信各种协议中,相对Ethernet, USB, SATA, PCI-Express等传输速度达数百上千兆字节每秒的总线,I2C和SPI常称为&小&协议。但是,我们不能忘记的是各种总线的用途是什么。&大&协议是用于系统外的整个系统之间通信的,&小&协议是用于系统内各芯片间的通信,没有迹象表明&大&协议有必要取代&小&协议。I2C和SPI的存在和流行体现了&够用就好&的哲学。
与非门科技(北京)有限公司 All Rights Reserved.
京ICP证:070212号
北京市公安局备案编号: 京ICP备:号i2c-gpio设备读写问题 - OMAP-L138 DSP+ARM(R) - 德州仪器在线技术支持社区
i2c-gpio设备读写问题
发表于3年前
<input type="hidden" id="hGroupID" value="19"
我在开发板上测试I2C设备的时候总是读写不成功,我参考的内核board-da850-evm.c里的i2c设备信息I2C_BOARD_INFO(&tps6507x&, 0x48) &I2C_BOARD_INFO(&&a href=&.cn/product/cn/tlv320aic23& target=&extwin&>tlv320aic23&/a>&, 0x1A),分别测试了这两个设备,但是读写失败,我打开的是i2c-1总线,i2c-0总线打不开,应该是没有编译进内核。下面是我测试是串口打印出的消息:&/p>
&p>please input slave addr:0x1A&/p>
&p>input slave addr is:0x1a&br>please input reg addr:0x0200&/p>
&p>input reg addr is:0x200&br>input command,optional only within:&#39;1&#39;,&#39;2&#39;,&#39;3&#39;,&#39;0&#39;.&br>3&br>write i2c testi2c i2c-1: sendbytes: NAK bailout.&/p>
&p>write -1 byte at 0x200&br>23 bytes write success&br>bad command&/p>&div style=&clear:&>&/div>" />
i2c-gpio设备读写问题
此问题尚无答案
All Replies
我在开发板上测试I2C设备的时候总是读写不成功,我参考的内核board-da850-evm.c里的i2c设备信息I2C_BOARD_INFO(&tps6507x&, 0x48) &I2C_BOARD_INFO(&&, 0x1A),分别测试了这两个设备,但是读写失败,我打开的是i2c-1总线,i2c-0总线打不开,应该是没有编译进内核。下面是我测试是串口打印出的消息:
please input slave addr:0x1A
input slave addr is:0x1aplease input reg addr:0x0200
input reg addr is:0x200input command,optional only within:&#39;1&#39;,&#39;2&#39;,&#39;3&#39;,&#39;0&#39;.3write i2c testi2c i2c-1: sendbytes: NAK bailout.
write -1 byte at 0x20023 bytes write successbad command
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
举人1760分
#1:确实你I2C设备地址,你板子上的I2C设备和DA850-EVM上的不同的话,那就要在你调用的函数中修改I2C设备的地址了。
#2:我看你想访问I2C设备的0X200地址,你确认这个地址是有效的?
#3:I2C设备的地址通常用7个bit来表示,在SCL的第八个脉冲期间,SDA为低电平,并在时钟的高电平期间保持住,这时为&写&,反之为&读&。这里有个参数转化的问题,要看具体的函数要你传参用是7bit的地址,还是8bit的读写地址。
write i2c testi2c i2c-1: sendbytes: NAK bailout.
#4:对于I2C-1,提示没有收到ACK验证,即NOACK,这个很可能是地址不对。在SCL的第9个脉冲期间,从设备拉低SDA,并在SCL的高电平期间保持住,这就是一个确认ACK,否则就是NOACK。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
我查了下,板子上的设备接的的I2C0,而我在测试程序里只能打开/dev/i2c-1,不能打开/dev/i2c-0,我觉得这个i2c-1应该指的是i2c-gpio模拟总线,我想是不是就是这个的问题?
至于#2,我试过了很多地址,结果都一样,所以不存在这个问题。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
举人1760分
#1:你的板子接的是I2C0,你的内核当中有I2C0的驱动吗?别人板子上用的是GPIO模拟的I2C,你板子上用是真正的I2C,物理连接都不同,那驱动肯定不同啊
#2:这个地址不知道你怎么理解的,如果我没理解错的话,应该是CODEC当中寄存器的地址,在有效的范围内才能做测试,但目前来看主要问题先不在这里。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
&我的GPIO1[4],GPIO1[5]模拟i2c总线,设备也是接在这个总线上的,物理连接应该是相同的吧
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
举人1760分
你用的是IO模拟I2C,你现在Linux内核当中运行的驱动和你当前的硬件匹配吗?板子是你自己设计的?驱动也是你自己编写的吗?
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
i2c的gpio口模拟的驱动在linux中是现成的,就叫i2c-gpio.c
你搜下内核,有用这个驱动的例子,你要做的就是menuconfig中使能这个功能,然后platform架构声明一个设备,用来传递gpio,然后设备和驱动名对应上,自然这个i2c bus上就能用这个了吧?
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
你说得很有道理,之前似乎陷入了一个误区。一般的gpio引脚模拟i2c和特殊的gpio引脚复用为i2c总线引脚应该是两回事吧?我把这两者搞混淆了。怎么在platform_device中申明24lc64这个设备呢?网上找不到类似的例程。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
举人1760分
例程当中GPIO引脚和楼主自身的GPIO引脚很可能不一致,至少应该修改下例程中的这部分,在编译吧
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
板子是自己设计的,驱动内核中有。gpio1[4] gpio1[5]本来就可以复用为i2c0引脚,这个是真实的i2c总线,而不是模拟的i2c总线,是不是这样的呢?
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
修改了呀,但是把gpio1[4] gpio1[5]引脚修改成gpio2[14] gpio2[15]后,向总线发数据,总线上检测不到信号。而把它改成gpio1[2] gpio1[3]后,是可以正常读数据的,因为gpio1[2] gpio1[3]与gpio1[4] gpio1[5]一样,都是可以复用为i2c0总线的两个引脚。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.连接多个相同地址I2C设备的C51程序 - 51单片机 - 电子工程世界网
连接多个相同地址I2C设备的C51程序
10:29:05来源: eefocus 关键字:&&&&
本人初学C,曾为这个问题大伤脑筋^_^,就是一个系统有两个以上的的,无法用两个同一对SDA/SCL引脚# "stc.h"& &#include ".h"&&&&&sbit scl0=P3^5;& &sbit sda0 = P3^4;& &sbit scl1= P3^3;& &sbit sda1 = P3^2;& &//这里只写了两个I2C设备,如果需要可以再加上 sbit scl2= sbit sda2= 实际上多个设备的scl脚可以共用&&&&unsigned&char&iic_delay_e = 8;& &&&&scl(device,ve);& &void&sda(device,value);& &bit sdasense(char&device);& &&&// delay&&&void&iic_delay(unsigned&char&m)& &{& && &&unsigned&char&n;& && &&for(n=0;n<m;n++);& &}& &&&//&&&void&scl(device,value)& &{& && &&if&(device==0)& && &&&//设备1&&&& && &&&scl1=& && &&if&(device==1)& && &&&//设备2&&&& && &&&scl2=& &}& &void&sda(device,value)& &{& && &&if&(device==0)& && &&&//设备1&&&& && &&&sda1=& && &&if&(device==1)& && &&&//设备2&&&& && &&&sda2=& &}& &&&bit sdasense(char&device)& &{& &switch(device)& && & {& && && &&&case&1:&urn&sda1;& && && && && && && && &&&case&2:&return&sda2;& && && && && && && & }& &}& &&&//启动I2C的函数,当scl为高电平时使sda一个负跳变&&&&void&iic_start(device)& &{& && & sda(device,1);& && & scl(device,1);& && & iic_delay(iic_delay_time);& && & sda(device,0);& && & iic_delay(iic_delay_time);& && & scl(device,0);& && & iic_delay(iic_delay_time/2);& &}& &&&//终止I2C总线,当scl为高电平时使sda产生一个正跳变&&&void&iic_stop(device)& &{& && & scl(device,0);& && & sda(device,0);& && & scl(device,1);& && & iic_delay(iic_delay_time);& && & sda(device,1);& && & iic_delay(iic_delay_time);& &}& &&&//发送应答信号&&&void&iic_ack(device) {& && & sda(device,0);& && & scl(device,1);& && & scl(device,0);& && & sda(device,1);& &}& &&&//发送无应答信号&&&void&iic_noack(device)& &{& && & sda(device,1);& && & scl(device,1);& && & scl(device,0);& &}& &&&//检测应答信号&&&bit iic_testack(device)& &{& && && && &//真确应答,返回0&&&& & sda(device,1);& && & iic_delay(iic_delay_time);& && & scl(device,1);& && & iic_delay(iic_delay_time);& && & errorbit=sdasense(device);& && & scl(device,0);& && & iic_delay(iic_delay_time);& && &&return(errorbit);& &}& &&&//发送一个字节&&&void&iic_write8bit(device,unsigned&char&input)& &{& && &&unsigned&char&& && &&for(temp=0;temp<8;temp++)& && & {& && && &&&if((input<<temp)&0x80)& && && && && &sda(device,1);& && && &&&e&&& && && && &sda(device,0);& && && &&&scl(device,1);& &&&& && &&&iic_delay(iic_delay_time);& && && &&&scl(device,0);& && & }& &}& &&&//读一个字节&&&unsigned&char&iic_read8bit(device)& &{& && &&unsigned&char&temp,rbyte=0;& && &&for(temp=0;temp<8;temp++)& && & {& && && &&&scl(device,1);& && && &&&iic_delay(iic_delay_time);& && && &&&if(sdasense(device))& && && && && &rbyte=(rbyte<<1)+1;& && && &&&else&&& && && && &rbyte=rbyte<<1;& && && &&&scl(device,0);& && & }& && &&return(rbyte);& &}& &&&
关键字:&&&&
编辑:什么鱼 引用地址:
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。
微信扫一扫加关注 论坛活动 E手掌握
微信扫一扫加关注
芯片资讯 锐利解读
热门关键词
大学堂最新课程
汇总了TI汽车信息娱乐系统方案、优质音频解决方案、汽车娱乐系统和仪表盘参考设计相关的文档、视频等资源
热门资源推荐
频道白皮书
何立民专栏
北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。同一I2C总线下,接两个设备,不能识别问题。 - 我的提问 -
中国电子技术论坛 -
最好最受欢迎电子论坛!
后使用快捷导航没有帐号?
同一I2C总线下,接两个设备,不能识别问题。
15:31:28  
Linux系统,同一I2C总线下接了音频与RTC设备,单个测试都能正常工作,但全接上就只有音频能正常工作,RTC设备则不能识别了。 求教大神!
Powered by
供应链服务
商务及广告合作
Jeffery Guo
关注我们的微信
供应链服务 PCB/IC/PCBA
版权所有 (C) 深圳华强聚丰电子科技有限公司2048人阅读
linux下i2c驱动笔记
1.&几个基本概念
1.1.&设备模型
由&总线()&设备()&驱动()&组成,在该模型下,所有的设备通过总线连接起来,即使有些设备没有连接到一根物理总线上,为其设置了一个内部的、虚拟的总线,用以维持总线、驱动、设备的关系。
因此,对于实现一个下的设备驱动,可以划分为两大步:
1、设备注册;
2、驱动注册。
当然,其中还有一些细节问题:
1、驱动的函数
2、驱动和设备是怎么进行绑定的。
1.2.&i2c设备驱动的几个数据结构
i2c_adapter:
每一个对应一个物理上的控制器,在总线驱动函数中动态创建。通过注册到。
i2c_algorithm:
i2c_algorithm中的关键函数,以为单位产生访问需要的信号。不同的平台所对应的是不同的,需要根据所用平台的硬件特性实现自己的方法以填充的指针;在上即是函数。
i2c_client:
代表一个挂载到总线上的从设备,包含该设备所需要的数据:
该从设备所依附的控制器&struct&i2c_adapter&*adapter
该从设备的驱动程序
该i2c从设备的访问地址addr,&name
该i2c从设备的名称。
2.&i2c总线驱动
2.1.&功能划分
从硬件功能上可划分为:控制器和外设(从设备)。每个控制器总线上都可以挂载多个外设。中对控制器和外设分开管理:通过&i2c-sun6i.c&文件完成了控制器的设备注册和驱动注册;通过i2c-core.c为具体的外设提供了统一的设备注册接口和驱动注册接口,它分离了设备驱动和硬件控制的实现细节(如操作的寄存器)。
2.2.&i2c-sun6i.c
该文件是与具体硬件平台相关的,对应于系列芯片。该文件实际上是总线驱动的实现,本质上就是向内核注册总线设备、注册总线驱动、实现总线传输的时序控制算法。控制器被注册为设备,如下:
if&(twi_used_mask &&TWI0_USED_MASK) platform_device_register(&sun6i_twi0_device);&if(twi_used_mask &&TWI1_USED_MASK) platform_device_register(&sun6i_twi1_device);&if(twi_used_mask &&TWI2_USED_MASK) platform_device_register(&sun6i_twi2_device);&if(twi_used_mask &&TWI3_USED_MASK) platform_device_register(&sun6i_twi3_device);&if(twi_used_mask)&return&platform_driver_register(&sun6i_i2c_driver);
需要注意的是:设备与驱动的对应关系是多对一的;即如果设备类型是一样的,会共用同一套驱动,因此上面代码只是注册了一次驱动platform_driver_register(&sun6i_i2c_driver)。&
设备注册:
将控制器设备注册为设备,为每一个控制器定义一个struct&platform_device数据结构,并且把.name都设置为(后面会通过名字进行匹配驱动的),然后是调用将设备注册到上。
设备注册完成后其直观的表现就是在文件系统下出现:
通过进行的注册过程,说到底就是对struct&platform_device这个数据结构的更改,逐步完成.dev.parent、、的赋&#20540;,然后将加入到的链表上。
驱动注册:
步骤和设备注册的步骤类&#20284;,也是为驱动定义了一个数据结构:
struct&platform_driver&sun6i_i2c_
因为一个驱动是可以对应多个设备的,而在系统里的个控制器基本上是一致的(区别就是寄存器的地址不一样),所以上面注册的个设备共享的是同一套驱动。
设备与驱动匹配
1.match过程
i2c_add_driver--&i2c_register_driver--&i2c_bus_type--&.match-&i2c_device_match--&of_driver_match_device/i2c_match_id(比较i2c_driver-&id_table-&name和client-&name,如果相同,则匹配上,匹配上之后,运行driver_register调用driver_probe_device进行设备与驱动绑定。),
2.probe过程
初始化和函数,然后调用i2c_add_driver进行驱动注册。主要函数调用流程:
i2c_add_driver--&i2c_register_driver&--&&driver_register&--&&bus_add_driver&--&&driver_attach--&driver_probe_device--&really_probe(里面讲设备的驱动指针指向驱动,如果匹配成功,执行dev-&bus-&probe即设备驱动里的probe),--&driver_bound(绑定)
需要注意的是,这个函数遍历了总线上()的所有设备,寻找与驱动匹配的设备,并把满足条件的设备结构体上的驱动指针指向驱动,从而完成了驱动和设备的匹配(函数完成)。
如果匹配到设备,这时就需要执行的函数,最终会调用设备驱动的函数()。
2.2.1&&sun6i_i2c_probe
在函数中完成了大量的工作,包括硬件初始化、中断注册、为每个控制器创建等。
1268&pdata = pdev-&dev.platform_1269&if&(pdata ==&NULL) {1270&return&-ENODEV;1271}12721273&res = platform_get_resource(pdev, IORESOURCE_MEM,&0);1274&irq = platform_get_irq(pdev,&0);1275&if&(res == NULL || irq &&0) {1276&return&-ENODEV;1277}12781279&if&(!request_mem_region(res-&start, resource_size(res), res-&name)) {1280return&-ENOMEM;1281&}
首先得到当前设备的私有数据指针,并将其保留在;进而通过platform_get_resource得到该设备占用的内存资源,并申请:。同时将irq资源也保留下来。&
12881289&strlcpy(i2c-&adap.name,&&sun6i-i2c&,&sizeof(i2c-&adap.name));1290&i2c-&adap.owner =&THIS_MODULE;1291&i2c-&adap.nr = pdata-&bus_1292&i2c-&adap.retries =3;1293&i2c-&adap.timeout =&5*HZ;1294&i2c-&adap.class&= I2C_CLASS_HWMON |I2C_CLASS_SPD;1295&i2c-&bus_freq = pdata-&1296&i2c-&irq =&1297&i2c-&bus_num = pdata-&bus_1298&i2c-&status =&I2C_XFER_IDLE;1299&i2c-&suspended =0;1300&spin_lock_init(&i2c-&lock);1301&init_waitqueue_head(&i2c-&wait);
初始化,并初始化一个工作队列&。&通过申请资源;通过申请资源,中断的处理服务函数是:;sun6i_i2c_hw_init,对控制进行硬件初始化;i2c-&adap.algo&=&&sun6i_i2c_algorithm,初始化控制器的总线传输算法,设备驱动调用;将初始化好的注册到:。
至此,函数完成。
2.2.2&&sun6i_i2c_core_process
i2c控制器的中断服务程序调用了,总线的实际传输控制也是在该函数里完成的。
主要流程:
读取控制器当前状态,,保留在中;根据的&#20540;进行分支跳转,控制的工作状态;传输完成,调用,唤醒工作队列。
2.2.3&&sun6i_i2c_xfer
每一个控制器设备,在驱动绑定后,都会创建一个,用以描述该控制器,的建立与初始化是在驱动的时候建立的。每一个包含了一个结构体的指针,是用来对外提供操作控制器的函数接口的,主要是函数,对应于,实际就是:
static&int&sun6i_i2c_xfer(struct&i2c_adapter *adap,&struct&i2c_msg *msgs,&int&num)
该函数的功能是通知需要对外设进行数据交换,需要交换的信息通过传入。实际上是调用了进行传输。
因为总线读写速率有限,启动传输后,通过进入休眠,直到中断唤醒或者超时;中断唤醒是由完成的。
3.&i2c设备驱动
3.1.&驱动注册
i2c从设备的驱动注册,使用的是提供的接口:;其调用如下:
i2c_register_driver&--&&driver_register&--&&bus_add_driver;
对进行分析:
关于数据结构的&
设备驱动模型是通过对设备驱动进行层次管理的,因此应该包含成员,是将包含在中,再在中包含;我们可以理解是的私有数据,由内核进行操作。
struct&driver_private&是在驱动注册的开始,动态申请,并初始化的。
klist_init(&priv-&klist_devices,&NULL,&NULL);
初始化设备链表,每一个与该驱动匹配的都会添加到该链表下。
priv-&kobj.kset&=&bus-&p-&drivers_
指定该驱动所属的;
kobject_init_and_add
初始化,并将添加到其对应的集合中(即)。
该函数最终是调用将添加到对应的中;需要主要的是,如果的如果为,在此会将其设置为所属集合的:
parent&=&kobject_get(&kobj-&kset-&kobj);
接下来是为创建文件夹:;从而能从目录下显示。
driver_attach,将驱动和设备进行绑定
将遍历总线上的设备链表,查找可以匹配的设备,并绑定。
driver_attach&--&&&bus_for_each_dev(drv-&bus,&NULL,&drv,&__driver_attach);
将函数指针传入,将每个查找得到的进行驱动匹配。
bus_for_each_dev:
遍历总线上的所有设备,因为总线上的设备都是链表上的一个节点,因此该函数其实就是对链表的遍历,具体可以参考。
__driver_attach(源码位置):
进行设备和驱动匹配,如果匹配成功,尝试进行绑定。
1. 首先进行匹配确认:;
调用关系:&
--&&&of_driver_match_device
&&i2c_match_id
可以看出,最终有两种方式进行驱动匹配查询:
方法一:通过对比;
方法二:通过对比;
方法二实际上就是对比
i2c_driver-&id_table-&name&和是否一致。
2. 如果匹配确认,进行驱动与设备绑定:;
调用关系:&
&--&&dev-&bus-&probe
&&&&driver_bound
在中,首先将设备的驱动指针指向该驱动:。
对应于,即是:,最终调用驱动的函数。
最后是,将驱动与设备进行绑定:
其实就是调用:将设备节点添加到驱动的
调用,将被注册的驱动添加到总线的上;
klist_add_tail(&priv-&knode_bus,&&bus-&p-&klist_drivers);
&module_add_driver(drv-&owner,&&drv)
在创建目录
3.2.&设备注册
方式一:设备动态发现注册
在的最后:
INIT_LIST_HEAD(&driver-&clients);&i2c_for_each_dev(driver, __process_new_driver);
观察i2c_for_each_dev:&
int&i2c_for_each_dev(void&*data,&int&(*fn)(struct&device *,&void&*)){&int& mutex_lock(&core_lock); res&= bus_for_each_dev(&i2c_bus_type, NULL, data, fn); mutex_unlock(&core_lock);&return&}
其实就是遍历总线上的链表,对得到的每一个,执行。&
i2c_detect实现了设备发现:在注册驱动后,通过检测是否有适合的设备连接在总线上。实现如下:
在每一个上遍历驱动给出的地址列表(),由函数完成;最终会调用(即设备驱动提供的设备发现函数);如果发现满足条件的设备,执行i2c_new_device,为设备建立;并且将设备添加到链表上(),通过函数完成,最后调用,尝试绑定驱动。将添加到驱动的设备链表上:list_add_tail(&client-&detected,&&driver-&clients)
方式二:设备之静态注册
Linux&3.3&提供了静态定义的方式来注册设备,接口原型:linux-3.3/drivers/i2c/i2c-boardinfo.c
int&__initi2c_register_board_info(int&busnum,&struct&i2c_board_info&const&*info, unsigned len)
核心内容:&
申请,用以描述一个外设;list_add_tail(&devinfo-&list,&&__i2c_board_list),将加入链表,以供后续查找;
扫描,创建
i2c_register_board_info只是把设备描述符加入到了__i2c_board_list,并没有创建,当调用注册时,会扫描,创建;具体调用:
i2c_register_adapter&
--&&i2c_scan_static_board_info&
--&&i2c_new_device&
--&&device_register
在&完成了创建,以及设备注册。
由上面的注册流程可知,i2c_register_board_info应该在i2c_register_adapter之前完成,否则中的节点不会被扫描到。
由上述分析可知,设备驱动是通过i2c_register_driver注册的,设备是通过i2c_new_device注册的,在最后,这两个函数都尝试进行驱动和设备绑定(driver_attach和);因此不管是先注册驱动还是先注册设备,最后都能够将合适的驱动和设备进行绑定。
有两种方式进行设备注册:
1、通过i2c_register_board_info,在系统启动之初静态地进行设备注册(电源驱动就是这样做的);
2、实现设备驱动的函数,在驱动加载的时候动态检测创建设备,平台的触摸屏驱动就是通过这种方式。
Linux是通过在驱动数据结构中内嵌、,完成了设备驱动的层次管理的,理解、对理解设备驱动模型很重要。
4.&i2c驱动架构图
1、i2c_add_adapter
2、i2c_new_device/i2c_register_board_info
3、i2c_add_driver
4、调用中注册的函数进行匹配
5、调用中注册的函数进行匹配
6、i2cdev_attach_adapter
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:48749次
排名:千里之外
转载:58篇
(1)(1)(1)(1)(2)(1)(8)(1)(6)(3)(9)(1)(1)(1)(6)(8)(2)(3)(3)(6)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 考勤系统连接不上设备 的文章

 

随机推荐