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。
7位地址格式与传输时序 7位地址格式与传输时序 主设备 起始条件 地址字节 (8位) A6 A5 A4 A3 A2 A1 A0 R/W 7位地址 方向 从设备 说明: 主设备发送起始条件后,紧接着发送地址字节。高7位为设备地址,最低位R/W=0表示写,R/W=1表示读。 从设备收到地址后,若匹配则在第9个时钟周期拉低SDA作为应答(ACK)。

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 标志显式声明。
10位地址格式与传输流程 10位地址格式与传输流程 主设备 S 第一字节 11110 A9 A8 R/W 第二字节 A7 A6 A5 A4 A3 A2 A1 A0 从设备 10位地址传输流程: 1. 主设备发送起始条件后,发送第一字节:高5位 11110 + 地址高2位 (A9 A8) + R/W位。 2. 所有支持10位地址的设备识别 11110 前缀,并检查 A9 A8 是否匹配。 3. 匹配的设备在第二字节发送后,将完整10位地址与自身地址比较,一致则应答。 4. 后续数据传输与7位地址模式相同。

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;
}
I2C地址空间分布图 I2C 7位地址空间分布图 保留 可用地址范围 (0x08 ~ 0x77) 保留 0x00 0x08 0x77 0x7F 地址空间详细说明: • 0x00 ~ 0x07:保留地址,包括广播地址、起始字节、CBUS 地址、高速模式标志。 • 0x08 ~ 0x77:可用地址范围,共 112 个地址,供普通 I2C 设备使用。 • 0x78 ~ 0x7B:10位地址标志前缀(11110xx),不可用于7位地址设备。 • 0x7C ~ 0x7F:保留给未来扩展,当前不可用。 • 驱动开发时,应使用 i2c_check_addr_validity() 函数验证地址合法性。

3.6 地址冲突与解决方案

在实际项目中,多个设备可能共享同一地址,导致总线冲突。以下是常见场景及解决方案:

  • 硬件地址引脚: 许多 I2C 芯片提供地址选择引脚(如 A0、A1、A2),通过拉高或拉低改变地址。例如,LM75 的地址为 0x48 + (A2<<2) + (A1<<1) + A0。
  • 多路复用器(MUX): 使用 I2C 多路复用器(如 PCA9548)将总线分割为多个通道,每个通道挂载相同地址的设备。
  • 地址转换器: 使用地址转换芯片(如 PCA9518)动态映射地址。
  • 软件仲裁: 在驱动中通过 GPIO 控制设备使能引脚,分时访问。
最佳实践: 在硬件设计阶段,应规划好每个设备的地址,避免冲突。驱动开发时,使用 i2cdetect -y <bus> 扫描总线,确认设备地址是否唯一。若发现冲突,优先调整硬件地址引脚,其次考虑添加 MUX。