BeagleBone BlackのPRUを学ぶ(その1)

電子工作のマテリアルとして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

次回はこれを実行してみようと思う。

タイトルとURLをコピーしました