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位寻址传输时序

7位寻址传输时序 SCL SDA S 7位从设备地址 (A6-A0) R/W ACK 数据字节 (8位) P 说明:S=起始条件,P=停止条件,ACK=从设备应答位。 7位地址 + R/W位 组成第一个字节发送,从设备匹配地址后回复ACK。

3.2 10位寻址模式

10 位寻址扩展了 I2C 的地址空间,允许连接更多从设备。它使用两个字节来传输地址。

特性 7位寻址 10位寻址
地址位数 7 位 10 位
最大设备数 112(可用) 1024
地址字节数 1 字节 2 字节
首字节高5位 地址位 A6-A2 11110xx(保留标识)
兼容性 所有设备 仅支持10位寻址的设备

10位寻址传输过程

  1. 首字节:高 5 位固定为 11110,接着是地址的高 2 位(A9-A8),最后是 R/W 位。
  2. 次字节:地址的低 8 位(A7-A0)。
  3. 应答:每个地址字节后从设备都需要回复 ACK。
驱动注意事项:在 Linux 内核中,10 位地址通过 I2C_CLIENT_TEN 标志位标识。使用 i2c_new_client_device() 时需设置 flags |= I2C_CLIENT_TEN。并非所有 I2C 控制器都支持 10 位寻址,需检查控制器驱动能力。

10位寻址帧结构

10位寻址帧结构 S 11110 | A9-A8 | R/W (首字节) ACK A7-A0 (低8位地址) (次字节) ACK 数据... P 说明:10位寻址首字节高5位固定为11110,用于与7位寻址区分。 首字节中的 A9-A8 为10位地址的最高2位,次字节为低8位。 每个地址字节后都需要从设备应答,主设备才能继续发送。

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 寻址模式选择策略

在实际嵌入式系统中,选择哪种寻址模式取决于硬件设计和系统需求:

  1. 优先使用 7 位寻址:兼容性最好,控制器支持最广泛,驱动开发最简单。
  2. 10 位寻址适用场景:当总线上需要超过 112 个从设备时,或设备本身只支持 10 位寻址。
  3. 广播地址使用:用于系统级同步、复位或固件升级场景。
  4. 地址冲突检测:在驱动初始化时,使用 i2c_check_addr_busy() 检查地址是否已被占用。

寻址模式决策流程

寻址模式选择决策流程 开始选择寻址模式 设备数量 > 112 ? 使用10位寻址 使用7位寻址 检查控制器驱动兼容性

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 位寻址用于扩展地址空间,广播地址用于系统级通信。在驱动开发中,务必避开保留地址,并根据设备手册正确配置地址格式。