博客专栏

EEPW首页 > 博客 > I2C总线协议分析

I2C总线协议分析

发布人:嵌入式Linux 时间:2023-01-13 来源:工程师 发布文章
I2C总线概念

I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的设备之间通信。I2C的两根线SDA(串行数据线)和SCL(串行时钟线)都是双向I/O线,接口电路为开漏输出,需通过上拉电阻接电源VCC,当总线空闲时,两根线都是高电平。

常见的硬件结构图(一个适配器,两根线,若干设备而已)


I2C总线通信时序

使用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位为单位的,所以当主机要往从机写数据时时序如下:

  1. 发送start信号

  2. 发送7位地址+1个读写位0(0表示写,1表示读)

  3. 从机收到地址后,发送ACK应答信号

  4. 主机收到应答信号后发送要写的8位数据

  5. 若从机收到主机发送的数据,发送ACK应答信号

  6. 如果主机要继续写,那么回到步骤4,如果写完了那么发送stop信号,终止通信

当主机要从从机读取数据时时序如下:

  1. 发送start信号

  2. 发送7位地址+1个读写位1(0表示写,1表示读)

  3. 从机收到地址后,发送ACK应答信号

  4. 主机收到应答信号后等待接收从机的数据

  5. 从机发送主机要读取的数据

  6. 若主机收到从机发送的数据,发送ACK应答信号

  7. 如果主机要继续读,那么回到步骤4,如果读完了那么发送stop信号,终止通信


那么在具体的使用场景中是什么样子呢?从机设备内部往往有很多寄存器,如何读写这些寄存器呢?以RPR0521这个sensor作为从设备的实例进行分析:

主机写RPR0521中某个寄存器(寄存器的地址是8位的,寄存器中数据也是8位的)

  1. 主机发送完7位的从机地址和写位

  2. 主机发送8位的要写的从机的内部寄存器地址

  3. 从机收到后发送ACK

  4. 主机收到ACK后,然后发送要往这个寄存器写的数据

  5. 如果主机不继续写数据就直接发送stop,如果还要往下一个寄存器继续写(寄存器地址必须连续)那么回到步骤4发送下一个数据,直到写完发送stop


主机读RPR0521中某个寄存器的值(寄存器的地址是8位的,寄存器中数据也是8位的)

  1. 主机发送完7位的从机地址和写位(一定要注意,先写然后读)

  2. 主机发送8位的要读的从机的内部寄存器地址(用于确定要读的寄存器的地址)

  3. 从机收到后发送ACK

  4. 主机收到ACK后发送7位的从机地址和读位,然后等待接收数据

  5. 主机收到ACK和从机发送过来的数据

  6. 如果主机不读了就发送stop,如果继续读就回到步骤5(从机会自动发送连续寄存器的数据)


常用debug手段

在实际项目中,通常会出现读不到数据,那么我们就需要debug,最常见的debug手段就是使用示波器抓时序,下图是I2C数据传输的时序:


SDA的数据在SCL位高电平时保持稳定,在SCL为低电平时数据改变,所以我们应该在时钟周期的高电平期间读取有效数据进行分析。

以上是我总结的I2C总线的基本协议,如有不足欢迎指出,谢谢阅读!


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。



关键词: I2C 总线协议

相关推荐

技术专区

关闭