I2C总线协议分析
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的设备之间通信。I2C的两根线SDA(串行数据线)和SCL(串行时钟线)都是双向I/O线,接口电路为开漏输出,需通过上拉电阻接电源VCC,当总线空闲时,两根线都是高电平。
常见的硬件结构图(一个适配器,两根线,若干设备而已)
使用I2C通信时,必须指定主从设备,一般包含有I2C控制器的处理器被配置成主设备,挂接在i2c总线上的外设作为从设备。通信开始都是由主设备发起的,在i2c总线上的每个设备都有一个7bit位的地址,称为i2c设备地址。
主设备如何发起开始和停止通信信号?
在SCL线为高电平时,将SDA线由高拉低,即发出一个start开始信号;当SCL为高电平时,将SDA由低拉高,即发送一个stop停止信号;那么这些操作都是由主设备的I2C控制器完成的。
I2C总线上有很多的设备,如何保证一对一的通信?
在I2C总线上的每个设备都有一个7bit位的地址,在I2C总线处于空闲状态时,如果有主设备想发起通信,那么将由它先发出一个start信号占有总线,紧接着发送这个主设备想要进行通信的从设备的7bit位的地址,这个地址在I2C总线上处于广播状态,即总线上的所有设备都能看到这个地址,如果某一个从设备发现总线上传输的地址和自己的设备地址一样,那么就发送一个应答信号,这时主从设备间的通信就建立了,这个时候I2C总线将处于busy状态,其他的设备无法再使用总线,从而在总线上建立了一个一对一的通信。当通信结束时,由主设备发送一个stop信号,释放总线,其他的设备就可以再次占用总线通信了。
I2C上的主从设备如何通信?
在I2C总线上传输的数据都是8bit位为单位的,所以当主机要往从机写数据时时序如下:
发送start信号
发送7位地址+1个读写位0(0表示写,1表示读)
从机收到地址后,发送ACK应答信号
主机收到应答信号后发送要写的8位数据
若从机收到主机发送的数据,发送ACK应答信号
如果主机要继续写,那么回到步骤4,如果写完了那么发送stop信号,终止通信
当主机要从从机读取数据时时序如下:
发送start信号
发送7位地址+1个读写位1(0表示写,1表示读)
从机收到地址后,发送ACK应答信号
主机收到应答信号后等待接收从机的数据
从机发送主机要读取的数据
若主机收到从机发送的数据,发送ACK应答信号
如果主机要继续读,那么回到步骤4,如果读完了那么发送stop信号,终止通信
那么在具体的使用场景中是什么样子呢?从机设备内部往往有很多寄存器,如何读写这些寄存器呢?以RPR0521这个sensor作为从设备的实例进行分析:
主机写RPR0521中某个寄存器(寄存器的地址是8位的,寄存器中数据也是8位的)
主机发送完7位的从机地址和写位
主机发送8位的要写的从机的内部寄存器地址
从机收到后发送ACK
主机收到ACK后,然后发送要往这个寄存器写的数据
如果主机不继续写数据就直接发送stop,如果还要往下一个寄存器继续写(寄存器地址必须连续)那么回到步骤4发送下一个数据,直到写完发送stop
主机读RPR0521中某个寄存器的值(寄存器的地址是8位的,寄存器中数据也是8位的)
主机发送完7位的从机地址和写位(一定要注意,先写然后读)
主机发送8位的要读的从机的内部寄存器地址(用于确定要读的寄存器的地址)
从机收到后发送ACK
主机收到ACK后发送7位的从机地址和读位,然后等待接收数据
主机收到ACK和从机发送过来的数据
如果主机不读了就发送stop,如果继续读就回到步骤5(从机会自动发送连续寄存器的数据)
常用debug手段
在实际项目中,通常会出现读不到数据,那么我们就需要debug,最常见的debug手段就是使用示波器抓时序,下图是I2C数据传输的时序:
SDA的数据在SCL位高电平时保持稳定,在SCL为低电平时数据改变,所以我们应该在时钟周期的高电平期间读取有效数据进行分析。
以上是我总结的I2C总线的基本协议,如有不足欢迎指出,谢谢阅读!
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。