以下の記事を試す
32. Linux on Zynq / Real-Time Video Processing
https://sites.google.com/site/powellsshowcase/home/32linuxonzynqreal-timevideoprocessing
1. GitHubレポジトリをクローン
git clone https://github.com/andrewandrepowell/zybo_petalinux_video_hls
2. ビットストリームを生成
Vivadoを起動し、zybo_petalinux_video_hls.xprを開く
Automatically Upgrade IPを指定して、IPコアをアップグレードする。
PSのGPIOを使う必要があるので、ZYNQでMIO GPIOの設定を行う。
ZYNQブロックをダブルクリックし、MIO Configurationを開く
GPIO MIO=MIO、EMIO GPIO(Width)=64に設定した。
その後Generate Bitstreamする。
3. クロスコンパイル環境(Debian)にOpenCVをインストールする
OpenCVのインストールはこの記事を参考:
Zynq上のDebianにpyenvでPython3とOpencvをインストール
http://d.hatena.ne.jp/seinzumtode/20171123/1511470206
Pythonのバージョンは3.4.7(pyenv), OpenCVのバージョンは3.0.0
(クロスコンパイルDebian環境の作り方は以下の記事を参照:)
ubuntuにzynqのクロス環境debianをdebootstrapで入れる
http://d.hatena.ne.jp/seinzumtode/20171225/1514177692
4. SDKの起動
まず古いハードウェアプロジェクトを削除する(VivadoからLaunch SDKして、block_design_0_wrapperプロジェクトをDeleteする)
その後VivadoでハードウェアをExportし、Launch SDKでSDKを起動する。
今回試したいLinuxプロジェクトはvideo_processing_app_0である。
main.ccを開くと、OpenCV関連のヘッダファイルが見えていないので、以降でこれらを追加する
6. コンパイラの設定
7. リンカースクリプトの設定
リンクするライブラリ(-l)
(デフォルトではlibtiffとかlibjpegとか"lib"の接頭辞がついていたので、それらは外す)
dl opencv_videoio opencv_imgcodecs opencv_highgui opencv_imgproc opencv_photo opencv_video opencv_features2d opencv_objdetect opencv_shape opencv_core opencv_ml tiff webp IlmImf png jpeg jasper z pthread rt
リンカーフラグでsysrootとrpathを指定する。
20180321追記:rpathの指定はrpath=dirのように、=(イコール)が必要。-Wl,-rpath=のところで、-Wl, -rpathのように空白をいれない。
--sysroot="/home/shohei/zynqfs" -Wl,-rpath=/home/shohei/zynqfs/lib/arm-linux-gnueabihf -Wl,-rpath=/home/shohei/zynqfs/usr/lib/arm-linux-gnueabihf
8. Petalinuxの設定
いつも通りにビルドする。
カーネル設定で必要なのはUVCカメラ(V4L)、Userspace I/Oあたり。
生成したbitstreamを元に、BOOT.BINを用意する
9. デバイスツリーの設定
ここで激しくハマった。FilterのVDMAにはReadとWriteの2チャンネルあるのだが、それぞれに対してトップモジュール(というのか?)的にデバイスを宣言しないといけない。(下でいう、dma0とdma1)
UVCカメラの設定をしておくのと(次を参考→Zybo+PetalinuxでUVCカメラを使う:http://d.hatena.ne.jp/seinzumtode/20171120/1511167136 )、各デバイスはuioとして見えるようにしておく(compatible = generic=uio)。
DTSの設定はここを参考に:(https://github.com/andrewandrepowell/zybo_petalinux_video_hls/tree/master/petalinux_proj/subsystems/linux/configs/device-tree)
以下の設定をすることで、Linuxに入ったときに、uioが見えるようになる。
shohei@debian8-zynq:~$ ls -l /dev/uio* crw------- 1 root root 245, 0 1月 1 00:00 /dev/uio0 crw------- 1 root root 245, 1 1月 1 00:00 /dev/uio1 crw------- 1 root root 245, 2 1月 1 00:00 /dev/uio2 crw------- 1 root root 245, 3 1月 1 00:00 /dev/uio3 crw------- 1 root root 245, 4 1月 1 00:00 /dev/uio4 crw------- 1 root root 245, 5 1月 1 00:00 /dev/uio5 crw------- 1 root root 245, 6 1月 1 00:00 /dev/uio6 shohei@debian8-zynq:~$ cat /sys/class/uio/uio*/maps/map0/name /amba_pl/axi_dispctrl@43c00000 /amba_pl/gpio@41200000 /amba_pl/dma@43000000 /amba_pl/dma0@43010000 /amba_pl/dma1@43010000 /amba_pl/filt@43c10000 /amba_pl/gpio@41210000
system.dtsの抜粋
PLの設定
amba_pl { #address-cells = <0x1>; #size-cells = <0x1>; compatible = "simple-bus"; ranges; axi_dispctrl@43c00000 { compatible = "generic-uio"; reg = <0x43c00000 0x10000>; xlnx,blue-width = <0x5>; xlnx,green-width = <0x6>; xlnx,red-width = <0x5>; xlnx,use-bufr-div5 = <0x0>; }; gpio@41200000 { #gpio-cells = <0x2>; #interrupt-cells = <0x2>; compatible = "generic-uio"; gpio-controller; interrupt-controller; interrupt-parent = <0x4>; interrupts = <0x0 0x1d 0x4>; reg = <0x41200000 0x10000>; xlnx,all-inputs = <0x1>; xlnx,all-inputs-2 = <0x0>; xlnx,all-outputs = <0x0>; xlnx,all-outputs-2 = <0x1>; xlnx,dout-default = <0x0>; xlnx,dout-default-2 = <0x0>; xlnx,gpio-width = <0x4>; xlnx,gpio2-width = <0x4>; xlnx,interrupt-present = <0x1>; xlnx,is-dual = <0x1>; xlnx,tri-default = <0xffffffff>; xlnx,tri-default-2 = <0xffffffff>; }; dma@43000000 { #dma-cells = <0x1>; clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_mm2s_aclk"; clocks = <0x1 0xf 0x1 0xf 0x1 0xf>; compatible = "generic-uio"; interrupt-parent = <0x4>; interrupts = <0x0 0x1e 0x4>; reg = <0x43000000 0x10000>; xlnx,addrwidth = <0x20>; xlnx,flush-fsync = <0x1>; xlnx,num-fstores = <0x4>; dma-channel@43000000 { compatible = "xlnx,axi-vdma-mm2s-channel"; interrupts = <0x0 0x1e 0x4>; xlnx,datawidth = <0x20>; xlnx,device-id = <0x0>; xlnx,genlock-mode; }; }; dma0@43010000 { #dma-cells = <0x1>; clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk", "m_axi_s2mm_aclk"; clocks = <0x1 0xf 0x1 0xf 0x1 0xf 0x1 0xf 0x1 0xf>; compatible = "generic-uio"; interrupt-parent = <0x4>; interrupts = <0x0 0x20 0x4>; reg = <0x43010000 0x10000>; xlnx,addrwidth = <0x20>; xlnx,flush-fsync = <0x1>; xlnx,num-fstores = <0x4>; dma-channel@43010000 { compatible = "xlnx,axi-vdma-mm2s-channel"; interrupts = <0x0 0x20 0x4>; xlnx,datawidth = <0x20>; xlnx,device-id = <0x1>; }; }; dma1@43010000 { #dma-cells = <0x1>; clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk", "m_axi_s2mm_aclk"; clocks = <0x1 0xf 0x1 0xf 0x1 0xf 0x1 0xf 0x1 0xf>; compatible = "generic-uio"; interrupt-parent = <0x4>; interrupts = <0x0 0x21 0x4>; reg = <0x43010000 0x10000>; xlnx,addrwidth = <0x20>; xlnx,flush-fsync = <0x1>; xlnx,num-fstores = <0x4>; dma-channel@43010030 { compatible = "xlnx,axi-vdma-s2mm-channel"; interrupts = <0x0 0x21 0x4>; xlnx,datawidth = <0x20>; xlnx,device-id = <0x1>; xlnx,genlock-mode; }; }; filt@43c10000 { compatible = "generic-uio"; interrupt-parent = <0x4>; interrupts = <0x0 0x1f 0x4>; reg = <0x43c10000 0x10000>; xlnx,s-axi-control-bus-addr-width = <0x4>; xlnx,s-axi-control-bus-data-width = <0x20>; }; gpio@41210000 { #gpio-cells = <0x2>; compatible = "generic-uio"; gpio-controller; reg = <0x41210000 0x10000>; xlnx,all-inputs = <0x0>; xlnx,all-inputs-2 = <0x0>; xlnx,all-outputs = <0x1>; xlnx,all-outputs-2 = <0x0>; xlnx,dout-default = <0x1>; xlnx,dout-default-2 = <0x0>; xlnx,gpio-width = <0x1>; xlnx,gpio2-width = <0x20>; xlnx,interrupt-present = <0x0>; xlnx,is-dual = <0x0>; xlnx,tri-default = <0xffffffff>; xlnx,tri-default-2 = <0xffffffff>; }; };
bootargsの設定(uioを有効化するための設定)
chosen { bootargs = "console=ttyPS0,115200 earlyprintk root=/dev/nfs nfsroot=192.168.100.205:/tftpboot/nfsroot,tcp ip=dhcp rw uio_pdrv_genirq.of_id=generic-uio"; stdout-path = "serial0:115200n8"; };
Webカメラの設定
usb@e0002000 { compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2"; status = "okay"; clocks = <0x1 0x1c>; dr_mode = "host"; // ←←←←ここを追加 interrupt-parent = <0x4>; interrupts = <0x0 0x15 0x4>; reg = <0xe0002000 0x1000>; usb-phy = <&usb_phy0>; // ←←←←ここを追加 }; /{ usb_phy0: phy0 { compatible = "ulpi-phy"; #phy-cells = <0>; reg = <0xe0002000 0x1000>; view-port = <0x170>; drv-vbus; }; };
9. Linuxを起動する。
OpenCVのライブラリの場所を読み込むための引数としてLD_LIBRARY_PATHをつけて、さらにsudo権限で起動する。
起動スクリプトにした。
./run.sh
#!/bin/bash sudo LD_LIBRARY_PATH=/home/shohei/.pyenv/versions/3.4.7/usr/local/lib/ ./video_process_app_0.elf
実行
shohei@debian8-zynq:~$ ./run.sh [sudo] password for shohei: Checking to see if the video stream opened and setting resolution... Configuring display... Configuring framebuffer with opencv Mats... Configuring standalone GPIO driver... Configuring filt core... Running main application...
なんか下が切れた画像が表示されて止まる。
VDMAのWriteでページフレームを指定するSOF(Start of Frame)(AXIのtuser信号に乗っかってる?)が帰ってこないので無限にスタックしているようである。
(Vivado上でBlock diagramをみると、VDMA1に対してSOF on tuserを送出する必要があるのは、解像度変換を行っているHLS IPコアのようにみえる)
ソフトウェア上では、linuxmmap.cppのwait()の中でread(2)しているのだが、ここで無限読み込み待ち状態に入っている。
main.cc
//ループ処理の最後 /* Trigger VDMA with fsync. Wait until interrupt is triggered. */ XGpio_DiscreteWrite( &fsync_obj, 1, 0 ); //ここでVDMAのWrite(vdma_1_1=linuxmmapオブジェクト)に対してwait()する filt_vdma_mmap_1_obj.wait(); filtvdma_clear_vdma_write_int( &filtvdma_obj ); filt_vdma_mmap_1_obj.ready(); XGpio_DiscreteWrite( &fsync_obj, 1, 1 );
linuxmmap.cpp
uint32_t linuxmmap::wait() { if ( isuio ) { uint32_t nints; //ここのread()で無限待機状態に入っている if ( read( fd, &nints, sizeof( nints ) ) != sizeof( nints ) ) throw std::runtime_error( "Interrupt failed!" ); return nints; } return 0; }
これ以上追えなくなってスタックしたので、PYNQのJupyter notebookからHDMI入力を入れて使う方法を進めてみることにする。
参考:
https://sites.google.com/site/powellsshowcase/home/32linuxonzynqreal-timevideoprocessing
https://www.xilinx.com/support/answers/69159.html
https://forums.xilinx.com/t5/Embedded-Linux/Petalinux-2017-1-Cross-Compiling/td-p/768533
https://forums.xilinx.com/t5/SDSoC-Environment-and-reVISION/How-to-link-OpenCV-library-with-SDSoC/td-p/761682
https://stackoverflow.com/questions/33519085/cannot-specify-multiple-rpath-in-eclipse-cdt
https://forum.digilentinc.com/topic/2719-how-to-register-my-device-as-uio-on-petalinux/
https://github.com/andrewandrepowell/zybo_petalinux_video_hls/tree/master/petalinux_proj/subsystems/linux/configs/device-tree