Linux I2C(一)之常用的几种实例化(i2c_client )
Linux下I2C驱动介绍
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协议详解
I2C(Inter-Integrated Circuit)协议是一种双向串行总线,也称作IIC、TWI(Two-Wire Interface)或SMBus(System Management Bus),由Philips公司于1982年开发,用来连接多个微处理器和其它通信芯片。
I2C协议有两根线,分别是SCL(时钟线)和SDA(数据线),使用双线的好处就是只要两根线就可以完成数据传输,而不需要增加额外的线路,能够大大减少系统所需要的线路,减少系统的复杂度和成本。
I2C协议需要一个主控制器来控制整个系统,主控制器通过SCL线来发送时钟,并通过SDA线来发送和接收数据,从控制器则只负责接收数据。
I2C协议有7个基本信号,START、STOP、ACK、NACK、READ、WRITE和REPEAT START,START在传输数据前发出,STOP则在传输结束后发出,ACK和NACK则用来表示接收方是否正确接收到数据,READ和WRITE则用来指示当前传输的数据是读数据还是写数据,REPEAT START则用来重新开始新一轮的传输。
I2C协议的最大优点是简单、易用,而且可以支持多个从控制器,不过它的缺点也是显而易见的,它的传输速度相对较慢,而且它的传输距离也有限,约在50cm左右。
I2C详解——精选推荐
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总线原理及应用实例
I2C总线原理及应用实例I2C总线是一种串行通信总线,全称为Inter-Integrated Circuit,是Philips(飞利浦)公司在1982年推出的一种通信协议。
它可以用于连接各种集成电路(Integrated Circuits,ICs),如处理器、传感器、存储器等。
I2C总线的原理是基于主从架构。
主设备(Master)负责生成时钟信号,并发送和接收数据,从设备(Slave)通过地址识别和响应主设备的命令。
I2C总线使用两根线来传输数据,一根是时钟线(SCL),用于主设备生成的时钟信号;另一根是数据线(SDA),用于双向传输数据。
1. 主设备发送起始位(Start)信号,将SDA线从高电平拉低;然后通过SCL线发送时钟信号,用于同步通信。
2.主设备发送从设备的地址,从设备通过地址识别确定是否响应。
3.主设备发送要传输的数据到从设备,从设备响应确认信号。
4. 主设备可以继续发送数据,或者发送停止位(Stop)信号结束通信。
停止位是将SDA线从低电平拉高。
1.温度监测器:I2C总线可以连接到温度传感器上,通过读取传感器的输出数据,进行温度的监测和控制。
主设备可以设置警报阈值,当温度超过阈值时,可以触发相应的措施。
2.显示屏:很多智能设备上的显示屏都采用了I2C总线,如液晶显示屏(LCD)或有机发光二极管(OLED)等。
主设备通过I2C总线发送要显示的信息,并控制显示效果,如亮度、对比度、清晰度等参数。
3.扩展存储器:I2C总线可以用于连接外部存储器,如电子存储器(EEPROM)。
通过I2C总线,可以读取和写入存储器中的数据,实现数据的存储和传输。
4.触摸屏控制器:许多触摸屏控制器也使用了I2C总线,主要用于将触摸信号传输给主设备,并接收主设备的命令。
通过I2C总线,可以实现对触摸屏的操作,如单击、滑动、缩放等。
5.电源管理器:一些电源管理器也采用了I2C总线,用于控制和监测电池电量、充电状态、电压、电流等参数。
linux系统i2c协议详解
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通信原理及程序详细讲解
I2C通信原理及程序详细讲解I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于连接微控制器、传感器和其他外部设备。
I2C通信协议由荷兰飞利浦公司于1982年开发,它使用两根信号线(SDA和SCL)进行数据传输。
I2C通信协议采用主从结构,一个主设备(如微控制器)可以连接多个从设备(如传感器)。
主从设备之间通过SDA和SCL线进行数据传输。
SDA线是双向数据线,用于传输数据,SCL线是时钟线,用于同步数据传输。
I2C通信协议中,设备的地址是一个重要概念。
每个设备都有一个唯一的地址,通过该地址可以选择和通信特定的设备。
地址由7个位组成,其中最高位是固定的,并取决于设备是主设备还是从设备。
如果最高位为0,则表示该设备是主设备;如果最高位为1,则表示该设备是从设备。
通过以下步骤,让我们详细了解如何在I2C总线上进行通信。
1.初始化I2C总线:在程序开始时,需要初始化I2C总线。
这通常包括初始化SDA和SCL引脚,设置时钟频率等。
具体的初始化步骤取决于使用的硬件和软件环境。
2.发送开始信号:开始信号表示I2C数据传输的开始。
它由主设备发送,并且SDA线从高电平转为低电平时发出。
发送开始信号后,SDA线上的数据将被解释为地址数据。
3.发送设备地址:主设备发送一个包含设备地址和读/写位(R/W)的数据字节。
设备地址是唯一的,并且由主设备选择。
读/写位指示从设备是要读取数据还是写入数据。
4.等待从设备响应:主设备发送设备地址后,会等待从设备的响应。
从设备将响应一个应答位(ACK)来确认地址接收成功。
如果收到ACK位,则继续进行下一步,否则可能是设备未连接或通信错误。
5.发送数据:主设备发送数据给从设备。
数据可以是命令、配置或实际数据,具体取决于应用场景。
发送数据的方式是将每个数据字节传输到SDA线上,并在每个数据字节后发送一个ACK位。
6.接收数据:从设备将数据发送给主设备。
数据可以是传感器读数、存储器数据等。
i2c驱动传入probe的参数解释
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函数的函数指针。
I2C的原理与应用
I2C的原理与应用I2C(Inter-Integrated Circuit)是一种串行通信协议,由飞利浦公司于1980年代开发,用于在数字电子系统中连接各个芯片。
它主要使用两根线进行通信,即SDA(Serial Data Line,串行数据线)和SCL (Serial Clock Line,串行时钟线),同时支持多主机和多从机的通信方式。
I2C协议被广泛应用于各种数字设备的互连,包括传感器、存储器、协处理器等。
I2C的通信原理如下:1.总线结构:I2C总线包含一个主机和多个从机。
主机负责控制总线,并发起数据传输请求;从机等待主机发送命令,并根据命令执行相应操作。
2.时序:I2C总线上的通信需要依靠时钟信号进行同步。
主机通过时钟信号SCL驱动数据传输。
数据线SDA上的数据在时钟信号的上升沿或下降沿进行采样和发送。
3.起始和停止位置:数据传输始于主机发送一个起始信号,结束于主机发送一个停止信号。
起始信号通知所有从机总线上的数据传输即将开始;停止信号表示数据传输已经结束。
4.地址与数据传输:在起始信号之后,主机发送一个地址帧给从机。
地址帧的最高位表示读写操作,从机通过地址帧判断自身是否为数据传输的对象,并相应地进行操作。
主机可以在同一个传输过程中多次发送数据,并且可以从一个从机读取多个字节的数据。
I2C的应用广泛,以下是一些常见的应用领域:1.传感器:I2C通信协议在许多传感器和芯片中得到应用,例如加速度计、陀螺仪、温度传感器和压力传感器等。
这些传感器通过I2C协议与主处理器进行通信,并将采集到的数据传输到主处理器进行处理。
2. 存储器:I2C接口也广泛应用于存储器设备,如EEPROM (Electrically Erasable Programmable Read-Only Memory)和FRAM (Ferroelectric Random Access Memory)。
这些存储器设备可以通过I2C总线进行读写操作,从而存储和检索数据。
I2C实例解析
实例解析linux内核I2C体系结构(1)一、概述谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完成。
下面比较下这两种驱动。
第一种方法的好处(对应第二种方法的劣势)有:●思路比较直接,不需要花时间去了解linux内核中复杂的I2C子系统的操作方法。
第一种方法问题(对应第二种方法的好处)有:●要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器操作;●要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写出的程序可移植性差;●对内核的资源无法直接使用。
因为内核提供的所有I2C设备器及设备驱动都是基于I2C子系统的格式。
I2C适配器的操作简单还好,如果遇到复杂的I2C适配器(如:基于PCI的I2C适配器),工作量就会大很多。
本文针对的对象是熟悉I2C协议,并且想使用linux内核子系统的开发人员。
网络和一些书籍上有介绍I2C子系统的源码结构。
但发现很多开发人员看了这些文章后,还是不清楚自己究竟该做些什么。
究其原因还是没弄清楚I2C子系统为我们做了些什么,以及我们怎样利用I2C子系统。
本文首先要解决是如何利用现有内核支持的I2C适配器,完成对I2C设备的操作,然后再过度到适配器代码的编写。
本文主要从解决问题的角度去写,不会涉及特别详细的代码跟踪。
二、I2C设备驱动程序编写首先要明确适配器驱动的作用是让我们能够通过它发出符合I2C标准协议的时序。
在Linux内核源代码中的drivers/i2c/busses目录下包含着一些适配器的驱动。
如S3C2410的驱动i2c-s3c2410.c。
当适配器加载到内核后,接下来的工作就要针对具体的设备编写设备驱动了。
编写I2C设备驱动也有两种方法。
一种是利用系统给我们提供的i2c-dev.c来实现一个i2c 适配器的设备文件。
然后通过在应用层操作i2c适配器来控制i2c设备。
i2c_register_driver函数详解
i2c_register_driver函数详解在嵌入式软件开发中,I2C(Inter-Integrated Circuit)总线是一种常用的串行通信接口,用于在微控制器和外部设备之间传输数据。
i2c_register_driver函数是Linux内核中一个重要的函数,用于注册I2C 驱动程序。
本文将详细解析i2c_register_driver函数的功能、参数和应用。
一、i2c_register_driver函数概述i2c_register_driver函数是在Linux内核中注册一个I2C驱动程序的函数。
它的作用是将驱动程序与对应的I2C适配器绑定,使得操作系统能够正确地识别和管理该驱动程序。
在驱动程序注册后,当相应的I2C设备连接到系统时,驱动程序将会自动加载并为该设备提供服务。
二、i2c_register_driver函数参数i2c_register_driver函数包含一个结构体参数,该结构体用于指定驱动程序的相关信息和功能。
1. struct i2c_driverstruct i2c_driver是一个定义I2C驱动程序的结构体,包含了以下重要的成员:- .driver:指向内核的struct device_driver结构体,用于描述驱动程序的信息,如名称、文件操作方法等。
- .probe:指向I2C设备探测函数的指针,用于在设备连接时进行初始化和配置。
- .remove:指向I2C设备移除函数的指针,用于在设备断开连接时进行清理和释放资源。
- .id_table:指向I2C设备ID表的指针,用于匹配设备和驱动程序。
2. I2C设备探测函数(probe函数)I2C设备探测函数是I2C驱动程序的核心功能之一,在I2C设备连接到系统时被调用。
该函数的作用是检测和初始化I2C设备,并将设备与驱动程序进行绑定。
在probe函数中,可以执行一系列必要的操作,如配置寄存器、分配内存、注册字符设备等。
i2c参数
i2c参数I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器和外部设备。
它是一种双线制通信协议,包括一个数据线(SDA)和一个时钟线(SCL),可以同时连接多个设备。
1. I2C的基本原理和工作方式:I2C协议由两根线组成:数据线(SDA)和时钟线(SCL)。
数据通过SDA线传输,时钟信号在SCL线上传输。
通信始终由主设备(通常是微控制器)控制,它生成时钟信号并发送或接收数据。
从设备被动地响应主设备的命令。
2. I2C的物理层和电气特性:I2C使用开漏输出(open-drain)架构,这意味着总线上的设备可以将线拉低(逻辑0),但无法将其拉高(逻辑1)。
线上有一个上拉电阻来提供默认的逻辑高电平。
因此,在总线空闲状态时,线上均为逻辑高电平。
3. I2C的地址格式和设备选择:I2C设备有7位或10位地址,其中7位地址是最常见的。
每个设备必须有唯一的地址。
主设备通过发送设备地址来选择特定的从设备进行通信。
4. I2C的数据传输模式:I2C支持两种数据传输模式:字节传输模式和块传输模式。
字节传输模式下,每次传输只发送一个字节的数据。
块传输模式下,可以发送多个字节的数据,最多达到32字节。
5. I2C的起始和停止条件:通信开始时,主设备发送起始条件(start condition),即在SCL为高电平时,SDA从高电平下跳到低电平。
通信结束时,主设备发送停止条件(stop condition),即在SCL为高电平时,SDA从低电平上跳到高电平。
起始和停止条件用于标识通信的开始和结束。
6. I2C的速度选择:I2C支持不同的速度选择,可根据实际需求进行配置。
常用的速度包括标准模式(100 kbps)、快速模式(400 kbps)和高速模式(3.4 Mbps)。
7. I2C的应用:I2C广泛用于连接各种外部设备,如传感器、显示屏、存储器、扩展模块等。
它也被用于构建复杂的系统,如工业自动化系统、嵌入式系统和消费电子产品等。
linux i2c注册流程
linux i2c注册流程Linux I2C注册流程I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接在计算机系统中的多个外部设备。
在Linux系统中,I2C总线的设备驱动程序通过I2C核心子系统进行注册和管理。
本文将介绍Linux I2C注册流程的具体步骤,帮助读者了解Linux系统中I2C设备的注册过程。
1. 硬件连接和配置在开始之前,首先需要进行硬件连接以及相关I2C控制器的配置。
通常,I2C总线上的每个设备都有一个唯一的7位或10位地址。
在Linux系统中,I2C控制器通过设备树(Device Tree)或Platform数据结构进行配置。
根据硬件和芯片特定的要求,需要指定控制器的一些参数,例如时钟频率、地址模式等。
2. I2C核心子系统I2C核心子系统是Linux内核中用于管理I2C设备的模块,包含了驱动程序和各种API函数。
它将I2C设备的操作进行了抽象,并提供了一组统一的接口供驱动程序使用。
I2C核心的代码位于"drivers/i2c"目录下。
3. I2C驱动程序I2C设备驱动程序是一种与特定硬件相关的内核模块,用于与I2C设备进行通信和控制。
驱动程序的代码一般位于"drivers/i2c/busses"目录下。
Linux内核已经提供了一些通用的I2C驱动程序供使用,例如“i2c-gpio”用于模拟I2C总线。
4. I2C设备结构体在编写自定义I2C驱动程序之前,需要定义一个I2C设备结构体。
该结构体用于描述设备的各种属性,包括设备的名称、地址、信号模式以及设备特定的配置等。
通常可以基于设备树或Platform数据结构进行初始化。
5. I2C适配器I2C适配器是用于控制I2C设备的总线控制器。
在Linux系统中,每个适配器都对应一个I2C控制器,通过/sys/bus/i2c/devices目录进行管理。
适配器结构体定义了适配器和它管理的设备之间的关系。
Linux驱动之i2c用户态调用
一、概述I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.二、用户态实现设备驱动在Linux内核代码文件i2c-dev.c中实现了I2C适配器设备文件的功能,针对每个适配器生成一个主设备号为89的设备节点(次设备号为0-255),I2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read(),write(),和ioctl()等文件操作接口,在用户空间的应用层就可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。
i2c适配器的设备节点是/dev/i2c-x,其中x是数字。
由于适配器编号是动态分配的(和注册次序有关),所以想了解哪一个适配器对应什么编号,可以查看/sys/class/i2c-dev/目录下的文件内容。
三、用户态调用3.1、i2c-dev用户空间操作i2c,需要包含以下头文件。
打开适配器对应的设备节点i2c-dev为打开的线程建立一个i2c_client,但是这个i2c_client并不加到i2c_adapter的client链表当中。
他是一个虚拟的临时client,当用户打开设备节点时,它自动产生,当用户关闭设备节点时,它自动被释放。
3.2、ioctl()查看include/linux/i2c-dev.h文件,可以看到i2c支持的IOCTL命令1.#define I2C_RETRIES0x0701/*设置收不到ACK时的重试次数*/2.#define I2C_TIMEOUT0x0702/*设置超时时限的jiffies*/3.#define I2C_SLAVE0x0703/*设置从机地址*/4.#define I2C_SLAVE_FORCE0x0706/*强制设置从机地址*/5.#define I2C_TENBIT0x0704/*选择地址位长:=0for7bit,!=0for10bit*/6.#define I2C_FUNCS0x0705/*获取适配器支持的功能*/7.#define I2C_RDWR0x0707/*Combin ed R/W transfer(one STOP only)*/8.#define I2C_PEC0x0708/* !=0to use PEC with SMBus*/9.#define I2C_SMBUS0x0720/*SMBus transfer*/例如:1、设置重试次数:ioctl(fd, I2C_RETRIES,m);设置适配器收不到ACK时重试的次数为m。
i2c读写程序的详细讲解
i2c读写程序的详细讲解I2C即Inter-IntegratedCircuit(内部集成电路),是一种同步串行总线技术,它可以用来连接多个芯片,并使用它们之间的2条双向数据总线进行通信。
I2C总线可以通过5根线实现,其中2条用于数据传输,另外3条用于控制传输过程:SCL(时间同步线)、SDA(数据线)、VCC(电源线)。
I2C在光学芯片、DSP和ARM芯片等领域都得到了广泛应用,能够实现在一个系统或介质中共享数据,有助于节省系统开发成本和实现系统节能。
第二部分:I2C读写程序I2C读写程序是通过I2C总线实现数据读写的特定程序,主要由以下步骤构成:1、设置I2C总线:通过一系列硬件设置完成I2C总线的初始化,以满足对应数据读写的要求;2、发送I2C开始信号:在进行数据读写前,需要发送一个开始信号,以通知主从端可以进行通信;3、发送I2C地址:根据读写操作,发送I2C地址;4、发送I2C数据:根据读写操作,发送相关数据;5、接收I2C数据:根据读写操作,接收相关数据;6、发送I2C停止信号:发送I2C停止信号,结束数据读写过程。
第三部分:I2C读写程序实例下面以C语言为例,介绍在I2C通讯操作中读写程序的编写流程: 1、I2C总线的初始化:可以使用如下函数来设置I2C总线的参数,完成I2C总线的初始化:#include <linux/i2c.h>#include <linux/i2c-dev.h>int i2c_init (int busno);其中busno表示I2C总线号;2、发送I2C开始信号:可以使用如下函数来发送I2C开始信号:int i2c_smbus_write_start(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;3、发送I2C地址:可以使用如下函数来发送I2C地址:int i2c_smbus_write_byte(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;4、发送I2C数据:可以使用如下函数发送I2C数据:int i2c_smbus_write_byte_data(int busno, int addr, int data);其中busno表示I2C总线号,addr表示要发送的I2C地址,data 表示要发送的数据;5、接收I2C数据:可以使用如下函数接收I2C数据:int i2c_smbus_read_byte_data(int busno, int addr);其中busno表示I2C总线号,addr表示要读取的I2C地址;6、发送I2C停止信号:可以使用如下函数发送I2C停止信号:int i2c_smbus_write_stop(int busno);其中busno表示I2C总线号;第四部分:结论以上就是I2C读写程序的详细讲解,可以看出,I2C读写程序的实现步骤非常简单,只需要对每个步骤做出正确的设置,就可以实现I2C数据读写操作。
LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)
LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)⼀. Linux I2C驱动架构Linux内核⾥,I2C驱动框架可以分为两层,adapter驱动和deivce驱动。
Adapter驱动也可以理解为I2C总线驱动,指的是SOC⾥的I2C控制器驱动。
⼀个SOC可能包含多个I2C控制器,⽽每个控制器的使⽤⽅式是相同的(寄存器参数、收发数据的⽅法等),因此多个控制器可以共⽤⼀套adapter驱动;Deivce驱动,对应的是SOC外围的I2C设备,不同类型I2C设备需要开发不同的设备驱动,同⼀类型的I2C设备可以使⽤⼀种驱动,但是每⼀个I2C设备都由⼀个唯⼀的client来描述。
⼆. Adapter配置DTSI⽂件(kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi)描述了RK3399Pro所有的I2C控制器信息:i2c0: i2c@ff3c0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3c00000x00x1000>;clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c0_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c1: i2c@ff110000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1100000x00x1000>;clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c1_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c2: i2c@ff120000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1200000x00x1000>;clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c2_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c3: i2c@ff130000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1300000x00x1000>;clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c3_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c5: i2c@ff140000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1400000x00x1000>;clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c5_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c6: i2c@ff150000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1500000x00x1000>;clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c6_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c7: i2c@ff160000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1600000x00x1000>;clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c7_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c4: i2c@ff3d0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3d00000x00x1000>;clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c4_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c8: i2c@ff3e0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3e00000x00x1000>;clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c8_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};可以看出,该SOC共有9个I2C控制器,分别为I2C0~I2C8, 每个控制器对应了不同的寄存器基地址(例如I2C0对应0xff3c0000),它们的compatible匹配属性都是"rockchip,rk3399-i2c",也就是对应了同⼀个adapter驱动。
i2c协议
i2c协议I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在电子设备之间进行数据传输。
它由Philips公司于1982年开发,后来成为通用的面向数据传输的协议。
I2C协议是一种主从式的协议,允许一个主设备与多个从设备进行通信。
I2C协议的设计目标是提供简单、高效、可靠的数据传输。
它使用两根线(SDA和SCL)进行双向传输。
SDA线用于数据传输,SCL线用于时钟同步。
在传输过程中,主设备负责控制时钟信号,从设备根据时钟信号进行数据的读取和写入。
I2C协议的操作流程如下:1. 主设备发送起始信号(Start):当主设备要与从设备通信时,它先发送一个低电平的起始信号。
这告诉所有从设备,通信即将开始。
2. 主设备发送设备地址+读/写位:主设备发送从设备地址,并确定通信是读操作还是写操作。
设备地址由7位组成,可以支持最多128个不同的从设备。
3. 从设备响应:当从设备检测到设备地址匹配时,它发送一个应答信号(ACK)。
如果没有从设备响应,则表示该设备不存在或无法访问。
4. 数据传输:主设备发送或接收数据。
如果是写操作,主设备发送数据到从设备;如果是读操作,主设备接收从设备发送的数据。
每发送或接收一个字节,需要等待从设备发送一个应答信号。
5. 主设备停止信号(Stop):当通信完成时,主设备发送一个高电平的停止信号。
这告诉所有从设备,通信已经结束。
I2C协议的特点之一是可以实现多主设备的通信。
多主设备通信时,需要主设备之间进行仲裁,以决定哪个主设备有权控制总线。
I2C使用仲裁位(Arbitration)来实现主设备之间的冲突检测和冲突解决。
在I2C协议中,从设备的寻址方式有两种:7位寻址和10位寻址。
7位寻址模式支持最多128个从设备,10位寻址模式支持最多1024个从设备。
另一个重要的概念是数据传输速率(Bit Rate)。
I2C支持多个数据传输速率,从几千位每秒到几百千位每秒不等。
i2c的原理及应用
i2c的原理及应用1. 什么是i2ci2c(Inter-Integrated Circuit)是一种通信协议,用于在集成电路之间进行数据传输。
它是一种串行通信协议,通常用于连接多个集成电路芯片,如传感器、显示屏等。
2. i2c的工作原理i2c协议使用两根信号线进行通信:主机发送数据的SDA线和控制信号的SCL 线。
通信是通过主机发起传输并选择从机设备进行通信。
下面是i2c传输的步骤:1.主机发送起始位:主机将SDA线从高电平拉低,然后拉低SCL线。
2.主机发送设备地址和读写位:主机将设备地址和读写位发送到SDA线上,并拉高SCL线。
3.主机等待从机响应:主机等待从机设备响应,响应由SDA线上的电平状态决定。
4.传输数据:主机和从机设备之间可以传输数据,每次传输都由主机提供时钟信号。
5.主机发送停止位:主机将SDA线从低电平拉高,然后拉高SCL线,表示传输结束。
3. i2c的应用领域i2c通信协议在许多电子设备中被广泛应用,以下是一些常见的应用领域:3.1 传感器i2c协议非常适合连接各种类型的传感器,包括温度传感器、湿度传感器、压力传感器等。
它能够提供高速、可靠的数据传输,方便将传感器模块集成到各种电子设备中。
3.2 显示屏i2c协议也可以用于连接显示屏,如液晶显示屏和OLED显示屏等。
通过i2c总线,可以通过发送指令和数据,控制显示屏的亮度、对比度、内容等。
3.3 存储设备i2c协议还可以用于连接存储设备,如EEPROM、Flash存储器等。
通过i2c总线,可以读取和写入存储设备中的数据,方便进行配置和数据存储。
3.4 工业自动化i2c通信协议在工业自动化领域也有广泛的应用。
它可以用于传输传感器数据、控制器之间的通信、参数配置等。
3.5 嵌入式系统i2c协议在嵌入式系统中也被广泛使用。
它可以用于连接各种外设,如键盘、鼠标、音频设备等,实现嵌入式系统的功能扩展。
4. i2c的优点i2c通信协议具有以下几个优点:•多设备连接i2c支持多个设备通过同一条总线进行通信,简化了设备之间的连接,降低了硬件成本。
I2C详细介绍及编程
I2C详细介绍及编程I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于连接微控制器、传感器、存储器等设备,以实现数据通信。
本文将详细介绍I2C的原理、特点以及编程。
一、I2C的原理和特点I2C协议由飞利浦(Philips)公司于1982年开发,旨在简化数字电路上周边设备的通信。
I2C使用两条线(SCL和SDA)进行数据传输,其中SCL是时钟线,SDA是数据线。
这种双线式的通信使得I2C可以同时进行数据传输和电源供给,极大地简化了设备之间的连接。
在I2C通信中,主设备(通常是微控制器)发起通信,而从设备被动应答。
主设备通过在SCL线上产生时钟信号来控制通信节奏,并通过SDA 线实现数据传输。
数据的传输可以是单向的(主设备向从设备发送数据)或双向的(主设备与从设备之间的双向数据传输)。
I2C协议中的从设备通过一个唯一的地址来识别和寻址。
主设备可以选择与一个或多个从设备进行通信,只需发送相应的地址即可。
在开始通信前,主设备会发送一个开始信号,然后跟着从设备地址和读写位,然后才是数据或命令。
从设备在收到自己地址后会发出应答信号,主设备接收到应答信号后才会继续发送数据。
通信结束后,主设备会发送停止信号。
I2C的特点包括:1.双向通信:主设备和从设备之间可以进行双向的数据传输,减少通信线的需求和复杂度。
2.主-从结构:I2C通信中有一个主设备控制通信的发起和终止,而从设备被动应答。
3.多从结构:主设备可以与多个从设备进行通信,只需要发送不同的地址。
4.低速传输:I2C通信的时钟频率相对较低,一般在100kHz或400kHz。
二、I2C的编程实现在进行I2C编程之前,需要确保硬件上有I2C接口。
常见的I2C接口引脚包括SCL(时钟线)和SDA(数据线),同时需要进行相应的电源连接。
I2C编程的具体实现会有所差异,根据不同的硬件平台和编程语言而有所不同。
以下是一个基于Arduino平台的简单示例:```cpp#include <Wire.h>#define DEVICE_ADDRESS 0x50void setuWire.begin(;Serial.begin(9600);void loo//发送命令Wire.beginTransmission(DEVICE_ADDRESS);Wire.write(0x00); // 使用写入地址0x00Wire.write(0x01); // 写入数据0x01Wire.endTransmission(;delay(100);//读取数据Wire.requestFrom(DEVICE_ADDRESS, 1);if (Wire.available()int data = Wire.read(;Serial.print("Received: ");Serial.println(data);}delay(1000);```上述示例代码中,我们使用Wire库来实现I2C通信。
linux i2c 读写函数
linux i2c 读写函数I2C(Inter-IntegratedCircuit)是一种串行通信协议,用于连接低速外设,例如传感器、LCD屏幕和EEPROM等。
在Linux中,I2C 驱动程序提供了一组函数,用于读写I2C设备。
以下是一些常用的I2C读写函数:1. i2c_smbus_read_byte_data()该函数用于从I2C设备中读取一个字节的数据。
它的参数包括I2C设备的地址、寄存器地址和一个标志,用于指示是否使用PMBus 协议。
函数返回读取的字节数据。
2. i2c_smbus_write_byte_data()该函数用于向I2C设备写入一个字节的数据。
它的参数包括I2C 设备的地址、寄存器地址和写入的数据。
函数返回0表示成功,否则表示失败。
3. i2c_smbus_read_word_data()该函数用于从I2C设备中读取两个字节的数据。
它的参数包括I2C设备的地址、寄存器地址和一个标志,用于指示是否使用PMBus 协议。
函数返回读取的两个字节数据。
4. i2c_smbus_write_word_data()该函数用于向I2C设备写入两个字节的数据。
它的参数包括I2C 设备的地址、寄存器地址和写入的数据。
函数返回0表示成功,否则表示失败。
5. i2c_transfer()该函数用于进行I2C总线数据传输。
它的参数包括一个指向i2c_msg结构体数组的指针,每个i2c_msg结构体表示一次数据传输。
函数返回传输的i2c_msg结构体数量。
以上是一些常用的I2C读写函数,可以根据需要选择适当的函数进行使用。
在使用这些函数时,应该注意设备的地址、寄存器地址和传输的数据等参数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
* struct i2c_board_info - template for device creation * @type: chip type, to initialize i2c_ * @flags: to initialize i2c_client.flags * @addr: stored in i2c_client.addr * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node * @acpi_node: ACPI device node * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's * a device at a given address. Drivers commonly need more information than * that, such as chip type, configuration, associated IRQ, and so on. * * i2c_board_info is used to build tables of information listing I2C devices * that are present. This information is used to grow the driver model tree. * For mainboards this is done statically using i2c_register_board_info(); * bus numbers identify adapters that aren't yet available. For add-on boards, * i2c_new_device() does this dynamically with the adapter already known. */ struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; void *platform_data; struct dev_archdata *archdata; struct device_node *of_node; struct acpi_dev_node acpi_node; int irq; }; i2c_register_board_info: /** * i2c_register_board_info - statically declare I2C devices * @busnum: identifies the bus to which these devices belong * @info: vector of i2c device descriptors * @len: how many descriptors in the vector; may be zero to reserve * the specified bus number. * * Systems using the Linux I2C driver stack can declare tables of board info * while they initialize. This should be done in board-specific init code * near arch_initcall() time, or equivalent, before any I2C adapter driver is * registered. For example, mainboard init code could define several devices,
方一:
使用 arch/arm/mach-s3c24xx/mach-mini2440.c 举例: static struct i2c_board_info mini2440_i2c_devs[] __initdata = { { /* 遇到与”24c08 一样的名称”的驱动就会与之绑定, 0x50 是 I2C 设备的地址 */ I2C_BOARD_INFO("24c08", 0x50), .platform_data = &at24c08, }, }; /* 这里的 0 代表:i2c-0 总线 */ i2c_register_board_info(0, mini2440_i2c_devs, ARRAY_SIZE(mini2440_i2c_devs)); 到这里我们可以说就完成了第一种方式的实例化。 使用 i2c_register_board_info 去实例化必须知道我们使用的 I2C 设备是挂载到哪个总线 上,并知道设备的地址。 在 Linux 启 动 的 时 候 会 将 信 息 进 行 收 集 , i2c 适 配 器 会 扫 描 已 经 静 态 注 册 的 i2c_board_info,通过调用 i2c_register_board_info 函数将包含所有 I2C 设备的 i2c_board_info 信息的 i2c_devinfo 变量加入到__i2c_board_list 链表中,并调用 i2c_new_device 为其实例化 一个 i2c_client。在驱动加载的时候遇到同名的 i2c_board_info 就会将 i2c_client 和 driver 绑 定,并且执行 driver 的 probe 函数。 这种方式一般放在平台的代码中。 struct i2c_board_info : /**
方式三:
如果连 i2c 设备的地址不知道,我们可以提供一个地址列表供系统探测。 使用 drivers/media/pci/bt8xx/bttv-input.c 举例: /* Instantiate the I2C IR receiver device, if present */ void init_bttv_i2c_ir(struct bttv *btv) {
方式二:
使用 arch/arm/mach-ux500/board-mop500-uib.c 举例: void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info, unsigned n) { struct i2c_adapter *adap; struct i2c_client *client; int i; /* 获得一个总线,当然必须知道我们设备要挂载在哪个总线上,busnum 就是总线编号 */ adap = i2c_get_adapter(busnum); if (!adap) { pr_err("failed to get adapter i2c%d\n", busnum); return; } for (i = 0; i < n; i++) { /* 将 i2c_board_info 所描述的器件与适配器进行关联,并实例化 i2c_client */ client = i2c_new_device(adap, &info[i]); if (!client) pr_err("failed to register %s to i2c%d\n", info[i].type, busnum); } /* 与 i2c_get_adapter 对应,释放资源 */ i2c_put_adapter(adap); } 别忘了在注销驱动或者出错的情况下调用 i2c_unregister_device(struct i2c_client *client) 去释放资源。 这种方式与方式一的差别是不需要在编译内核的时候就要知道设备挂载哪个总线上、 设 备的地址是什么。灵活性变强了。
* as could the init code for each daughtercard in a board stack. * * The I2C devices will be created later, after the adapter for the relevant * bus has been registered. After that moment, standard driver model tools * are used to bind "new style" I2C drivers to the devices. The bus number * for any device declared using this routine is not available for dynamic * allocation. * * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. */ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { int status; down_write(&__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); if (!devinfo) { pr_debug("i2c-core: can't register boardinfo!\n"); status = -ENOMEM; break; } devinfo->busnum = busnum; devinfo->board_info = *info; list_add_tail(&devinfo->list, &__i2c_board_list); } up_write(&__i2c_board_lock); return status; }