###1. i2c总线
I2C最初是由Philips提出,用于IC之间的互联,如今已经被全球超过50个公司的1000+个ICs所使用,已经是一个世界标准, 其标准文档为《I2C-bus specification and user manual》,I2c总线的特点如下:
- 只需要两根线,一个串行数据线(SDA)额一个串行时钟线(SCL)
- 使用 主-从 机的设计, 是真正的多主机总线,如果有两个或多个主机初始化数据传输,可以通过冲突检测和仲裁来防止数据被破坏
- 串行的8位双向数据传输在标准模式下达到100kb/s,快速模式下是400kb/s,超速模式下是3.4Mb/s
- 总线上连接的最大IC数量由总线最大的电容所限制
- 与多种不同的控制总线是兼容的,比如SMBus(系统管理总线),PMBus(电源管理总线),IPMI(智能平台管理总线),DDC(显示数据通道)以及ATCA(高级电信架构)
i2C总线理论上传输速度可以为
- 100KHz (标准)
- 400KHz (全速)
- 1MHz (快速)
- 3.4MHz (高速)
目前还没有成熟的3.4MHz速率的产品, I2C总线是板内总线,总线内部有地址管理和仲裁机制,在总线容量、slave地址等技术指标正确的情况下,数据的完整性和安全性是有保证的
i2c相关信息可参考 i2c bus
###2. i2c总线的负载能力
i2c总线上可连接的的设备数目受总线上电容大小的限制:
- 标准模式(100KHz)时, 总线电容 <= 400pF
- 快速模式(400KHz)时, 总线电容 <= 200Pf
###3. SDA/SCL 的上拉
i2c的 SDA 和 SCL 线都是“漏极开漏“或者”集电极开漏”, 只能输出’0’不能输出‘1’, 所以必须在接口外接上拉, 在空闲时, SDA/SCL 均为高电平
I2C的上拉电阻可以是1.5K,2.2K,4.7K, 电阻的大小对时序有一定影响,对信号的上升时间和下降时间也有影响,一般接1.5K或2.2K, 上拉电阻的计算公式是
Rmin={Vdd(min)-o.4V}/3mA
Rmax=(T/0.874) *c
T=1us 100KHz
T=0.3us 400KHz
c 为总线电容
电源电压限制了上拉电阻的最小值, 总线电容限制了上拉电阻的最大值
###4. i2c 速率自适应
i2c是一个同步总线(根据时钟的快慢来传递数据), 理论上无限慢都可以,甚至可以忽快忽慢都没有关系(使用GPIO模拟I2C主机时,甚至可以停顿几秒再继续通讯)
从机会声明其支持的速率, 比如支持标准模式(100KHz)时, 则主机可以使用不大于100KHz的任意时钟速率来和该从机通讯, 支持快速模式(400KHz)时, 则主机可以使用不大于400KHz的任意时钟速率来和该从机通讯
由于i2c总线采用主从模式, SCL完全由主机端控制来产生时钟周期(有一个特殊的情况,从机可以将SCL拉低使总线处于wait状态), 因此总线的时钟频率需要在主机端进行设置, 一旦设置之后, 主机和所有从 机进行通讯时, 均输出相同的时钟速率, 但是这一速率可以被从机延展
i2c总线通过clock-Stretching来适应不同的时钟速率:
- 在byte级, 若从机不能及时的完成下一个字节操作时(例如需要进行准备工作), 则其可以在ACK之后, 将SCL拉低, 进入wait状态直到可以进行下一步操作, 可用于 标准/全速/快速/高速模式
- 在bit级, I2C总线上的从设备可以通过增长每一个时钟的低周期来降低总线时钟.所以每个主机可以适应这个设备的内部操作速率,不能用于 高速模式
###5. i2c的数据传输
i2c总线上的传输(读/写)由主机发起, 以Star标记开始, 可以传输多个字节, 每一个字节为8bit, 每传输一个字节后必须跟一个ACK位,最后以Stop标记结束传输
i2c总线上, 每一个字节传输时, 数据从最高有效位(MSB)开始传输
SDA数据的有效性: 在SCL为高时, SDA必须维持电平稳定, 数据才有效, 在SCL为低时, SDA可以改变状态
i2c总线上的传输, 在Start信号之后的第一个字节为地址字节(要寻址的设备的地址)和r/w位(代表是主机从从机处读取数据还是主机向从机写数据)
####5.1 Start/Stop/re-Start条件
若在SCL维持高电平期间,改变SDA的状态, 作为传输的 Start/Stop 标志
理论上,i2c主机应该在每一次总线传输(总线传输是指若干个i2c读操作或者若干个i2c写操作)完成后, 产生Stop信号, 然后再产生Start位
Start --- 总线传输 --- Stop ...... Start --- 总线传输 --- Stop
i2c主机也可在总线传输结束后, 不产生Stop 信号, 直接产生Start信号, 开始下一次总线传输, 是为 re-Start 信号
Start --- 总线传输 --- Start --- 总线传输 --- ...... --- 总线传输 --- stop
兼容I2C总线的设备在接收到Start条件或retart条件时都一定要重启它们的总线逻辑,并且期望主机发送从机地址
开始条件后立马跟着一个终止条件是不合法的格式.很多设备在设计时考虑了这一点,可以处理
####5.2 wait 状态
如果从机要执行一些功能后才能接收或者发送新的完整数据,比如说服务一个内部中断,那么它可以将时钟线SCL拉低来强制使主机进入wait状态.当从机准备好新的字节数据传输时,释放时钟线SCL,数据传输便继续进行
硬件i2c主机可以检测到wait状态,暂停总线的操作, 而在GPIO模拟i2c时, 需要在其进行时钟周期的高电平阶段的操作时, 先检测SCL是否被从机拉高
####5.3 AKC/NAK
每次传输一个字节后, 必须有一个 ACK/NACK 位, 即第9个bit进行 ACK/NACK
ACK应答信号定义如下: 在ACK的第9个时钟脉冲中发送方释放SDA线,若接收方确认接收成功则将SDA拉低,使得在这个时钟脉冲的高电平期间保证SDA是低电平.建立和保持时间也应该计算在内
NACK应答信号定义如下: 在ACK的第9个时钟脉冲中发送方释放SDA线,若接收方确认接收不成功,则不操作SDA, 因SDA上拉,因此在这个时钟脉冲的高电平期间是低电平. 建立和保持时间也应该计算在内
若产生了ACK信号, 发送放可以继续发送, 若产生了NACK信号, 则主机可以发起Stop信号终止传输, 或者发起Re-Start信号开始新的传输
有5种情况会导致产生NACK:
- 总线当前的传输地址上没有接收器,所以没有设备用ACK来响应
- 因为接收者正在处理一些实时的功能,尚未准备与主机的通信,所以接收者不能收发
- 在传输期间,接收者收到不能识别的数据或者命令
- 在传输期间,接收者无法接收更多的数据字节
- 主-接收器要通知从-发送器传输的结束
i2c协议并不负责重传, 因此若有传输错误, 可通过软件重新发起传送
####5.3 i2c总线传输的方向
i2c总线的传输由主机发起, 可以是读操作(数据由从机发送到主机), 也可以是写操作(数据由主机发送到从机), 也可以是复合操作(即传输方向发生改变)
复合操作在访问i2c接口的EEPROM时比较常用, 在读取内容时, 先通过写操作, 写入要读取的地址, 然后发起重复开始信号, 执行读操作, 读取内容
###6. 时钟同步和仲裁
i2c总线是一个多主机总线, 当总线上有多个主机同时发起传输时, 就需要检测冲突, 并且仲裁由哪一个主机来占用总线进行操作, 在单主机系统中, 不需要时钟同步和仲裁
####6.1 时钟同步
每一个主机拉低SCL的时长称为低电平周期, 拉高SCL的时长称为高电平周期
时钟同步通过i2c主机的SCL线与来实现: 当SCL线电平从高到低时, 会引起所有的主机开始计算它的低电平周期,例如, 在主机1的时钟周期为低时, 它就会拉低SCL, 在主机1的时钟周期为高时, 它会释放SCL,则SCL应为高电平, 此时, 如果还有主机2的时钟周期为低, 则SCL不会被释放, 还是保持为低电平, 此时, 主机1进入HIGH wait-state, 当所有的主机的低电平周期都结束了,时钟线才回到高电平.这时所有主机的时钟和SCL的状态一致,所有的主机开始计数他们的高电平周期.第一个结束高电平的主机将SCL线重新拉低
即在多主机系统中, 同步的SCL时钟的低电平周期由所有主机中最长的低电平周期决定,高电平周期由最短的高电平周期决定
####6.2 总线仲裁
仲裁处理是逐个bit进行的.在每个bit,当SCL为高,每个主机都check一下来看看SDA的电平是否和它发送的电平吻合.这个过程可能会持续很多个bit.只要传输是同一的,那么两个主机可以无误的完成完整的传输.当一个主机试着发送高,但是检测到SDA为低,那么这个主机知道自己失去仲裁然后关掉自己的SDA输出.另外的主机就会去完成它的传输.
在仲裁处理过程中没有信息丢失.失去仲裁的主机在它失去仲裁的字节末尾处产生时钟脉冲,当总线空闲时必须重启它的传输.
如果一个主机包含从机的功能,当它在寻址阶段丢失仲裁,那么赢得仲裁的主机可能会寻址它.丢失仲裁的主机必须立即切换到它的从模式.
因为I2C总线只是仅由地址来控制,数据只由赢得仲裁的主机发送,这里没有最重要的主机,在总线上也没有优先级顺序.
在仲裁处理正在进行的时候,一个主机发送重复的开始条件或者是终止条件而另一个主机仍然在发送数据,那么这时候有一个未定的状态.换句话说,下面的条件下会出现这种情况:
- 主机1发送重复的开始条件,主机2发送一个数据位
- 主机1发送终止条件,主机2发送一个数据位
- 主机1发送重复的开始条件,主机2发送终止条件
###7. i2c从机地址和保留地址
通常, i2c总线上在Start信号之后的第一个字节为从机地址以及读写位,且最高有效位先发送, 即第一个字节的高bit[7:1]用于表示从机地址, bit[0]表示读写位
对于第一个byte的分配如下:
- 0000 000 0 : 通用的广播地址
- 0000 000 1 : 开始字节
- 0000 001 x : 保留的,使得同一个系统可CBUS总线兼容的设备和I2C总线兼容的设备.I2C兼容的设备不允许响应这个地址
- 0000 010 x : 为不同总线格式保留的
- 0000 011 x : 7bit从机地址
- 0000 1xx x : hsmode
- 1111 1xx x : 保留, 用于扩展
- 1111 0xx x : 10bit地址
####7.1 广播地址
Start 信号之后的第一个字节 为 ‘0000 0000’ 代表通用广播地址, 通用广播地址用于寻址所有的i2c设备, 若从机在响应广播地址时不需要额外的数据, 则它可以不产生应答,否则, 从机需要作为接收端来接收并处理主机发出的第2个字节
对于广播地址后的第二个字节, 根据最低位的bit的值, 有不同的意义, 当最低有效位为0时:
- 0000 0110 : 软件复位设备(并不是所有的设备都支持软件复位), 然后并且进入从机地址编程模式, 可以通过硬件写从机地址的可编程部分(从机地址的编程过程要参照datesheet), 需要注意的时, 设备复位后, 不能拉低SDA和SCL, 这样将会锁死i2c总线
- 0000 0100 : 进入从机地址编程模式, 可以通过硬件写从机地址的可编程部分(从机地址的编程过程要参照datesheet)
- 0000 0000 : 不能作为广播地址后的字节出现
####7.2 开始字节
微控制器有两种方式连接到I2C总线上.有片上的硬件I2C总线接口的微控制器可以编程为只接收总线的中断请求.当设备没有这样的接口(例如通过gpio模拟i2c),它必须要通过软件手段(轮询)来检测总线.很明显,微控制器检测的时间或者轮询总线的时间越多,实现自己功能的时间就越少
因此快速硬件设备和依赖软件轮询的相对慢速微控制器是有速度差别的.
在这种情况下,数据传输前有一个比正常时间长很多的起始过程.起始过程组成如下:
- 一个开始条件(S)
- 一个开始字节(0000 0001)
- 应答位(ACK)
主机发送完开始条件后,发送开始字节(0000 0001), 作为从机的的微控制器可以以低采样率来采样SDA线知道开始字节的7个0中的一个被侦测到.在侦测到SDA线的低电平后,微控制器可以切换到更高的采样率来探测用于同步的重复开始条件
####7.3 7bit地址
7bit地址为 “0000 011 x” 到 “1110 xxx x“ 因此, 有效的 7bit地址为 0x03 ~ 0x77
####7.4 10bit 地址
10bit的寻址扩展可能寻址的数目.有7bit地址和10bit地址的设备可以连接到相同的I2C总线上,而且7bit寻址和10bit寻址都可以用在所有的总线速度模式下.不过,10bit寻址用的不多
10bit的从机地址由开始条件(S)或重复开始条件(Sr)后的两个字节组成.第一个字节的前7位是1111 0XX, XX是10bit地址的最高有效位的前两位.第一个字节的第8bit是读写位,决定传输方向
则10 bit地址的范围为
第一字节前7位 第二字节
1111 0xx xxxx xxxx
###8. i2c 总线死锁
I2C总线协议能够保证总线正常的读写操作。但是,当I2C主设备异常复位时(看门狗动作,板上电源异常导致复位芯片动作,手动按钮复位等等)有可能导致I2C总线死锁产生。此时, 若不设法将i2c总线恢复则该总线将一直处于busy状态
####8.1 死锁的原因
在I2C主设备进行读写操作的过程中.主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从设备输出应答信号,将SDA信号拉为低电平。如果这个时候主设备异常复位,SCL就会被释放为高电平。此时,如果从设备没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。而对于I2C主设备来说.复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电平。这样,I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种死锁状态
同样,当I2C进行读操作,I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0,也会导致I2C总线进入死锁状态
####8.2 解决的方法
- 选用带有复位输入的i2c器件
- 将所有的从I2C设备的电源连接在一起,通过MOS管连接到主电源,而MOS管的导通关断由I2C主设备来实现
- 在I2C从设备设计看门狗的功能
- 在I2C主设备中增加I2C总线恢复程序。每次I2C主设备复位后,如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来。这种方法有很大的局限性,因为大部分主设备的I2C模块由内置的硬件电路来实现,软件并不能够直接控制SCL信号模拟产生需要时钟脉冲
- 在I2C总线上增加一个额外的总线恢复设备。这个设备监视I2C总线。当设备检测到SDA信号被拉低超过指定时间时,就在SCL总线上产生9个时钟脉冲,使I2C从设备完成读操作,从死锁状态上恢复出来。总线恢复设备需要有具有编程功能,一般可以用单片机或CPLD实现这一功能
- 在I2C上串人一个具有死锁恢复的I2C缓冲器,如Linear公司的LTC4307o是一个双向的I2C总线缓冲器,并且具有I2C总线死锁恢复的功能。LTC4307总线输人侧连接主设备,总线输出侧连接所有从设备。当LTC4307检测到输出侧SDA或SCL信号被拉低30ms时,就自动断开I2C总线输人侧与输出侧的连接.并且在输出侧SCL信号上产生16个时钟脉冲来释放总线。当总线成功恢复后,LTC4307再次连接输人输出侧,使总线能够正常工作