3. I2C地址与寻址:7位地址与10位地址格式、广播地址、保留地址、地址分配规则

I2C总线采用地址-响应机制实现多设备通信。每个从设备在总线上拥有唯一地址,主设备通过发送目标地址来选择通信对象。本章深入解析7位与10位地址格式、特殊地址(广播/保留)以及地址分配规则,帮助你在驱动开发中正确配置设备地址。

3.1 7位地址格式

标准I2C总线使用7位地址,这是最广泛使用的寻址模式。地址在数据传输的起始条件后立即发送,占用第一个字节的高7位,最低位(LSB)为读写方向位(R/W)。

关键结构: 第一个字节 = [A6 A5 A4 A3 A2 A1 A0] + [R/W]
R/W = 0 表示主设备写(发送数据),R/W = 1 表示主设备读(接收数据)。
7位地址帧格式 S A6 A5 A4 A3 A2 A1 A0 R/W ACK 起始 方向 从设备应答 7位地址范围 0x00 ~ 0x7F 有效地址:0x08~0x77 保留地址除外
驱动提示: 在Linux内核中,7位地址通常以左对齐方式存储(即地址值左移1位,最低位为0)。例如,设备地址0x48在驱动中常表示为0x90(左移1位)。使用 i2c_client 结构体时,addr 字段存储的是7位原始地址(0x48),内核会自动处理移位。

3.2 10位地址格式

当总线上设备数量超过112个(7位地址上限)时,I2C规范定义了10位地址扩展模式。10位地址占用两个字节传输,第一个字节的前5位固定为 11110 作为标识,后2位为地址的高2位;第二个字节为地址的低8位。

字节 位域 值/含义
字节1(高5位) Bit[7:3] 11110 — 10位地址标识
字节1(高2位地址) Bit[2:1] 地址位 A9 ~ A8
字节1(最低位) Bit[0] R/W 读写方向位
字节2 Bit[7:0] 地址位 A7 ~ A0(低8位)
10位地址帧格式(两字节传输) S 11110 标识 A9 A8 R/W ACK A7 A6 A5 A4 A3 A2 A1 A0 ACK 10位标识 方向 低8位地址 10位地址范围:0x000 ~ 0x3FF(共1024个地址) 第一个字节高5位固定为11110,与7位地址的0x78~0x7F保留区不冲突
兼容性注意: 并非所有I2C从设备都支持10位地址。在Linux内核中,使用10位地址需要设置 I2C_CLIENT_TEN 标志。驱动开发时,务必查阅设备数据手册确认地址模式。

3.3 广播地址与通用呼叫

I2C规范定义了一个广播地址(General Call Address):0x00(7位)。当主设备发送地址 0x00 且R/W位为0(写操作)时,所有支持广播的从设备都会响应并接收后续数据。

  • 广播地址值: 7位 0x00,第一个字节为 0x00(R/W=0)。
  • 用途: 主设备向所有从设备发送全局命令,如系统复位、状态查询等。
  • 从设备响应: 从设备可以选择性地响应广播地址,非强制要求。
  • 第二个字节含义: 广播后的第一个数据字节决定命令类型:
    • 0x04 — 从设备复位(通过硬件复位引脚)
    • 0x06 — 从设备复位(通过软件命令)
    • 0x00 — 不执行操作(空呼叫)
广播地址(通用呼叫)通信流程 主设备 S + 0x00 + W 从设备1 从设备2 从设备3 从设备4 ACK ACK ACK

3.4 保留地址

I2C规范保留了一些特殊地址用于协议控制。这些地址不允许分配给普通从设备。以下是7位地址空间中的保留地址表:

7位地址 R/W位 用途 说明
0x00 0 通用呼叫(广播地址) 所有从设备可选响应
0x01 — 起始字节 用于慢速设备同步
0x02 — CBUS地址 保留给CBUS兼容设备
0x03 — 保留 未来扩展用途
0x04 ~ 0x07 — 高速模式(Hs-mode) 主设备代码,用于高速模式仲裁
0x78 ~ 0x7B — 10位地址标识 高5位为11110,用于10位地址扩展
0x7C ~ 0x7F — 保留 未来扩展用途
地址分配红线: 普通从设备可用的7位地址范围为 0x08 ~ 0x77(共112个地址)。10位地址模式下,保留区 0x78~0x7B 被复用为扩展标识,因此10位地址不会与7位地址冲突。

3.5 地址分配规则与Linux内核实践

I2C设备地址分配遵循以下原则,驱动开发时必须严格遵守:

  1. 唯一性: 同一I2C总线上每个从设备地址必须唯一,地址冲突会导致通信失败。
  2. 避免保留区: 不得使用 0x00~0x07 和 0x78~0x7F 范围内的地址。
  3. 硬件可配置: 多数I2C芯片通过引脚(如A0、A1、A2)设置地址,驱动需读取硬件配置。
  4. 动态检测: 内核提供 i2c_detect 机制,通过发送地址并检测ACK来枚举设备。

在Linux内核中,地址配置通常在设备树(Device Tree)或板级文件中完成:

/* 设备树示例:7位地址0x48 */
&i2c1 {
    status = "okay";
    clock-frequency = <100000>;

    temperature_sensor: tmp102@48 {
        compatible = "ti,tmp102";
        reg = <0x48>;  /* 7位I2C地址 */
    };
};

/* 内核驱动中获取地址 */
static int my_probe(struct i2c_client *client)
{
    dev_info(&client->dev, "device addr: 0x%02x\n", client->addr);
    /* client->addr 存储原始7位地址,无需移位 */
    return 0;
}
调试技巧: 使用 i2cdetect -y <bus_number> 命令扫描总线上的设备。该命令会向所有有效地址发送读请求,有ACK响应的地址即为已连接的设备。注意:扫描可能干扰某些敏感设备,生产环境中慎用。

3.6 地址冲突与解决方案

当多个设备使用相同地址时,总线会出现地址冲突。常见场景及解决方案如下:

场景 原因 解决方案
同型号传感器并联 芯片默认地址相同 使用地址选择引脚(A0/A1/A2)配置不同地址
不同设备地址重叠 厂商未遵循地址分配规范 更换设备型号或使用I2C多路复用器(如PCA9548)
地址被保留区占用 误用0x00~0x07或0x78~0x7F 修改设备地址或更换兼容芯片
10位地址与7位地址混淆 驱动未正确设置地址模式标志 在 i2c_client 中设置 I2C_CLIENT_TEN 标志
I2C地址空间分配总览(7位) 0x00-0x07 保留 0x08 ~ 0x77(112个可用地址) 普通从设备地址 0x78-0x7B 10位标识 0x7C-0x7F 保留 广播/保留 设备可用区 10位扩展 地址分配核心原则 1. 避免保留地址 2. 同一总线地址唯一 3. 硬件可配置 4. 驱动与设备树一致
驱动开发常见错误: 在 i2c_board_info 或设备树中填写地址时,容易将7位地址错误地左移1位。内核期望的是原始7位地址(如0x48),而不是左移后的0x90。如果地址错误,设备将无法被正确匹配,probe函数也不会被调用。