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位地址的传输过程分为两个阶段:
- 首字节(头字节):主机发送
1111 0XX+ R/W。其中高5位固定为11110,紧接着的两位(XX)是10位地址的最高两位(bit 9 和 bit 8)。 - 次字节:主机继续发送一个字节,包含10位地址的低8位(bit 7 ~ bit 0)。
兼容性注意: 并非所有I2C从设备都支持10位地址。在嵌入式Linux中,10位地址的使用相对较少,主要用于需要大量从设备的复杂系统或特定传感器网络。驱动中需要通过
I2C_CLIENT_TEN 标志来声明设备使用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(广播地址),这通常是错误的,需要检查硬件设计或通过引脚配置修改地址。
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>;。