3. I2C设备地址与寻址:7位地址与10位地址格式、广播地址、保留地址
I2C 总线上的每个从设备都有一个唯一的地址,主设备通过地址来识别并选择要通信的目标。理解地址格式、保留地址和广播机制是驱动开发的基础,错误的地址配置会导致通信失败或总线冲突。
3.1 7位地址格式
标准 I2C 总线使用 7 位地址,这是最广泛使用的寻址模式。地址在每次通信的起始条件后立即发送,占用第一个字节的高 7 位,最低位(LSB)为读写方向位(R/W)。
关键点: 7 位地址空间理论上支持 128 个设备(0x00 ~ 0x7F),但其中 16 个地址被保留用于特殊用途,实际可用地址为 112 个。
驱动开发提示: 在 Linux 内核中,i2c_client 的 addr 字段存储的是 7 位地址(左对齐),而不是包含 R/W 位的完整字节。例如,设备地址 0x48 在代码中直接赋值为 0x48。
3.2 10位地址格式
为了扩展地址空间,I2C 规范引入了 10 位地址模式。10 位地址使用两个字节传输,第一个字节的前 5 位固定为 11110,作为 10 位地址的标志,后跟地址的高 2 位和 R/W 位;第二个字节为地址的低 8 位。
| 特性 | 7位地址 | 10位地址 |
|---|---|---|
| 地址位数 | 7 位 | 10 位 |
| 最大设备数 | 112(可用) | 1024(可用) |
| 传输字节数 | 1 字节 | 2 字节 |
| 首字节特征 | 高7位为地址 | 高5位为 11110 |
| 兼容性 | 所有设备 | 仅支持10位地址的设备 |
| Linux 内核表示 | addr 直接赋值 |
需设置 I2C_CLIENT_TEN 标志 |
注意: 10 位地址与 7 位地址不能混用在同一总线上与同一设备通信。主设备在发送 10 位地址前,必须确保从设备支持 10 位寻址模式。在 Linux 驱动中,使用
i2c_client 时需通过 I2C_CLIENT_TEN 标志显式声明。
3.3 广播地址与通用呼叫
I2C 总线定义了 广播地址(General Call Address),地址值为 0x00(7 位)。当主设备发送地址 0x00 且 R/W 位为 0(写操作)时,所有支持广播的从设备都应应答并接收后续数据。
- 广播地址格式: 0x00 + W(0x00 字节)
- 用途: 主设备向所有从设备发送全局命令,如复位、状态查询等。
- 从设备响应: 从设备可以选择性应答,非强制要求。
- 第二字节含义: 通常为命令字节,例如 0x06 表示复位,0x04 表示写可编程地址。
驱动开发提示: 在 Linux 内核中,广播地址通常由 i2c-core 或特定驱动处理。普通设备驱动不应主动使用 0x00 地址,以免干扰总线管理。若需实现广播监听,需注册
I2C_CLIENT_SLAVE 并处理通用呼叫。
3.4 保留地址
I2C 规范保留了一些特殊地址,用于总线管理、高速模式、10 位地址标志等。这些地址不能被普通设备使用。
| 7位地址 | 用途 | 说明 |
|---|---|---|
| 0x00 | 通用呼叫(广播地址) | 主设备向所有从设备发送命令 |
| 0x01 | 起始字节 | 用于慢速 MCU 的起始条件探测 |
| 0x02 | CBUS 地址 | 保留给 CBUS 兼容设备 |
| 0x03 | 保留 | 未来扩展用途 |
| 0x04 ~ 0x07 | 高速模式(Hs-mode) | 用于高速模式主设备地址 |
| 0x78 ~ 0x7B | 10位地址标志 | 10位地址第一字节的前缀 11110xx |
| 0x7C ~ 0x7F | 保留 | 未来扩展或测试用途 |
避坑指南: 在设备树或驱动中配置设备地址时,务必避开保留地址段。常见错误是将 10 位地址设备的地址误配置为 7 位地址范围,导致地址冲突。使用
i2cdetect 工具扫描总线时,保留地址区域通常显示为 "UU"(保留)或 "--"(无设备)。
3.5 地址探测与驱动配置
在驱动开发中,正确配置设备地址是第一步。以下是一个典型的 I2C 设备地址配置示例:
// 7位地址设备示例:温度传感器 LM75 地址 0x48
static struct i2c_board_info lm75_info = {
I2C_BOARD_INFO("lm75", 0x48),
};
// 10位地址设备示例:需要设置 I2C_CLIENT_TEN 标志
static struct i2c_board_info ten_bit_dev_info = {
I2C_BOARD_INFO("mydevice", 0x0280), // 10位地址 0x280
.flags = I2C_CLIENT_TEN,
};
// 在驱动 probe 函数中检查地址有效性
static int my_probe(struct i2c_client *client)
{
if (client->addr == 0x00) {
dev_err(&client->dev, "Invalid address: broadcast address\n");
return -EINVAL;
}
if (client->addr >= 0x78 && client->addr <= 0x7F) {
dev_err(&client->dev, "Invalid address: reserved range\n");
return -EINVAL;
}
// 正常初始化流程...
return 0;
}
3.6 地址冲突与解决方案
在实际项目中,多个设备可能共享同一地址,导致总线冲突。以下是常见场景及解决方案:
- 硬件地址引脚: 许多 I2C 芯片提供地址选择引脚(如 A0、A1、A2),通过拉高或拉低改变地址。例如,LM75 的地址为
0x48 + (A2<<2) + (A1<<1) + A0。 - 多路复用器(MUX): 使用 I2C 多路复用器(如 PCA9548)将总线分割为多个通道,每个通道挂载相同地址的设备。
- 地址转换器: 使用地址转换芯片(如 PCA9518)动态映射地址。
- 软件仲裁: 在驱动中通过 GPIO 控制设备使能引脚,分时访问。
最佳实践: 在硬件设计阶段,应规划好每个设备的地址,避免冲突。驱动开发时,使用
i2cdetect -y <bus> 扫描总线,确认设备地址是否唯一。若发现冲突,优先调整硬件地址引脚,其次考虑添加 MUX。