概述
本文为I2C协议的简要解析,旨在帮助日常开发中遇到的I2C协议的问题,详细的I2C协议,请查看飞利浦半导体公司发布的文档。除了标准的I2C协议外,还有其他兼容I2C协议,比如smbus、pmbus, 和现在I2C协议的升级版本I3C协议。
物理拓扑
这是从NXP I2C协议文档中复制的一张图片,I2C的物理链接拓扑如下所示:
从上面的图片中我们可以得出I2C总线物理上有如下的特点:
1、I2c总线有两个信号线组成,一条是SCL时钟线,另外一条是SDA数据线;
2、I2C总线属于主从通信模型,只有master会发起通信,slave从设备只负责响应,但是作为I2C的升级版本I3C,据说slave也能发起通信;
3、SCL:Serial Clock 时钟线:由主机输出时钟节拍,同步所有数据收发。
4、SDA:Serial Data 数据线:双向传输地址 + 读写数据,开漏输出结构。
5、所有设备 SCL、SDA 分别并联在一起;
6、必须上拉电阻(典型 4.7kΩ)到 VCC,空闲时两根线都是高电平;
7、I2C总线上有1 个主机 Master(MCU/CPU),多个从机 Slave(EEPROM、RTC、ADC等);
8、在从机地址7位模式中,理论上最多挂载设备数(2^7=128) 个,但是部分地址为保留地址,实际可用 112 个;
9、总线速率:
1)标准模式:100kHz
2)快速模式:400kHz(最常用)
3)高速模式:1MHz/3.4MHz
4)超高速:5MHz
I2C设备地址
I2C设备支持两种地址模式,分别是7位地址模式和10位地址模式,通常我们接触的7位地址模式比较常见。在I2C设备驱动的适配中,我们常常需要确定I2C设备的地址,但是大部分的数据手册,提供的I2C通信中的地址,比如在EEROM数据手册中提供的读地址0xA1, 写地址0xA0,那我们如何确定i2c设备的地址呢,
I2C通信的地址由两部分组成:7bit设备地址+1bit读写标记,因此如果你的I2C设备手册只提供读写地址,我们可以通过如下的计算方式,获得I2C设备地址:
1、I2C设备地址 = I2C读地址 >> 1 or I2C设备地址 = I2C写地址 >> 1;
2、将右移后的7bit地址的最高位补0,则构成了I2C设备的地址,比如对于EEROM的读地址0xA1,将0xA1 >> 1后,最高位补0,则得到EEROM的设备地址为0x50;
I2C时序信号
总线空闲:
当I2C总线处于空闲状态时,SCL和SDA都处于高电平状态
起始信号 Start
SCL 维持高电平期间,SDA 由高电平跳变到低电平告诉所有从机:主机即将开始传输数据
停止信号 Stop
SCL 维持高电平期间,SDA 由低电平跳变到高电平告诉从机:本次通信结束,总线释放
数据有效性时序
这个是大家比较忽略的一点,在I2C协议中,当SCL处于高电平时,此时的SDA的电平表示I2C数据位,当SCL处于低电平时,SDA处于可变化数据状态,不是有效的I2C数据位,因此我们在使用示波器或者逻辑分析仪分析I2C波形时,可以通过这种方式来确定,SDA数据的正确性;
设备应答和非应答时序
在I2C通信中的第9个SCL时钟时,对SDA进行采样,当SDA处于低电平时,则表示从设备应答,当SDA处于高电平时,则表示从设备无应答;通过这种手段,我们可以通过观察示波器或者逻辑分析仪的波形来确定I2C设备的工作状态;
通信数据
如下一个I2C数据的传输过程,I2C数据传输传输单元是字节进行的,因此在比如读或者写一个I2C设备的内部寄存器地址,并且是高位在前,地位在后;如下展示的是完整读或者写一个寄存器的传输过程;
从通信过程中我们可以得到如下的信息:
1)主机发送START,开启传输;
2)不管是读还是写,I2C第一个字节的数据都是从设备地址+读写标记位;
3)不管是读还是写操作,则第二个字节数据为I2C设备的内部寄存器的地址;
4)如果是读操作,则第三个字节为读到的I2C设备内部寄存器的数据,如果是写操作,则第三个字节为写入I2C设备内部寄存器的数据;
5)读或者写完成后,主机发送STOP;
当然,我们可以在I2C通信中,一次通信中操作多个I2C设备的内部寄存器,关于这部分的传输过程,感兴趣的同学,自己完成探索,这里不再描述;
总结
本文为作为一个Linux嵌入式工程师的视角简要描述了I2c协议,感兴趣的同学,可以去nxp上学习完整i2c协议;