3. I2C 寻址模式:7位寻址与10位寻址、广播地址、保留地址
I2C 总线上的每个从设备都有一个唯一的地址,主设备通过发送地址来选择要通信的从设备。理解 I2C 的寻址模式是驱动开发和调试的基础。本章将深入剖析 7 位寻址、10 位寻址、广播地址以及保留地址的机制与使用场景。
3.1 7位寻址模式
7 位寻址是 I2C 最基础、最常用的寻址方式。地址字节的高 7 位(D7-D1)构成设备地址,最低位(D0)为读写标志位(R/W)。
- 地址范围:0x00 ~ 0x7F(共 128 个地址),但其中 16 个地址被保留用于特殊用途,实际可用地址为 112 个。
- 传输格式:主设备发送起始条件后,先发送 1 字节地址(7 位地址左移 1 位 + R/W 位)。
- 典型应用:绝大多数 I2C 传感器、存储器、IO 扩展芯片均使用 7 位寻址。
驱动开发要点:在 Linux 内核中,7 位地址通过
i2c_client 结构体的 addr 字段表示,地址值范围为 0x03 ~ 0x77(排除保留地址)。
常见误区:许多数据手册给出的地址是 8 位格式(含 R/W 位),例如 0xA0。在驱动中需要右移 1 位得到 7 位地址 0x50。
7位寻址传输时序
3.2 10位寻址模式
10 位寻址扩展了 I2C 的地址空间,允许连接更多从设备。它使用两个字节来传输地址。
| 特性 | 7位寻址 | 10位寻址 |
|---|---|---|
| 地址位数 | 7 位 | 10 位 |
| 最大设备数 | 112(可用) | 1024 |
| 地址字节数 | 1 字节 | 2 字节 |
| 首字节高5位 | 地址位 A6-A2 | 11110xx(保留标识) |
| 兼容性 | 所有设备 | 仅支持10位寻址的设备 |
10位寻址传输过程
- 首字节:高 5 位固定为
11110,接着是地址的高 2 位(A9-A8),最后是 R/W 位。 - 次字节:地址的低 8 位(A7-A0)。
- 应答:每个地址字节后从设备都需要回复 ACK。
驱动注意事项:在 Linux 内核中,10 位地址通过
I2C_CLIENT_TEN 标志位标识。使用 i2c_new_client_device() 时需设置 flags |= I2C_CLIENT_TEN。并非所有 I2C 控制器都支持 10 位寻址,需检查控制器驱动能力。
10位寻址帧结构
3.3 广播地址(General Call Address)
广播地址为 0x00(7 位地址),用于主设备向总线上所有从设备发送通用消息。并非所有从设备都会响应广播地址,需要设备支持该功能。
- 地址值:0x00(7位),发送时首字节为 0x00。
- 第二字节含义:
- 0x06:复位所有从设备(硬件复位)。
- 0x04:写入可编程部分(如配置寄存器)。
- 其他值:由具体设备定义。
- 驱动处理:Linux 内核中,从设备驱动可通过
I2C_CLIENT_SLAVE标志注册对广播地址的响应。
调试技巧:使用
i2cget -y <bus> 0x00 可以测试总线是否支持广播地址。如果返回数据,说明总线上有设备响应广播。
3.4 保留地址
I2C 规范保留了 16 个 7 位地址(0x00 ~ 0x0F)用于特殊用途。驱动开发中应避免将这些地址分配给普通从设备。
| 7位地址 | 用途 | 说明 |
|---|---|---|
| 0x00 | 广播地址 | 通用呼叫地址 |
| 0x01 | 起始字节 | 用于慢速MCU的起始条件 |
| 0x02 | CBUS地址 | 保留给CBUS兼容设备 |
| 0x03 | 保留 | 未来扩展用途 |
| 0x04-0x07 | 高速模式地址 | Hs模式主设备代码 |
| 0x08-0x0F | 保留 | 用于10位寻址标识 |
关键提醒:在编写设备树或配置 I2C 从设备地址时,务必避开保留地址范围(0x00-0x0F)。使用
0x10-0x77 范围内的地址是安全的。如果设备手册给出的地址落在保留区内,请仔细核对手册是否使用了 8 位地址表示法。
3.5 寻址模式选择策略
在实际嵌入式系统中,选择哪种寻址模式取决于硬件设计和系统需求:
- 优先使用 7 位寻址:兼容性最好,控制器支持最广泛,驱动开发最简单。
- 10 位寻址适用场景:当总线上需要超过 112 个从设备时,或设备本身只支持 10 位寻址。
- 广播地址使用:用于系统级同步、复位或固件升级场景。
- 地址冲突检测:在驱动初始化时,使用
i2c_check_addr_busy()检查地址是否已被占用。
寻址模式决策流程
3.6 驱动代码示例:地址配置
以下代码展示了在 Linux 内核驱动中如何配置 7 位和 10 位地址:
/* 7位地址配置示例 */
static const struct i2c_device_id mydevice_id[] = {
{ "my_sensor", 0 },
{ }
};
static int mydevice_probe(struct i2c_client *client)
{
/* 7位地址:client->addr 范围 0x03-0x77 */
dev_info(&client->dev, "7-bit address: 0x%02x\n", client->addr);
return 0;
}
/* 10位地址配置示例 */
static const struct i2c_device_id mydevice_10bit_id[] = {
{ "my_10bit_dev", 0 },
{ }
};
static int mydevice_10bit_probe(struct i2c_client *client)
{
/* 检查是否启用了10位寻址标志 */
if (client->flags & I2C_CLIENT_TEN)
dev_info(&client->dev, "10-bit address: 0x%04x\n", client->addr);
else
dev_err(&client->dev, "10-bit mode not enabled!\n");
return 0;
}
/* 设备树匹配表 */
static const struct of_device_id mydevice_of_match[] = {
{ .compatible = "vendor,my-sensor", .data = NULL },
{ /* 10位地址设备 */ .compatible = "vendor,my-10bit-dev", .data = (void *)I2C_CLIENT_TEN },
{ }
};
设备树配置提示:对于 10 位地址设备,在设备树中需要添加
reg = <0x1A0>;(10 位地址值),并在驱动中通过 of_device_is_compatible() 检查后设置 I2C_CLIENT_TEN 标志。
3.7 调试与验证方法
在调试 I2C 寻址问题时,可以使用以下工具和方法:
- i2cdetect:扫描总线上的设备,显示 7 位地址列表。
- 逻辑分析仪:捕获 SCL/SDA 波形,验证地址字节是否正确发送。
- 内核调试信息:启用
CONFIG_I2C_DEBUG_BUS和CONFIG_I2C_DEBUG_ALGO查看地址传输细节。 - 地址冲突检测:使用
i2c_check_addr_busy()在驱动加载前检查地址是否已被占用。
| 调试工具 | 命令/方法 | 适用场景 |
|---|---|---|
| i2cdetect | i2cdetect -y <bus> |
快速查看总线上所有7位地址设备 |
| i2cget | i2cget -y <bus> <addr> |
读取指定地址设备的寄存器值 |
| 逻辑分析仪 | 捕获 SCL/SDA 波形 | 验证10位寻址时序是否正确 |
| 内核调试 | echo 'file i2c-core.c +p' > /sys/kernel/debug/dynamic_debug/control |
查看内核I2C核心层的地址处理细节 |
掌握 I2C 寻址模式是驱动开发的基础。7 位寻址适用于大多数场景,10 位寻址用于扩展地址空间,广播地址用于系统级通信。在驱动开发中,务必避开保留地址,并根据设备手册正确配置地址格式。