BeagleBone Tips

BeagleBone Blackにふれる機会があったので、気付いた点、嵌りそうなポイントをまとめていきたいと思う。

周辺I/Oの設定

BBBではcape managerというので、周辺I/Oの設定をおこないます。BBBに限らず、マイコンボードではI/Oピンが限られているし、割込みリソースも潤沢とはいえないので、機能を必要に応じて起動、割当てすることによって、ユーザー毎に必要なI/Oを確保しようという仕組みです。

確認方法は以下の通りで、デフォルトでは次のようになっている。

root@beaglebone:~# cat /sys/devices/bone_capemgr.9/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

設定変更は、/boot/uEnv.txtで行う。以下のケースではHDMIをdisableとし、UARTをenableにしている。特に、UARTに関してはコメント文に書いてないので良くわすれる。書式はv3.8.xとv4.0で若干異なる。

余談であるが、UART3は出力専用となっており、RXピンが存在しない。また、UART0はピンヘッダではなく、J1に接続されている。

slotファイルに動的にslot番号を書き込んで増やせるという情報もあるが、私はresource busyになって上手くいかなかった。

cape_enable=capemgr.enable_partno=BB-UART1,BB-UART2,BB-UART4,BB-UART5
cape_disable=capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN,BB-BONE-EMMC-2G

リブート後次のように変化していれば意図した設定になっている。上手くいかないときは起動時のlogを確認しましょう。

root@beaglebone:/lib/firmware# cat /sys/devices/platform/bone_capemgr/slots
 0: PF----  -1
 1: PF----  -1
 2: PF----  -1
 3: PF----  -1
 4: P-O-L-   1 Override Board Name,00A0,Override Manuf,BB-UART1
 5: P-O-L-   0 Override Board Name,00A0,Override Manuf,BB-UART2
 6: P-O-L-   2 Override Board Name,00A0,Override Manuf,BB-UART4
 7: P-O-L-   3 Override Board Name,00A0,Override Manuf,BB-UART5

周辺I/Oの設定(上級編)

予め用意されているdtbファイルでは、pull up/downなどは設定出来ないので、任意の設定にしたい場合は、自前で用意する必要がある。特に、boot configurationなどに利用されている一部のピンで、外部回路でpull up/downを行うと、起動しなくなったりする場合があるので、こういった場合に有用だ。
dtbファイルはdtsファイルと呼ばれるテキストファイルと、dtcコマンドを用いて相互に変換することができる。

dtb -> dts

dtc -I dtb -O dts am335x-boneblack.dtb > /root/am335x-boneblack.dts

dts -> dtb

dtc -O dtb -o BB-SPI1-01-00A0.dtbo -b 0 -@ BB-SPI1-01-00A0.dts

ちなみに、dtbファイルを読み込ませるタイミングは以下の3通りがある。1,2の方法を使う場合、mkinitramfsでinitrdを作り直しておく必要がある。

  1. /boot/dtbs以下におかれている標準で読み込まれるdtbファイルを/boot/uEnv.txtで指定する。
  2. /lib/firmware以下におかれているdtbファイルを/boot/uEnv.txtで指定して標準をオーバーライド
  3. /lib/firmware以下におかれているdtbファイルを/dtc/default/capemgrで指定して起動後に設定を変更する。

AM335xの各I/Oピンの設定はTIのPinMuxUtilityを用いて、GUIで行う事が出来る。
現在、ダウンロードして利用するソフトと、オンラインで利用するタイプがある。オンラインで利用するタイプはmyTIのアカウント登録が必要である。料金については何れも無料。

http://www.ti.com/tool/pinmuxtool

ピン割り当てがコンフリクトしているものは、その旨表示が出るので、エラーが無い状態に設定をして、outputタブを開くとgenerated filesの項目にソースファイルが出来上がっている。

Cのソースと、devicetree.txtというファイルが含まれているが、このファイルからdtsファイルに紐付ける方法が不明だったので、この方法は保留とした。
参考:http://wiki.sharedcircuits.com/index.php/BeagleBone_Black

dtsファイルを作るスクリプトや、webページが公開されているので、これを利用することにした。
1ピンづつしか指定できないので、必要なピン数分取得したのち、マージした。

作成したファイルを参考までに置いておく。
BB-MYIO-00A0.dts BB-MYIO-00A0.dtbo

見つからない場合は上記のような方法に頼る必要があるのだが、TIのサイトで調べる場合、チップへの結線を確認しながらになるし、個人のwebサイトは使えなくなったりしている場合があり、もっと簡便な方法を考えた。
/boot/dtbs/<kernel>/以下に置いてあるdtbファイルから適当なファイルを選んで、dtsに変換してマージしていくか、ソースを見て必要な部分をマージしていく方法だ。
am335x-boneblack.dtbあたりを見ると、殆どのGPIOが記述されているので、例えばUARTに幾つかGPIOを足したいといった場合はこれで用が足りる。

上記のように作成したdtboファイルを/etc/firmware以下に置いておき、/etc/default/capemgrで指定した。

# Options to pass to capemgr
CAPE=BB-MYIO

uEnv.txtで指定する方法も試したが、エラーは出ないものの、起動後に/sys/class/gpio/exportにGPIOの番号を書き込んでも、動的にデバイスファイルが作成されなくなる不具合があった。

周辺I/Oの設定 on Linux beaglebone 4.14.71-ti-r80

前述の記述は、2016年5月、多分kernel 4.0.xとかの頃のものだと思います。その後kernelを新しくした所設定方法に変更があったので主に更新点を述べたいと思う。

custom capeの作成

dtsファイルには特に変更はない。dtcコマンドで次のようにエラーが出るので、no-unit_address_vs_regオプションを指定する必要があった。これは書式の問題のような気がするがオプションで下位互換性が提供されているようなので調べていない。

root@beaglebone:~# dtc -O dtb -o BB-MYIO-00A0.dtbo -b 0 -@ BB-MYIO-00A0.dts
BB-MYIO-00A0.dtbo: Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property
BB-MYIO-00A0.dtbo: Warning (unit_address_vs_reg): Node /fragment@1 has a unit name, but no reg property
root@beaglebone:~# dtc -W no-unit_address_vs_reg -O dtb -o BB-MYIO-00A0.dtbo -b 0 -@ BB-MYIO-00A0.dts

動的設定の方法

動的に変更は出来なくなった模様。
Kernel Overlays are going bye-bye, too many bugs, too many race conditions, no kernel maintainers interested. We've said our farewells and U-Boot Overlays is the way forward: https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays With multiple parties working on the U-Boot infrastructure.

設定状況は次のようにして確認できるようだ。

root@beaglebone:/sys/devices/platform/bone_capemgr# /opt/scripts/tools/version.sh
git:/opt/scripts/:[1aa73453b2c980b75e31e83dab7dd8b6696f10c7]
eeprom:[A335BNLTEIA01609BBBK03BB]
model:[TI_AM335x_BeagleBone_Black]
dogtag:[BeagleBoard.org Debian Image 2018-10-07]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot 2018.09-00002-g0b54a51eee]:[location: dd MBR]
kernel:[4.14.71-ti-r80]
nodejs:[v6.14.4]
uboot_overlay_options:[enable_uboot_overlays=1]
uboot_overlay_options:[uboot_overlay_addr0=/lib/firmware/BB-UART1-00A0.dtbo]
uboot_overlay_options:[uboot_overlay_addr1=/lib/firmware/BB-UART2-00A0.dtbo]
uboot_overlay_options:[uboot_overlay_addr2=/lib/firmware/BB-UART4-00A0.dtbo]
uboot_overlay_options:[uboot_overlay_addr3=/lib/firmware/BB-UART5-00A0.dtbo]
uboot_overlay_options:[uboot_overlay_addr4=/lib/firmware/BB-MYIO-00A0.dtbo]
uboot_overlay_options:[disable_uboot_overlay_video=1]
uboot_overlay_options:[disable_uboot_overlay_audio=1]
uboot_overlay_options:[disable_uboot_overlay_adc=1]
uboot_overlay_options:[uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-14-TI-00A0.dtbo]
uboot_overlay_options:[enable_uboot_cape_universal=1]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade ]
pkg:[bb-cape-overlays]:[4.4.20180928.0-0rcnee0~stretch+20180928]
pkg:[bb-wl18xx-firmware]:[1.20180517-0rcnee0~stretch+20180517]
pkg:[kmod]:[23-2rcnee1~stretch+20171005]
pkg:[librobotcontrol]:[1.0.3-git20181005.0-0rcnee0~stretch+20181005]
pkg:[firmware-ti-connectivity]:[20170823-1rcnee1~stretch+20180328]
groups:[debian : debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal i2c bluetooth netdev cloud9ide gpio pwm eqep admin spi tisdk weston-launch xenomai]
cmdline:[console=ttyO0,115200n8 bone_capemgr.uboot_capemgr_enabled=1 root=/dev/mmcblk1p1 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 quiet]
dmesg | grep pinctrl-single
[    1.107493] pinctrl-single 44e10800.pinmux: 142 pins at pa f9e10800 size 568
[    1.181570] pinctrl-single 44e10800.pinmux: pin PIN51 already requested by ocp:bs_pinmode_pinmux; cannot claim for ocp:P8_34_pinmux
[    1.193558] pinctrl-single 44e10800.pinmux: pin-51 (ocp:P8_34_pinmux) status -22
[    1.201021] pinctrl-single 44e10800.pinmux: could not request pin 51 (PIN51) from group pinmux_P8_34_default_pin  on device pinctrl-single
[    1.224168] pinctrl-single 44e10800.pinmux: pin PIN46 already requested by ocp:bs_pinmode_pinmux; cannot claim for ocp:P8_39_pinmux
[    1.236130] pinctrl-single 44e10800.pinmux: pin-46 (ocp:P8_39_pinmux) status -22
[    1.243591] pinctrl-single 44e10800.pinmux: could not request pin 46 (PIN46) from group pinmux_P8_39_default_pin  on device pinctrl-single
[    1.267335] pinctrl-single 44e10800.pinmux: pin PIN45 already requested by ocp:bs_pinmode_pinmux; cannot claim for ocp:P8_42_pinmux
[    1.279287] pinctrl-single 44e10800.pinmux: pin-45 (ocp:P8_42_pinmux) status -22
[    1.286747] pinctrl-single 44e10800.pinmux: could not request pin 45 (PIN45) from group pinmux_P8_42_default_pin  on device pinctrl-single
[    1.310766] pinctrl-single 44e10800.pinmux: pin PIN40 already requested by ocp:bs_pinmode_pinmux; cannot claim for ocp:P8_45_pinmux
[    1.322714] pinctrl-single 44e10800.pinmux: pin-40 (ocp:P8_45_pinmux) status -22
[    1.330177] pinctrl-single 44e10800.pinmux: could not request pin 40 (PIN40) from group pinmux_P8_45_default_pin  on device pinctrl-single
[    1.352225] pinctrl-single 44e10800.pinmux: pin PIN41 already requested by ocp:bs_pinmode_pinmux; cannot claim for ocp:P8_46_pinmux
[    1.364157] pinctrl-single 44e10800.pinmux: pin-41 (ocp:P8_46_pinmux) status -22
[    1.371615] pinctrl-single 44e10800.pinmux: could not request pin 41 (PIN41) from group pinmux_P8_46_default_pin  on device pinctrl-single
[    1.393321] pinctrl-single 44e10800.pinmux: pin PIN30 already requested by ocp:bs_pinmode_pinmux; cannot claim for ocp:P9_12_pinmux
[    1.405263] pinctrl-single 44e10800.pinmux: pin-30 (ocp:P9_12_pinmux) status -22
[    1.412723] pinctrl-single 44e10800.pinmux: could not request pin 30 (PIN30) from group pinmux_P9_12_default_pin  on device pinctrl-single
dmesg | grep gpio-of-helper
[    1.119393] gpio-of-helper ocp:cape-universal: ready
END

起動時の設定

uEnv.txtへの設定は次のような書式に変更となった。

uboot_overlay_addr0=/lib/firmware/BB-UART1-00A0.dtbo
uboot_overlay_addr1=/lib/firmware/BB-UART2-00A0.dtbo
uboot_overlay_addr2=/lib/firmware/BB-UART4-00A0.dtbo
uboot_overlay_addr3=/lib/firmware/BB-UART5-00A0.dtbo
uboot_overlay_addr4=/lib/firmware/BB-MYIO-00A0.dtbo

Watchdog timerの使い方

shellからコントロールする方法

デバイスは/dev/watchdogとして見えているので、これに対して何らかの書込みを行う事でenableとなる。
以後60秒以内に次の文字を書き込まないと、システムがリセットされる。
'V'を書き込むことでWDTをdisableに設定することが出来る。

/dev/watchdogに何か文字を書き込んで、closeするときにenableのままだと次のメッセージが出る。

watchdog: watchdog0: watchdog did not stop!

プログラムからコントロールする方法

shellと同様の操作に加え、ioctlによりより細かな操作を行うことが出来る。 詳しくはこちら
タイムアウト値の変更などを行う場合は、こちらの方法を使う必要がある。
例)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/watchdog.h>

void main(){
    int fd=open("/dev/watchdog", O_WRONLY);
    if(fd < 0)
        perror("open");
    for (int8_t i=0; i <10; i++) {
        if(ioctl(fd, WDIOC_KEEPALIVE, 0) < 0)
            perror("ioctl");
        sleep(10);
    }
    // disable WDT
    int opt=WDIOS_DISABLECARD;
    if(ioctl(fd, WDIOC_SETOPTIONS, &opt) < 0)
        perror("ioctl");
    close(fd);
}