3. I2C地址与寻址模式:7位地址与10位地址、广播地址、保留地址

I2C总线协议的核心在于其独特的寻址机制。与SPI等总线通过独立的片选信号(CS)选择从设备不同,I2C完全依靠设备地址来区分总线上的多个从机。理解地址结构、寻址模式以及特殊地址的用途,是进行I2C驱动开发和设备树配置的基础。

3.1 7位地址模式

7位地址是I2C最基础、最常用的寻址模式。在标准模式下,主机在发送起始条件(START)后,首先发送一个字节的数据,该字节的高7位即为从机地址,最低位(LSB)为读写方向位(R/W)。

  • 地址范围:0x00 ~ 0x7F(共128个地址)。
  • 有效地址:实际可分配给设备的地址为0x08 ~ 0x77(共112个),其余地址被保留用于特殊用途。
  • 方向位:0表示主机将要写入(WRITE),1表示主机将要读取(READ)。
驱动开发要点: 在设备树中,7位地址通常直接以 reg = <0x48>; 的形式声明。内核I2C子系统会自动处理地址左移一位的操作(将7位地址放入8位字节的高7位),因此驱动开发者只需填写真实的7位从机地址即可。
常见误区: 部分数据手册会给出8位地址(即已经左移并包含方向位的地址),例如0x90(读)/0x91(写)。此时需要将其右移一位,得到真实的7位地址0x48,再填入设备树。

3.2 10位地址模式

为了突破7位地址(最多112个设备)的限制,I2C规范引入了10位地址模式。该模式通过一种特殊的协议序列来传输10位地址,兼容7位地址设备。

10位地址的传输过程分为两个阶段:

  1. 首字节(头字节):主机发送 1111 0XX + R/W。其中高5位固定为 11110,紧接着的两位(XX)是10位地址的最高两位(bit 9 和 bit 8)。
  2. 次字节:主机继续发送一个字节,包含10位地址的低8位(bit 7 ~ bit 0)。
兼容性注意: 并非所有I2C从设备都支持10位地址。在嵌入式Linux中,10位地址的使用相对较少,主要用于需要大量从设备的复杂系统或特定传感器网络。驱动中需要通过 I2C_CLIENT_TEN 标志来声明设备使用10位地址。
7位地址与10位地址帧结构对比 7位地址与10位地址帧结构对比 7位地址帧: S 7位从机地址 (A6~A0) R/W ACK 示例:地址 0x48 (7'b1001000) + 写操作 (0) → 发送字节 0x90 10位地址帧: S 1111 0XX (头字节) R/W ACK 地址低8位 (A7~A0) ACK 示例:地址 0x2A3 (10'b10 1010 0011) + 读操作 (1) → 头字节: 1111 0101, 次字节: 1010 0011 说明:S = 起始条件,R/W = 读写位 (0写/1读),ACK = 从机应答位。10位地址需要两个字节完成地址传输。

3.3 广播地址与通用呼叫

广播地址(General Call Address)是I2C协议中一个特殊的保留地址,其值为 0x00。当主机发送地址 0x00 且方向位为写(WRITE)时,表示这是一个通用呼叫,理论上所有支持广播的从设备都应响应并接收后续的数据。

广播地址的典型应用场景:

场景 描述
系统复位 主机发送广播地址后,跟一个特定的复位命令字节(如0x06),所有支持该功能的从设备执行软件复位。
地址分配 在某些可配置地址的从设备中,主机通过广播地址发送一个“地址分配”命令,为设备动态分配唯一地址。
状态查询 主机广播一个查询命令,要求所有从设备报告其状态(如忙/闲)。
驱动开发注意: 大多数通用I2C从设备(如EEPROM、温度传感器)不支持广播地址。在编写驱动时,除非数据手册明确说明支持通用呼叫,否则不应依赖此功能。误用广播地址可能导致总线上的设备产生意外响应。

3.4 保留地址

I2C规范为特殊用途保留了一些地址,这些地址不能分配给普通的从设备。驱动开发者在配置设备树或编写驱动时,应避免使用这些地址。

I2C保留地址表(7位地址):

地址范围 (7位) 用途 说明
0x00 通用呼叫地址 用于广播,所有支持广播的设备必须响应。
0x01 起始字节地址 用于慢速MCU的起始字节协议,避免总线冲突。
0x02 CBUS地址 保留给CBUS(一种与I2C兼容的早期总线)设备。
0x03 保留 用于未来扩展或特定系统功能。
0x04 ~ 0x07 高速模式主码 用于高速模式(Hs-mode)的地址分配和仲裁。
0x78 ~ 0x7B 10位地址后缀 用于10位地址模式的特殊标识。
0x7C ~ 0x7F 保留 用于未来扩展或测试模式。
设备树配置建议: 在编写设备树时,务必查阅从设备的数据手册,确认其I2C地址是否落在保留地址范围内。例如,某些传感器可能默认地址为0x00(广播地址),这通常是错误的,需要检查硬件设计或通过引脚配置修改地址。
I2C 7位地址空间分布图 I2C 7位地址空间分布图 (0x00 ~ 0x7F) 保留 有效地址范围 (0x08 ~ 0x77) 保留 0x00 0x08 0x77 0x7F 地址空间说明: • 保留地址 (0x00-0x07):用于广播、起始字节、CBUS、高速模式主码等特殊协议。 • 有效地址 (0x08-0x77):共112个地址,可分配给I2C从设备。这是驱动开发中最常用的区域。 • 保留地址 (0x78-0x7F):用于10位地址后缀和未来扩展,普通设备不应使用。 • 驱动开发中,设备树 reg 属性必须填写有效地址范围内的值,否则内核可能拒绝注册设备。

3.5 驱动测试中的地址验证

在编写I2C驱动并进行测试时,地址验证是第一步。错误的地址配置会导致通信失败,且难以排查。以下是驱动测试中常用的地址验证方法:

  • 使用i2cdetect工具:在用户空间,通过 i2cdetect -y <bus_number> 命令扫描总线,可以快速查看哪些地址有设备响应。这是验证硬件连接和地址配置最直接的方法。
  • 内核调试信息:在驱动初始化时,打印出设备树解析得到的地址,与数据手册对比。例如:dev_info(&client->dev, "I2C device addr: 0x%02x\n", client->addr);
  • 逻辑分析仪抓取:对于疑难问题,使用逻辑分析仪抓取I2C总线上的实际波形,确认主机发送的地址字节是否正确(包括方向位)。
实战案例: 某项目中,驱动开发者将设备树中的地址配置为 reg = <0x90>;(8位地址),导致内核I2C子系统将其解释为7位地址0x48,但实际设备地址为0x48。虽然最终通信成功,但这是一个典型的“巧合正确”案例,在更换设备或升级内核后可能引发问题。正确的做法是始终使用7位地址 reg = <0x48>;。