干货 | 解锁多重姿势为Beaglebone Black制作cape
如果你买来BBB是为了搞跟硬件相关的项目,那你八成需要制作一个cape。cape是BBB官方的叫法,其实就是指BBB的软件和硬件外设。通过学习device tree我们了解到BBB是使用capemgr和device tree来控制cape的,通过向$SLOTS传入dtbo文件来加载某个cape,像这样:
echo BB-ADC > $SLOTS
但有时候我们不想每次都手动输入这样一条命令来启用某个cape,而是想让它开机自动启动。这时就需要用到本文讲的内容了。
要做到开机自动启动,你只需要增加一个eeprom(官方推荐的型号是CAT24C256),并把它接到特定的引脚上,里面写上符合规定格式的内容就行了。系统在启动时会检查特定引脚上有没有符合规定格式的eeprom,如果有的话,就按照eeprom里面的内容自动加载相应的dtbo文件。
还记得我们 cat $SLOTS 看到了什么吗?
cat /sys/devices/bone_capemgr.*/slots
0: 54:PF---
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
5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
这里前4项为什么是空的呢?因为它们就是给那些有EEPROM的实体cape预留的位置。不难看出,这样的实体cape最多只能插4个。
这里的知识比较零散,我将分点阐述:
eeprom的地址必须在0x54到0x57之间,否则系统不会加载。科普一下:不管什么牌子的eeprom芯片,它们的地址都是一样的,高4位是1010,低3位对应着芯片的A2,A1,A0这3个引脚的电平(有的芯片只有A1和A0),所以通过外接电路就能改变eeprom的地址。也就是说eeprom的地址只可能是0x50到0x57这8种,如果A2保持高电平,那么就只有0x54到0x57这4个地址可用了(这就是SRM(BBB官方参考手册)里eeprom电路中把A2接高电平的原因。
eeprom必须连接到BBB的I2C2_SCL和I2C2_SDA引脚上(在系统中看到的是i2c-1)。因为I2C2这两个引脚的默认功能就是i2c功能。这也告诉我们,程序中尽量不要永久改变这两个引脚的功能复用,否则就没法加载cape了。
BBB最多只支持同时插4个eeprom,它们的地址必须互不相同。
如果一次插入多个eeprom,会依次读取之。准确来说,读取顺序就是从0x54到0x57的顺序。为什么如此强调overlay的加载顺序呢?因为一旦前面加载的overlay占用了某些片上资源,其他overlay就不能再用了。比如我要做的LCD使用的引脚跟默认加载的HDMI用的引脚是有重叠的,当系统启动时首先加载了LCD的overlay,那么HDMI就不能再加载了。
eeprom上WP引脚是写保护用的,一旦上拉,就不能进行写入了。所以自己做电路的时候可以把它悬空或者拉低。
下面先介绍如何进行读写,再介绍该写入什么东西。
首先确定eeprom的地址。由A0,A1,A2三个引脚的电平确,按照上面刚刚说的,比如我把A0,A1接地,A2拉高,地址就是0x54。
然后在命令行操作:
cd /sys/bus/i2c/devices/1-0054/ #到eeprom目录中
cat eeprom | hexdump -C #读取eeprom内容并以字符形式显示
echo -e "\xaa\x55\x33\xeeA1Beaglebone LCD4 Cape\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0000A1BeagleboardToys\x00BB-BONE-LCD4-01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" > eeprom #写入内容
cat eeprom | hexdump -C #确认是否写入成功
其中\x开头的字符代表按ASCII码值写入。上面就写入了官方LCD4 cape的eeprom内容。如果你想自制LCD cape,使用的LCD面板参数跟官方的一样的话,那么系统使用的驱动程序就是一样的,所以就可以直接用上面的eeprom内容加载BBB自带的dtbo文件了,就不必自己重写dtbo文件了。
写入内容时,要按照SRM里的标准(如下图),最重要的是要把头6个字节\xaa\x55\x33\xeeA1以及后面的版本号00A1和要调用的dtbo文件名BB-BONE-LCD4-01写对,其他的比Number of Pins什么的都无所谓。空余的地方必须用\x00补全,用其他字符会产生错误。
经过上面的方法配置好eeprom后,系统就能在启动时自动加载对应的dtbo文件了。但是这里还是再强调一下dts文件编写的注意事项。
文件名必须是 boardname-version.dts 的形式,比如 BB-BONE-LCD4-01-00A0.dts。这里面BB-BONE-LCD4-01就是boardname,00A0就是version号。(其实dts的名字无所谓了,关键是编译出来的dtbo名字必须是它,为了统一,就都这么规定吧)。
version必须是00AX的形式,X从0开始按版本依次增加,而且,想命名00A1,必须有00A0的存在才行!不能跨越版本!
dts文件里面会有part-number和version这两项,其内容必须跟文件名相符!part-number就是boardname。
编译完的dtbo文件必须放到 /lib/firmware/ 目录中才可以加载。
OK,上面介绍了所有cape通用的内容。具体某个cape需要加载特定的驱动,那就是如何写dts文件和配置驱动的问题了,在此就不做讨论啦。
其实不用eeprom的话,也可以通过修改uEnv.txt文件来实现自动加载dtbo文件。USB连接好BBB以后在电脑里会出现一个盘符,里面有一个叫做uEnv.txt的文件。通过它可以设置系统启动时加载或禁止加载的dtbo。比如我想在系统启加载BB-ADC。我们就可以打开它,在下面添加一行:
optargs=quiet capemgr.enable_partno=BB-ADC
然后安全弹出这个盘符,重启BBB就行啦。
我们知道BBB启动会自动加载HDMI,而HDMI与LCD公用了部分引脚。如果我们想启动后再插上LCD,然后 echo BB-BONE-LCD4-01 > $SLOTS 来加载LCD cape的话,会提示你File exists,就是因为HDMI已经首先加载了,那些引脚就不能再动了。但我们可以配置uEnv.txt使得启动时不自动加载HDMI,方法是在uEnv.txt中添加一行:
optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
就OK啦。
注意,如果想同时实现上面两个,即禁用HDMI并加载ADC的话,不能简简单单把上面两句话写进去,应该合并成一句话:
optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN capemgr.enable_partno=BB-ADC
否则会失败。
所以,使用eeprom的意义就在于方便啦。什么也不用配置,买回来插上就能用。如果你爱折腾的话,那么实现方法就多了去啦。
上面说的修改uEnv.txt的方法其实跟用eeprom的效果是差不多的——一个不能用的话另一个也不能用= =!
6月的Angstrom系统(终端输入 uname -a 查看你的BBB里装的是哪个版本的系统)有bug,如果你自己编译了一个dtbo文件,即便放进 /lib/firmware 目录下也不能自动加载(/lib/firmware里原本就有的可以加载是因为它们已经被编译进内核了)。所以除非你自己编译一遍系统,否则不能用这个办法在启动时自动加载自己的cape。刚说了用uEnv.txt跟用eeprom差不多……所以也不行。
9月的Angstrom系统稍微修改了这个bug,但还是不好用——系统启动时会在加载cape那步停留60秒才继续……本来Angstrom是以启动速度快见长的,只需10秒。这一下拖了太多后腿了。(而且9月的Angstrom系统增添了新的bug——LCD电阻触摸屏指针会漂移!想自己解决这个问题当然依旧只能重新编译系统——不是每个人都有耐心编译系统玩的!所以即便它是新系统,我还是果断使用6月的吧,至少触摸屏正常。)
总之,无论哪个版本的Angstrom系统,eeprom和uEnv.txt法都不太好使,下面就介绍一个完全不同的招数:使用systemd。
Step by step教学:
Step 1.
在/etc/systemd/system目录下新建一个文件,命名mystartup.service(名字可以自定),内容如下:
[Unit]
Description=My script
[Service]
ExecStart=/home/root/mystartup.sh
[Install]
WantedBy=multi-user.target
Description是写给自己看的注释,可以随便写。mystartup.sh是要启动时自动执行的脚本。
注意:不能写成ExecStart=/bin/sh /path/to/script.sh这样的,直接按上面给出的例子写就好了。
Step 2.
然后在 /home/root 目录新建一个mystartup.sh,内容如下:
#!/bin/sh
echo BB-YOUR-CAPE > /sys/devices/bone_capemgr.8/slots
注意:
1、这里必须用sh脚本,不能用bash脚本。
2、sh脚本中不能使用bone_capemgr.*这样的通配符,必须是bone_capemgr.8或者.9(根据你的系统来写)
3、当然,dtbo文件还是必须得放在 /lib/firmware 下才行。
Step 3.
最后执行命令:
systemctl enable myscript.service
就可以了。重启BBB会发现成功加载了dtbo。
如果你执行dmesg | grep capemgr,会发现加载dtbo的时间点跟用eeprom或uEnv.txt不同,所以跟启动以后手动输入 echo 命令的效果类似。
我当然推荐第六种方法。预计在找到更好的办法之前,这就是我将来在Development Kit里采用的办法了。想要使用我的Kit的话建议掌握这个小技巧。
最后这句写给能看懂的人,看不懂就不必深究了:crontab @reboot 在BBB的Angstrom里不好使,不用尝试了。似乎会被系统kill掉。