给香橙派 Zero 2 适配 1-wire 总线

最近听说未知狐(xfox.fun)一直在为它的香橙派 Zero 2 不支持 1-wire 总线发愁。所以我毫不犹豫地接下了这个工作。:-)

所以说,从哪入手呢?毕竟我连 1-wire 是啥都不知道,至于把它叫做单总线就更让人困惑了。经过一顿 Wikipedia 的搜索,知道这玩意叫 1-wire。很好理解,就是通过一条数据线传输数据(一般做法是一条 RX 一条 TX)。

未知狐从 GitHub 上找到了一个叫 opi18b20 的项目,是一个 Linux  内核模块。不幸的是,opi18b20 是给香橙派 Zero 用的。基本控制方法是操作 CPU 寄存器来控制 GPIO 的模式与状态。但问题是香橙派 Zero 的 CPU 与 Zero 2 的差了一大截,前者是 32 位的、后者是 64 位的。看来不学习一番 Zero 2 的 CPU 寄存器是没法整成了,是么?

好吧,并不是。香橙派的板上有两个 LED 灯,这两个 LED 灯显然是内核操纵的(后面设备树有体现)。这就说明,内核有驱动 GPIO 的驱动。那么问题来了,怎么调用它?一种方法是从内核内部调用 pinctl 完成,另一种方法是从 userspace (用户态这个词同样很让人困惑)通过系统调用来完成。

未知狐也意识到了这一点,他把 opi18b20 的控制函数修改为 wiringOP (wiringPI 的 fork)的实现。但是,当驱动运行在用户态时,所有的时序问题就没法保证了。最后这个尝试还是失败了。

我当时注意到了未知狐说香橙派*不支持* 1-wire 总线,所以:一定有其它 SBC 支持 1-wire 总线。没错,经过一番搜索后,发现树莓派支持 1-wire 总线。开启方法是在 /boot/config.txt 加入下面的内容:

dtoverlay=w1-gpio

哈!w1-gpio 是什么成为了解决问题的关键。搜索引擎告诉我这是 Linux 内核中的 1-wire 子系统,而 1-wire 子系统支持的 master 的设备中就有 gpio(即通过 GPIO 控制)。开启方法只需要添加 dtoverlay 或在设备树中声明。(我决定两个一起尝试)

现在一切都明朗了起来,所以我们要找到设备树文件。香橙派官方提供了构建需要的 Linux 源代码(linux-orangepi),但我在里面找不到那个设备树文件。从仓库上看,应该是分支的不同所致。可是不能光纸上谈兵(因为我找不到那个分支),我找未知狐要到了香橙派的 ssh 决定一探究竟。首先,看看 /boot 里面有什么,然后找到了对应的设备树文件。一番搜索后,锁定了 orange-pi-5.16-sunxi64 分支,路径是 arch/arm64/boot/dts/allwinner

修改 dts 文件来支持 1-wire 总线(以前没写过,也不知道咋写):

对设备树的改动

注意到了么?里面也定义 led,也就印证了前面的猜想。但是里面还有个树莓派 Zero 2 B 的设备树,我也不知道用的是哪个。后来就把两个都改了。然后发现里面有个 overlay 文件夹,这大概就是 dtoverlay。所以我把注意力转向了 overlay。

不出所料,里面有 sun50i-a64-w1-gpio.dts sun50i-h5-w1-gpio.dts sun50i-h6-w1-gpio.dts 就是没有 h616 的。也好办,自己写一个。经过比对以后,它们之间的差别不大,只有  compatible pins 和 gpios 的差别。写了个 h616 的:

新的 dtoverlay 的比对

arch/arm64/boot/dts/allwinner/overlay/Makefile 中加入 sun50i-h616-w1-gpio.dtbo,让构建系统编译新的 overlay。

在内核根目录执行 make dtbs 就能得到编译过后的 dtb 文件。然后修改 orangepiEnv.txt 使它加载 overlay 文件。

最后大功告成!(用的 overlay,新的设备树没测试)这是最终得到的 dtoverlay 和设备树:prebuilt-dtbs

在香橙派上通过 1-wire 读取温度传感器