Linux_I2C总线分析(主要是probe的方式)1
- 格式:doc
- 大小:468.00 KB
- 文档页数:8
1、I2C概述I2C是philips公司提供的外设总线,I2C有两条数据线,一条是串行数据线SDA、一条是时钟线SCL,使用SDA和SCL实现了数据的交换,便于布线。
I2C总线方便用在EEPROM、实时钟、小型LCD等与CPU外部的接口上。
2、Linux下的驱动思路Linux系统下编写I2c驱动主要有两种方法:一种是把I2C当做普通字符设备来使用;另一种利用Linux下驱动的体系结构来实现。
第一种方法:优点:思路比较直接,不用花费大量时间去了解Linux系统下I2C体系结构缺点:不仅对I2C设备操作要了解,还有了解I2C的适配器操作不仅对I2C设备器和设备操作需要了解,编写的驱动移植性差,内核提供的I2C设备器都没有用上。
第二种方法:第一种的优点就是第二种的缺点,第一种的缺点就是第二种的优点。
3、I2C框架概述Linux的I2C体系结构分为3部分:1)I2C核心I2C核心提供了I2C总线驱动和设备驱动的注册和注销的方法,I2C 通信方法(algorithm)上层,与具体适配器无关的代码,检测设备上层的代码等。
2)I2C总线驱动I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可以直接受CPU来控制。
3)I2C设备驱动I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备端挂在受CPU控制的适配器上,通过I2C适配器与CPU交换数据。
Linux下的I2C体系结构:1)Linux下的I2C体系结构4、I2C设备驱动编写方法首先让我们明白适配器驱动的作用是让我们能够通过它发出标准的I2C时序,在linux内核源代码中driver/I2C/buss包含一些适配器的驱动,例如s3c2410的驱动I2C-s3c2410.c,适配器被加载到内核中,接下的任务就是实现设备驱动的编写。
编写设备驱动的方法主要分为两种方法:第一种:利用设备提供的I2C-dev.c来实现I2C适配器设备文件,然后通过上层应用程序来操作I2C设备器来控制I2C设备。
I2C串行总线的组成及工作原理I2C是一种常用的串行通信协议,用于在电子设备之间进行数据传输。
它的全称是Inter-Integrated Circuit,即片间串行总线。
1. 主设备(Master Device):负责发起通信请求并控制整个传输过程的设备。
主设备通常是微控制器、处理器或其他智能设备。
2. 从设备(Slave Device):被主设备控制的设备。
从设备可以是各种外围设备,如传感器、存储器、显示器等。
3. SDA(Serial Data Line):用于数据传输的双向串行数据线。
主设备和从设备都可以发送和接收数据。
4. SCL(Serial Clock Line):用于同步数据传输的时钟线。
主设备产生时钟信号来同步数据传输。
5. VCC(Supply Voltage):提供电源电压给I2C总线上的设备。
6. GND(Ground):提供共地连接。
I2C总线的工作原理如下:1.初始化:主设备发起一次总线初始化,在I2C总线上产生一个启动信号。
启动信号表示I2C总线上有新的数据传输将开始。
2.寻址:主设备发送一个7位的设备地址到总线上指定要与之通信的从设备。
I2C总线上可以存在多个从设备,每个设备都有唯一的地址。
3.数据传输:主设备发送数据或者命令到从设备,或者从设备向主设备发送数据回复。
数据通过SDA线传输,时钟通过SCL线提供。
4.确认(ACK):数据传输完成后,每个接收设备都会回复一个确认信号,表示它已经成功接收数据。
主设备和从设备都可以发送确认信号。
5.停止:主设备发送一个停止信号来结束一次数据传输过程。
停止信号表示I2C总线上没有更多的数据传输。
I2C总线的工作原理是基于主从结构的,主设备控制数据传输的流程。
主设备通过发送启动信号来开始一个数据传输过程,并通过发送设备地址和数据来与特定的从设备进行通信。
通过SCL线的时钟同步,主设备和从设备可以准确地进行数据传输,避免了数据丢失和冲突。
i2cdetect的用法-回复标题:[i2cdetect的用法]详解i2cdetect是一款在Linux系统中广泛使用的命令行工具,用于检测I2C 总线上的设备。
本文将详细解释i2cdetect的用法,并通过一些实例演示如何使用这个工具。
一、了解I2C总线和i2cdetectI2C(Inter-Integrated Circuit)是一种串行通信协议,允许微控制器和其他设备之间的简单双向通信。
I2C总线上可以连接多个设备,每个设备都有一个唯一的地址。
i2cdetect是I2C调试工具的一部分,可以用来扫描I2C总线并显示出所有连接到该总线的设备及其地址。
二、安装i2cdetect在大多数Linux发行版中,i2cdetect已经预装。
如果没有预装,可以通过包管理器进行安装。
例如,在Debian和Ubuntu上,可以使用以下命令进行安装:sudo apt-get install i2c-tools三、使用i2cdetect1. 打开终端,输入以下命令以获取系统的I2C总线列表:ls /dev/i2c*输出可能类似于:/dev/i2c-0, /dev/i2c-1等。
2. 使用i2cdetect扫描特定的I2C总线。
例如,要扫描/dev/i2c-0总线,输入以下命令:sudo i2cdetect -y 0其中,“-y”选项表示即使总线未被分配也要强制访问,后面的数字“0”表示要扫描的I2C总线。
3. 在扫描完成后,i2cdetect会显示一个表格,其中列出了所有连接到指定I2C总线的设备及其地址。
例如,输出可能如下所示:0 1 2 3 4 5 6 7 8 9 a b c d e f00:10:20:30:40:50: UU UU UU UU UU UU UU UU60:70:在这个例子中,“UU”表示该地址没有设备响应,而空白则表示该地址有设备存在但没有被探测到。
四、解读i2cdetect的输出i2cdetect的输出是一个16x16的表格,每行代表一个八位的十六进制地址。
I2C详解1、基本概念主机初始化发送,产⽣时钟信号和终⽌发送的器件从机被主机寻址的器件发送器发送数据到总线的器件接收器从总线接收数据的器件多主机同时有多于⼀个主机尝试控制总线但不破坏报⽂仲裁是⼀个在有多个主机同时尝试控制总线,但只允许其中⼀个控制总线并使报⽂不被破坏的过程同步两个或多个器件同步时钟信号的过程2、硬件结构每⼀个I2C总线器件内部的SDA、SCL引脚电路结构都是⼀样的,引脚的输出驱动与输⼊缓冲连在⼀起。
其中输出为漏极开路的场效应管、输⼊缓冲为⼀只⾼输⼊阻抗的同相器。
这种电路具有两个特点:(1)由于SDA、SCL 为漏极开路结构,借助于外部的上拉电阻实现了信号的“线与”逻辑;(2)引脚在输出信号的同时还将引脚上的电平进⾏检测,检测是否与刚才输出⼀致。
为“时钟同步”和“总线仲裁”提供硬件基础。
3、时钟同步如果从机希望主机降低传送速度可以通过将SCL主动拉低延长其低电平时间的⽅法来通知主机,当主机在准备下⼀次传送发现SCL的电平被拉低时就进⾏等待,直⾄从机完成操作并释放SCL线的控制控制权。
这样以来,主机实际上受到从机的时钟同步控制。
可见SCL 线上的低电平是由时钟低电平最长的器件决定;⾼电平的时间由⾼电平时间最短的器件决定。
这就是时钟同步,它解决了I2C总线的速度同步问题。
4、主机发送数据流程(1)主机在检测到总线为“空闲状态”(即SDA、SCL 线均为⾼电平)时,发送⼀个启动信号“S”,开始⼀次通信的开始(2)主机接着发送⼀个命令字节。
该字节由7 位的外围器件地址和1 位读写控制位R/W 组成(此时R/W=0)(3)相对应的从机收到命令字节后向主机回馈应答信号ACK(ACK=0)(4)主机收到从机的应答信号后开始发送第⼀个字节的数据(5)从机收到数据后返回⼀个应答信号ACK(6)主机收到应答信号后再发送下⼀个数据字节(7)当主机发送最后⼀个数据字节并收到从机的ACK 后,通过向从机发送⼀个停⽌信号P结束本次通信并释放总线。
I2C总线简介1.概述:I²C是Inter-Integrated Circuit的缩写,发音为"eye-squared cee" or"eye-two-cee", 它是一种两线接口。
I²C 只是用两条双向的线,一条 Serial Data Line (SDA) ,另一条Serial Clock (SCL)。
SCL:上升沿将数据输入到每个EEPROM器件中;下降沿驱动EEPROM器件输出数据。
(边沿触发)SDA:双向数据线,为OD门,与其它任意数量的OD与OC门成"线与"关系。
2.输出级每一个I2C总线器件内部的SDA、SCL引脚电路结构都是一样的,引脚的输出驱动与输入缓冲连在一起。
其中输出为漏极开路的场效应管,输入缓冲为一只高输入阻抗的同相器,这种电路具有两个特点:1)由于SDA、SCL为漏极开路结构(OD),因此它们必须接有上拉电阻,阻值的大小常为1k8, 4k7 and 10k ,但1k8 时性能最好;当总线空闲时,两根线均为高电平。
连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线"与"关系。
2)引脚在输出信号的同时还将引脚上的电平进行检测,检测是否与刚才输出一致,为"时钟同步"和"总线仲裁"提供了硬件基础。
3.主设备与从设备系统中的所有外围器件都具有一个7位的"从器件专用地址码",其中高4位为器件类型,由生产厂家制定,低3位为器件引脚定义地址,由使用者定义。
主控器件通过地址码建立多机通信的机制,因此I2C总线省去了外围器件的片选线,这样无论总线上挂接多少个器件,其系统仍然为简约的二线结构。
终端挂载在总线上,有主端和从端之分,主端必须是带有CPU的逻辑模块,在同一总线上同一时刻使能有一个主端,可以有多个从端,从端的数量受地址空间和总线的最大电容 400pF的限制。
linux系统i2c协议详解I2C总线概述I2C(两线接口)是一种串行通信协议,用于连接嵌入式系统中的集成电路(IC)。
它以其低成本、低功耗和高可靠性著称。
I2C总线需要两条双向信号线:串行数据线(SDA)和串行时钟线(SCL)。
这些信号线由一个主设备控制,可以与多个从设备通信。
I2C通信I2C通信由以下步骤组成:起始条件:主设备将SDA线下拉至低电平,同时保持SCL线为高电平。
设备地址:主设备发送7位或10位从设备地址,后跟一个读/写位。
数据传输:主设备和从设备交换数据。
停止条件:主设备将SDA线拉至高电平,同时保持SCL线为高电平。
主设备和从设备I2C总线上的设备分为两种:主设备和从设备。
主设备:发起通信并控制总线。
通常是主微控制器或处理器。
从设备:响应主设备请求并提供或接收数据。
可以是传感器、执行器或其他外围设备。
I2C寻址从设备通过唯一的7位或10位地址进行寻址。
地址的最高位表示是否可读/写,0表示写,1表示读。
I2C模式I2C协议支持以下模式:主写从读:主设备向从设备写入数据,然后从从设备读取数据。
主读从写:主设备从从设备读取数据,然后向从设备写入数据。
从读从写:两个从设备在主设备的监督下进行通信。
I2C传输速率I2C传输速率通常在10kbps到400kbps之间。
速率由主设备设置。
I2C错误检测I2C协议包含几个错误检测机制,例如校验和和超时。
这些机制有助于确保数据的可靠传输。
I2C应用I2C总线用于各种应用,包括:传感器和执行器接口EEPROM和闪存编程LED和LCD控制模拟-数字转换器(ADC)和数字-模拟转换器(DAC)接口电源管理时钟同步I2C优点I2C协议的优点包括:低成本:无需额外的硬件接口低功耗:仅使用两根信号线高可靠性:错误检测机制确保数据完整性容易使用:简单的协议易于实施广泛采用:支持广泛的设备和库I2C缺点I2C协议的缺点包括:数据速率低:与其他串行接口相比,数据速率较低主机限制:总线上只能有一个主设备总线无仲裁:在总线冲突的情况下,没有内置的仲裁机制有限的寻址范围:仅支持有限数量的设备地址I2C技术演进I2C协议正在不断发展,以满足新应用的需求。
I2C驱动传入probe的参数解释在进行I2C设备的驱动开发过程中,常常会涉及到I2C驱动的probe 函数。
probe函数是Linux内核驱动中的一种特殊函数,它在驱动被加载并且设备被检测到时被调用,用于初始化设备并注册设备驱动。
在编写I2C驱动的probe函数时,通常需要传入不同的参数进行配置和初始化。
本文将对I2C驱动传入probe的参数进行解释和说明,帮助读者更好地理解和使用I2C设备驱动。
1. struct i2c_client *client在I2C驱动的probe函数中,通常需要传入一个指向structi2c_client结构体的指针作为参数。
这个结构体是I2C设备在内核中的表示,包含了I2C设备的位置区域、总线信息、驱动信息等。
通过这个参数,我们可以获取I2C设备的各种信息,并进行相应的初始化和配置。
2. const struct i2c_device_id *id另一个常见的参数是一个指向const struct i2c_device_id结构体的指针,用于指定要注册的设备驱动的ID信息。
这个结构体中通常包含了设备的厂商ID、设备类型、设备名称等信息,用于匹配加载指定的设备驱动。
在probe函数中,我们可以使用这个参数来判断当前检测到的I2C设备是否匹配当前的驱动,从而进行相应的初始化和注册操作。
3. int (*probe)(struct i2c_client *client, const struct i2c_device_id *id)最后一个重要的参数是probe函数本身。
这个参数是一个函数指针,用于指定实际的probe函数的位置区域。
在probe函数中,我们可以根据传入的client和id参数,进行设备的初始化、资源的申请、注册设备驱动等操作。
通过这个函数指针参数,内核可以在加载驱动并检测到设备时正确地调用对应的probe函数。
I2C驱动传入probe的参数包括指向I2C设备结构体的指针、指向设备ID信息的指针以及probe函数的函数指针。
Linux I2C 总线浅析㈠ Overview内核空间层次!i2c adapter 是一个struct, 用来抽象一个物理i2c bus ,而且还和linux 设备驱动架构柔和在一起..如果只说硬件的话,就是在CPU内部集成的一个I2C控制器(提供给用户的就是那几个register),硬件上并没的所谓的adapter,client这些东东,,adapter和client都是linux 驱动软件抽象出来的东西资料帖子:i2c_algorithm {/* If an adapter algorithm can't do I2C-level access, set master_xferto NULL. If an adapter algorithm can do SMBus access, setsmbus_xfer. If set to NULL, the SMBus protocol is simulatedusing common I2C messages *//* master_xfer should return the number of messages successfullyprocessed, or a negative value on error */i nt (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);i nt (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data *data);/* To determine what the adapter supports */u32 (*functionality) (struct i2c_adapter *);};/** i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it.*/struct i2c_adapter {s truct module *owner;u nsigned int id;u nsigned int class; /* classes to allow probing for */c onst struct i2c_algorithm *algo; /* the algorithm to access the bus */v oid *algo_data;/* data fields that are valid for all devices */u8 level; /* nesting level for lockdep */s truct mutex bus_lock;i nt timeout; /* in jiffies */i nt retries;s truct device dev; /* the adapter device */i nt nr;c har name[48];s truct completion dev_released;};Linux的I2C体系结构分为3个组成部分:1·I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
这部分是与平台无关的。
2·I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现。
I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。
经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。
不同的CPU平台对应着不同的I2C总线驱动。
总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。
但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。
这部分在MTK 6516中是由MTK已经帮我们实现了的,不需要我们更改。
3· I2C设备驱动:I2C设备驱动是对I2C硬件体系结构中设备端的实现。
设备一般挂接在受CPU控制的I2C 适配器上,通过I2C适配器与CPU交换数据。
I2C设备驱动主要包含了数据结构i2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数。
在Linux内核源代码中的drivers 目录下的文件,实现了I2C适配器设备文件的功能,应用程序通过“i2c-%d”文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等来访问这个设备。
应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器并控制I2C设备的工作方式。
设备驱动则是与挂在I2C总线上的具体的设备通讯的驱动。
通过I2C总线驱动提供的函数,设备驱动可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备通讯。
这部分在MTK 6516中是由具体的设备实现的。
(比如camera)struct i2c_client:代表一个挂载到i2c总线上的i2c从设备,该设备所需要的数据结构,其中包括该i2c从设备所依附的i2c主设备 struct i2c_adapter *adapter 该i2c 从设备的驱动程序struct i2c_driver *driver 作为i2c从设备所通用的成员变量,比如addr, name等该i2c从设备驱动所特有的数据,依附于dev->driver_data下struct i2c_adapter:代表主芯片所支持的一个i2c主设备。
struct i2c_algorithm *algo:是该i2c主设备传输数据的一种算法,或者说是在i2c总线上完成主从设备间数据通信的一种能力。
Linux的i2c子系统新、旧架构并存。
主要分为旧架构(Legacy)也有人称之为adapter方式,和新的架构new-style的方式。
这俩者的区别主要在于设备注册和驱动注册的不同。
对于Legacy的设备注册是在驱动运行的时候动态的创建,而新式的new-style则是采用静态定义的方式。
注:MTK在版上用的是Legacy的架构,而在版上用的是new-style的架构。
(在这里我就只说明的new-style的实现方法)要完成I2C设备的驱动,我们可以分三步走:第一步:完成适配器的注册(总线);第二步:完成I2C client的设备注册(设备);第三步:完成I2C client驱动的注册(驱动);我们分别给予介绍:()⑴就总线而言,其本质只需要我们填充俩个结构体就可以了:i2c_adapter;i2c_algorithm;i2c_add_adapter(i2c->adap); 往总线上添加对应的适配器;struct i2c_adapter {struct module *owner;unsigned int id;unsigned int class; /* classes to allow probing for */const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data;/* --- administration stuff. */int (*client_register)(struct i2c_client *);int (*client_unregister)(struct i2c_client *);/* data fields that are valid for all devices */u8 level; /* nesting level for lockdep */struct mutex bus_lock;struct mutex clist_lock;int timeout; /* in jiffies */int retries;struct device dev; /* the adapter device */int nr; /*该成员描述了总线号*/struct list_head clients; /* i2c_client结构链表,该结构包含device,driver 和 adapter结构*/char name[48];struct completion dev_released;};static struct i2c_algorithm mt6516_i2c_algorithm = {.master_xfer = mt6516_i2c_transfer,.smbus_xfer = NULL,.functionality = mt6516_i2c_functionality,};2、设备注册第一步:记得以前的i2c设备驱动,设备部分喜欢驱动运行的时候动态创建,新式的驱动倾向于向传统的linux 下设备驱动看齐,采用静态定义的方式来注册设备,使用接口为:int __init i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len){int status;mutex_lock(&__i2c_board_lock);/* dynamic bus numbers will be assigned after the last static one */if (busnum >= __i2c_first_dynamic_bus_num)__i2c_first_dynamic_bus_num = busnum + 1;for (status = 0; len; len--, info++) {struct i2c_devinfo *devinfo;devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); */res = driver_register(&driver->driver);if (res)return res;pr_debug("i2c-core: driver [%s] registered\n", driver->;INIT_LIST_HEAD(&driver->clients);/* Walk the adapters that are already present */mutex_lock(&core_lock);bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);mutex_unlock(&core_lock);return 0;}设备和驱动的关联过程:首先当I2C从设备和I2C驱动如果处于同一条总线上,那么其在设备和驱动注册之后,将会促使I2C_bus_type中的match获得调用;()如下:struct bus_type i2c_bus_type = {.name = "i2c",.match = i2c_device_match,.probe = i2c_device_probe,.remove = i2c_device_remove,.shutdown = i2c_device_shutdown,.suspend = i2c_device_suspend,.resume = i2c_device_resume,};继续跟进i2c_device_match;i2c_match_id(driver->id_table, client) != NULL;我们回到i2c_device_probe;这个函数的关键是:status = driver->probe(client, i2c_match_id(driver->id_table, client));它将函数的流程交回到了driver->probe的手中;流程图:过程分享:1、设备和驱动的关联大家知道,对于一个驱动程序有两个元素不可或缺,即设备和驱动,一般驱动都是通过设备名和驱动名的匹配建立关系的,最开始我从代码中只能发现驱动的注册,却不见设备注册的踪影,令人疑惑,跟踪发现,在i2c adapter注册时会遍历i2c_board_info这样一个结构,而这个结构在29以前或更早的内核里是不存在的,它会完成驱动与设备的匹配问题,2、名字匹配一个i2c驱动是可以有多个名字的,即一个驱动程序可以支持多个设备,该机制是通过struct i2c_device_id实现的,驱动中建立这么一个结构体数组,i2c架构层便会扫描该数组,与设备名去匹配,匹配成功的都会进入相应probe函数。