Linux驱动-通过逻辑分析仪-认识-分析IIC波形

提示:通过逻辑分析仪-认识-分析IIC波形

文章目录

前言-目标

做软件的本身对硬件相关的波形、原理、操作比较困难,知识点欠缺。所以在很多日常基本问题前无从下手,这里分析一下波形,搞清楚IIC波形,让对波形问题不再恐惧。

一、知识点储备(重点)

总线拓扑结构

  • I2C 总线采用主从式架构,由一个主设备(Master)和一个或多个从设备(Slave)组成。 主设备负责发起数据传输,从设备则响应主设备的请求

物理层接口

I2C 总线使用两根线路进行通信:

  • SCL(Serial Clock Line)时钟线,由主设备提供时钟信号。
  • SDA(Serial Data Line)数据线,用于双向传输数据。

通信协议

I2C 采用同步串行通信方式,主设备发起通信并提供时钟。 主设备首先发送一个"启动"信号,然后发送从设备地址和数据传输方向(读或写)。 从设备在收到自己的地址后,会发送应答信号,表示已准备好接收或发送数据。 之后主设备和从设备就可以开始传输数据。 通信结束时,主设

备发送"停止"信号。

寻址机制

  • I2C 使用 7 位地址空间,最多可寻址 127 个从设备。 地址空间的前 7 位用于指定从设备,最后1 位用于表示读/写方向。
  • 每一个 12C 外设都会对应一个唯一的地址(这个地址可以从 I2C 外设器件的数据手册中得到) , 主机和从机之间的通信就是通过这个地址来确定主机要和哪个从机进行通信的。

起始信号和终止信号

所有的交互都是以 START(S)信号开始,并以 STOP§信号终止, 具体的起始信号和终止信号

通信时序图如下所示

  • 起始信号(START): 是由总线控制器生成的,定义为 SDA 线从高电平到低电平的跳变,同时 SCL线保持高电平。
  • 终止信号(STOP): 是由总线控制器生成的,定义为 SDA 线从低电平到高电平的跳变,同时 SCL线保持高电平。

数据格式

    1. 每一个传输到 SDA 线上的字节长度都必须是 8 位。 每次传输可以包含任意数量的字节。
    1. 每个字节之后都必须跟一个应答位(Acknowledge bit)。
    1. 数据以最高有效位(MSB)优先的顺序传输。
    1. 如果目标设备在处理内部中断等操作时无法立即接收或发送另一个完整的字节数据,它可以通过拉低 SCL 线来将控制器置于等待状态。 当目标设备准备好接收下一字节数据时,释放SCL 线即可继续数据传输

应答信号和非应答信号

    1. 应答信号发生在每个字节传输之后。 应答位让接收设备向发送设备表明字节数据已经成功接收,可以发送下一个字节了。
    1. 当发送设备在第 9 个时钟脉冲期间释放 SDA 线时,接收设备可以拉低 SDA 线并在此时钟高电平期间保持稳定低电平,这就定义了应答信号。
    1. 如果在第 9 个时钟脉冲期间 SDA 线保持高电平,则定义为非应答信号。 控制器可以产生停止信号中止传输,或者重复启动信号开始新的传输。
      应答信号和非应答信号时序如下图所示

读写方向

  • 1.数据传输格式, 首先发送一个 7 位的目标地址,后跟一个读/写方向位(R/W 位)。
  • 2.读/写方向位是第 8 位,0 表示写操作(WRITE), 1 表示读操作(READ)。
  • 3.数据传输总是由控制器产生的停止条件§来结束。 但如果控制器需要继续在总线上通信,它可以产生一个重复启动条件(Sr)来寻址其他目标设备,而无需先产生停止条件。

这些基本的机制、概念特别重要,不然没法分析波形,没法看懂波形,没法了解和理解IIC通讯。

二、分析波形需求

学会看波形,比如通过波形知道IIC 开始、停止、每个波形段做了什么事情。

三、参考资料

Linux驱动-IIC完善FT5X06设备节点和驱动

Linux驱动-I2C通信-FT5X06驱动程序部分编写

RK3568驱动指南|第十五篇 I2C-第176章 通过逻辑分析仪认识I2C波形

四、实战分析波形

我们拿 上一篇笔记对IIC 操作来进行波形分析:

java 复制代码
    ft5x06_write_reg(0x80,0x4b,1);
    value = ft5x06_read_reg(0x80);

IIC开始波形

总结来看:

  • 在数据传输之前, 主机要先发送一个起始信号, 起始信号为 SDA 线从高电平到低电平的跳变,同时 SCL 线保持高电平, 就对应下图所示部分,逻辑分析仪软件也用一个绿色的远点进行了
    标注

IIC写波形

写芯片FT5X06地址0x38 波形

分析如下 示意图:0x38 是哪里来的? Linux驱动-IIC完善FT5X06设备节点和驱动 是我们再设备树中配置的IIC 芯片地址呀。

总结来看:

  • 传输了一个 8 位的数据, 分别为 7 位的地址和读写方向, 前七个时钟周期的值为0111000, 转换为 16 进制就是 0x38, 也就是 FT5X06 的芯片地址, 第 8 个时钟周期为 0, 表示
    读写方向为写入。
  • 然后是一个 ACK 应答信号, 这里为 0 低电平表示 I2C 外设已发送应答

写寄存器地址0x80波形

有了如上的基础概念和芯片地址分析,那么发送外设寄存器地址0x80 波形分析如下:红色标记部分

写寄存器数据0x4b波形

IIC停止信号波形

发送完成之后主机会发送一个终止信号, 终止信号为 SDA 线从低电平到高电平的跳变,同时 SCL 线保持高电平

写操作分为以下步骤总结

  • 1.主机发送一个起始信号
    -2.主机发送 I2C 外设的地址和写操作, 等待应答信号
  • 3.从机发送应答信号
  • 4.主机要发送寄存器的地址, 等待应答信号
  • 5.从机发送应答信号
  • 6.主机发送要写入的寄存器的数据, 等待应答信号
  • 7.从机发送应答信号
  • 8.主机要发送终止信号, 如果写多个寄存器, 重复 6,7 步骤。

IIC读波形

读波形: value = ft5x06_read_reg(0x80);

写芯片FT5X06地址0x38 波形

分析如下 示意图:0x38 是哪里来的? Linux驱动-IIC完善FT5X06设备节点和驱动 是我们再设备树中配置的IIC 芯片地址呀。

为什么读也要写一次呢? 这个 在 Linux驱动-I2C通信-FT5X06驱动程序部分编写 讲过这个知识点,i2c_msg 信息如下:

java 复制代码
struct i2c_msg msgs[2] = {
		[0] = {
			.addr = ft5x06_client->addr, // I2C从机地址0x38
			.flags = 0,                  // 标志0 = I2C写操作
			.len = sizeof(reg_addr),     // 长度1字节(寄存器地址)
			.buf = &reg_addr,            // 缓冲区:要读取的寄存器号
		},
		[1] = {
			.addr = ft5x06_client->addr,
			.flags = I2C_M_RD,           // I2C_M_RD = 读操作标志
			.len = sizeof(data),         // 读取1字节返回值
			.buf = &data,                // 读到的数据存入data
		},
	};

总结来看:

  • 传输了一个 8 位的数据, 分别为 7 位的地址和读写方向, 前七个时钟周期的值为0111000, 转换为 16 进制就是 0x38, 也就是 FT5X06 的芯片地址, 第 8 个时钟周期为 0, 表示
    读写方向为写入。
  • 然后是一个 ACK 应答信号, 这里为 0 低电平表示 I2C 外设已发送应答

读寄存器地址0x80波形

其实和写一模一样的波形,因为在第一步骤如上已经发送了主机的0x38 地址,给了写操作。 这里 读寄存器地址 其实就是前七位数据位和8为写操作。 和上面的一模一样的波形。

读取0x4B数据

IIC 停止信号波形

读操作总结步骤

  • 1.主机发送一个起始信号
  • 2.主机要发送 12C 外设地址和写操作, 等待应答信号
  • 3.从机发送应答信号
  • 4.主机要发送要读取的寄存器的地址, 等待应答信号
  • 5.从机发送应答信号
  • 6.主机发送起始信号
  • 7.主机发送要读取的 12C 外设的地址和读操作, 等待应答信号
  • 8.从机发送应答信号
  • 9.从机发送数据, 也就是要读取的寄存器的数据, 等待应答或者非应答信号
  • 10.主机如果不在读取数据, 就要发送非应答信号, 如果继续读取, 就发送应答信号

总结

  • 这里分析了波形,实际波形可能是波纹不是方波,这个很正常,但是分析是一样的分析方法
  • 搞清楚波形对应的代码、代码对应的波形很有帮助
  • 分析波形其实是最简单事情,务必掌握