3. 从机地址的软件配置:设备树中 reg 属性的正确写法
设备树里配 I2C 从机地址,说白了就是写对 reg 属性。这行代码看着简单,但我见过太多人在这上面翻车。地址写错一位,整个驱动就认不到设备。
我个人习惯,拿到一款新 I2C 器件,第一件事就是翻数据手册,找到那个 7 位从机地址。嗯,这里有个坑——手册上给的地址,跟你在设备树里写的,往往不是同一个数。
3.1 7 位地址 vs 8 位地址:你写对了吗?
I2C 协议里,从机地址是 7 位的。但很多数据手册会把地址写成 8 位,左移了一位,最低位补了个 R/W 位。举个例子:
| 器件 | 手册给出的地址 | 实际 7 位地址 | 设备树 reg 值 |
|---|---|---|---|
| LM75 温度传感器 | 0x90 (8 位) | 0x48 | 0x48 |
| MPU6050 陀螺仪 | 0xD0 (8 位) | 0x68 | 0x68 |
| AT24C02 EEPROM | 0xA0 (8 位) | 0x50 | 0x50 |
看清楚了吗?设备树里 reg 属性填的是 7 位地址,不是手册上那个带 R/W 位的 8 位值。我曾经带过一个新人,他照着手册抄了 0x90 进去,结果驱动死活 probe 不到设备。排查了半天,最后发现地址多了一位。
⚠️ 常见错误: 把 8 位地址直接写入 reg 属性。内核 I2C 子系统会自动左移一位去匹配硬件,你写 0x90,内核实际发的是 0x120,总线上的从机根本不会应答。
3.2 reg 属性的标准写法
设备树里 I2C 节点的 reg 属性,格式其实很固定:
/* 标准写法:reg = <地址>; */
&i2c1 {
status = "okay";
clock-frequency = <100000>;
/* 温度传感器 LM75,7 位地址 0x48 */
lm75: temperature-sensor@48 {
compatible = "national,lm75";
reg = <0x48>;
};
/* 加速度计 MPU6050,7 位地址 0x68 */
mpu6050: accelerometer@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
};
};
注意几个细节:
- 节点名要带地址后缀:比如
temperature-sensor@48,这个@48必须跟reg里的值一致。内核会拿这个做校验,不一致会报 warning。 - 地址用十六进制:别写十进制,看着别扭,也容易出错。
- 一个节点只配一个地址:除非你的器件是多地址复合设备,否则别写多个值。
3.3 多地址设备怎么办?
有些 I2C 器件,比如某些音频编解码器或 FPGA 桥接芯片,会占用多个从机地址。这时候 reg 属性要写成数组:
/* 多地址设备示例 */
codec: audio-codec@1a {
compatible = "some,vendor-codec";
reg = <0x1a 0x1b 0x1c>;
reg-names = "primary", "secondary", "debug";
};
reg-names 是个好习惯。我在移植一个 TI 的音频芯片时,它有三个地址空间:主控制、DSP 调试、GPIO 扩展。不加名字的话,驱动里只能靠索引去猜哪个地址是干嘛的,维护起来很痛苦。
3.4 地址冲突:一个容易被忽略的问题
同一个 I2C 总线上,不能有两个设备用同一个地址。听起来是废话,但实际项目中经常撞车。比如:
- LM75 默认地址 0x48,跟某些电源管理芯片的地址冲突
- 多个同型号传感器挂同一条总线,地址没做硬件跳线区分
解决办法:
- 硬件上改地址:很多芯片有 ADDR 引脚,拉高拉低可以切换地址范围。
- 软件上换总线:把冲突的设备挪到另一条 I2C 控制器上。
- 用 GPIO 模拟:实在不行,给其中一个设备单独用 GPIO 模拟 I2C。
💡 我的习惯: 画原理图阶段就跟硬件工程师确认好每个 I2C 设备的地址,列个表贴在工位上。等板子回来再改设备树,那叫一个折腾。
3.5 地址配置的完整流程
我画了张图,把从拿到芯片到设备树配好的流程串起来:
3.6 验证地址配置是否正确
设备树写完了,怎么知道地址对不对?我最常用的方法:
- i2cdetect 扫描:板子起来后,跑
i2cdetect -y <bus-number>,看看对应地址上有没有设备应答。 - 看内核日志:
dmesg | grep i2c,如果地址不匹配,内核会打印 "failed to probe" 之类的信息。 - 直接读写测试:用
i2cget和i2cset工具,手动发一个读操作,看能不能拿到数据。
🔑 关键点: 设备树里的 reg 属性,填的是 7 位从机地址。手册上给的 8 位地址,记得右移一位再写进去。多地址设备用数组,配合 reg-names 让驱动更清晰。
地址配对了,驱动 probe 才能成功。这一步错了,后面所有调试都是白费功夫。我自己的经验是,每次拿到新板子,第一件事就是拿 i2cdetect 扫一遍,确认所有设备都在预期地址上。嗯,这个习惯帮我省了不少排查时间。