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,以保持总线控制权。
3.3 数据传输格式与字节规则
I2C 数据传输以字节(8位)为单位,每个字节后跟随一个应答位(ACK/NACK)。数据传输遵循以下规则:
- MSB 优先: 每个字节从最高位(MSB)开始传输。
- 应答机制: 每发送完一个字节,接收方在第9个SCL周期拉低SDA表示应答(ACK),保持高电平表示非应答(NACK)。
- 数据有效性: 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),驱动开发者无需手动移位,内核会自动处理。
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 读操作时序如下:
- START:主设备产生起始条件。
- 发送从设备地址 + 写位:发送 0x70(7位地址 0x38 + W)。
- 等待 ACK:FT5x06 拉低 SDA 应答。
- 发送寄存器地址:发送要读取的寄存器地址(如 0x00)。
- 等待 ACK:FT5x06 应答。
- 重复起始条件:主设备产生 Repeated START。
- 发送从设备地址 + 读位:发送 0x71(7位地址 0x38 + R)。
- 等待 ACK:FT5x06 应答。
- 读取数据字节:主设备读取 N 个字节,每字节后发送 ACK。
- 发送 NACK + STOP:读取最后一个字节后,主设备发送 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 | 驱动核心通信接口 |