電子工作のマテリアルとしてBBBを魅力的なものにしている要素の一つとしてPRUがある。
これから少しPRUについて学んでいこうと思う。
閑話。
PRUはBBBのSoCであるAM335xのサブシステムの一つ、Programmable Real-Time Unit Subsystem and Industrial Communication Subsystem (PRU-ICSS)に 二つあるプロセッサの通称であるようだ。
PRUの情報に関しては以下で説明される。
AM335x Sitara? Processors Technical Reference Manual
Page 196 “Programmable Real-Time Unit Subsystem and Industrial Communication Subsystem (PRU-ICSS)”
二つのPRU(PRU0,PRU1)はそれぞれユーザーがプログラムを記述し実行させ、AM335xにあるペリフェラルの制御や、ARM Coretex-A8コアとの連携ができる。
PRUはDSPではない。
PRUには積和命令/除算命令どころか積算命令すら無く、加算命令と減算命令はあるものの符号無し算術命令しかない。
これは、畳み込み計算処理に必要な積和演算や固定小数点算術計算が苦手である事を意味する。
Program memoryは8KByteで1命令32bit(4Byte)であるので、Programは2K(2048)Step以内で記述する必要がある。
PRU単体でIIRフィルタ処理等を行うには相当の工夫が必要になるだろう。
また、PRUはいわゆるコプロセッサでもない。
PRUにはARM Coretex-A8の特別なインストラクションと紐づけして動作する機能はなく、あくまでも独立したプロセッサとしして機能し、 ARM Coretex-A8とは内部RAMや割り込みコントローラを含む各種ペリフェラルにより連携する。
よって、PRUとARM Coretex-A8との間の連携はそれほど高速なものではない。
Linuxは多重割り込みを許可しないOSであるので、割り込み処理中や割り込み禁止中による処理遅延には考慮が必要。
とはいうものの、PRUとARM Coretex-A8との連携は非常に強力かつ有用だ。
なぜならば、お互いの欠点を補いあう事により、応用範囲が広がるからだ。
言うまでもなく、LinuxはリアルタイムOSではない。
Kernel-Landの処理においてさえも、例えば500μsec毎のGPIの定期監視処理を低ジッタで実現させる事ができない。
このような処理は通常FIFOやDMAを備えたハードウェアの支援が必要になる。
ここでまさにハードウェアの支援をPRUに肩代わりさせることができる。
つまり、PRUに500μsec毎にGPIを監視させ、内部RAM上に構成するリングバッファに記録させ、2KByte毎にARM Coretex-A8に割り込みを発生させるような応用だ。
PRUが算術演算が苦手であると書いたが、複雑な算術演算はARM Coretex-A8に担当させればよい。
ARM Coretex-A8はPRUに比べて高速な算術演算が可能である。
IIRフィルタ付きのDA変換を行いたいような場合、PRUでDA変換を担当させ、必要な量のIIRフィルタ計算をARM Coretex-A8で先行して一定量まとめて実行し、 RAM上のリングバッファに格納、PRUで出力タイミングを計りDA変換出力させると良い。
群遅延は発生するが、低ジッタは期待できるだろう。
昨今のSoCではARM CoretexA9マルチコアにARM7/ARM9やDSPを含む構成となっていて、もっと強力な連携ができるようであるが、 安価なBBBで複数プロセッサによる制御が行えるのは非常に嬉しい。
PRUのアセンブラインストラクションに関しては以下。
PRU Assembly Instructions – Texas Instruments Wiki
閑話休題。
よく纏められたチュートリアルがあるので今回はこれをなぞることとする。
BeagleBone Black: Introduction to PRU-ICSS
(※リンク切れ)
ただし、参照記事はBBB Rev.C以前のAngstromベースでの記載になっている。
追試行は、Rev.C上で以下で作成したDebian環境で行っている。
BeagleBone Blackのkernelの再構築を試みる
追試行において記載通りにならない所があったが、手順は必要に応じて変えている。
また参照元を手順通りなぞるとexample_appsを2回makeする事になるので手順を入れ替える。
興味が無い記述は読み飛ばしてもいる。
以下追試行。
先ず、デフォルトではPRU-ICSSが無効となっている問題を解決する。
具体的にはam335x-boneblack.dtbではpruss@4a300000がstatus = “disabled”となっているためprussdrvファイルが生成されていない。
よってexample_appsを実行するとドライバファイルのopenに失敗する。
対策はいくつかあるようだが、参照元ではam335x-boneblack.dtbを書き換えてしまう方法を紹介している。
手順としては以下。
・am335x-boneblack.dtbを逆コンパイルしてam335x-boneblack.dtsを生成
・am335x-boneblack.dtsを編集してpruss@4a300000をstatus = “okay”に修正
・am335x-boneblack.dtsをコンパイルしてam335x-boneblack.dtbとし差し替え
am335x-boneblack.dtbからam335x-boneblack.dtsを生成する。
一応バックアップも保存しておく。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ cd /boot/uboot/dtbs/ debian@beaglebone:/boot/uboot/dtbs$ sudo cp am335x-boneblack.dtb am335x-boneblack.dtb.original debian@beaglebone:/boot/uboot/dtbs$ sudo -s root@beaglebone:/boot/uboot/dtbs# dtc -I dtb -O dts am335x-boneblack.dtb > am335x-boneblack.dts root@beaglebone:/boot/uboot/dtbs#
am335x-boneblack.dtsを編集する。
root@beaglebone:/boot/uboot/dtbs# nano -w am335x-boneblack.dts
「pruss@4a300000」の文字列を探し、後続する「status = “disabled”;」を「status = “okay”;」に修正する。
pruss@4a300000 { compatible = "ti,pruss-v2"; ti,hwmods = "pruss"; ti,deassert-hard-reset = "pruss", "pruss"; reg = <0x4a300000 0x80000>; ti,pintc-offset = <0x20000>; interrupt-parent = <0x1>; status = "okay"; interrupts = <0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b>; linux,phandle = <0x35>; phandle = <0x35>; };
am335x-boneblack.dtsからam335x-boneblack.dtbを生成する。
root@beaglebone:/boot/uboot/dtbs# dtc -I dts -O dtb am335x-boneblack.dts > am335x-boneblack.dtb root@beaglebone:/boot/uboot/dtbs# exit exit debian@beaglebone:/boot/uboot/dtbs$ sudo sync debian@beaglebone:/boot/uboot/dtbs$ sudo sync debian@beaglebone:/boot/uboot/dtbs$ sudo sync debian@beaglebone:/boot/uboot/dtbs$ reboot
これでデフォルト状態でpruss@4a300000がstatus = “okay”となりprussdrvファイルが生成されるはず。
am335x_pru_packageを取得する。
作業フォルダは~$pruとし、am335x_pru_packageをgit cloneする。
debian@beaglebone:~$ mkdir pru debian@beaglebone:~$ cd pru/ debian@beaglebone:~/pru$ git clone git://github.com/beagleboard/am335x_pru_package.git Cloning into 'am335x_pru_package'... remote: Counting objects: 806, done. remote: Total 806 (delta 0), reused 0 (delta 0) Receiving objects: 100% (806/806), 8.27 MiB | 1023 KiB/s, done. Resolving deltas: 100% (395/395), done. debian@beaglebone:~/pru$
CROSS_COMPILEに余計な定義があるので外す。
debian@beaglebone:~/pru$ export CROSS_COMPILE= debian@beaglebone:~/pru$
インターフェースライブラリのmake。
debian@beaglebone:~/pru$ cd ~/pru/am335x_pru_package/pru_sw/app_loader/interface debian@beaglebone:~/pru/am335x_pru_package/pru_sw/app_loader/interface$ make clean rm -rf release debug *~ ../lib/* debian@beaglebone:~/pru/am335x_pru_package/pru_sw/app_loader/interface$ make all gcc -I. -Wall -I../include -c -g -O0 -D__DEBUG -o debug/prussdrv.o prussdrv.c ar rc ../lib/libprussdrvd.a debug/prussdrv.o gcc -I. -Wall -I../include -c -O3 -mtune=cortex-a8 -march=armv7-a -o release/prussdrv.o prussdrv.c ar rc ../lib/libprussdrv.a release/prussdrv.o gcc -I. -Wall -I../include -c -fPIC -g -O0 -D__DEBUG -o debug/prussdrv_PIC.o prussdrv.c gcc -shared -o ../lib/libprussdrvd.so debug/prussdrv_PIC.o gcc -I. -Wall -I../include -c -fPIC -O3 -mtune=cortex-a8 -march=armv7-a -o release/prussdrv_PIC.o prussdrv.c gcc -shared -o ../lib/libprussdrv.so release/prussdrv_PIC.o debian@beaglebone:~/pru/am335x_pru_package/pru_sw/app_loader/interface$ sudo make install install -m 0755 -d /usr/local/lib install -m 0755 -d /usr/local/include install -m 0644 ../lib/* /usr/local/lib install -m 0644 ../include/prussdrv.h ../include/pruss_intc_mapping.h /usr/local/include debian@beaglebone:~/pru/am335x_pru_package/pru_sw/app_loader/interface$
pasmのmake。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/app_loader/interface$ cd ~/pru/am335x_pru_package/pru_sw/utils/pasm_source/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/utils/pasm_source$ source ./linuxbuild debian@beaglebone:~/pru/am335x_pru_package/pru_sw/utils/pasm_source$
example_appsのmakeを行うが、pasm_2を使う事になっているので解決が必要。
参照元の説明ではリネームとしているがここではシンボリックリンクを作成する。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/utils/pasm_source$ cd .. debian@beaglebone:~/pru/am335x_pru_package/pru_sw/utils$ ln -s pasm pasm_2 debian@beaglebone:~/pru/am335x_pru_package/pru_sw/utils$
example_appsをmakeする。
debian@beaglebone:~$ cd ~/pru/am335x_pru_package/pru_sw/example_apps/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ export CROSS_COMPILE= debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ make clean for dir in PRU_memAccess_DDR_PRUsharedRAM PRU_memAccessPRUDataRam PRU_PRUtoPRU_Interrupt; do make -C $dir clean LIBDIR_APP_LOADER="../../app_loader/lib" LIBDIR_EDMA_DRIVER="" INCDIR_APP_LOADER="../../app_loader/include" INCDIR_EDMA_DRIVER="" BINDIR="../bin"; done make[1]: Entering directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM' rm -rf obj/ *~ ../../app_loader/include/*~ ../bin/PRU_memAcc_DDR_sharedRAM make[1]: Leaving directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM' make[1]: Entering directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccessPRUDataRam' rm -rf obj/ *~ ../../app_loader/include/*~ ../bin/PRU_memAccessPRUDataRam make[1]: Leaving directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccessPRUDataRam' make[1]: Entering directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_PRUtoPRU_Interrupt' rm -rf obj/ *~ ../../app_loader/include/*~ ../bin/PRU_PRUtoPRU_Interrupt make[1]: Leaving directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_PRUtoPRU_Interrupt' for bin_file in PRU_memAcc_DDR_sharedRAM.bin PRU_memAccessPRUDataRam.bin PRU_PRU0toPRU1_Interrupt.bin PRU_PRU1toPRU0_Interrupt.bin; do rm -fr bin/$bin_file; done debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ make mkdir -p bin for dir in PRU_memAccess_DDR_PRUsharedRAM PRU_memAccessPRUDataRam PRU_PRUtoPRU_Interrupt; do make -C $dir CROSS_COMPILE="" LIBDIR_APP_LOADER="../../app_loader/lib" LIBDIR_EDMA_DRIVER="" INCDIR_APP_LOADER="../../app_loader/include" INCDIR_EDMA_DRIVER="" BINDIR="../bin"; done make[1]: Entering directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM' gcc -Wall -I../../app_loader/include -D__DEBUG -O2 -mtune=cortex-a8 -march=armv7-a -c -o obj/PRU_memAcc_DDR_sharedRAM.o PRU_memAcc_DDR_sharedRAM.c gcc -Wall -I../../app_loader/include -D__DEBUG -O2 -mtune=cortex-a8 -march=armv7-a -o ../bin/PRU_memAcc_DDR_sharedRAM obj/PRU_memAcc_DDR_sharedRAM.o -L../../app_loader/lib -lprussdrv make[1]: Leaving directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM' make[1]: Entering directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccessPRUDataRam' gcc -Wall -I../../app_loader/include -D__DEBUG -O2 -mtune=cortex-a8 -march=armv7-a -c -o obj/PRU_memAccessPRUDataRam.o PRU_memAccessPRUDataRam.c gcc -Wall -I../../app_loader/include -D__DEBUG -O2 -mtune=cortex-a8 -march=armv7-a -o ../bin/PRU_memAccessPRUDataRam obj/PRU_memAccessPRUDataRam.o -L../../app_loader/lib -lprussdrv make[1]: Leaving directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccessPRUDataRam' make[1]: Entering directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_PRUtoPRU_Interrupt' gcc -I../../app_loader/include -D__DEBUG -O2 -mtune=cortex-a8 -march=armv7-a -c -o obj/PRU_PRUtoPRU_Interrupt.o PRU_PRUtoPRU_Interrupt.c gcc -I../../app_loader/include -D__DEBUG -O2 -mtune=cortex-a8 -march=armv7-a -o ../bin/PRU_PRUtoPRU_Interrupt obj/PRU_PRUtoPRU_Interrupt.o -L../../app_loader/lib -lprussdrv make[1]: Leaving directory `/home/debian/pru/am335x_pru_package/pru_sw/example_apps/PRU_PRUtoPRU_Interrupt' for a_file in PRU_memAccess_DDR_PRUsharedRAM/PRU_memAcc_DDR_sharedRAM.p PRU_memAccessPRUDataRam/PRU_memAccessPRUDataRam.p PRU_PRUtoPRU_Interrupt/PRU_PRU0toPRU1_Interrupt.p PRU_PRUtoPRU_Interrupt/PRU_PRU1toPRU0_Interrupt.p ; \ do \ ../utils/pasm_2 -V3 -b $a_file ; \ done ; \ mv *.bin bin PRU Assembler Version 0.86 Copyright (C) 2005-2013 by Texas Instruments Inc. Pass 2 : 0 Error(s), 0 Warning(s) Writing Code Image of 16 word(s) PRU Assembler Version 0.86 Copyright (C) 2005-2013 by Texas Instruments Inc. Pass 2 : 0 Error(s), 0 Warning(s) Writing Code Image of 14 word(s) PRU Assembler Version 0.86 Copyright (C) 2005-2013 by Texas Instruments Inc. Pass 2 : 0 Error(s), 0 Warning(s) Writing Code Image of 16 word(s) PRU Assembler Version 0.86 Copyright (C) 2005-2013 by Texas Instruments Inc. Pass 2 : 0 Error(s), 0 Warning(s) Writing Code Image of 14 word(s)
出力された.binファイルを手動でコピー。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ cp ./bin/PRU_PRU0toPRU1_Interrupt.bin ./PRU_PRUtoPRU_Interrupt/obj/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ cp ./bin/PRU_PRU1toPRU0_Interrupt.bin ./PRU_PRUtoPRU_Interrupt/obj/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ cp ./bin/PRU_memAcc_DDR_sharedRAM.bin ./PRU_memAccess_DDR_PRUsharedRAM/obj/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ cp ./bin/PRU_memAccessPRUDataRam.bin ./PRU_memAccessPRUDataRam/obj/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps$ cd ~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj/ debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ gcc PRU_memAcc_DDR_sharedRAM.o -L../../../app_loader/lib/ -lprussdrv -lpthread -o mytest.out debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$
生成したmytest.outを実行する。
root権限ではなく./mytest.outを実行するとSegmentation faultとなるようだ。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ ./mytest.out INFO: Starting PRU_memAcc_DDR_sharedRAM example. Segmentation fault debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ sudo ./mytest.out
少し追ってみよう。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ strace ./mytest.out execve("./mytest.out", ["./mytest.out"], [/* 20 vars */]) = 0 brk(0) = 0x11000 uname({sys="Linux", node="beaglebone", ...}) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fe1000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=62166, ...}) = 0 mmap2(NULL, 62166, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb6fb6000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/usr/lib/libprussdrv.so", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0h\16\0\0004\0\0\0"..., 512) = 512 lseek(3, 8844, SEEK_SET) = 8844 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1000) = 1000 lseek(3, 8580, SEEK_SET) = 8580 read(3, "A4\0\0\0aeabi\0\1*\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 53) = 53 fstat64(3, {st_mode=S_IFREG|0644, st_size=9844, ...}) = 0 mmap2(NULL, 41924, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6fab000 mprotect(0xb6fad000, 32768, PROT_NONE) = 0 mmap2(0xb6fb5000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2) = 0xb6fb5000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/arm-linux-gnueabihf/libpthread.so.0", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\355O\0\0004\0\0\0"..., 512) = 512 lseek(3, 66332, SEEK_SET) = 66332 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1400) = 1400 lseek(3, 65924, SEEK_SET) = 65924 read(3, "A4\0\0\0aeabi\0\1*\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 53) = 53 fstat64(3, {st_mode=S_IFREG|0755, st_size=100447, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fe0000 mmap2(NULL, 107028, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6f90000 mprotect(0xb6fa0000, 28672, PROT_NONE) = 0 mmap2(0xb6fa7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf) = 0xb6fa7000 mmap2(0xb6fa9000, 4628, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb6fa9000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/arm-linux-gnueabihf/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\rn\1\0004\0\0\0"..., 512) = 512 lseek(3, 891684, SEEK_SET) = 891684 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1360) = 1360 lseek(3, 891244, SEEK_SET) = 891244 read(3, "A2\0\0\0aeabi\0\1(\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 51) = 51 fstat64(3, {st_mode=S_IFREG|0755, st_size=893044, ...}) = 0 mmap2(NULL, 935208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6eab000 mprotect(0xb6f83000, 28672, PROT_NONE) = 0 mmap2(0xb6f8a000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd7) = 0xb6f8a000 mmap2(0xb6f8d000, 9512, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb6f8d000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fdf000 set_tls(0xb6fdf4c0, 0xb6fdfb98, 0xb6fe4048, 0xb6fdf4c0, 0xb6fe0828) = 0 mprotect(0xb6f8a000, 8192, PROT_READ) = 0 mprotect(0xb6fa7000, 4096, PROT_READ) = 0 mprotect(0xb6fe3000, 4096, PROT_READ) = 0 munmap(0xb6fb6000, 62166) = 0 set_tid_address(0xb6fdf068) = 3243 set_robust_list(0xb6fdf070, 0xc) = 0 futex(0xbe89b6c0, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, b6fdf000) = -1 EAGAIN (Resource temporarily unavailable) rt_sigaction(SIGRTMIN, {0xb6f94cad, [], SA_SIGINFO|0x4000000}, NULL, 8) = 0 rt_sigaction(SIGRT_1, {0xb6f94bc1, [], SA_RESTART|SA_SIGINFO|0x4000000}, NULL, 8) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0 fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(248, 0), ...}) = 0 ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 opost isig icanon echo ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fde000 write(1, "\n", 1 ) = 1 write(1, "INFO: Starting PRU_memAcc_DDR_sh"..., 50INFO: Starting PRU_memAcc_DDR_sharedRAM example. ) = 50 open("/dev/uio0", O_RDWR|O_SYNC) = -1 EACCES (Permission denied) open("/sys/class/uio/uio0/maps/map0/addr", O_RDONLY) = 3 read(3, "0x4a300000\n", 20) = 11 close(3) = 0 open("/sys/class/uio/uio0/maps/map0/size", O_RDONLY) = 3 read(3, "0x80000\n", 20) = 8 close(3) = 0 mmap2(NULL, 524288, PROT_READ|PROT_WRITE, MAP_SHARED, -1, 0) = -1 EBADF (Bad file descriptor) --- SIGSEGV (Segmentation fault) @ 0 (0) --- +++ killed by SIGSEGV +++ Segmentation fault [/shell] "/dev/uio0"のopenがPermission deniedで失敗している。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ ls -la /dev | grep uio crw------- 1 root root 246, 0 Jan 1 2000 uio0 crw------- 1 root root 246, 1 Jan 1 2000 uio1 crw------- 1 root root 246, 2 Jan 1 2000 uio2 crw------- 1 root root 246, 3 Jan 1 2000 uio3 crw------- 1 root root 246, 4 Jan 1 2000 uio4 crw------- 1 root root 246, 5 Jan 1 2000 uio5 crw------- 1 root root 246, 6 Jan 1 2000 uio6 crw------- 1 root root 246, 7 Jan 1 2000 uio7 debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$
インターフェースライブラリを用いたサンプルはroot権限で実行する前提となるようだ。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ sudo ./mytest.out INFO: Starting PRU_memAcc_DDR_sharedRAM example. INFO: Initializing example. INFO: Executing example. INFO: Waiting for HALT command. INFO: PRU completed transfer. Example executed succesfully. debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$
「Example executed succesfully.」と出れば成功とのこと。
一応straceで比較確認。
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$ sudo strace ./mytest.out execve("./mytest.out", ["./mytest.out"], [/* 14 vars */]) = 0 brk(0) = 0x11000 uname({sys="Linux", node="beaglebone", ...}) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fa7000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=62166, ...}) = 0 mmap2(NULL, 62166, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb6f7c000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/usr/lib/libprussdrv.so", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0h\16\0\0004\0\0\0"..., 512) = 512 lseek(3, 8844, SEEK_SET) = 8844 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1000) = 1000 lseek(3, 8580, SEEK_SET) = 8580 read(3, "A4\0\0\0aeabi\0\1*\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 53) = 53 fstat64(3, {st_mode=S_IFREG|0644, st_size=9844, ...}) = 0 mmap2(NULL, 41924, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6f71000 mprotect(0xb6f73000, 32768, PROT_NONE) = 0 mmap2(0xb6f7b000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2) = 0xb6f7b000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/arm-linux-gnueabihf/libpthread.so.0", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\355O\0\0004\0\0\0"..., 512) = 512 lseek(3, 66332, SEEK_SET) = 66332 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1400) = 1400 lseek(3, 65924, SEEK_SET) = 65924 read(3, "A4\0\0\0aeabi\0\1*\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 53) = 53 fstat64(3, {st_mode=S_IFREG|0755, st_size=100447, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fa6000 mmap2(NULL, 107028, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6f56000 mprotect(0xb6f66000, 28672, PROT_NONE) = 0 mmap2(0xb6f6d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf) = 0xb6f6d000 mmap2(0xb6f6f000, 4628, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb6f6f000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/arm-linux-gnueabihf/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\rn\1\0004\0\0\0"..., 512) = 512 lseek(3, 891684, SEEK_SET) = 891684 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1360) = 1360 lseek(3, 891244, SEEK_SET) = 891244 read(3, "A2\0\0\0aeabi\0\1(\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 51) = 51 fstat64(3, {st_mode=S_IFREG|0755, st_size=893044, ...}) = 0 mmap2(NULL, 935208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6e71000 mprotect(0xb6f49000, 28672, PROT_NONE) = 0 mmap2(0xb6f50000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd7) = 0xb6f50000 mmap2(0xb6f53000, 9512, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb6f53000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fa5000 set_tls(0xb6fa54c0, 0xb6fa5b98, 0xb6faa048, 0xb6fa54c0, 0xb6fa6828) = 0 mprotect(0xb6f50000, 8192, PROT_READ) = 0 mprotect(0xb6f6d000, 4096, PROT_READ) = 0 mprotect(0xb6fa9000, 4096, PROT_READ) = 0 munmap(0xb6f7c000, 62166) = 0 set_tid_address(0xb6fa5068) = 3400 set_robust_list(0xb6fa5070, 0xc) = 0 futex(0xbebfb850, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, b6fa5000) = -1 EAGAIN (Resource temporarily unavailable) rt_sigaction(SIGRTMIN, {0xb6f5acad, [], SA_SIGINFO|0x4000000}, NULL, 8) = 0 rt_sigaction(SIGRT_1, {0xb6f5abc1, [], SA_RESTART|SA_SIGINFO|0x4000000}, NULL, 8) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0 fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(248, 0), ...}) = 0 ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 opost isig icanon echo ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fa4000 write(1, "\n", 1 ) = 1 write(1, "INFO: Starting PRU_memAcc_DDR_sh"..., 50INFO: Starting PRU_memAcc_DDR_sharedRAM example. ) = 50 open("/dev/uio0", O_RDWR|O_SYNC) = 3 open("/sys/class/uio/uio0/maps/map0/addr", O_RDONLY) = 4 read(4, "0x4a300000\n", 20) = 11 close(4) = 0 open("/sys/class/uio/uio0/maps/map0/size", O_RDONLY) = 4 read(4, "0x80000\n", 20) = 8 close(4) = 0 mmap2(NULL, 524288, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb6df1000 open("/sys/class/uio/uio0/maps/map1/addr", O_RDONLY) = 4 read(4, "0x9d5c0000\n", 20) = 11 close(4) = 0 open("/sys/class/uio/uio0/maps/map1/size", O_RDONLY) = 4 read(4, "0x40000\n", 20) = 8 close(4) = 0 mmap2(NULL, 262144, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x1) = 0xb6db1000 write(1, "\tINFO: Initializing example.\r\n", 30 INFO: Initializing example. ) = 30 open("/dev/mem", O_RDWR) = 4 mmap2(NULL, 268435455, PROT_READ|PROT_WRITE, MAP_SHARED, 4, 0x80000) = 0xa6db1000 write(1, "\tINFO: Executing example.\r\n", 27 INFO: Executing example. ) = 27 brk(0) = 0x11000 brk(0x32000) = 0x32000 open("./PRU_memAcc_DDR_sharedRAM.bin", O_RDONLY) = 5 fstat64(5, {st_mode=S_IFREG|0644, st_size=64, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fa3000 fstat64(5, {st_mode=S_IFREG|0644, st_size=64, ...}) = 0 _llseek(5, 0, [0], SEEK_SET) = 0 read(5, "\200$\4\221\340\340\4\35\200$\4\201\340 \1$\301\2\0$\201( $\200!\0\341\300\20\0$"..., 64) = 64 _llseek(5, 64, [64], SEEK_SET) = 0 close(5) = 0 munmap(0xb6fa3000, 4096) = 0 write(1, "\tINFO: Waiting for HALT command."..., 34 INFO: Waiting for HALT command. ) = 34 read(3, "\1\0\0\0", 4) = 4 write(1, "\tINFO: PRU completed transfer.\r\n", 32 INFO: PRU completed transfer. ) = 32 write(1, "Example executed succesfully.\r\n", 31Example executed succesfully. ) = 31 munmap(0xb6df1000, 524288) = 0 munmap(0, 0) = -1 EINVAL (Invalid argument) munmap(0xb6db1000, 262144) = 0 close(3) = 0 munmap(0xa6db1000, 268435455) = 0 close(4) = 0 exit_group(0) = ? debian@beaglebone:~/pru/am335x_pru_package/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj$
PRU_memAccess_DDR_PRUsharedRAMは/dev/memを用いてDDRに書き込んだ値を、PRU0を用いてPRUのShared RAMに転送する。
ソースコードを見れば、少なくともPRU0が動作している事が納得できるが、ターミナルに「Example executed succesfully.」とプリントされるだけであるので地味だ。
参照元にはもう少し見た目にわかりやすい例が載っている。
Example 1 – PRU0 blinking LED
次回はこれを実行してみようと思う。