树莓派 3b+ 没有 /dev/i2c-*

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树莓派 3b+ 没有 /dev/i2c-*相关的知识,希望对你有一定的参考价值。

引言

今天,使用树莓派驱动 mpu6050 时,发现 /dev 目录下没有 i2c-0、i2c-1 类似的文件。查看 Ubuntu、BananaPi M1 系统中是存在的。
咦?树莓派中的 i2c 设备文件去哪了?

环境

硬件:树莓派 3b+
软件:buildroot,make O=RPi3/ raspberrypi3_defconfig

问题

使用 buildroot 编译出来的 sdcard.img 烧录到 SD 卡运行后,在 /dev 目录下没有生成 i2c-0、i2c-1 类似的文件。

相关原因

由于 buildroot 支持的板子只有 raspberrypi3,没有 3b+ ,所以使用 3b+ 的用户需要自己再适配下。

原因 1:i2c-dev.ko

内核需要开启在 /dev 目录下产生 i2c 设备文件的功能—— I2C device interface,

我这边是将其编译成了模块(M),不然要替换 Kernel,比较麻烦,不利于调试。
编译好后,会生成 i2c-dev.ko。
兴致冲冲地跑去将 i2c-dev.ko 安装到内核,想着问题就解决了。
没成想,安装完后 /dev 目录下依然没有产生 i2c-* 文件。
🙄🙄🙄 什么情况。。。

查看 /proc/devices

# cat /proc/devices
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  4 ttyS
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  5 ttyprintk
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 89 i2c
128 ptm
136 pts
...

已然看到 89 i2c,说明 i2c 驱动已经注册成功了啊,为什么不产生 /dev/i2c-* 呢?
那就手动创建一下

mknod /dev/i2c-1 c 89 1

竟然能够创建成功,那就使用一下

# i2cdetect -y 1
i2cdetect: can't open '/dev/i2c-1': No such device or address

报错了,说明驱动还是有问题。

原因 2:i2c-bcm2835.ko

束手无策,只能查看源码了,打开 i2c-dev.c,

module_init(i2c_dev_init);
	i2c_dev_init()
		i2c_for_each_dev(NULL, i2cdev_attach_adapter);
		
i2cdev_attach_adapter()
	dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr);
	cdev_device_add()

看到是在 i2cdev_attach_adapter() 中创建 “i2c-%d” 文件的。
没有执行到这里?
经过加 printk() 调试,发现果真没有执行过 i2cdev_attach_adapter(),
那是哪个条件不满足呢?
那就追踪它的调用者 i2c_for_each_dev()

i2c_for_each_dev()
	bus_for_each_dev()
		while (!error && (dev = next_device(&i))) 
			error = fn(dev, data);
		

原来是没有找到 device,那它在找什么设备呢?为什么没找到呢?
最后发现,原来它是在找 I2C adaptor 或者叫 I2C controller(我认为它俩是一个东西的不同叫法),
树莓派 3b+ 的 I2C controller 如下

咦?M?那就去安装它

# insmod /lib/modules/5.10.92-v7/kernel/drivers/i2c/busses/i2c-bcm2835.ko

再次查看 /dev 目录,
还是没有 i2c-*
崩溃!!!

原因 3:设备树

最后发现,原来是安装了 I2C 控制器的驱动,但是设备树里面并没有让 I2C 控制器使能,也就是说系统中只有驱动,没有硬件
使能 I2C 控制器
编译出 bcm2710-rpi-3-b-plus.dtb 后,使用上一篇文章介绍的方法,更新到 SD 卡中,重启
执行

# insmod /lib/modules/5.10.92-v7/kernel/drivers/i2c/i2c-dev.ko
# insmod /lib/modules/5.10.92-v7/kernel/drivers/i2c/busses/i2c-bcm2835.ko

检查

# ls /dev/i2c-*
/dev/i2c-1  /dev/i2c-2

哇!终于有了

使用

# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

漂亮!

总结

  • I2C 总线在 kernel 中就一个,bus->name = “i2c”
  • 在树莓派 3b+ SOC 中,有两个 I2C 控制器,i2c1、i2c2。它们是同种类型的器件,所以使用相同的驱动:i2c-bcm2835.ko。
  • 在设备树中填写这两个控制器,在安装 i2c-bcm2835.ko 驱动时,就会通过 i2c bus 对 驱动 和 外设 进行匹配,匹配之后,就会在 /dev 目录产生两个设备节点文件 i2c-1、i2c-2,这两个设备节点文件就对应两个 I2C 控制器。
  • 对这两个设备文件读写,就会在对应的引脚发出 I2C 信号。这样就可以在应用层写具体外设(如 mpu6050)的驱动代码了,如《Banana Pi M1 读取 MPU6050(Shell 脚本方式)》
  • 通过上面这点,就能明白,I2C 控制器 及其 驱动I2C 外设 及其 驱动,的区别与联系了。

以上是关于树莓派 3b+ 没有 /dev/i2c-*的主要内容,如果未能解决你的问题,请参考以下文章

树莓派3B远程VNC的设置(包括开机启动)

树莓派系列-6-Qt控制树莓派GPIO(3B V1.2)

树莓派系列-6-Qt控制树莓派GPIO(3B V1.2)

(三十)树莓派3B+ 1-wire获取DS18B20温度

Win10 IoT系列 04树莓派3B开机并解决7寸触摸屏适配问题

树莓派3B使用教程