我们已经知道beagleboard官网上有一些官方的硬件外设,比如lcd显示屏之类的,他们管这些外设叫做cape。其实应该说只要是修改了芯片引脚功能,或占用了空闲的引脚的东西,都可以叫做cape。比如之前我们提到的开启某些引脚的I2C功能,其实也是给设备添加了一个虚拟的(virtual)cape。当我们想要使用一个cape的时候,需要做两件事:配置BBB引脚的功能,启动相应的驱动程序。而device tree基本就是用来干这两件事的。
下面我们就来依次认识device tree文件,修改dts文件,编译dts文件,加载device tree,验证是否加载成功。
/*
* Copyright (C) 2013 CircuitCo
*
* Virtual cape for UART1 on connector pins P9.24 P9.26
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";
/* identification */
part-number = "BB-UART1";
version = "00A0";
/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P9.24", /* uart1_txd */
"P9.26", /* uart1_rxd */
/* the hardware ip uses */
"uart1";
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
bb_uart1_pins: pinmux_bb_uart1_pins {
pinctrl-single,pins = <
0x184 0x20 /* P9.24 uart1_txd.uart1_txd MODE0 OUTPUT (TX) */
0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd MODE0 INPUT (RX) */
>;
};
};
};
fragment@1 {
target = <&uart2>; /* really uart1 */
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bb_uart1_pins>;
};
};
};
可以看到,dts文件是一个树形结构,是由若干节点和属性组成的。compatible = "ti,beaglebone", "ti,beaglebone-black"; 这行代码上面相邻行的斜杠"/"代表根节点,下面的fragment@0和fragment@1是其两个子节点。其中根节点下面的属性声明了本dts文件适用的平台,它的名字、版本号,使用了哪些引脚和硬件资源等。fragment@0节点中配置了两个BBB引脚的功能,把它们设置成了uart1的tx和rx功能。fragment@1节点中使能了uart1这个硬件设备(启用了相应的驱动)。
pinctrl-single,pins = <
0x184 0x20 /* P9.24 uart1_txd.uart1_txd MODE0 OUTPUT (TX) */
0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd MODE0 INPUT (RX) */
>;
其中第一列的0x184和0x180分别是P9.24和P9.26的地址,第二列的0X20代表要配置成什么功能。它们都是怎么确定的呢?这里就要用到pdf文档《BBB引脚功能速查表》了(请百度找此表,在EEWORLD论坛的一篇帖子中)。我们首先找到P9.24所在的行(在第2页的中间),然后在第三列中可以看到它的偏移地址(OFFSET)是184。至于功能配置,我们按照pdf第2页下面的GPIO Settings提示来写。我们需要把这个引脚配置成“快速模式”、“使能输入”、“使能下拉”、“功能0(uart1_txd)”。每一位按照相应的功能来写,即00100000,即0x20。
cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins
因为这个目录很常用,我把它存成了环境变量$PINS。以后我使用 cat $PINS 就可以了。
root@beaglebone:~# cat $PINS | grep 984
pin 97 (44e10984) 00000037 pinctrl-single
可以看到,这个引脚的当前功能是0x37,即00110111,从最后三位看出是功能7,查表知是GPIO功能。
part-number = "BB-UART1";
version = "00A0";
第一个是名字,第二个是版本号。你自己写的dts文件要新起一个名字,版本号则必须按照00A0,00A1……这样的顺序依次排下去。你的dts文件名必须是“名字+版本号.dts”的格式,如这里的BB-UART1-00A0.dts。
dtc -I dts -O dtb -@ BB-UART1-00A0.dts > BB-UART1-00A0.dtbo
dtbo反编译成dts:
dtc -I dtb -O dts BB-UART1-00A0.dtbo > BB-UART1-00A0.dts
(注:有的网站上编译用的是这样的命令:dtc -O dtb -o BB-UART1-00A0.dtbo -b 0 -@ BB-UART1-00A0.dts,其实都一样啦。我觉得上面给出的写法更好记一点。)
echo BB-UART1 > /sys/devices/bone_capemgr.8/slots
slot这个单词是“插槽”的意思,看,很形象吧!我要插上一个cape,就向这个“插槽”里“插入”(echo)相应的设备。echo这个命令的含义是“向标准设备输出”嘛。因为这个目录很常用,所以我把它存成环境变量$SLOTS,这样以后只需写 echo BB-UART1 > $SLOTS 即可了。
cat $SLOTS
可以查看当前已经加载的所有cape。比如在我的BBB上执行命令后得到输出:
root@beaglebone:~# cat $SLOTS
0: 54:P---L Beaglebone LCD4 Cape,00A1,BeagleboardToys,BB-BONE-LCD4-01
1: 55:PF---
2: 56:PF---
3: 57:PF---
4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
7: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-ADC
8: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-UART1
前面说了slots是“插槽”的意思,可以看到我这里已经“插入”了4个cape,包括1个实体的LCD cape和3个虚拟cape。
-sh: echo: write error: File exists
另外注意上面显示的几个已加载cape里的这部分内容“ff:P-O-L”,这里最后的“L”代表这个cape已经被load,即已经启用。也许你将来会遇到虽然显示在$SLOTS里,但是没有这个“L”的cape,那样的话它基本等于不存在。
echo -8 > $SLOTS
但因为系统bug的原因,这样操作会导致系统重启……所以目前只能通过重启系统来卸载cape。等出系统更新也许就解决这个bug 了。