i2c协议详解

        i2c协议是一种串行通信总线,有sda数据线和scl时钟线。每个设备通过唯一地址连接到总线上,可以连接到同一总线上的设备数量受最大总线电容的限制。

速率:

standard-mode :100kbit/s

fast-mode :400kbit/s

fast-mode plus: 1Mbit/s

high-speed mode : 3.4Mbit/s

ultra-fast mode : 5Mbit/s (仅支持单向传输)

high-fast mode 和 ultra-fast mode时序跟前三种不太一样,下面是前三种时序。 

Standard-mode, Fast-mode and Fast-mode Plus 模式

时序:

        高电平:通过电流源或者上拉电阻将scl和sda拉到高电平,每个设备连接的VDD不一样,其高低电平也不一样,因此后来将输入参考电平设为VIL=0.3VDD,VIH=0.7VDD(以前:VIL=1.5V,VIH=3V)。

空闲:scl与sda均为高电平

起始条件:scl为高,sda从高拉到低

停止条件:scl为高,sda从低拉到高

        起始条件和停止条件均由主机发起,scl也由主机控制。从起始条件开始到停止条件结束之前,都认为总线处于传输状态,当发送重复起始条件时,busy状态保持。

数据变换:scl高电平时,sda保持不变,scl为低电平时,变换数据(在scl上升沿将所要传输的数据放到sda上,scl下降沿采样)。

数据帧格式:

        数据以8位为一组传输,每个scl时钟周期传输一位,先传高位再传低位,每传输完一个byte后,第九个scl时钟必须要有应答信号ack(来自于从机或者主机),可以一次传输多个字节。如果从机不能接收或传输一个完整字节的数据,例如服务于内部中断时,可以保持时钟线SCL LOW强制主机进入等待状态。当从机准备好接收另一个字节数据并释放时钟线SCL时,数据传输继续进行。

        应答信号:在scl第九个时钟的高电平上,若sda为低则为应答信号,若为高则为no_ack,主机需产生stop信号以停止此次传输,或者生成restart信号再次开启传输。

7位地址的读写:

        检测到起始位之后,主机在随后的8个时钟周期发送7位地址+1位读写位,读写位中,0表示主机向从机写数据,1则表示主机向从机读数据,第9个时钟周期匹配的从机返回ack信号,然后开始传输数据(将数据写进对应寄存器或者从对应寄存器读出数据),格式分别如下图所示:

写数据
读数据

        想要在中途变换数据的传输方向,则重新发送起始信号,然后发送地址和读写位重新开始:

        而对于不同方式的寄存器读写,又可将数据帧细分为以下格式,支持哪种格式则由自己的设计决定(word address为寄存器地址):

写数据
读数据

10位地址的读写:

        10位寻址扩展了可连接的设备数量。7位和10位地址可以连接到同一i2c总线,7位和10位寻址都可以在所有总线速度模式下使用。目前,10位寻址并没有被广泛使用。

        10位从机地址由起始条件或重复起始条件后的前两个字节组成,第一个字节格式为1111_0xx和读写位构成,xx位十位地址中的高两位(这时候可能会有多个设备匹配并返回ack信号-(1))。第二个字节为十位地址中的低八位,寻址到设备后(只有一个匹配并返回A2),读写格式如下图所示,数据传输时ack信号的产生与7位地址的相同。7位地址读写数据帧都可以用于10位地址中,以下是其中的两种。

写帧格式
读帧格式(收到地址后变换传输方向,重新发送s)

High-speed mode

        hs模式向下兼容低速模式。主机在hs模式传输期间不执行仲裁或时钟同步,加快bit处理能力。而从机在hs模式和F/ s模式之间的唯一区别是它们运行的速度。hs模式启动条件如下:

1. START condition (S)
2. 8-bit controller code (0000 1XXX)
3. Not-acknowledge bit (A)
接收到上述条件后,主机切换到快速模式,只有在STOP条件(P)后才切换回F/ s模式。所有从机接收到0000_1XXX之后,都切换到hs模式,每个连接的设备必须识别' S 00001XXX A '序列,并且必须将其内部电路从快速模式设置切换到hs模式设置。每个连接的设备必须识别停止条件(P),并将其内部电路从hs模式设置切换回t1时间之前的f/s模式。数据帧格式如下:

ultra-fast mode

        传输速度为5MHz,只能单向写数据,不能读。该协议由START、目标地址、读写位、第9时钟和停止位组成。读写位仅为“写”,第9时钟上的数据位被驱动为HIGH,由于总线的单向特性而忽略了ACK周期。此时连接在总线上的设备没有线与功能,因此最先发起数据传输的设备为唯一主机。总裁和同步在此模式中不存在。如果连接到总线的设备结合了必要的接口硬件,则很容易检测启动和停止条件。然而,没有这样的接口的微控制器每个时钟周期必须至少采样SDA线两次。数据帧格式如下:

        由于目标无法响应第九个时钟周期,因此不需要ACK和NACK。但是,时钟周期保留,以便与i2c总线协议保持一致。ACK和NACK也被称为第九个时钟周期。控制器产生所有时钟脉冲,包括第9个时钟脉冲。第九个数据位总是被驱动为HIGH(' 1 ')。目标设备在任何时候都不允许驱动SDA线。

保留地址

        0000_XXX和1111_XXX为保留地址,所以7位地址的取值范围为0x07~0x78,不包括0x07和0x78。

其中保留地址的作用如下:

        [1]广播地址,用于软件复位等功能。用于同时对连接到i2c总线的每个设备进行寻址。但是,如果设备不需要在一般调用结构中提供任何数据,它可以不响应。如果一个设备确实需要来自一般呼叫地址的数据,它就会响应。控制器实际上并不知道确认了多少设备。第二个字节和其后的字节由能够处理该数据的每个目标接收器响应。不能处理其中一个字节的目标必须通过不响应来忽略它。通用调用地址的含义总是在第二个字节中指定。如下:

第二字节含义如下:

当最低位B为0时:

0000_0110(06h):通过硬件复位和写入目标地址的可编程部分。对广播地址响应的设备在第二字节中接收到该数据后,都要复位,并接受其地址的可编程部分。且要确保设备掉电后不会拉低SDA和SCL线,否则总线将该挂死。
0000_0100(04h):用硬件编写目标地址的可编程部分,行为如上,但设备不复位。0000_0000(0h):第二个字节不允许发送该字节。其余的字节还没有定义,收到忽略不响应。

        当最低位B为1时:第二字节序列是通过'硬件调用'。即此时由键盘等硬件设备传输,可以对其进行编程以传输所需的目标地址。由于硬件控制器事先不知道消息必须传输到哪个设备,它只能生成这个硬件通用调用和它自己的地址。

        [2]start byte,用于延长数据传输之前的起始条件。I2C总线上至少要有一个master(微控制器或者DSP)连接,如果微控制器具有片上硬件I2C总线接口,那它可以被编程为只能被总线的请求中断。当微控制没有这样的接口时,它必须不断地通过软件来监控总线,不断地轮询或监视总线的行为,这势必影响了数据传送的安全性,也增加了功耗。在这种情况下,如果采取正常情况下的start条件(在SCL为高期间,SDA由高拉低),这个过程相对是很短暂的,微控制器可能监视不到这个start条件。所以,在数据传输之前,为了确保微控制器可以采样到总线上的START条件,可以使用一个比正常情况长得多的start过程(发送0000_0001),以此便于微控制器以较低的频率采样SDA线。当微控制器检测到起始字节中的七个0中的任意一个0时,就可以切换到更快的速率,找到0000_0001之后的重复启动(Sr)条件,然后开始之后的传输。传输过程如下:

  • maser先产生一个START条件;
  • maser发送start byte(0000_0001) ;
  • start byte字节传输之后的一拍,不能有任何slave响应ACK
  • master产生一个restart条件。

[3]CBUS地址:兼容CBUS设备,发送该地址后不允许响应。

[4]为兼容其他协议预留的地址。只有能够使用这种格式和协议的i2c总线兼容设备才允许响应此地址。

device ID:

        提供制造商等信息,由24bits组成,12bit的制造商名称,9bit的零件标识,3bit的设备版本。设备信息只可读。读取方式如下:

1、发送start 条件

2、发送保留设备ID地址,后面的R/W位设置为' 0 '(写):' 1111 1000 '。

3、发送想要读取设备信息的设备地址,最低位可忽略,即发送X。

4、发送重复开始条件。

5、控制器发送保留设备ID i2c总线地址,后面的R/W位设为' 1 '(读):' 1111 1001 '。

6、接下来的三个字节可以读取设备信息,依次为12位的制造商信息,9位的设备信息,3位的版本信息。

7、发送nack停止读取,然后产生停止条件。

同步和仲裁:

        两个设备可以同时在空闲总线上开始传输,并且必须有一种方法来决定哪一个控制总线并完成传输,这是通过时钟同步和仲裁完成的。在单控制器系统中,不需要时钟同步和仲裁。

       同步:数据同步通过线与功能完成,将每个设备的输出级开漏或者开集电极,以线与方式连接到总线上。当同时有多个设备想要传输数据时,首先拉高总线的设备失去控制权限,当另一个控制器产生“low”时,第一个产生“high”的控制器将失去仲裁。因此,SCL线由具有最长低电平周期的设备控制,低周期较短的设备在此期间进入高等待状态。scl低电平则由时钟LOW周期最长的设备决定,HIGH周期由时钟HIGH周期最短的设备决定。

        仲裁:主机只有在总线空闲时才可以开始传输,多个主机可以在启动条件的最小保持时间(tHD;STA)内生成start 信号,从而在总线上产生有效的启动条件。然后需要仲裁来确定哪个控制器将完成其传输。步骤如下:

        在scl为高电平期间,每个主机都检查sda线的值与自己传输的值是否一致,如果一致则继续传输,这个过程可能需要很多比特。两个控制器实际上可以毫无错误地完成整个事务,只要传输是相同的。如果不一致时,该设备失去仲裁,停止对sda线的控制。失去仲裁的设备可以产生时钟scl脉冲,直到失去仲裁的字节结束,并且必须在总线空闲时重新开启传输。如果设备还包含slave模式,并且在寻址阶段失去仲裁,则获得仲裁的设备可能正在尝试寻址它。因此,失去仲裁的设备必须立即切换到可寻址模式。如下图所示:

清除总线:

        如果SCL一直被意外情况拉低,若I2C设备有HW(hardware)复位端口,优先使用HW复位信号重置总线。如果I2C设备没有HW复位端口,则循环给设备上电,激活内部强制的POR (power - on reset)电路。

        如果SDA被意外情况拉高,则主机优先将SCL发送9个时钟脉冲,使总线保持低电平的设备应该在这9个时钟内的某个时间释放它。如果不是,则使用HW复位或循环电源清除总线。

参考:

1、I2C-bus specification and user manual

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Linux操作系统下,I2C是一种常见的通信协议,用于连接主机与各种外部设备,如传感器、扩展模块等。在编写Linux下的I2C代码时,需要使用Linux提供的I2C子系统,它包含了各种函数和结构体,用于管理和操作I2C总线。 首先,我们需要创建一个I2C设备的句柄,可以使用函数`open()`打开对应的设备文件,如`/dev/i2c-0`。如果成功打开设备文件,就可以使用`ioctl()`函数进行各种设置和控制操作。例如,通过`I2C_SLAVE`命令可以指定要与之通信的从设备的地址。 接下来,我们可以使用`i2c_smbus_*()`系列函数来进行I2C通信。这些函数封装了一些常用的I2C操作,如读写字节、读取寄存器等。对于特定的I2C设备,可能还需要使用其他特定的函数进行访问。 在使用`i2c_smbus_*()`函数进行通信时,需要注意传入的参数。例如,读操作需要指定要读取的字节个数,写操作需要指定要写入的数据。同时,还要注意处理函数的返回值,以便判断操作是否成功。 另外,可以使用`close()`关闭I2C设备的句柄,释放资源。 需要注意的是,编写Linux下的I2C代码需要有一定的编程基础和对Linux系统的了解。还需要查阅相关的资料,了解具体的设备地址、寄存器映射关系,以及所需的操作命令和数据格式等。 总之,编写Linux下的I2C代码需要熟悉Linux系统提供的I2C子系统和相关函数,同时还需要了解具体的设备和通信协议的细节。只有掌握了这些知识,才能有效地进行I2C通信,并与外部设备进行数据交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值