3. I2C协议基础:总线工作原理与数据传输格式

FT5x06 触摸屏控制器通过 I2C(Inter-Integrated Circuit)总线与主处理器通信。I2C 是一种同步、多主从、串行通信总线,仅需两根线(SCL 时钟线、SDA 数据线)即可连接多个设备。理解 I2C 协议是驱动移植与调试的前提。

3.1 I2C总线物理层与电气特性

I2C 总线使用开漏(Open-Drain)输出,通过上拉电阻将 SCL 和 SDA 线拉至高电平。总线空闲时,SCL 和 SDA 均为高电平。

参数 标准模式 (Standard) 快速模式 (Fast) 高速模式 (High-Speed)
最大时钟频率 100 kHz 400 kHz 3.4 MHz
最大总线电容 400 pF 400 pF 100 pF
上拉电阻典型值 4.7 kΩ 2.2 kΩ 1.0 kΩ
最大从设备数量 127 (7位地址) 127 (7位地址) 127 (7位地址)
FT5x06 工作模式: FT5x06 支持标准模式(100 kHz)和快速模式(400 kHz)。在驱动初始化时,通常配置 I2C 控制器时钟为 100 kHz 以确保兼容性,调试稳定后可切换至 400 kHz 提升吞吐量。

3.2 起始条件与停止条件

I2C 总线上数据传输的起始和停止由 SDA 和 SCL 的电平变化定义:

  • 起始条件(START): SCL 为高电平时,SDA 从高电平切换到低电平。
  • 停止条件(STOP): SCL 为高电平时,SDA 从低电平切换到高电平。
关键点: 起始和停止条件只能由主设备(Master)产生。每次传输必须以 START 开始,以 STOP 结束。连续传输时,可使用重复起始条件(Repeated START)代替 STOP + START,以保持总线控制权。
I2C 起始条件与停止条件时序 SCL SDA START SDA下降沿 STOP SDA上升沿 数据有效

3.3 数据传输格式与字节规则

I2C 数据传输以字节(8位)为单位,每个字节后跟随一个应答位(ACK/NACK)。数据传输遵循以下规则:

  1. MSB 优先: 每个字节从最高位(MSB)开始传输。
  2. 应答机制: 每发送完一个字节,接收方在第9个SCL周期拉低SDA表示应答(ACK),保持高电平表示非应答(NACK)。
  3. 数据有效性: SCL 高电平时,SDA 数据必须保持稳定;SCL 低电平时,SDA 允许变化。
位序 位 7 (MSB) 位 6 位 5 位 4 位 3 位 2 位 1 位 0 (LSB) ACK
数据 D7 D6 D5 D4 D3 D2 D1 D0 低电平

3.4 7位地址与读写位

I2C 从设备使用唯一地址进行寻址。FT5x06 使用 7 位地址,地址值为 0x38(7位)。在传输时,主设备发送的地址字节由 7 位地址和 1 位读写标志组成:

  • 地址字节格式: [A6 A5 A4 A3 A2 A1 A0 R/W]
  • R/W = 0: 主设备写操作(发送数据到从设备)。
  • R/W = 1: 主设备读操作(从从设备接收数据)。
常见混淆点: FT5x06 的 7 位地址 0x38 左移一位后得到 0x70(写地址)和 0x71(读地址)。在 Linux 内核 I2C 子系统中,i2c_client 的 addr 字段存储的是 7 位地址(0x38),驱动开发者无需手动移位,内核会自动处理。
7位地址字节结构 A6 A5 A4 A3 A2 A1 A0 R/W 7位从设备地址 读写位 示例:FT5x06 地址 0x38 → 写字节 0x70 (0111 0000) | 读字节 0x71 (0111 0001)

3.5 10位地址扩展

当系统中从设备数量超过 127 个时,I2C 规范定义了 10 位地址模式。10 位地址使用两个字节传输:

  • 第一个字节: 1111 0XX + R/W(XX 为地址高 2 位)。
  • 第二个字节: 地址低 8 位。
特性 7位地址 10位地址
地址范围 0x00 ~ 0x7F 0x000 ~ 0x3FF
保留地址 0x00 ~ 0x07, 0x78 ~ 0x7F 0x000 ~ 0x007, 0x3F8 ~ 0x3FF
传输字节数 1 字节地址 + 1 位 R/W 2 字节地址 + 1 位 R/W
FT5x06 支持 是(地址 0x38) 否
FT5x06 地址确认: 在驱动移植时,使用 i2cdetect -y <bus> 命令扫描 I2C 总线,若在地址 0x38 处检测到设备,则说明 FT5x06 硬件连接正常。这是调试的第一步。

3.6 I2C 完整读写时序

以 FT5x06 读取触摸点数据为例,完整的一次 I2C 读操作时序如下:

  1. START:主设备产生起始条件。
  2. 发送从设备地址 + 写位:发送 0x70(7位地址 0x38 + W)。
  3. 等待 ACK:FT5x06 拉低 SDA 应答。
  4. 发送寄存器地址:发送要读取的寄存器地址(如 0x00)。
  5. 等待 ACK:FT5x06 应答。
  6. 重复起始条件:主设备产生 Repeated START。
  7. 发送从设备地址 + 读位:发送 0x71(7位地址 0x38 + R)。
  8. 等待 ACK:FT5x06 应答。
  9. 读取数据字节:主设备读取 N 个字节,每字节后发送 ACK。
  10. 发送 NACK + STOP:读取最后一个字节后,主设备发送 NACK 并产生停止条件。
FT5x06 I2C 读操作完整时序 START 0x70 (写) ACK 寄存器地址 ACK R-START 0x71 (读) ACK 数据字节 ACK 最后字节 NACK STOP 主→从 主→从 图例说明 起始/停止条件 地址字节 应答 (ACK) 非应答 (NACK) 寄存器地址 数据字节

3.7 Linux 内核 I2C 传输接口

在 Linux 驱动中,I2C 通信通过内核提供的 API 完成。FT5x06 驱动通常使用以下接口:

// 单次消息传输
int i2c_master_send(struct i2c_client *client, const char *buf, int count);
int i2c_master_recv(struct i2c_client *client, char *buf, int count);

// 组合消息传输(支持重复起始条件)
struct i2c_msg msgs[2];
msgs[0].addr = client->addr;
msgs[0].flags = 0;          // 写
msgs[0].len = 1;
msgs[0].buf = ®_addr;

msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;   // 读
msgs[1].len = data_len;
msgs[1].buf = data_buf;

int ret = i2c_transfer(client->adapter, msgs, 2);
驱动调试建议: 在 FT5x06 驱动 probe 函数中,首先使用 i2c_master_send 写入一个已知寄存器(如设备ID寄存器 0xA8),然后使用 i2c_master_recv 读取并验证返回值。若读取值与数据手册一致,则 I2C 通信链路正常。

3.8 本章小结

知识点 核心要点 FT5x06 相关
起始/停止条件 SCL 高电平时 SDA 跳变 每次传输必须包含
数据传输格式 MSB 优先,每字节后 ACK 寄存器地址 + 数据
7位地址 地址字节 = 7位地址 + R/W FT5x06 地址 0x38
10位地址 2字节地址,兼容 7 位 FT5x06 不支持
Linux API i2c_master_send/recv, i2c_transfer 驱动核心通信接口