i2c子系统
Linux I2C子系统
Linux I2C子系统一、硬件特性1.1 概述I2C总线是由Philips公司开发的两线式串行总线,这两根线为时钟线(SCL)和双向数据线(SDA)。
由于I2C总线仅需要两根线,因此在电路板上占用的空间更少,带来的问题是带宽较窄。
I2C在标准模式下传输速率最高100Kb/s,在快速模式下最高可达400kb/s。
属于半双工。
在嵌入式系统中,I2C应用非常广泛,大多数微控制器中集成了I2C总线,一般用于和RTC,EEPROM,智能电池电路,传感器,LCD以及其他类似设备之间的通信。
1.2 I2C总线传输时序1.3 I2C总线的信号状态1、空闲状态:SDA和SCL都是高电平;2、开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据;3、结束条件(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据;4、数据有效:在SCL的高电平期间,SDA保持稳定,数据有效。
SDA的改变只能发生在SCL的低电平期间;5、ACK信号:数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。
1.4 从设备地址I2C总线从设备使用7位地址,最后一个为读写控制位。
下图是eeprom的原理图,我们可以计算出它的地址为0x50。
1.5 I2C读写方式多字节写的时序多字节读的时序二、I2C子系统2.1 LinuxI2C子系统架构在内核中已经提供I2C子系统,所以在做I2C驱动之前,就必须要熟悉该子系统。
2.2 三大组成部分1、I2C核心(i2c-core)I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(algorithm)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
2、I2C总线驱动(I2Cadapter/Algo driver)I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力。
I2C工作原理范文
I2C工作原理范文I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在集成电路之间进行通信。
它由Philips公司(现在是恩智浦半导体公司)于1982年推出,并已广泛应用于各种电子设备和嵌入式系统中。
I2C的工作原理如下:1.总线拓扑结构:I2C使用两根线进行通信,一根是串行数据线(SDA),另一根是串行时钟线(SCL)。
所有I2C设备都连接到同一条总线上,并且每个设备都有一个唯一的7位地址。
2. 主从模式:I2C通信分为主设备(Master)和从设备(Slave)。
主设备是发起通信的一方,负责控制总线上的通信。
从设备则是被动接收和响应来自主设备的命令或数据。
3. 起始信号和停止信号:I2C通信始于主设备发送一个起始信号(Start)和一个从设备地址。
起始信号告诉所有从设备,接下来的通信将是针对一些特定从设备的。
停止信号(Stop)则标志着一次通信的结束。
4.寄存器读写:主设备通过发送一个从设备地址和一个读/写位来指定是读取还是写入数据。
在写入模式下,主设备发送数据字节到从设备;在读取模式下,主设备请求从设备发送数据字节。
5.硬件应答:在每个字节的传输结束后,接收方(主设备或从设备)都会返回一个应答位。
如果接收方成功接收到了字节,则返回一个低电平的应答位;否则,返回一个高电平的非应答位。
6.时钟同步:I2C通信的时钟由主设备控制。
主设备在SCL线上产生时钟信号,而从设备则根据这个信号来同步自己的时钟。
总的来说,I2C通信是通过主设备发起的,它控制总线上的通信流程和时钟信号。
从设备根据主设备发送的命令或数据来执行相应的操作,并通过应答位来确认是否成功接收到数据。
这种通信协议适用于多个设备之间进行简单的数据交换和控制操作。
I2C的优点是可以同时连接多个设备,并且只需要两根线就能实现通信。
这大大减少了总线的复杂性和成本。
同时,I2C还具有可靠性高、速度适中、容错能力强等特点,使得它成为了很多电子设备中主要的串行通信协议之一总之,I2C是一种简单、灵活且可靠的串行通信协议。
i2c的基本工作原理
I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在芯片之间进行数据传输。
它由飞利浦半导体(现在的恩智浦半导体)于1982年开发,并广泛应用于各种电子设备中。
I2C具有简单、高效和可靠的特点,成为众多芯片和模块之间常用的通信接口之一。
本文将详细介绍I2C的基本工作原理。
一、总线架构I2C采用了主从结构的总线架构,其中主设备(Master)负责发起数据传输请求,而从设备(Slave)则在接收到请求后进行响应。
一个I2C总线上可以连接多个从设备,每个从设备都有一个唯一的地址。
主设备通过发送起始信号(Start)来启动通信,然后选择要与之通信的从设备地址,最后发送停止信号(Stop)结束通信。
二、物理层I2C使用双线制进行数据传输,包括数据线(SDA)和时钟线(SCL)。
数据线上的信号是双向的,用于传输数据。
时钟线则由主设备控制,用于同步数据传输。
三、起始和停止信号I2C通信以起始信号(Start)和停止信号(Stop)来标识通信的开始和结束。
起始信号由主设备产生,它表示将要发起一次新的通信。
停止信号同样由主设备产生,表示一次通信的结束。
四、数据传输格式I2C采用了基于字节的数据传输格式。
每个字节都由8位二进制数据组成,包括7位数据位和1位数据方向位。
数据方向位为0表示发送数据,为1表示接收数据。
在每个字节的传输过程中,都会先发送数据方向位,然后再发送数据位。
五、时钟同步I2C使用时钟同步机制来确保通信的准确性。
时钟线由主设备产生,并控制整个数据传输过程的时序。
在每个时钟周期中,数据线上的数据必须稳定,并且只有在时钟线为低电平时才能改变。
六、地址传输在I2C通信中,每个从设备都有一个唯一的7位地址。
主设备通过发送地址来选择要与之通信的从设备。
地址由8个位组成,最高位是固定的0或1,用于表示读(1)或写(0)操作。
其余的7位用于指定从设备的地址。
七、数据传输流程I2C通信的数据传输流程如下:1. 主设备发送起始信号(Start)。
i2c的工作原理
i2c的工作原理1. 引言i2c是一种串行通信接口,被广泛应用于各种电子设备之间的通信。
本文将详细介绍i2c的工作原理。
2. i2c的概述i2c是Inter-Integrated Circuit的缩写,最早由飞利浦公司(现在的恩智浦公司)在1980年代开发并推出。
它采用2根传输线(即SDA和SCL),用于在多个设备之间进行数据传输。
i2c具有简单、低成本、高可靠性的特点,非常适合中小规模的系统集成。
3. i2c的物理层i2c的物理层采用比特传输技术,即通过不同电平来表示不同的值。
在i2c中,SDA线是串行数据线,SCL线是串行时钟线。
这两根线通过上拉电阻连接到VCC,通常在3V到5V之间。
3.1 时钟同步i2c通信采用主从模式,由一个主设备控制通信的起始和停止。
主设备通过控制SCL线的电平变化来同步通信。
当主设备将SCL线拉低时,通信开始;当主设备释放SCL线时,通信停止。
所有的从设备在SCL线上都能感知到这些时钟变化。
3.2 数据传输i2c的数据传输通过在SDA线上传输二进制数据来实现。
每个数据位都在SCL时钟的边沿传输,当时钟从低电平变为高电平时,数据被采样。
4. i2c的工作机制i2c的工作机制可以分为地址传输阶段和数据传输阶段。
4.1 地址传输阶段在i2c通信开始时,主设备首先发送一个地址和读/写位,用于指定要访问的从设备。
地址是从设备在总线上的唯一标识。
读/写位用于指示主设备是要将数据发送给从设备还是从从设备读取数据。
4.2 数据传输阶段在地址传输阶段之后,主设备和从设备可以进行数据传输。
数据传输可以分为两种模式:主设备发送数据和主设备读取数据。
4.2.1 主设备发送数据在主设备发送数据时,它将数据逐位地发送到SDA线上,并由SCL线上的时钟同步。
1.主设备拉低SDA线,将第一个数据位(即最高位)发送到总线上。
2.主设备通过改变SCL线的电平来同步通信。
3.从设备在SCL线的上升沿采样数据位。
文档:、linux-308内核I2C触摸屏移植
Linux3.0.8平台搭建移植文档——I2C触摸屏移植1.I2C子系统goodix电容屏采用I2C接口与处理器连接,我们要首先确保linux内核拥有对I2C子系统的支持,下面我们从子系统的配置和电容屏驱动两个方面进行移植修改1)配置I2C子系统支持#make menuconfigDevice Drivers ---><*> I2C support --->[*] Enable compatibility bits for old user-space (NEW)<*> I2C device interface< > I2C bus multiplexing support (NEW)[*] Autoselect pertinent helper modules (NEW)I2C Hardware Bus support --->进入I2C Hardware Bus support选项,选中以下内容:*** I2C system bus drivers (mostly embedded / system-on-chip) ***< > Synopsys DesignWare (NEW)<*> GPIO-based bitbanging I2C< > OpenCores I2C Controller (NEW)< > PCA9564/PCA9665 as platform device (NEW)<*> S3C2410 I2C Driver< > Simtec Generic I2C interface (NEW)...2.GOODIX电容屏移植1)添加goodix电容屏驱动将“goodix_touch.c”文件copy到drivers/input/touchscreen/目录下,并将"goodix_touch.h"、"goodix_queue.h"文件copy到include/linux/目录下,并修改Kconfig文件及Makefile文件支持触摸屏驱动的配置和编译#vi driver/input/touchscreen/Kconfig在config TOUCHSCREEN_TPS6507X选项的后面添加以下内容:config TOUCHSCREEN_GOODIXtristate "GOODIX based touchscreen"depends on I2ChelpIt is a android driver to support Gooidx's touchscreen whose nameis guitar on s5pv210 platform. The touchscreen can support multi-touch not more than two fingers.Say Y here to enable the driver for the touchscreen on theS5V SMDK board.If unsure, say N.To compile this driver as a module, choose M here:the module will be called goodix_touch.ko.#vi driver/input/touchscreen/Makefile在文件最后添加如下内容:obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_touch.o2)添加i2c_board_info资源(电容屏)#vi arch/arm/mach-s5pv210/mach-smdkv210.c在smdkv210_i2c_devs0结构体数组定义中添加以下内容:...{ I2C_BOARD_INFO("24c08", 0x50), }, /* Samsung S524AD0XD1 */ { I2C_BOARD_INFO("wm8580", 0x1b), },{I2C_BOARD_INFO("Goodix-TS", 0x55),.irq = IRQ_EINT(4),},...3)配置电容屏选项#make menuconfigDevice Drivers --->Input device support --->...[*] Touchscreens ---><*> GOODIX based touchscreen4)make将在arch/arm/boot/下生成编译好的可执行程序zImage下载到开发板即可,执行命令“cat /dev/input/event0”,然后用手触摸屏幕会在终端看到输出打印的乱码信息,表示移植成功,如果没有打印信息或没有“/dev/input/event0”这个设备说明移植失败。
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设备。
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协议类型
在Linux 操作系统中,I2C(Inter-Intergrated Circuit)是一种常用的串行通信协议,用于在电路板上的集成电路之间进行数据传输。
Linux 提供了I2C 的相关功能和驱动程序,以便在系统中使用和控制I2C 设备。
下面是一些常见的Linux I2C 协议类型:1. 标准模式(Standard Mode): 标准模式是I2C 总线上最常见的协议类型,它支持最低传输速率为100 Kbps,每个数据字节由8 位数据位和1 位ACK(应答)位组成。
2. 快速模式(Fast Mode): 快速模式是一种高速的I2C 通信协议,其最高传输速率为400 Kbps。
每个数据字节由8 位数据位和1 位ACK 位组成。
3. 快速模式加(Fast Mode Plus): 快速模式加是快速模式的扩展,增加了一个叫做Tlow(Fm+) 的参数,可以在某些硬件平台上支持更高的传输速率,最高可达到1 Mbps。
4. 高速模式(High-Speed Mode): 高速模式是一种更快的I2C 通信协议,其最高传输速率可以达到3.4 Mbps。
高速模式在物理层上使用了不同的电气特性和数据传输方式,以支持更高的速率。
5. 低速模式(Low-Speed Mode): 低速模式是一种较慢的I2C 通信协议,最低传输速率为10 Kbps。
低速模式主要用于通信距离较短或更为噪声敏感的应用场景。
这些不同的协议类型允许根据具体的应用需要选择适当的速率和性能。
在Linux 中,可以借助I2C 子系统的API 和驱动程序来实现对I2C 设备的访问和控制。
通过适当的配置和编程,可以在Linux 系统中轻松地使用和操作I2C 设备。
除了上述提到的几种常见的Linux I2C 协议类型之外,还有一些其他的协议类型和扩展可以在Linux 中使用,包括:1. 高速模式Plus(High-Speed Mode Plus): 高速模式Plus 是高速模式的一个扩展,最高传输速率可以达到 5 Mbps,并且支持更多的设备间距离。
I2C子系统分析
I2C子系统分析与其他子系统类似,为了方便i2c设备驱动的开发,避免因为I2C控制器的硬件差异而导致设备驱动的差异性,linux对I2C总线进行了封装。
为I2C设备、控制器、及驱动提供了统一的注册平台,同时为数据传输提供了统一的接口。
I2C总线作为一类抽象的总线模型,具体的通信由总线控制器i2c_adapter所提供的总线驱动算法i2c_algorithm来完成(对应i2c-s3c2410.c文件)。
与用户空间的交互由设备驱动完成,由i2c-dev结构维护。
i2c_driver结构维护了一类设备的驱动方法,i2c_client结构维护i2c子系统中独立的i2c设备(对应i2c-dev.c文件)。
另外,设备只完成与I2C-core的数据交互,不能与适配器直接通信,真正数据的传输由i2c-core调用相应的i2c控制器完成。
I2C驱动架构如下所示:一、 关于设备驱动:以i2c-dev.c设备驱动的加载为例,当设备加载时,由module_init(i2c_dev_init);入口,对应的流程如下:对应程序如下:static int __init i2c_dev_init(void){int res;printk(KERN_INFO "i2c /dev entries driver\n");//以字符型设备驱动的形式注册设备res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);if (res)goto out;//为设备创建一个类,便于自动创建设备节点i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");if (IS_ERR(i2c_dev_class)) {res = PTR_ERR(i2c_dev_class);goto out_unreg_chrdev;}res = i2c_add_driver(&i2cdev_driver);if (res)goto out_unreg_class;return 0;out_unreg_class:class_destroy(i2c_dev_class);out_unreg_chrdev:unregister_chrdev(I2C_MAJOR, "i2c");out:printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);return res;}首先来看看描述设备驱动的一个重要数据结构:struct i2c_driver {unsigned int class;//所属的I2C设备类/* Notifies the driver that a new bus has appeared or is about to be* removed. You should avoid using this if you can, it will probably* be removed in a near future.*/int (*attach_adapter)(struct i2c_adapter *);//总线加入时的回调函数(legacy drivers使用)int (*detach_adapter)(struct i2c_adapter *);//总线移除时的回调函数/* Standard driver model interfaces */int (*probe)(struct i2c_client *, const struct i2c_device_id *);int (*remove)(struct i2c_client *);/* driver model interfaces that don't relate to enumeration */void (*shutdown)(struct i2c_client *);int (*suspend)(struct i2c_client *, pm_message_t mesg);int (*resume)(struct i2c_client *);/* a ioctl like command that can be used to perform specific functions* with the device.*/int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);struct device_driver driver; //设备驱动模型中的driver模型const struct i2c_device_id *id_table;//该驱动所支持的I2C设备的ID号/* Device detection callback for automatic device creation */int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);const struct i2c_client_address_data *address_data;struct list_head clients;//检查到的符合该驱动的I2C设备列表};完成了字符设备的注册后,将设备驱动通过i2c_add_driver注册进i2c-core。
LinuxI2C总线详解
Linux I2C 总线详解㈠ OverviewLinux的I2C体系结构分为3个组成部分:·I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
这部分是与平台无关的。
·I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现。
I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。
经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。
不同的CPU平台对应着不同的I2C 总线驱动。
总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。
但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。
这部分在MTK 6516中是由MTK已经帮我们实现了的,不需要我们更改。
· I2C设备驱动:I2C设备驱动是对I2C硬件体系结构中设备端的实现。
设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。
I2C设备驱动主要包含了数据结构i2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数。
在Linux内核源代码中的drivers 目录下的i2c_dev.c文件,实现了I2C适配器设备文件的功能,应用程序通过“i2c-%d”文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等来访问这个设备。
应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器并控制I2C设备的工作方式。
设备驱动则是与挂在I2C总线上的具体的设备通讯的驱动。
I2C串行总线的组成及工作原理
I2C串行总线的组成及工作原理I2C(Inter-Integrated Circuit)是一种串行总线技术,用于连接微控制器(MCU)、传感器、存储器和其他外围设备。
它由荷兰公司Philips(现在的恩智浦)在1982年推出,作为一种简化的通信协议,用于在主设备和从设备之间进行数据传输。
I2C的组成I2C总线由以下几个主要组成部分组成:1. 主设备(Master):主设备是I2C总线的主要管理者,它决定了总线上的通信活动。
主设备负责产生时钟信号和启动传输。
一个I2C总线可以有多个主设备,但每次只能有一个主设备处于活动状态。
2. 从设备(Slave):从设备是主设备的辅助设备,它们被分配唯一的地址,用于与主设备进行通信。
从设备只能在被主设备选中时才能传输数据。
3. 时钟(Clock):I2C总线是一种同步协议,使用一个全局时钟信号来同步数据传输。
主设备生成时钟信号,从设备根据时钟来确定数据传输的时序。
4.数据线(SDA):数据线用于双向传输数据,主设备和从设备通过该线路发送和接收数据。
数据线上的电平可以是高电平或低电平,用于传输二进制数据。
5.时钟线(SCL):时钟线用于传输时钟信号,它由主设备控制。
时钟的频率决定了数据传输的速度。
I2C的工作原理I2C总线的工作原理可以简单分为以下几个步骤:1.主设备发送启动信号:主设备向总线发送一个低电平(SDA从高电平转为低电平),并保持时钟线为高电平。
这表示总线上即将开始一次传输。
2.主设备发送设备地址:主设备发送从设备的地址和读写位。
地址是从设备的唯一标识符,读写位用于指示该传输是读取还是写入操作。
3.从设备应答(ACK):在主设备发送地址后,从设备首先发送一个应答位,用于确认自己被选中。
应答是由从设备将数据线置为低电平。
4.主设备发送或接收数据:在成功选中从设备后,主设备可以发送或接收数据。
数据的传输是通过在每个时钟周期内改变数据线上的电平来实现的。
5.从设备应答(ACK):当主设备发送完希望传输的数据后,从设备必须发送一个应答位,以确认数据已经接收。
linux的I2C子系统详解
Linux中I2C驱动子系统详解Author :AstonMail : astonqa@写在前面首先,本教程不来自于权威书籍或文献,完全为本人个人理解的描述。
限于水平,其中若有错误及不当,敬请指正、不胜感激。
其次,本教程撰写过程中虽参考了网络上各种资料,但不同于网上大部分资料的粗略介绍或只关注一个点。
相反,本教程从全局出发,全面描述了I2C总线及设备在linux系统中的实现方法,适合于希望对linux中I2C子系统进行详细、彻底学习的人士共享与阅读。
第一部分:框架描述第二部分:I2C总线与实际硬件介绍第三部分:linux中I2C子系统与主要数据结构分析一个I2C设备要在linux下使用,必须包含两个驱动:I2C总线驱动和I2C设备驱动。
涉及到的主要数据结构有i2c_adapter, i2c_client, i2c_driver,i2c_algorithm(均包含在include/linux/i2c.h中),这几个数据结构是I2C驱动中主要的数据抽象,搞清楚这几个数据结构的意义是理解I2C驱动架构的前提。
i2c_adapter用来虚拟I2C适配器,所谓的适配器即用来匹配其两端连接的设备的器件。
在这里,I2C适配器是一个虚拟的器件,该器件用来匹配I2C总线上连接的设备和I2C主控制器。
因此可以认为:i2c_adapter对应的物理实体就是SoC内部的I2C控制器。
i2c_algorithm是一个纯软件层面的数据抽象,没有对应的物理实体。
它用来描述一个i2c_adapter(实质是一个I2C控制器)的通信时序,这其实很好理解。
大家都知道,I2C总线上的通信双方要完成通信需要按照一定的时序吧,如下图即是S3C2440中I2C控制器的主发送时序(即2440作为I2C主设备向外部连接的从设备发送信息)。
i2c_algorithm中封装的方法旨在描述该种时序,I2C总线驱动中最终需要靠这里封装的方法来操作I2C控制器硬件发送通信时序。
Linux内核I2C子系统初始化驱动架构
device_driver{ }.name 在 驱 动中指定
i2c_driver{} .driver *id_table *probe ... ...
tv168_probe()
device_driver{} *p *bus *name ... ...
driver_private{} .knode_bus ... ...
I2C 子系统初始化驱动架构
目标:
分析整理 i2c 子系统初始化驱动架构;
本文要点:
1、i2c 重要数据结构及关系图; 2、i2c 子系统初始化驱动架构;
硬件框图:
2012 年 12 月 22 日
scl0 adapter i2c-0
sda0
scl1 adapter i2c-1
sda1
scl2 adapter i2c-2
i2c_register_board_info(busnum, ...)
复制到
i2c_board _info{}
i2c_devinfo{}
.busnum
.list
(等待与适配器匹配)
链入
__i2c_board_list
说明:
i2c_board_info{}
这 里 有 两 个 i2c_board_info{} 结 构 , 一 个 是 前 面 构 造 的 i2c_board_info{} , 另 一 个 在
*archdata
... ...
dev_archdata{} 开发人员自己使用
开发人员自己使用
i2c_board_info{}
i2c_devinfo{} int busnum .board_info struct list_head list
i2c子系统
i2c子系统i2c subsystem的故事还要从很久以前说起,那是一个混沌初开的年代......1、板子初始化arch/arm/mach-msm/board-msm7x30.cstatic void __init msm7x30_init(void){......(1) platform_add_devices(devices, ARRAY_SIZE(devices));......(2) msm_device_i2c_init();msm_device_i2c_2_init();......(3) i2c_register_board_info(4 /* QUP ID */, msm_camera_boardinfo,ARRAY_SIZE(msm_camera_boardinfo));......}(1) 在此处注册了很多的platform_device devices[],在这一堆的platform_devices中有msm_device_i2c,msm_device_i2c_2,这样两个设备(具体的区别还没有弄清楚,有可能是该板子有两条i2c总线),它们其实就是很容易被人们遗忘的i2c controler,它们被当作platform_device在板子初始化时进行注册。
platform_device的注册过程不详细讲述了,只讲一下最重要的两部match和probe:a、matchdrivers/base/base.h120 static inline int driver_match_device(struct device_driver *drv,121 struct device *dev)122 {)>123 return drv->bus->match ? drv->bus->match(dev, drv) : 1;124 }call bus->match671 static int platform_match(struct device *dev, struct device_driver *drv)672 {673 struct platform_device *pdev = to_platform_device(dev);674 struct platform_driver *pdrv = to_platform_driver(drv);675676 /* match against the id table first */677 if (pdrv->id_table)678 return platform_match_id(pdrv->id_table, pdev) != NULL;679680 /* fall-back to driver name match */681 return (strcmp(pdev->name, drv->name) == 0);682 }首先看platform_driver有没有定义id_table,有的话:644 static const struct platform_device_id *platform_match_id(645 const struct platform_device_id *id,646 struct platform_device *pdev)647 {648 while (id->name[0]) {649 if (strcmp(pdev->name, id->name) == 0) { platform_driver有可能支持多个platform_device,所以可能会有多个platform_device_id项650 pdev->id_entry = id;651 return id;652 }653 id++;654 }655 return NULL;656 }比较platform_device->name和platform_driver->id_entry->name,否则platform_device->name和device_driver->nameb、probestatic int really_probe(struct device *dev, struct device_driver *drv)120 if (dev->bus->probe) {121 ret = dev->bus->probe(dev);122 if (ret)123 goto probe_failed;124 } else if (drv->probe) {125 ret = drv->probe(dev);126 if (ret)127 goto probe_failed;128 }这里先看能不能call bus->probe,不能则call devices_driver->probe483 int platform_driver_register(struct platform_driver *drv) 484 {485 drv->driver.bus = &platform_bus_type;486 if (drv->probe)'> 487 drv->driver.probe = platform_drv_probe;488 if (drv->remove)489 drv->driver.remove = platform_drv_remove;490 if (drv->shutdown)491 drv->driver.shutdown = platform_drv_shutdown;}> 492493 return driver_register(&drv->driver);494 }486和487先看有没有platform_driver->probe,有就对device_driver->probe赋值platform_drv_probe,在上面调用devices_driver->probe实际就是调用platform_drv_probe,而platform_drv_probe又会调用platform_driver->probe,这个probe是用户写的具体设备驱动的probe。
I2C子系统(二)
I2C子系统(二)2、I2C ArchitectureI2C 采用的 GPIO 一般为开漏模式,支持线与功能,但是开漏模式无法输出高电平,所以需要外部上拉。
Vdd 可以采用5V、3.3V、1.8V 等,电源电压不同,上拉电阻阻值也不同。
一般总线上认为,低于0.3Vdd为低电平,高于0.7Vdd为高电平。
推挽结构和开漏结构推挽结构:使用两个三极管或MOSFET,以推挽方式存在于电路中。
电路工作时,两只对称的开关管每次只有一个导通,所以导通损耗小、效率高。
既可以向负载灌电流,也可以从负载抽取电流。
推拉式输出级既提高电路的负载能力,又提高开关速度。
图中上面是 NPN 型三极管,下面是 PNP 型三极管。
分别有以下两种情况:输出高电平:向负载灌电流。
输出低电平:从负载拉电流。
三极管和 MOS 管效果类似,不赘述。
开漏结构(OD):对比推挽结构,开漏结构只有一个三极管或者MOS管。
之所以叫开漏,是因为MOS管分为三极:源极、栅极、漏极。
漏极开路输出,所以叫开漏;如果是三极管:基极、集电极、发射极,集电极开路,所以叫开集输出(OC)。
开集输出(OC),NPN 三极管:这个结构很好分析:Vin 高电平,三极管导通,对外输出低电平,外部被直接拉到低。
Vin 低电平,集电极(C)开路,输出电平状态由外部决定。
以上分析均采用三极管,MOS管类似。
因此,推挽结构可以输出高低电平。
开漏输出只能输出低电平,高电平由外部电路决定。
对比总结如下:电平跳变速度,推挽输出由CPU控制,高低电平跳变速度快(0->1),开漏输出由外部上拉电阻决定,上拉电阻小,反应速度快,从低电平到高电平跳变速度就快,但电阻小电流就大,功耗就高,反之亦然。
所以开漏输出的外部上拉电阻要兼顾速度和功耗。
上拉电阻小,信号边沿陡峭,信号好,但是功耗高。
电平转换:推挽输出输出的高低电平只有0和Vdd,开漏输出的高电平由外部上拉电阻决定,多少V都可以,只要不超过MOS管击穿电压。
I2C子系统(五)
I2C子系统(五)5、I2C Hs-modeHS mode 为什么单独讲解?因为高速模式和其他模式有很多不一样的地方。
1.速度高达 3.4MHz。
2.Hs 模式下,主机 SDAH 有一个开漏输出 buffer, SCLH 有一个输出的开漏极下拉和电流源上拉电路,这个电流源电路缩短了 SCLH 信号的上升时间。
任何时侯在 Hs 模式只有一个主机的电流源有效。
3.在多主机系统的Hs 模式中,不执行仲裁和时钟同步,以加速位处理能力。
仲裁过程一般在前面用 F/S 模式传输主机码后结束。
4.Hs 模式主机器件以高电平和低电平是 1:2 的比率产生一个串行时钟信号。
解除了建立和保持时间的时序要求。
5.还可以选择 Hs 模式器件有内建的电桥。
在 Hs 模式传输中,Hs 模式器件的高速数据 SDAH 和高速串行时钟 SCLH 线通过这个电桥与F/S 模式器件的 SDA 和 SCL 线分隔开来。
减轻了SDAH 和 SCLH 线的电容负载,使上升和下降时间更快。
6.Hs 模式从机器件与 F/S 从机器件的唯一差别是它们工作的速度。
Hs 模式从机在 SCLH 和 SDAH输出有开漏输出的缓冲器。
SCLH 管脚可选的下拉晶体管可以用于拉长 SCLH 信号的低电平,但只允许在 Hs 模式传输的响应位后进行。
7.Hs 模式器件的输出可以抑制毛刺,而且 SDAH 和 SCLH 输出有一个 Schmitt 触发器8.Hs 模式器件的输出缓冲器对 SDAH 和 SCLH 信号的下降沿有斜率控制功能9.调整了串行数据SDA 和串行时钟SCL 信号的时序。
没有必要与其他总线系统如 CBUS 兼容,它们不能在增加的位速率下工作。
10.如果快速模式器件的电源电压被关断,SDA 和SCL 的I/O 管脚必须悬空,不能阻塞总线。
11.连接到总线的外部上拉器件必须调整以适应快速模式 I2C 总线更短的最大允许上升时间。
对于负载最大是 200pF 的总线,每条总线的上拉器件可以是一个电阻;对于负载在200pF~400pF 之间的总线,上拉器件可以是一个电流源(最大值3mA)或者是一个开关电阻电路,如下图:只有 Hs 模式器件的系统的物理 I2C 总线配置(可选)串联电阻器 Rs 保护 I2C 总线设备的 I/O 免受总线上的高压尖峰影响,并将振铃和干扰降至最低。
i2c 原子操作
i2c 原子操作I2C原子操作是一种用于在电子设备之间进行通信的通信协议。
它主要用于在微控制器、传感器和其他外设之间传输数据。
I2C原子操作允许设备之间在同一总线上进行通信,从而简化了电路设计和布线。
在I2C原子操作中,数据传输是通过两个线路实现的:串行数据线(SDA)和串行时钟线(SCL)。
数据传输的起始由主设备发起,主设备发送一个起始信号来指示通信的开始。
然后,主设备发送设备地址和读/写位,以选择要与之通信的从设备。
接下来,主设备和从设备之间开始传输数据,主设备发送数据字节并等待从设备的确认。
一旦数据字节被接收,从设备将发送一个确认信号。
在数据传输的最后,主设备发送一个停止信号来结束通信。
I2C原子操作具有以下特点:1. 简化通信:通过使用统一的总线和协议,I2C原子操作简化了设备之间的通信。
这使得多个设备可以在同一总线上进行通信,减少了系统中的电路复杂性。
2. 多设备支持:I2C原子操作支持多个从设备连接到同一总线上。
每个设备都有一个唯一的地址,主设备可以选择与之通信的设备。
3. 低功耗:I2C原子操作设计用于低功耗应用。
它使用两个线路来传输数据,这降低了功耗。
4. 灵活性:I2C原子操作具有灵活性,可以根据应用的需要进行配置。
它可以在不同的速率下运行,从而提供不同的数据传输速度和延迟。
使用I2C原子操作时,需要注意以下几点:1. 总线冲突:由于多个设备共享同一总线,使用I2C原子操作时可能会出现总线冲突。
为了避免冲突,可以使用仲裁器或者在设计时避免同时使用多个设备。
2. 电气特性:I2C原子操作对电气特性有一定的要求,如电压水平和电流。
在设计电路时,需要确保符合I2C原子操作的电气规范。
3. 时钟同步:I2C原子操作的正常工作需要时钟同步。
主设备和从设备之间的时钟应该是同步的,以确保数据的正确传输。
总的来说,I2C原子操作是一种可靠且灵活的通信协议,适用于许多电子设备之间的数据传输。
通过遵循相关的电气规范和时序要求,可以实现可靠的通信,并简化系统的设计和布线。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
491 drv->driver.shutdown = platform_drv_shutdown;
}> 492
493 return driver_register(&drv->driver);
494 }
486和487
ARRAY_SIZE(msm_camera_boardinfo));
这个函数主要是把i2c 的外围设备信息结构体struct ic2_board_info 分装进struct i2c_devinfo结构,再把这个结构放到__i2c_board_list这个链表上。
该函数的第一个参数其实是该i2c 设备所属的adapter的编号,不同的adapter使用的低层i2c通信协议算法可能不一样。
794 {
795 return platform_driver_register(&msm_i2c_driver);
796 }
platform_driver_register(&msm_i2c_driver) 的过程和platform_device_register的过程很相似,主要两部还是match和probe,不过这回platform_bus_type上已经有设备了,它回去probe设备,并最终调用platform_driver的probe函数msm_i2c_probe。我们来看一看该函数做了些什么。
platform_device的注册过程不详细讲述了,只讲一下最重要的两部match和probe:
a、match
drivers/base/base.h
120 static inline int driver_match_device(struct device_driver *drv,
121 struct device *dev)
platform_device->name和device_driver->name
b、probe
static int really_probe(struct device *dev, struct device_driver *drv)
120 if (dev->bus->probe) {
121 ret = dev->bus->probe(dev);
122 if (ret)
123 goto probe_failed;
124 } else if (drv->probe) {
125 ret = drv->probe(dev);
126 if (ret)
127 goto probe_failed;
pdev->name);
if (!ioarea) {
dev_err(&pdev->dev, "I2C region already claimed\n");
return -EBUSY;
}
clk = clk_get(&pdev->dev, "i2c_clk");
if (IS_ERR(clk)) {
672 {
673 struct platform_device *pdev = to_platform_device(dev);
674 struct platform_driver *pdrv = to_platform_driver(drv);
675
676 /* match against the id table first */
128 }
这里先看能不能call bus->probe,不能则call devices_driver->probe
483 int platform_driver_register(struct platform_driver *drv)
484 {
485 drv->driver.bus = &platform_bus_type;
......
}
(1) 在此处注册了很多的platform_device devices[],在这一堆的platform_devices中有
msm_device_i2c,
msm_device_i2c_2,
这样两个设备(具体的区别还没有弄清楚,有可能是该板子有两条i2c总线),它们其实就是很容易被人们遗忘的i2c controler,它们被当作platform_device在板子初始化时进行注册。
......
(2) msm_device_i2c_init();
msm_device_i2c_2_init();
......
(3) i2c_register_board_info(4 /* QUP ID */, msm_camera_boardinfo,
ARRAY_SIZE(msm_camera_boardinfo));
static int
msm_i2c_probe(struct platform_device *pdev)
{
......
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n");
2、i2c controler driver 的加载过程
drivers/i2c/busses/i2c-msm.c 该文件就是i2c controler的驱动程序。
780 static struct platform_driver msm_i2c_driver = {
781 .probe = msm_i2c_probe,
486 if (drv->probe)
'> 487 drv->driver.probe = platform_drv_probe;
488 if (drv->remove)
489 drv->driver.remove = platform_drv_remove;
122 {
)>123 return drv->bus->match ? drv->bus->match(dev, drv) : 1;
124 }
call bus->match
671 static int platform_match(struct device *dev, struct device_driver *drv)
i2c subsystem的故事还要从很久以前说起,那是一个混沌初开的年代......
1、板子初始化
arch/arm/mach-msm/board-msm7x30.c
static void __init msm7x30_init(void)
{
......
(1) platform_add_devices(devices, ARRAY_SIZE(devices));
646 struct platform_device *pdev)
647 {
648 while (id->(pdev->name, id->name) == 0) { platform_driver有可能支持多个platform_device,所以可能会有多个platform_device_id项
pr_err("failed to request I2C gpios\n");
msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
}
主要是gpio的申请和i2c controler 平台数据的赋值。
(3)i2c_register_board_info(4 /* QUP ID */, msm_camera_boardinfo,
dev_err(&pdev->dev, "Could not get clock\n");
ret = PTR_ERR(clk);
goto err_clk_get_failed;
}
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "platform data not initialized\n");
677 if (pdrv->id_table)
678 return platform_match_id(pdrv->id_table, pdev) != NULL;
679
680 /* fall-back to driver name match */
681 return (strcmp(pdev->name, drv->name) == 0);
return -ENODEV;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "no irq resource?\n");
return -ENODEV;
}
ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
682 }
首先看platform_driver有没有定义id_table,有的话:
644 static const struct platform_device_id *platform_match_id(