FC2カウンター FPGAの部屋 2017年07月
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Pmod Shield: Adapter Board for Uno R3 Standard to Pmod

Pmod Shield: Adapter Board for Uno R3 Standard to Pmod”が来ました。これは、PYNQやArty-Z7、Arty のArduino拡張コネクタに刺さって、Pmodコネクタを増設するボードです。
adapterB_Pmod_1_170731.jpg

adapterB_Pmod_2_170731.jpg

Arty-Z720のArduino拡張コネクタに挿入します。
adapterB_Pmod_3_170731.jpg

adapterB_Pmod_4_170731.jpg

これで、ミニ・ロボットカーにPYNQ(Arty-Z720でも良いですが)を搭載することができます。Pmodにモーターをつなぐ必要があるので。。。
  1. 2017年07月31日 11:47 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

enscript でソースコードをHTML にする

今までWindows ではSourceConverter でソースコードをHTML にしてきた。
Ubntu 16.04 を使うようになって、ソースコードのHTML 化をどうするか?考える必要が出てきた。調べてみると enscript というGNU Project のコマンドでテキストをHTML にすることができるようだ。

最初に”[linux] ソースコードをHTMLに変換するコマンド:enscript”を参考にした。
しかしどうも、タブが8キャラクタになってしまう。-T または、--tabsize を設定しても、やはりタブは8キャラクタだった。
出力後のHTML ファイルを見てみるとタブはそのままタブとして出力されていた。
タブをスペースに変換はしてくれないようなので、geany を立ち上げて、文書メニューから「タブを空白で置換」を選択して、タブをスペースに変換した。
C ソースコードをHTML 化するのに使用したコマンドは、
enscript --highlight=cpp --color -C --tabsize=4 -w html -o output.html straight_dataset_bmp.cpp
だった。

また、enscript_cpp というバッチファイルを作って、任意のC ソースコードをHTML に変換できるようにした。enscript_cpp の中身を示す。

enscript --highlight=cpp --color -C --tabsize=4 -w html -o output.html $1


HTML 化したコードには、<pre>タグが使われていて、FC2ブログでは良いのだが、ライブドア・ブログに持っていた時にきちんと表示されるかが心配だ。
enscript を使用したC ソースコードの表示例は、”Ubuntu 16.04 上のVivado HLS 2017.2 でOpenCV を使用したプロジェクトでエラー発生”に貼ってあるので参照のこと。
enscript のヘルプメッセージを貼っておく。

Usage: enscript [OPTION]... [FILE]...
Mandatory arguments to long options are mandatory for short options too.
  -#                         an alias for option -n, --copies
  -1                         same as --columns=1
  -2                         same as --columns=2
      --columns=NUM          specify the number of columns per page
  -a, --pages=PAGES          specify which pages are printed
  -A, --file-align=ALIGN     align separate input files to ALIGN
  -b, --header=HEADER        set page header
  -B, --no-header            no page headers
  -c, --truncate-lines       cut long lines (default is to wrap)
  -C[START], --line-numbers[=START]
                             precede each line with its line number
  -d                         an alias for option --printer
  -D, --setpagedevice=KEY[:VALUE]
                             pass a page device definition to output
  -e[CHAR], --escapes[=CHAR]       enable special escape interpretation
  -E[LANG], --highlight[=LANG]     highlight source code
  -f, --font=NAME            use font NAME for body text
  -F, --header-font=NAME     use font NAME for header texts
  -g, --print-anyway         nothing (compatibility option)
  -G                         same as --fancy-header
      --fancy-header[=NAME]  select fancy page header
  -h, --no-job-header        suppress the job header page
  -H[NUM], --highlight-bars[=NUM]  specify how high highlight bars are
  -i, --indent=NUM           set line indent to NUM characters
  -I, --filter=CMD           read input files through input filter CMD
  -j, --borders              print borders around columns
  -J,                        an alias for option --title
  -k, --page-prefeed         enable page prefeed
  -K, --no-page-prefeed      disable page prefeed
  -l, --lineprinter          simulate lineprinter, this is an alias for:
                               --lines-per-page=66, --no-header, --portrait,
                               --columns=1
  -L, --lines-per-page=NUM   specify how many lines are printed on each page
  -m, --mail                 send mail upon completion
  -M, --media=NAME           use output media NAME
  -n, --copies=NUM           print NUM copies of each page
  -N, --newline=NL           select the newline character.  Possible
                             values for NL are: n (`\n') and r (`\r').
  -o                         an alias for option --output
  -O, --missing-characters   list missing characters
  -p, --output=FILE          leave output to file FILE.  If FILE is `-',
                             leave output to stdout.
  -P, --printer=NAME         print output to printer NAME
  -q, --quiet, --silent      be really quiet
  -r, --landscape            print in landscape mode
  -R, --portrait             print in portrait mode
  -s, --baselineskip=NUM     set baselineskip to NUM
  -S, --statusdict=KEY[:VALUE]
                             pass a statusdict definition to the output
  -t, --title=TITLE          set banner page's job title to TITLE.  Option
                             sets also the name of the input file stdin.
  -T, --tabsize=NUM          set tabulator size to NUM
  -u[TEXT], --underlay[=TEXT]      print TEXT under every page
  -U, --nup=NUM              print NUM logical pages on each output page
  -v, --verbose              tell what we are doing
  -V, --version              print version number
  -w, --language=LANG        set output language to LANG
  -W, --options=APP,OPTION   pass option OPTION to helper application APP
  -X, --encoding=NAME        use input encoding NAME
  -z, --no-formfeed          do not interpret form feed characters
  -Z, --pass-through         pass through PostScript and PCL files
                             without any modifications
Long-only options:
  --color[=bool]             create color outputs with states
  --continuous-page-numbers  count page numbers across input files.  Don't
                             restart numbering at beginning of each file.
  --download-font=NAME       download font NAME
  --extended-return-values   enable extended return values
  --filter-stdin=NAME        specify how stdin is shown to the input filter
  --footer=FOOTER            set page footer
  --h-column-height=HEIGHT   set the horizontal column height to HEIGHT
  --help                     print this help and exit
  --help-highlight           describe all supported --highlight languages
                             and file formats
  --highlight-bar-gray=NUM   print highlight bars with gray NUM (0 - 1)
  --list-media               list names of all known media
  --margins=LEFT:RIGHT:TOP:BOTTOM
                             adjust page marginals
  --mark-wrapped-lines[STYLE]
                             mark wrapped lines in the output with STYLE
  --non-printable-format=FMT specify how non-printable chars are printed
  --nup-columnwise           layout pages in the N-up printing columnwise
  --nup-xpad=NUM             set the page x-padding of N-up printing to NUM
  --nup-ypad=NUM             set the page y-padding of N-up printing to NUM
  --page-label-format=FMT    set page label format to FMT
  --ps-level=LEVEL           set the PostScript language level that enscript
                             should use
  --printer-options=OPTIONS  pass extra options to the printer command
  --rotate-even-pages        rotate even-numbered pages 180 degrees
  --slice=NUM                print vertical slice NUM
  --style=STYLE              use highlight style STYLE
  --swap-even-page-margins   swap left and right side margins for each even
                             numbered page
  --toc                      print table of contents
  --ul-angle=ANGLE           set underlay text's angle to ANGLE
  --ul-font=NAME             print underlays with font NAME
  --ul-gray=NUM              print underlays with gray value NUM
  --ul-position=POS          set underlay's starting position to POS
  --ul-style=STYLE           print underlays with style STYLE
  --word-wrap                wrap long lines from word boundaries

Report bugs to <bug-enscript@gnu.org>.

  1. 2017年07月30日 06:16 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Ubuntu 16.04 上のVivado HLS 2017.2 でOpenCV を使用したプロジェクトでエラー発生

Ubuntu 16.04 上のVivado HLS 2017.2 でOpenCV を使用したプロジェクトで libjpeg.so.62 と libtiff.so.3 が無いと言われてコンパイルできなかったので、解決方法を書いておく。なお、VirtualBox 上のUbuntu 16.04 上のVivado HLS 2016.4 でも同様だった。

Vivado HLS 2017.2 の straight_dataset_bmp プロジェクトで、C シミュレーションをしようとしている。
とりあえず、最初の段階のコードなのだが、示しておこう。
straight_dataset_bmp.h を示す。(enscript を使用してHTML化した)


// straight_dataset_bmp.h
// 2017/07/24 by marsee
//

#ifndef __STRAIGHT_DATASET_BMP_H__
#define __STRAIGHT_DATASET_BMP_H__

#include "hls_video.h"

#define BMP_HEIGHT 600
#define BMP_WIDTH 800

#define REDUCTION_RATIO 0.075 // 1/13.3333... 60x45

#define DATASET_HEIGHT 56
#define DATASET_WIDTH 10

#define STRAIGHT_BMP_FILE_NAME straight
#define LEFT_TRUN_BMP_FILE_NAME left_turn
#define RIGHT_TRUN_BMP_FILE_NAME right_turn
#define STRAIGHT_NUM_OF_IMAGE 10
#define LEFT_TRUN_NUM_OF_IMAGE 10
#define RIGHT_TRUNNUM_OF_IMAGE 10

typedef hls::Scalar<3, unsigned char> RGB_PIXEL;
typedef hls::Mat<BMP_HEIGHT, BMP_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<BMP_HEIGHT, BMP_WIDTH, HLS_8UC1> GRAY_IMAGE;

#endif


straight_dataset_bmp.cpp を示す。


// straight_dataset_bmp.cpp
// 2017/07/24 by marsee
//

#include <iostream>
#include "hls_opencv.h"
#include "straight_dataset_bmp.h"

int main(){
char straight_fn[256] = "straight";
char left_turn_fn[256] = "left_turn";
char right_turn_fn[256] = "right_turn";
char bmp_file[256];

int i=0;
// refereed to http://opencv.jp/cookbook/opencv_img.html
// straight
//for(int i=0; i<STRAIGHT_NUM_OF_IMAGE; i++){
sprintf(bmp_file, "straight%d.bmp", straight_fn, i);
cv::Mat straight_img = cv::imread(bmp_file,1);
if(straight_img.empty())
return(-1);
cv::Mat reduct_img(straight_img.rows*0.075, straight_img.cols*0.075, straight_img.type());
cv::resize(straight_img, reduct_img, reduct_img.size(), cv::INTER_CUBIC);
cv::Mat gray_img;
cv::cvtColor(straight_img, gray_img, CV_BGR2GRAY);
sprintf(bmp_file, "straight_RED%d.bmp", i);
cv::imwrite(bmp_file, gray_img);
//}

return(0);
}


Cシミュレーションを行うとエラーだった。
wl_data_test_1_170728.png

エラーの内容を貼っておく。


Starting C simulation ...
/opt/Xilinx/Vivado_HLS/2017.2/bin/vivado_hls /home/masaaki/Vivado_HLS/straight_dataset_bmp/solution1/csim.tcl
INFO: [HLS 200-10] Running '/opt/Xilinx/Vivado_HLS/2017.2/bin/unwrapped/lnx64.o/vivado_hls'
INFO: [HLS 200-10] For user 'masaaki' on host 'masaaki-H110M4-M01' (Linux_x86_64 version 4.4.0-87-generic) on Fri Jul 28 05:06:19 JST 2017
INFO: [HLS 200-10] On os Ubuntu 16.04.2 LTS
INFO: [HLS 200-10] In directory '/home/masaaki/Vivado_HLS'
WARNING: [HLS 200-40] Environment variable 'C_INCLUDE_PATH' is set to :/usr/local/cuda/include.
INFO: [HLS 200-10] Opening project '/home/masaaki/Vivado_HLS/straight_dataset_bmp'.
INFO: [HLS 200-10] Opening solution '/home/masaaki/Vivado_HLS/straight_dataset_bmp/solution1'.
INFO: [SYN 201-201] Setting up clock 'default' with a period of 10ns.
INFO: [HLS 200-10] Setting target device to 'xc7z020clg400-1'
INFO: [SIM 211-2] *************** CSIM start ***************
INFO: [SIM 211-4] CSIM will launch GCC as the compiler.
Compiling ../../../straight_dataset_bmp.cpp in debug mode
Generating csim.exe
Makefile.rules:349: ターゲット 'csim.exe' のレシピで失敗しました
/usr/bin/ld: warning: libjpeg.so.62, needed by /opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libtiff.so.3, needed by /opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so, not found (try using -rpath or -rpath-link)
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFReadEncodedStrip' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_read_scanlines' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_alloc_huff_table' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_set_defaults' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_write_scanlines' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_finish_compress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFReadEncodedTile' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFGetField' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFReadRGBATile' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFScanlineSize' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFSetField' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_set_quality' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFSetWarningHandler' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_resync_to_restart' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFIsTiled' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFWriteScanline' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_destroy_decompress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFRGBAImageOK' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFOpen' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_CreateDecompress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_read_header' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFReadRGBAStrip' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFSetErrorHandler' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_stdio_src' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_destroy_compress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_stdio_dest' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `TIFFClose' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_finish_decompress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_start_decompress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_start_compress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_CreateCompress' に対する定義されていない参照です
/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/opencv/libopencv_highgui.so: `jpeg_std_error' に対する定義されていない参照です
collect2: ld returned 1 exit status
make: *** [csim.exe] エラー 1
ERROR: [SIM 211-100] CSim file generation failed: compilation error(s).
INFO: [SIM 211-3] *************** CSIM finish ***************
5
while executing
"source /home/masaaki/Vivado_HLS/straight_dataset_bmp/solution1/csim.tcl"
invoked from within
"hls::main /home/masaaki/Vivado_HLS/straight_dataset_bmp/solution1/csim.tcl"
("uplevel" body line 1)
invoked from within
"uplevel 1 hls::main {*}$args"
(procedure "hls_proc" line 5)
invoked from within
"hls_proc $argv"
Finished C simulation.


libjpeg.so.62 と libtiff.so.3 が無いと言われているみたいだ。

まずは、libjpeg.so.62 をなんとかしよう。
Re: Vivado HLS 2013.2 fails on ubuntu due to missing libtiff3 ”を参考にして、libjpeg62-dev をインストールした。
sudo apt-get install libjpeg62-dev
wl_data_test_2_170728.png

もう一度、Vivado HLS でCシミュレーションを行った。
wl_data_test_3_170728.png

libtiff.so.3 だけになった。

libtiff.so.3 は、”libtiff.so.3, undefined reference to `TIFFReadEncodedStrip'”を参考にして、tiff-3.9.7 をインストールした。
まずは、http://download.osgeo.org/libtiff/に行って、tiff-3.9.7.zip をダウンロードした。
wl_data_test_4_170728.png

tiff-3.9.7.zip を解凍して、tiff-3.9.7 ディレクトリにコピー&ペーストした。
wl_data_test_5_170728.png

cd tiff-3.9.7
ls
./configure

wl_data_test_6_170728.png

wl_data_test_7_170728.png

ステータスを示す。


Libtiff is now configured for x86_64-unknown-linux-gnu

Installation directory: /usr/local
Documentation directory: ${prefix}/share/doc/tiff-3.9.7
C compiler: gcc -g -O2 -Wall -W
C++ compiler: g++ -g -O2
Enable runtime linker paths: no
Enable linker symbol versioning: no
Support Microsoft Document Imaging: yes

Support for internal codecs:
CCITT Group 3 & 4 algorithms: yes
Macintosh PackBits algorithm: yes
LZW algorithm: yes
ThunderScan 4-bit RLE algorithm: yes
NeXT 2-bit RLE algorithm: yes
LogLuv high dynamic range encoding: yes

Support for external codecs:
ZLIB support: yes
Pixar log-format algorithm: yes
JPEG support: yes
Old JPEG support: yes
ISO JBIG support: yes

C++ support: yes

OpenGL support: yes


make
成功した。
wl_data_test_8_170728.png

sudo cp libtiff/.libs/libtiff.so.3* /opt/Xilinx/Vivado_HLS/2017.2/lib/lnx64.o/
sudo ldconfig

wl_data_test_10_170728.png
(注:Vivado HLS 2016.4 は”Re: Vivado HLS 2013.2 fails on ubuntu due to missing libtiff3 ”の通りのパスにコピーしたところ、うまく行った。このディスティネーション・ディレクトリにコピーする必要があるのは、2017.1 からなのかもしれない? /usr/lib64 にコピーできたということなので、Vivado HLSのバージョンではなく、Ubuntuのバージョンですよね? ともかく、/opt/Xilinx/Vivado_HLS/<Vivado HLSのバージョン番号>/lib/lnx64.o/にコピーすれば良いのでは?と思います)
注2 [2017/11/29] :Vivado 2017.3 では、Vivado_HLS ディレクトリにバージョンのディレクトリを作成しないで、Vivado に統合されてしまったようだ。libtiff.so.3* をコピーする位置は /opt/Xilinx/Vivado_HLS/2017.3/lib/lnx64.o/ にする必要があるようだ。
sudo cp libtiff/.libs/libtiff.so.3* /opt/Xilinx/Vivado/2017.3/lib/lnx64.o/
sudo ldconfig



再々度、Vivado HLS でCシミュレーションを行った。
wl_data_test_11_170729.png

ライブラリのエラーはなくなった。このエラーは画像ファイルが無いので出ている。

(2017/10/25:追記)
AR# 66184 インストール - Vivado ツールを Linux で実行するために必要なライブラリの検索方法”をやってみれば解消できるかもしれない?
  1. 2017年07月29日 06:39 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Ubuntu 16.04 にOpenCV 3.3.0 rc をインストールした

Ubuntu 16.04 にOpenCV 3.1.0 をインストールした”の続き。

前回は、Ubuntu 16.04 にOpenCV 3.1.0 をインストールしようとしたのだが、make でエラーになってしまった。どうやらCUDA 8.0 が悪さしているようだというのがわかった。dandelion さんからOpenCV 3.2 だったら大丈夫と教えていただいたので、OpenCV 3.2 以降をインストールすることにした。

UbuntuにOpenCV3.2とcontribをインストールする。”を参考にさせていただいた。
さて、前準備は前回思いっきりやってあるので、OpenCV のソースコードのダウンロードからやってみよう。
まずは、ホームディレクトリ下に OpenCV ディレクトリを生成し、移動した。
mkdir OpenCV
cd OpenCV


OpenCV ソースをダウンロードした。
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git


opencv ディレクトリに移動して、build ディレクトリを生成した。build ディレクトリに移動して、cmake を実行した。
cd opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_EXTRA_MODULES_PATH=~/OpenCV/opencv_contrib/modules

Ubuntu_OpenCV_11_170726.png

cmake のコンフィギュレーションを示す。

-- General configuration for OpenCV 3.3.0-rc =====================================
--   Version control:               3.3.0-rc-159-g06407b4
-- 
--   Extra modules:
--     Location (extra):            /home/masaaki/OpenCV/opencv_contrib/modules
--     Version control (extra):     3.3.0-rc-7-g067b0a6
-- 
--   Platform:
--     Timestamp:                   2017-07-27T05:33:25Z
--     Host:                        Linux 4.4.0-87-generic x86_64
--     CMake:                       3.3.2
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               RELEASE
-- 
--   CPU/HW features:
--     Baseline:                    SSE SSE2 SSE3
--       requested:                 SSE3
--     Dispatched code generation:  SSE4_1 SSE4_2 FP16 AVX AVX2
--       requested:                 SSE4_1 SSE4_2 AVX FP16 AVX2
--       SSE4_1 (2 files):          + SSSE3 SSE4_1
--       SSE4_2 (1 files):          + SSSE3 SSE4_1 POPCNT SSE4_2
--       FP16 (1 files):            + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
--       AVX (5 files):             + SSSE3 SSE4_1 POPCNT SSE4_2 AVX
--       AVX2 (7 files):            + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
-- 
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++ Compiler:                /usr/bin/c++  (ver 5.4.0)
--     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comment -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections  -msse -msse2 -msse3 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comment -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections  -msse -msse2 -msse3 -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     C Compiler:                  /usr/bin/cc
--     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-narrowing -Wno-comment -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections  -msse -msse2 -msse3 -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
--     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-narrowing -Wno-comment -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections  -msse -msse2 -msse3 -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
--     Linker flags (Release):
--     Linker flags (Debug):
--     ccache:                      NO
--     Precompiled headers:         YES
--     Extra dependencies:          gtk-3 gdk-3 pangocairo-1.0 pango-1.0 atk-1.0 cairo-gobject cairo gdk_pixbuf-2.0 gio-2.0 gthread-2.0 /usr/lib/x86_64-linux-gnu/libpng.so /usr/lib/x86_64-linux-gnu/libz.so /usr/lib/x86_64-linux-gnu/libtiff.so /usr/lib/x86_64-linux-gnu/libjasper.so /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/x86_64-linux-gnu/libImath.so /usr/lib/x86_64-linux-gnu/libIlmImf.so /usr/lib/x86_64-linux-gnu/libIex.so /usr/lib/x86_64-linux-gnu/libHalf.so /usr/lib/x86_64-linux-gnu/libIlmThread.so gstbase-1.0 gstreamer-1.0 gobject-2.0 glib-2.0 gstvideo-1.0 gstapp-1.0 gstriff-1.0 gstpbutils-1.0 dc1394 avcodec-ffmpeg avformat-ffmpeg avutil-ffmpeg swscale-ffmpeg freetype harfbuzz dl m pthread rt cudart nppc nppi npps cufft -L/usr/local/cuda/lib64
--     3rdparty dependencies:
-- 
--   OpenCV modules:
--     To be built:                 cudev core cudaarithm flann imgproc ml objdetect phase_unwrapping plot reg surface_matching video xphoto bgsegm cudabgsegm cudafilters cudaimgproc cudawarping dnn face freetype fuzzy img_hash imgcodecs photo shape videoio xobjdetect cudacodec highgui ts bioinspired dpm features2d line_descriptor saliency text calib3d ccalib cudafeatures2d cudalegacy cudaobjdetect cudaoptflow cudastereo datasets rgbd stereo structured_light superres tracking videostab xfeatures2d ximgproc aruco optflow stitching python2
--     Disabled:                    world contrib_world
--     Disabled by dependency:      -
--     Unavailable:                 java python3 viz cnn_3dobj cvv dnn_modern hdf matlab sfm
-- 
--   GUI: 
--     QT:                          NO
--     GTK+ 3.x:                    YES (ver 3.18.9)
--     GThread :                    YES (ver 2.48.2)
--     GtkGlExt:                    NO
--     OpenGL support:              NO
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/x86_64-linux-gnu/libz.so (ver 1.2.8)
--     JPEG:                        /usr/lib/x86_64-linux-gnu/libjpeg.so (ver )
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         /usr/lib/x86_64-linux-gnu/libpng.so (ver 1.2.54)
--     TIFF:                        /usr/lib/x86_64-linux-gnu/libtiff.so (ver 42 - 4.0.6)
--     JPEG 2000:                   /usr/lib/x86_64-linux-gnu/libjasper.so (ver 1.900.1)
--     OpenEXR:                     /usr/lib/x86_64-linux-gnu/libImath.so /usr/lib/x86_64-linux-gnu/libIlmImf.so /usr/lib/x86_64-linux-gnu/libIex.so /usr/lib/x86_64-linux-gnu/libHalf.so /usr/lib/x86_64-linux-gnu/libIlmThread.so (ver 2.2.0)
--     GDAL:                        NO
--     GDCM:                        NO
-- 
--   Video I/O:
--     DC1394 1.x:                  NO
--     DC1394 2.x:                  YES (ver 2.2.4)
--     FFMPEG:                      YES
--       avcodec:                   YES (ver 56.60.100)
--       avformat:                  YES (ver 56.40.101)
--       avutil:                    YES (ver 54.31.100)
--       swscale:                   YES (ver 3.1.101)
--       avresample:                NO
--     GStreamer:                   
--       base:                      YES (ver 1.8.3)
--       video:                     YES (ver 1.8.3)
--       app:                       YES (ver 1.8.3)
--       riff:                      YES (ver 1.8.3)
--       pbutils:                   YES (ver 1.8.3)
--     OpenNI:                      NO
--     OpenNI PrimeSensor Modules:  NO
--     OpenNI2:                     NO
--     PvAPI:                       NO
--     GigEVisionSDK:               NO
--     Aravis SDK:                  NO
--     UniCap:                      NO
--     UniCap ucil:                 NO
--     V4L/V4L2:                    NO/YES
--     XIMEA:                       NO
--     Xine:                        NO
--     Intel Media SDK:             NO
--     gPhoto2:                     NO
-- 
--   Parallel framework:            pthreads
-- 
--   Trace:                         YES (with Intel ITT)
-- 
--   Other third-party libraries:
--     Use Intel IPP:               2017.0.2 [2017.0.2]
--                at:               /home/masaaki/OpenCV/opencv/build/3rdparty/ippicv/ippicv_lnx
--     Use Intel IPP IW:            prebuilt binaries (2017.0.2)
--     Use Intel IPP Async:         NO
--     Use VA:                      NO
--     Use Intel VA-API/OpenCL:     NO
--     Use Lapack:                  NO
--     Use Eigen:                   NO
--     Use Cuda:                    YES (ver 8.0)
--     Use OpenCL:                  YES
--     Use OpenVX:                  NO
--     Use custom HAL:              NO
-- 
--   NVIDIA CUDA
--     Use CUFFT:                   YES
--     Use CUBLAS:                  NO
--     USE NVCUVID:                 NO
--     NVIDIA GPU arch:             20 30 35 37 50 52 60 61
--     NVIDIA PTX archs:
--     Use fast math:               NO
-- 
--   OpenCL:                        <Dynamic loading of OpenCL library>
--     Include path:                /home/masaaki/OpenCV/opencv/3rdparty/include/opencl/1.2
--     Use AMDFFT:                  NO
--     Use AMDBLAS:                 NO
-- 
--   Python 2:
--     Interpreter:                 /usr/bin/python2.7 (ver 2.7.12)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.12)
--     numpy:                       /home/masaaki/.local/lib/python2.7/site-packages/numpy/core/include (ver 1.11.0)
--     packages path:               lib/python2.7/dist-packages
-- 
--   Python 3:
--     Interpreter:                 /usr/bin/python3 (ver 3.5.2)
-- 
--   Python (for build):            /usr/bin/python2.7
-- 
--   Java:
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
-- 
--   Matlab:                        Matlab not found or implicitly disabled
-- 
--   Documentation:
--     Doxygen:                     NO
-- 
--   Tests and samples:
--     Tests:                       YES
--     Performance tests:           YES
--     C/C++ Examples:              NO
-- 
--   Install path:                  /usr/local
-- 
--   cvconfig.h is in:              /home/masaaki/OpenCV/opencv/build
-- -----------------------------------------------------------------
-- 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/masaaki/OpenCV/opencv/build


make を行った。
make -j $(nproc)
Ubuntu_OpenCV_12_170726.png

make が成功した。

sudo make install
Ubuntu_OpenCV_13_170726.png

sudo ldconfig
Ubuntu_OpenCV_14_170726.png

cmake のログでも出てきたが、OpenCV 3.3.0 rc をインストールしたようだ。

opencv/samples を見てみると、dnn やopencl やいろいろなサンプルがあって楽しみだ。
Ubuntu_OpenCV_15_170729.png
  1. 2017年07月29日 04:17 |
  2. OpenCV
  3. | トラックバック:0
  4. | コメント:0

Ubuntu 16.04 にOpenCV 3.1.0 をインストールした

白線追従用の画像を処理するためにUbuntu 16.04 にOpenCV 3.1.0 をインストールすることにした。
なお、”Ubuntu 16.04にOpenCV 3.1をインストールする手順”を参考にさせていただいた。

早速、下準備から、
sudo apt-get install build-essential cmake git
Ubuntu_OpenCV_1_170726.png

sudo apt-get install ffmpeg libopencv-dev libgtk-3-dev python-numpy python3-numpy libdc1394-22 libdc1394-22-dev libjpeg-dev libpng12-dev libtiff5-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libxine2-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libv4l-dev libtbb-dev qtbase5-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils unzip
Ubuntu_OpenCV_2_170726.png

wget https://github.com/Itseez/opencv/archive/3.1.0.zip
Ubuntu_OpenCV_3_170726.png

unzip 3.1.0
Ubuntu_OpenCV_4_170726.png

cd opencv-3.1.0
mkdir build
cd build

Ubuntu_OpenCV_5_170726.png

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D WITH_V4L=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..
Ubuntu_OpenCV_6_170726.png

成功した。コンフィギュレーションを貼っておく。

-- General configuration for OpenCV 3.1.0 =====================================
--   Version control:               unknown
-- 
--   Platform:
--     Host:                        Linux 4.4.0-87-generic x86_64
--     CMake:                       3.3.2
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               RELEASE
-- 
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++ Compiler:                /usr/bin/c++  (ver 5.4.0)
--     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wno-narrowing -Wno-delete-non-virtual-dtor -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -msse -msse2 -mno-avx -msse3 -mno-ssse3 -mno-sse4.1 -mno-sse4.2 -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wno-narrowing -Wno-delete-non-virtual-dtor -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -msse -msse2 -mno-avx -msse3 -mno-ssse3 -mno-sse4.1 -mno-sse4.2 -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     C Compiler:                  /usr/bin/cc
--     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wno-narrowing -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -msse -msse2 -mno-avx -msse3 -mno-ssse3 -mno-sse4.1 -mno-sse4.2 -ffunction-sections -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
--     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wno-narrowing -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -msse -msse2 -mno-avx -msse3 -mno-ssse3 -mno-sse4.1 -mno-sse4.2 -ffunction-sections -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
--     Linker flags (Release):
--     Linker flags (Debug):
--     Precompiled headers:         YES
--     Extra dependencies:          Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Test Qt5::Concurrent Qt5::OpenGL /usr/lib/x86_64-linux-gnu/libpng.so /usr/lib/x86_64-linux-gnu/libz.so /usr/lib/x86_64-linux-gnu/libtiff.so /usr/lib/x86_64-linux-gnu/libjasper.so /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/x86_64-linux-gnu/libImath.so /usr/lib/x86_64-linux-gnu/libIlmImf.so /usr/lib/x86_64-linux-gnu/libIex.so /usr/lib/x86_64-linux-gnu/libHalf.so /usr/lib/x86_64-linux-gnu/libIlmThread.so gstvideo-1.0 gstapp-1.0 gstbase-1.0 gstriff-1.0 gstpbutils-1.0 gstreamer-1.0 gobject-2.0 glib-2.0 dc1394 v4l1 v4l2 avcodec-ffmpeg avformat-ffmpeg avutil-ffmpeg swscale-ffmpeg dl m pthread rt /usr/lib/x86_64-linux-gnu/libGLU.so /usr/lib/x86_64-linux-gnu/libGL.so tbb atomic cudart nppc nppi npps cufft -L/usr/local/cuda/lib64
--     3rdparty dependencies:       libwebp
-- 
--   OpenCV modules:
--     To be built:                 cudev core cudaarithm flann imgproc ml video cudabgsegm cudafilters cudaimgproc cudawarping imgcodecs photo shape videoio cudacodec highgui objdetect ts features2d calib3d cudafeatures2d cudalegacy cudaobjdetect cudaoptflow cudastereo stitching superres videostab python2
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 java python3 viz
-- 
--   GUI: 
--     QT 5.x:                      YES (ver 5.5.1)
--     QT OpenGL support:           YES (Qt5::OpenGL 5.5.1)
--     OpenGL support:              YES (/usr/lib/x86_64-linux-gnu/libGLU.so /usr/lib/x86_64-linux-gnu/libGL.so)
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/x86_64-linux-gnu/libz.so (ver 1.2.8)
--     JPEG:                        /usr/lib/x86_64-linux-gnu/libjpeg.so (ver )
--     WEBP:                        build (ver 0.3.1)
--     PNG:                         /usr/lib/x86_64-linux-gnu/libpng.so (ver 1.2.54)
--     TIFF:                        /usr/lib/x86_64-linux-gnu/libtiff.so (ver 42 - 4.0.6)
--     JPEG 2000:                   /usr/lib/x86_64-linux-gnu/libjasper.so (ver 1.900.1)
--     OpenEXR:                     /usr/lib/x86_64-linux-gnu/libImath.so /usr/lib/x86_64-linux-gnu/libIlmImf.so /usr/lib/x86_64-linux-gnu/libIex.so /usr/lib/x86_64-linux-gnu/libHalf.so /usr/lib/x86_64-linux-gnu/libIlmThread.so (ver 2.2.0)
--     GDAL:                        NO
-- 
--   Video I/O:
--     DC1394 1.x:                  NO
--     DC1394 2.x:                  YES (ver 2.2.4)
--     FFMPEG:                      YES
--       codec:                     YES (ver 56.60.100)
--       format:                    YES (ver 56.40.101)
--       util:                      YES (ver 54.31.100)
--       swscale:                   YES (ver 3.1.101)
--       resample:                  NO
--       gentoo-style:              YES
--     GStreamer:                   
--       base:                      YES (ver 1.8.3)
--       video:                     YES (ver 1.8.3)
--       app:                       YES (ver 1.8.3)
--       riff:                      YES (ver 1.8.3)
--       pbutils:                   YES (ver 1.8.3)
--     OpenNI:                      NO
--     OpenNI PrimeSensor Modules:  NO
--     OpenNI2:                     NO
--     PvAPI:                       NO
--     GigEVisionSDK:               NO
--     UniCap:                      NO
--     UniCap ucil:                 NO
--     V4L/V4L2:                    Using libv4l1 (ver 1.10.0) / libv4l2 (ver 1.10.0)
--     XIMEA:                       NO
--     Xine:                        NO
--     gPhoto2:                     NO
-- 
--   Parallel framework:            TBB (ver 4.4 interface 9002)
-- 
--   Other third-party libraries:
--     Use IPP:                     9.0.1 [9.0.1]
--          at:                     /home/masaaki/opencv-3.1.0/3rdparty/ippicv/unpack/ippicv_lnx
--     Use IPP Async:               NO
--     Use VA:                      NO
--     Use Intel VA-API/OpenCL:     NO
--     Use Eigen:                   NO
--     Use Cuda:                    YES (ver 8.0)
--     Use OpenCL:                  YES
--     Use custom HAL:              NO
-- 
--   NVIDIA CUDA
--     Use CUFFT:                   YES
--     Use CUBLAS:                  NO
--     USE NVCUVID:                 NO
--     NVIDIA GPU arch:             20 21 30 35
--     NVIDIA PTX archs:            30
--     Use fast math:               NO
-- 
--   OpenCL:
--     Version:                     dynamic
--     Include path:                /home/masaaki/opencv-3.1.0/3rdparty/include/opencl/1.2
--     Use AMDFFT:                  NO
--     Use AMDBLAS:                 NO
-- 
--   Python 2:
--     Interpreter:                 /usr/bin/python2.7 (ver 2.7.12)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.12)
--     numpy:                       /home/masaaki/.local/lib/python2.7/site-packages/numpy/core/include (ver 1.11.0)
--     packages path:               lib/python2.7/dist-packages
-- 
--   Python 3:
--     Interpreter:                 /usr/bin/python3 (ver 3.5.2)
-- 
--   Python (for build):            /usr/bin/python2.7
-- 
--   Java:
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
-- 
--   Matlab:                        Matlab not found or implicitly disabled
-- 
--   Documentation:
--     Doxygen:                     NO
--     PlantUML:                    NO
-- 
--   Tests and samples:
--     Tests:                       YES
--     Performance tests:           YES
--     C/C++ Examples:              NO
-- 
--   Install path:                  /usr/local
-- 
--   cvconfig.h is in:              /home/masaaki/opencv-3.1.0/build
-- -----------------------------------------------------------------
-- 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/masaaki/opencv-3.1.0/build


make
Ubuntu_OpenCV_7_170726.png

エラーになってしまった。エラー内容を示す。

/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:120:54: error: ‘NppiGraphcutState’ has not been declared
     typedef NppStatus (*init_func_t)(NppiSize oSize, NppiGraphcutState** ppStat
                                                      ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:135:18: error: ‘NppiGraphcutState’ does not name a type
         operator NppiGraphcutState*()
                  ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:141:9: error: ‘NppiGraphcutState’ does not name a type
         NppiGraphcutState* pState;
         ^
In file included from /home/masaaki/opencv-3.1.0/build/modules/cudalegacy/precomp.hpp:75:0:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp: In constructor ‘{anonymous}::NppiGraphcutStateHandler::NppiGraphcutStateHandler(NppiSize, Npp8u*, {anonymous}::init_func_t)’:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:127:39: error: ‘pState’ was not declared in this scope
             nppSafeCall( func(sznpp, &pState, pDeviceMem) );
                                       ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp: In destructor ‘{anonymous}::NppiGraphcutStateHandler::~NppiGraphcutStateHandler()’:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:132:43: error: ‘pState’ was not declared in this scope
             nppSafeCall( nppiGraphcutFree(pState) );
                                           ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:132:49: error: ‘nppiGraphcutFree’ was not declared in this scope
             nppSafeCall( nppiGraphcutFree(pState) );
                                                 ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp: In function ‘void cv::cuda::graphcut(cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::Stream&)’:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:174:51: error: ‘nppiGraphcutGetSize’ was not declared in this scope
     nppSafeCall( nppiGraphcutGetSize(sznpp, &bufsz) );
                                                   ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:182:61: error: ‘nppiGraphcutInitAlloc’ was not declared in this scope
     NppiGraphcutStateHandler state(sznpp, buf.ptr<Npp8u>(), nppiGraphcutInitAll
                                                             ^
In file included from /home/masaaki/opencv-3.1.0/build/modules/cudalegacy/precomp.hpp:75:0:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:191:146: error: ‘nppiGraphcut_32s8u’ was not declared in this scope
 nsp.step), sznpp, labels.ptr<Npp8u>(), static_cast<int>(labels.step), state) );
                                                                            ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:196:146: error: ‘nppiGraphcut_32f8u’ was not declared in this scope
 nsp.step), sznpp, labels.ptr<Npp8u>(), static_cast<int>(labels.step), state) );
                                                                            ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp: In function ‘void cv::cuda::graphcut(cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, cv::cuda::Stream&)’:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:246:52: error: ‘nppiGraphcut8GetSize’ was not declared in this scope
     nppSafeCall( nppiGraphcut8GetSize(sznpp, &bufsz) );
                                                    ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:254:61: error: ‘nppiGraphcut8InitAlloc’ was not declared in this scope
     NppiGraphcutStateHandler state(sznpp, buf.ptr<Npp8u>(), nppiGraphcut8InitAl
                                                             ^
In file included from /home/masaaki/opencv-3.1.0/build/modules/cudalegacy/precomp.hpp:75:0:
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:267:146: error: ‘nppiGraphcut8_32s8u’ was not declared in this scope
 nsp.step), sznpp, labels.ptr<Npp8u>(), static_cast<int>(labels.step), state) );
                                                                            ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
/home/masaaki/opencv-3.1.0/modules/cudalegacy/src/graphcuts.cpp:274:146: error: ‘nppiGraphcut8_32f8u’ was not declared in this scope
 nsp.step), sznpp, labels.ptr<Npp8u>(), static_cast<int>(labels.step), state) );
                                                                            ^
/home/masaaki/opencv-3.1.0/modules/core/include/opencv2/core/private.cuda.hpp:165:52: note: in definition of macro ‘nppSafeCall’
 #define nppSafeCall(expr)  cv::cuda::checkNppError(expr, __FILE__, __LINE__, CV
                                                    ^
modules/cudalegacy/CMakeFiles/opencv_cudalegacy.dir/build.make:362: ターゲット 'modules/cudalegacy/CMakeFiles/opencv_cudalegacy.dir/src/graphcuts.cpp.o' のレシピで失敗しました
make[2]: *** [modules/cudalegacy/CMakeFiles/opencv_cudalegacy.dir/src/graphcuts.cpp.o] エラー 1
CMakeFiles/Makefile2:9285: ターゲット 'modules/cudalegacy/CMakeFiles/opencv_cudalegacy.dir/all' のレシピで失敗しました
make[1]: *** [modules/cudalegacy/CMakeFiles/opencv_cudalegacy.dir/all] エラー 2
Makefile:160: ターゲット 'all' のレシピで失敗しました
make: *** [all] エラー 2


どうやらCUDA 関係のエラーのようだ。
opencv3.10 does not support cuda8.0rc? #6677”とかを見ていろいろとやってみたが、うまく行かなかった。
ツィッターでdandelion さんから、「CUDA8だと一部モジュールがビルドできない問題があります。OpenCV 3.2で修正されてます。」と教えて頂いた。
よって、OpenCV 3.2 以降をインストールすることにした。
  1. 2017年07月28日 04:29 |
  2. OpenCV
  3. | トラックバック:0
  4. | コメント:0

家の2階にLANを通しました

家の2階が無線LANが弱いので、PLCアダプタを買って2階にLANを通しました。
PLCアダプタは「TP-Link PLCアダプター パワーライン インターネット接続 有線LAN コンセントLAN 2台キット 総務省指定 TL-PA4010 KIT」です。リンクするためにペアボタンを押しても、なかなかLEDが点滅してくれなくて焦りましたが、リセットしたら点滅してくれました。その後のリンクはすぐできました。結構安定しているし、スピードも計測はしていないですが、速いです。
2 階のPLCアダプタには、「BUFFALO 11ac/n/a/g/b 無線LAN親機(Wi-Fiルーター) ビームフォーミング対応 866+300Mbps WHR-1166DHP4」をつけました。これはブリッジモードで無線LANアクセスポイントとして使用しています。これでお手軽に2階の無線LAN環境が構築できました。
ちなみに、家では、NTTのフレッツ光に、Yahoo BBルータ+BBフォンのルーター機能を使っています。その下に1階はブリッジモードのロジテックの無線LANルータを使用しています。
  1. 2017年07月28日 03:58 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

HLS ビデオライブラリの hls::Window のVivado HLS 2015.4 以前とその後での変更点3(ソースコード)

HLS ビデオライブラリの hls::LineBuffer のVivado HLS 2015.4 以前とその後での変更点1(メモリ・ライン・バッファー)
HLS ビデオライブラリの hls::Window のVivado HLS 2015.4 以前とその後での変更点2(メモリ・ウインドウ・バッファー)
でメモリ・ライン・バッファーとメモリ・ウインドウ・バッファーのVivado HLS 2015.4 以前と以後の変更点を説明してきた。
今回は、ソースコードを貼っておこうと思う。Vivado HLSのソースコードはVivado HLS 2016.1 以降のメモリ・ライン・バッファーとメモリ・ウインドウ・バッファーのメソッドを使用している。それに対して、テストベンチはVivado HLS 2015.4 以前のメソッドを使用しているので、比べてみてほしい。
なお、これらのコードはガボール・フィルタのプロジェクトを使用している。

まずは、CソースコードのGabor_fiter_lh.cpp から貼っておく。

// Gabor_fiter_lh.cpp
// 2016/07/23 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "Gabor_filter_lh.h"

int conv_rgb2y(int rgb);

int Gabor_filter_lh(hls::stream<ap_axis<32,1,1,1> >& ins,
        hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<1> & RorL){
#pragma HLS INTERFACE ap_none port=RorL
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return

    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> gabor;

    hls::LineBuffer<ARRAY_SIZE-1, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
    hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;

    int gray_pix, val, i, j, x, y;

    do {
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            mbuf.shift_pixels_left();    // mbuf の列を1ビット左シフト
            for(i=0; i<ARRAY_SIZE-1; i++){
                mbuf.insert_pixel(linebuf.getval(i,x), i, ARRAY_SIZE-1);
            }
            gray_pix = conv_rgb2y(pix.data);
            mbuf.insert_pixel(gray_pix, ARRAY_SIZE-1, ARRAY_SIZE-1);

            // LineBuffer の更新
            linebuf.shift_pixels_up(x);
            linebuf.insert_bottom_row(gray_pix, x);

            // Gabor filter の演算
            for (j=0, val=0; j<ARRAY_SIZE-1; j++){
                for (i=0; i<ARRAY_SIZE-1; i++){
                    val += gabor_weight[(int)RorL][j][i] * mbuf(j,i);
                }
            }
            val = val/256// 256倍してあるので、1/256して戻す
            if (val<0)
                //val = -val; // 絶対値
                val = 0// マイナスの値を0に丸める
            else if (val>255)
                val = 255;

            // Gabor filter・データの書き込み
            gabor.data = (val<<16)+(val<<8)+val;
            // 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
            if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
                gabor.data = 0;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                gabor.user = 1;
            else
                gabor.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                gabor.last = 1;
            else
                gabor.last = 0;

            outs << gabor;    // AXI4-Stream へ出力
         }
     }
     return(0);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    return(y);
}


次に、テストベンチのGabor_filter_lh_tb.cpp を貼っておく。なお、メモリ・ライン・バッファーとメモリ・ウインドウ・バッファーのVivado HLS 2015.4 以前のコードが書いてある関数は、Gabor_filter_lh_soft() だ。

// Gabor_filter_lh_tb.cpp
// 2016/07/24 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "Gabor_filter_lh.h"
#include "bmp_header.h"

int Gabor_filter_lh(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<1> & RorL);

int conv_rgb2y_soft(int rgb);
int Gabor_filter_lh_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<1> & RorL);

#define CLOCK_PERIOD 10
#define RIGHT_OR_LEFT  LEFT_WEIGHT
#define BMP_FILE_NAME   "bmp_f_0823_0.bmp"

int main()
{
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins;
    hls::stream<ap_axis<32,1,1,1> > ins_soft;
    hls::stream<ap_axis<32,1,1,1> > outs;
    hls::stream<ap_axis<32,1,1,1> > outs_soft;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals;
    ap_axis<32,1,1,1> vals_soft;

    int m_seq = 1// M系列の値
    int i;
    int xor_shift;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw, *fbmpwf;
    int *rd_bmp, *hw_gabor, *sw_gabor;
    int blue, green, red;
    ap_uint<1> r_l;

    if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open test.bmp by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

    // ピクセルを入れるメモリをアロケートする
    if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate rd_bmp memory\n");
        exit(1);
    }
    if ((hw_gabor =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_gabor memory\n");
        exit(1);
    }
    if ((sw_gabor =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_gabor memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        pix.user = 0;
        pix.data = i;
        ins << pix;
    }

    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];

            if (j==0 && i==0)    // 最初のデータの時に TUSER を 1 にする
                pix.user = 1;
            else
                pix.user = 0;

            if (i == bmpihr.biWidth-1// 行の最後でTLASTをアサートする
                pix.last = 1;
            else
                pix.last = 0;

            ins << pix;
            ins_soft << pix;
        }
    }

    r_l = (ap_uint<1>)RIGHT_OR_LEFT;
    Gabor_filter_lh(ins, outs, r_l);
    Gabor_filter_lh_soft(ins_soft, outs_soft, r_l);

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_int<32> val = vals.data;
            ap_int<32> val_soft = vals_soft.data;

            hw_gabor[(j*bmpihr.biWidth)+i] = (int)val;
            sw_gabor[(j*bmpihr.biWidth)+i] = (int)val_soft;

            if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > 4){ // 2乗誤差が4よりも大きい
                printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %08x, SW = %08x\n", i, j, (int)val, (int)val_soft);
                //return(1);
            }
            //if (vals.last)
                //cout << "AXI-Stream is end" << endl;
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ハードウェアのラプラシアンフィルタの結果を temp_gabor.bmp へ出力する
    if ((fbmpw=fopen("temp_gabor.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open temp_gabor.bmp by binary write mode\n");
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
    fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
    // RGB データの書き込み、逆順にする
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = hw_gabor[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
            green = (hw_gabor[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
            red = (hw_gabor[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);

    // ソフトウェアのラプラシアンフィルタの結果を temp_gabor_float.bmp へ出力する
    if ((fbmpwf=fopen("temp_gabor_float.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open temp_gabor_float.bmp by binary write mode\n");
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpwf);
    fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpwf);
    fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpwf);
    fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpwf);
    fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpwf);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpwf);
    // RGB データの書き込み、逆順にする
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = sw_gabor[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
            green = (sw_gabor[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
            red = (sw_gabor[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

            fputc(blue, fbmpwf);
            fputc(green, fbmpwf);
            fputc(red, fbmpwf);
        }
    }
    fclose(fbmpwf);

    free(rd_bmp);
    free(hw_gabor);

    return 0;
}

int Gabor_filter_lh_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<1> & RorL){
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> gabor;

    hls::LineBuffer<ARRAY_SIZE-1, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
    hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;

    int gray_pix, val, i, j, x, y;
    float valf;

    do {    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            mbuf.shift_left();    // mbuf の列を1ビット左シフト
            for(i=ARRAY_SIZE-2; i>=0; --i){
                mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
            }
            gray_pix = conv_rgb2y_soft(pix.data);
            mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);

            // LineBuffer の更新
            linebuf.shift_down(x);
            linebuf.insert_bottom(gray_pix, x);

            // Gabor filter の演算
            for (j=0, valf=0; j<ARRAY_SIZE-1; j++){
                for (i=0; i<ARRAY_SIZE-1; i++){
                    valf += gabor_fweight[(int)RorL][j][i] * (float)mbuf(ARRAY_SIZE-1-j,i);
                }
            }

            val = (int)valf;
            if (val<0)
                //val = -val; // 絶対値
                val = 0// マイナスの値を0に丸める
            else if (val>255)
                val = 255;

            // Gabor filter・データの書き込み
            gabor.data = (val<<16)+(val<<8)+val;
            // 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
            if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
                gabor.data = 0;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                gabor.user = 1;
            else
                gabor.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                gabor.last = 1;
            else
                gabor.last = 0;

            outs << gabor;    // AXI4-Stream へ出力
         }
     }
     return(0);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    return(y);
}

  1. 2017年07月27日 05:34 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

HLS ビデオライブラリの hls::Window のVivado HLS 2015.4 以前とその後での変更点2(メモリ・ウインドウ・バッファー)

HLS ビデオライブラリの hls::LineBuffer のVivado HLS 2015.4 以前とその後での変更点”の続き。

hls::LineBuffer と同様に、hls::Window も行のインデックスとクラス・メソッドが変更になっているので紹介する。
hls::LineBuffer と同様に、hls::Window もガボール・フィルタでカーネルとして、重みとの演算に使用されている。

Vivado HLS 2015.4 以前のメモリ・ウインドウのデータ セットを引用する。”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2015.4) 2015 年 11 月 24 日”の”メモリ・ウインドウ・バッファー”の 194 ページの”表 2‐10 : メモリ ウ ィ ン ド ウ例のデー タ セッ ト”を引用する。
gabor_filter_lh2_3_170725.png

やはり、行が行2 から始まって、行1 、行0 とインデックスが減っているのが分かるだろうか?列は列0 から始まって増えていっている。メモリ・ウインドウを更新する際には、shift_left() メソッドでメモリ・ウインドウを1ビット左シフトし、insert()メソッドで、インデック0 以外にメモリ・ライン・バッファーの値を入力し、インデック0 には、現在の画像ピクセルの値を入力した。つまり、通常と逆のインデックスになっている。ソースコードを示す。

            mbuf.shift_left();    // mbuf の列を1ビット左シフト
            for(i=ARRAY_SIZE-2; i>=0; --i){
                mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
            }
            gray_pix = conv_rgb2y_soft(pix.data);
            mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);


前回同様に、Vivado HLS 2016.1 からは、この行のインデックスが通常と同様にインデックス 0 からとなっている。
下に、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2017.1) 2017 年 4 月 5 日”の”HLS ビデオライブラリ”の”メモリ ウィンドウ バッファー ”の221 ページの”2‐9: メモリ ウ ィ ン ド ウ例のデー タ セット”を引用する。
gabor_filter_lh2_4_170725.png

行のインデックスが列のインデックス同様に 0 から始まっているのが分かると思う。メモリ・ウインドウ・バッファーのメソッドも更新されている。メモリ・ウインドウ・バッファーのメソッドを示す。

• shift_pixels_up()
• shift_pixels_down()
• shift_pixels_left()
• shift_pixels_right()
• insert_pixel(value,row,colum)
• insert_row()
• insert_bottom_row()
• insert_top_row()
• insert_col()
• insert_left_col()
• insert_right_col()
• getval(row, column)


やはり、今まで使用していたshifft_left(), insert() が無くなっている。前回同様、互換性確保のためにshifft_left(), insert() メソッドなどの、Vivado HLS 2015.4 以前のコードも使用することができた。Vivado HLS 2016.1 以降の新しいメソッドを使用して、同様にメモリ・ウインドウの処理をする場合には、shift_pixels_left() と insert_pixel() を使用する。
新しいメソッドを使用した上と同様のコードを示す。

            mbuf.shift_pixels_left();    // mbuf の列を1ビット左シフト
            for(i=0; i<ARRAY_SIZE-1; i++){
                mbuf.insert_pixel(linebuf.getval(i,x), i, ARRAY_SIZE-1);
            }
            gray_pix = conv_rgb2y(pix.data);
            mbuf.insert_pixel(gray_pix, ARRAY_SIZE-1, ARRAY_SIZE-1);

  1. 2017年07月26日 05:00 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

HLS ビデオライブラリの hls::LineBuffer のVivado HLS 2015.4 以前とその後での変更点1(メモリ・ライン・バッファー)

ガボール・フィルタ (Gabor Filter) による白線検出5(hls::LineBuffer と hls::Window を使用2)”などで、Vivado HLS のHLS ビデオライブラリのhls::LineBuffer と hls::Window を使用してガボール・フィルタを実装した。

この時は知らなかったが、Vivado HLS 2016.1 から hls::LineBuffer と hls::Window のクラス・メソッドが大きく変更になった。Vivado HLS 2015.4 までは、 hls::LineBuffer と hls::Window の配列の並びは、列はインデックス 0 からなのだが、行はインデックス「行の配列の最大数」かになっていた。”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2015.4) 2015 年 11 月 24 日”の”メモリ・ライン・バッファー”の193 ページの”表 2‐7 : LineBuffer 例のデー タ セッ ト”を引用する。
gabor_filter_lh2_1_170725.png

行が行2 から始まって、行1 、行0 とインデックスが減っているのが分かるだろうか?列は列0 から始まって増えていっている。
メモリ・ライン・バッファーの値を更新するためにメモリ・ライン・バッファーの現在処理している列を上方向にシフトするのだが、Vivado HLS 2015.4 まででは、shift_down() メソッドを使用する。とっても紛らわしい。その後、現在のピクセル値を挿入するには、insert_bottom() メソッドを使用する。

Vivado HLS 2016.1 からは、この行のインデックスが通常と同様にインデックス 0 からとなっている。
下に、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2017.1) 2017 年 4 月 5 日”の”HLS ビデオライブラリ”の ” 2‐6: LineBuffer 例のデー タ セッ ト”を引用する。
gabor_filter_lh2_2_170725.png

行のインデックスが列のインデックス同様に 0 から始まっているのが分かると思う。
メモリ・ライン・バッファーのメソッドも更新されている。下に、メモリ・ライン・バッファーのメソッドを示す。

• shift_pixels_up()
• shift_pixels_down()
• insert_bottom_row()
• insert_top_row()
• getval(row,column)


上に示すように、今まで使用していた shift_down() メソッドが無くなっている。ただし、互換性確保のためにshift_down() メソッドというか、Vivado HLS 2015.4 以前のコードも使用することができた。
Vivado HLS 2015.4 以前のコードをVivado HLS 2016.1 以降のコードに書き直すと、shift_pixels_up() メソッドで現在処理している列を上方向にシフトし、insert_bottom_row() で現在のピクセル値を挿入する。
  1. 2017年07月25日 04:47 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

白線追従走行用畳み込みニューラルネットワークの製作1(概要)

MNIST手書き数字認識用ニューラルネットワークが完成したので、今度は本命のミニ・ロボットカーを白線間を走らせるための白線追従走行用畳み込みニューラルネットワーク(白線追従走行用CNN)を製作しよう。

白線追従走行用CNNを作るにあたって、最初は直線の白線間を追従走行するための畳み込みニューラルネットワーク(CNN)を作ろうと思う。具体的には、多少外れた位置にいても、直線の白線間に戻れるCNNを学習させようと思っている。まずは小手調べとして、直線を走行するためだけのCNNを学習させてみよう。とは言っても外れた場合も戻ってくるように異常状態を考えるといくらでもありそうだ。しかし、ある程度のシチュエーションで白線間に戻れるようにすれば良いかと思うので、そうしようと思う。白線が全く見えない状況で探索する必要は無いということだ。

具体的には、Zybot のカメラで撮影した写真を使って、どの程度の画像サイズでやってみるかを検討してみよう。
カメラで撮影した白線の様子を示す。サムネイルを示すが、真っ直ぐ、右旋回が必要、左旋回が必要な画像に分けてある。
wlt_cnn_5_170723.jpg

画像サイズは 800 x 600 ピクセルだ。なお、白線は塗装コンパネの上に白線を引いてある。すぐに撤去できるようにするためのアイデアなのだが、黄色は結構明るい色なので、心配だ。
これをPaint.net を使用して、試しに加工してみることにした。
wlt_cnn_1_170723.jpg

まずは、20分の1 に縮小してみた。サイズは、40 x 30 だ。
wlt_cnn_2_170723.jpg

白線の引かれている下 1/3 を切り取ってみよう。(画像サイズは 40 x 10 ピクセル)
wlt_cnn_3_170723.jpg

そして、これを白黒画像にする。
wlt_cnn_4_170723.jpg

これで 40 x 10 ピクセルの白線の画像ができた。これでデータセットを作って、学習させてみよう。とりあえず、30枚しかないので、状況を見て、1~数ピクセルを x または y 方向にずらした画像を追加してみよう。あまり画像を回転をすると、曲がらなければならない画像と一致してしまうかもしれない?なかなか難しそうだ。。。
  1. 2017年07月23日 11:19 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

ルンバ622を買いました

ロボット掃除機のiRobot のルンバ622 を買いました。追加 5年保証(落下・水没にも対応) も付けました。

なかなか掃除ができないので、いない間にお掃除してくれるととっても良いからです。

箱です。
Roomba_1_170723.jpg

箱の中身です。リモコンは取り出しちゃったので、入れておきました。
Roomba_2_170723.jpg

ルンバを取り出して、裏を撮りました。
Roomba_3_170723.jpg

表です。
Roomba_4_170723.jpg

ステーションを設置して、充電されているようなので、早速掃除をしてもらいました。
けなげに頑張ってくれています。部屋もきれいになりました。とっても良い物が買えました。値段もお安く買えるようになったんですね。この機能で十分です。


日本のメーカーは何故早くからロボット掃除機を作れなかったんでしょうか?仏壇のろうそくの火問題もあるようですが、解決可能だし仏壇無い家も多いですよね。それに、仏壇はしっかり作ってあるから、たとえろうそく立っていても倒れない気がします?
  1. 2017年07月23日 05:09 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

手書き数字認識用畳み込みニューラルネットワーク回路の製作9(Linuxでの動作2)

手書き数字認識用畳み込みニューラルネットワーク回路の製作8(Linuxでの動作1)”の続き。

前回はPYNQボードのDebian 上でカメラ画像を表示するアプリケーションソフトを作成して、カメラ画像を表示した。今回は、PYNQボードのDebian 上でピンクの四角枠を表示して、その中の手書き数字を認識した。

最初に、デバイスツリー・オーバーレイ、クロックの設定、FPGAのコンフィギュレーションを行う。all_settings_bat ファイルを作成した。all_settings_bat ファイルの中身を示す。

./devtov pynq_mnist_cnn
./clock_settings.sh
./fpgamag pynq_fastx_wrapper.bit


まずは、su になる必要があるので、
su コマンドを入力して、ルートのパスワード admin を入れてから、./all_settings_bat を実行して、su から exitする。
hand_draw_num_109_170721.png

./cam_disp を実行して、カメラ画像を表示してから、build ディレクトリに移動して、./pynq_mnist_cnn を実行する。
hand_draw_num_110_170721.png

手書き数字の 4 を認識した。
hand_draw_num_108_170721.jpg

hand_draw_num_107_170720.png

gcc で pynq_mnist_cnn.c をコンパイルすると浮動小数点数演算でのmnist_cnn は約 60.8 ms かかった。
次に、gcc の -O2 オプションを付けたところ、最初は 7 ms 程度だったが、キャッシュがフィルしたであろう 2 回目以降は約 6.13 ms で実行できているので、ハードウェアの2倍速くなった。
hand_draw_num_106_170720.png

ハードウェアの方が遅くなって残念な結果になったが、DSP をほとんど使用していないので、仕方ないのかもしれない?
本格的にリソースを使用するようにチューニングすると、PYNQボードには入らなくなってしまうと思うので、とりあえずは、今のままやっていくことにする。

build ディレクトリの構成を示す。重みやバイアス、Vivado HLS のドライバ・ファイルと pynq_mnist_cnn.c がある。
hand_draw_num_111_170721.png

Makefile を示す。

#Makefile
# Referred to http://www.ie.u-ryukyu.ac.jp/~e085739/c.makefile.tuts.html

PROGRAM = pynq_mnist_cnn
OBJS = pynq_mnist_cnn.o xmnist_conv_nn.o xmnist_conv_nn_linux.o xsquare_frame_gen.o xsquare_frame_gen_linux.o

CC = gcc
CFLAGS = -Wall -O2

.SUFFIXES: .c .o

.PHONY: all

all: pynq_mnist_cnn

pynq_mnist_cnn: $(OBJS)
    $(CC) -Wall -o $@ $(OBJS)
    
.c.o:
    $(CC) $(CFLAGS) -c $<

    
.PHONY: clean
clean:
    $(RM) $(PROGRAM) $(OBJS)


pynq_mnist_cnn.c を貼っておく。

//
// pynq_mnist_cnn.c
// 2017/07/17 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/time.h>

#include "xmnist_conv_nn.h"
#include "xsquare_frame_gen.h"
#include "af1_bias_float.h"
#include "af1_weight_float.h"
#include "af2_bias_float.h"
#include "af2_weight_float.h"
#include "conv1_bias_float.h"
#include "conv1_weight_float.h"

#define HORIZONTAL_PIXELS   800
#define VERTICAL_LINES      600
#define PIXEL_NUM_OF_BYTES  4
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

int max_int(int out[10]);
int max_float(float out[10]);
int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]);
float conv_rgb2y_soft(int rgb);

int main()
{
    int fd0, fd3, fd4;
    int fd_udmabuf, fd_paddr;
    volatile unsigned int *axis_switch_0, *axis_switch_1;
    volatile unsigned int *axi_gpio_0;
    volatile unsigned int *frame_buffer;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    struct termios save_settings;
    struct termios settings;
    int xval, yval;
    int inbyte_in;
    int result_disp = 0;
    unsigned int conv_addr;
    int max_id_float;
    struct timeval start_time, end_time;
    XMnist_conv_nn mcnn;
    XSquare_frame_gen sf_gen;
    int i, res;
    int max_id;
    int result[10];
    float result_float[10];

    // Reffered to http://d.hatena.ne.jp/mFumi/20101002/1286003738
    tcgetattr(0,&save_settings);
    settings = save_settings;

    settings.c_lflag &= ~(ECHO|ICANON);
    settings.c_cc[VTIME] = 0;
    settings.c_cc[VMIN] = 1;
    tcsetattr(0,TCSANOW,&settings);
    fcntl(0,F_SETFL,O_NONBLOCK);

    // axi_gpio_0 (uio0)
    fd0 = open("/dev/uio0", O_RDWR); // axi_iic_0
    if (fd0 < 1){
        fprintf(stderr, "/dev/uio0 (axi_gpio_0) open errorn");
        exit(-1);
    }
    axi_gpio_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, 0);
    if (axi_gpio_0 == MAP_FAILED){
        fprintf(stderr, "axi_gpio_0 mmap errorn");
        exit(-1);
    }
    
    // axis_switch_0 (uio3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_0
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_0) open errorn");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (axis_switch_0 == MAP_FAILED){
        fprintf(stderr, "axis_switch_0 mmap errorn");
        exit(-1);
    }
    
    // axis_switch_1 (uio4)
    fd4 = open("/dev/uio4", O_RDWR); // axis_switch_1
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (axis_switch_1) open errorn");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (axis_switch_1 == MAP_FAILED){
        fprintf(stderr, "axis_switch_1 mmap errorn");
        exit(-1);
    }
       
    // udmabuf4
    fd_udmabuf = open("/dev/udmabuf4", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd_udmabuf == -1){
        fprintf(stderr, "/dev/udmabuf4 open errorn");
        exit(-1);
    }
    frame_buffer = (volatile unsigned int *)mmap(NULL, (ALL_DISP_ADDRESS*3), PROT_READ|PROT_WRITE, MAP_SHARED, fd_udmabuf, 0);
    if (frame_buffer == MAP_FAILED){
        fprintf(stderr, "frame_buffer mmap errorn");
        exit(-1);
    }

    // phys_addr of udmabuf4
    fd_paddr = open("/sys/devices/soc0/amba/amba:udmabuf4/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd_paddr == -1){
        fprintf(stderr, "/sys/devices/soc0/amba/amba:udmabuf4/udmabuf/udmabuf4/phys_addr open errorn");
        exit(-1);
    }
    read(fd_paddr, attr, 1024);
    sscanf((const char *)attr, "%lx", &phys_addr);  
    close(fd_paddr);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);

    // Mnist_conv_nn, Square_frame_gen Initialize
    if (XMnist_conv_nn_Initialize(&mcnn, "mnist_conv_nn_0") != XST_SUCCESS){
        fprintf(stderr,"mnist_conv_nn_0 open error\n");
        exit(-1);
    }
    if (XSquare_frame_gen_Initialize(&sf_gen, "square_frame_gen_0") != XST_SUCCESS){
        fprintf(stderr,"square_frame_gen_0 open error\n");
        exit(-1);
    }

    // square_frame_gen initialize
    XSquare_frame_gen_Set_x_pos(&sf_gen, HORIZONTAL_PIXELS/2);
    xval = HORIZONTAL_PIXELS/2;
    XSquare_frame_gen_Set_y_pos(&sf_gen, VERTICAL_LINES/2);
    yval = VERTICAL_LINES/2;
    XSquare_frame_gen_Set_width(&sf_gen, 28);
    XSquare_frame_gen_Set_height(&sf_gen, 28);
    XSquare_frame_gen_Set_off_on(&sf_gen, 1); // on

    // XSquare_frame_gen start
    XSquare_frame_gen_DisableAutoRestart(&sf_gen);
    while(!XSquare_frame_gen_IsIdle(&sf_gen)) ;
    XSquare_frame_gen_Start(&sf_gen);
    XSquare_frame_gen_EnableAutoRestart(&sf_gen);

    // mnist_conv_nn initialize
    XMnist_conv_nn_Set_addr_offset(&mcnn, HORIZONTAL_PIXELS/2);
    XMnist_conv_nn_Set_in_r(&mcnn, (unsigned int)phys_addr+HORIZONTAL_PIXELS*(VERTICAL_LINES/2)*sizeof(int));
 
    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x80000000// 0x40 = 0x80000000, disable
    axis_switch_1[17] = 0x0// 0x44 = 0
    axis_switch_1[0] = 0x2// Comit registers
    
    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x1// 0x40 = 1;
    axis_switch_0[0] = 0x2// Comit registers
  
    axi_gpio_0[0] = 0// LED 0 clear

    printf("mnist_conv_nn_test, <h> : left, <k> : up, <j> : down, <l> : right, <r> : result, <d> : help, <q> : exit\n");
    
    while(1){   // main loop
        inbyte_in = getchar(); fflush(stdin);
        if (inbyte_in != EOF){
            if (inbyte_in == 'q')
                break;
            else if (inbyte_in < 'A' || inbyte_in > 'z')
                usleep(10000);
        }
        switch(inbyte_in) {
            case 'h' : // left
            case 'H' : // left -5
                if(inbyte_in == 'h' && xval > 0)
                    --xval;
                else if(inbyte_in == 'H' && xval >= 5)
                    xval -= 5;
                XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                XMnist_conv_nn_Set_addr_offset(&mcnn, xval);
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'l' : // right
            case 'L' : // right +5
                if(inbyte_in == 'l' && xval < HORIZONTAL_PIXELS-28)
                    xval++;
                else if(inbyte_in == 'L' && xval <= HORIZONTAL_PIXELS-28-5)
                    xval += 5;
                XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                XMnist_conv_nn_Set_addr_offset(&mcnn, xval);
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'k' : // up
            case 'K' : // up -5
                if(inbyte_in == 'k' && yval > 0)
                    --yval;
                else if(inbyte_in == 'K' && yval >= 5)
                    yval -= 5;
                XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                XMnist_conv_nn_Set_in_r(&mcnn, (unsigned int)phys_addr+HORIZONTAL_PIXELS*yval*sizeof(int));
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'j' : // down
            case 'J' : // down +5
                if(inbyte_in == 'j' && yval < VERTICAL_LINES-28)
                    yval++;
                else if(inbyte_in == 'J' && yval <= VERTICAL_LINES-28-5)
                    yval += 5;
                XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                XMnist_conv_nn_Set_in_r(&mcnn, (unsigned int)phys_addr+HORIZONTAL_PIXELS*yval*sizeof(int));
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'r' : // result check
                result_disp = 1;
                break;
            case 'd' : // help
            case 'D' :
                printf("mnist_conv_nn_test, <h> : left, <k> : up, <j> : down, <l> : right, <r> : result, <d> : help, <q> : exit\n");
                break;
            case 'q' : // exit
                return(0);
        }

        if(result_disp){
            printf("\nHardware\n");
            // XMnist_conv_nn start
            XMnist_conv_nn_DisableAutoRestart(&mcnn);
            while(!XMnist_conv_nn_IsIdle(&mcnn));
            gettimeofday(&start_time, NULL);
            XMnist_conv_nn_Start(&mcnn);
            while(!XMnist_conv_nn_IsIdle(&mcnn));
            gettimeofday(&end_time, NULL);
            if (end_time.tv_usec < start_time.tv_usec) {
                printf("conv_time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
            } else {
                printf("conv_time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
            }

            // mnist cnn result check
            for(i=0; i<5; i++){
                XMnist_conv_nn_Read_out_V_Words(&mcnn, i, &res, 1);
                result[i*2] = res & 0x0fff;
                if(result[i*2] & 0x800// minus
                    result[i*2] = 0xfffff000 | result[i*2]; // Sign extension

                result[i*2+1] = (res & 0x0fff0000) >> 16;
                if(result[i*2+1] & 0x800// minus
                    result[i*2+1] = 0xfffff000 | result[i*2+1]; // Sign extension
            }

            max_id = max_int(result);
            axi_gpio_0[0] = max_id;

            for(i=0; i<10; i++){
                printf("result[%d] = %x\n", i, result[i]);
            }
            printf("max_id = %d\n", max_id);

            printf("\nSoftware\n");
            conv_addr = (unsigned int)frame_buffer+HORIZONTAL_PIXELS*yval*sizeof(int);
            gettimeofday(&start_time, NULL);
            mnist_conv_nn_float((int *)conv_addr, xval, result_float);
            gettimeofday(&end_time, NULL);
            max_id_float = max_float(result_float);

           if (end_time.tv_usec < start_time.tv_usec) {
                printf("conv_time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
            } else {
                printf("conv_time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
            }

            for(i=0; i<10; i++){
                printf("result_float[%d] = %f\n", i, result_float[i]);
            }
            printf("max_id_float = %d\n", max_id_float);
            printf("\n");

            result_disp = 0;
        }
    }
            
    munmap((void *)axi_gpio_0, 0x10000);
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)frame_buffer, (ALL_DISP_ADDRESS*3));
    
    close(fd0);
    close(fd3);
    close(fd4);
    close(fd_udmabuf);
    
    // Reffered to http://d.hatena.ne.jp/mFumi/20101002/1286003738
    tcsetattr(0,TCSANOW,&save_settings);
    
    return(0);
}

int max_int(int out[10]){
    int max_id;
    int max = 0, i;

    for(i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]){
    
    int i, j, k, m, n, col, row;
    float buf[28][28];
    float conv_out[10][24][24];
    float pool_out[10][12][12];
    float dot1[100];
    float dot2[10];
   
    // 
    /*for (i=0; i<28; i++){        for (j=0; j<800; j++){            if (j>=addr_offset && j<addr_offset+28)                printf("%2x, ", (int)(conv_rgb2y_soft(in[i*800+j])*256.0));        }        printf("\n");    } */
    for(i=0; i<28; i++){
        for(j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28){
                buf[i][j-addr_offset] = (float)0.99609375 - (float)conv_rgb2y_soft(in[i*800+j]);
            }
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    for(i=0; i<10; i++){    //
        for(j=0; j<24; j++){
            for(k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                for(m=0; m<5; m++){
                    for(n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_fweight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_fbias[i];

                if(conv_out[i][j][k]<0// ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    for(i=0; i<10; i++){
        for(j=0; j<24; j += 2){
            for(k=0; k<24; k += 2){
                for(m=0; m<2; m++){
                    for(n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    for(col=0; col<100; col++){
        dot1[col] = 0;
        for(i=0; i<10; i++){
            for(j=0; j<12; j++){
                for(k=0; k<12; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

        if(dot1[col] < 0)   // ReLU
            dot1[col] = 0;
    }

    for(col=0; col<10; col++){
        dot2[col] = 0;
        for(row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_fweight[row][col];
        }
        dot2[col] += af2_fbias[col];

        out[col] = dot2[col];
    }

    return(0);
}

int max_float(float out[10]){
    int max_id, i;
    float max = 0;

    for(i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

float conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;
    float y_float;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;
    y = y_f >> 8// /256

    if (y >= 256)
        y = 255;

    y_float = (float)y/256.0;

    return(y_float);
}

  1. 2017年07月21日 04:20 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Bash on Windows 10にVivado WebPACK 2017.2をインストールした3(Vivado HLS)

Bash on Windows 10にVivado WebPACK 2017.2をインストールした2(日本語表示)”の続き。

前回は、Bash on Windows 10 の日本語表示について書いた。今回は、Bash on Windows 10 でVivado_HLSを使ってみよう。

PowerShell に vivado_hls & と入力して、Vivado HLS 2017.2 を立ち上げた。

Vivado HLS 2017.2 が立ち上がった。
Win10_Ubuntu_Vivado_24_170720.png

mnist_conv_nn10 プロジェクトを開いた。
Win10_Ubuntu_Vivado_20_170720.png

表示されているのは、Window 10 上でC コードの合成を行ったときの合成結果だ。

C シミュレーションを行った。
Win10_Ubuntu_Vivado_21_170720.png

out of memory allocating エラーで止まってしまった。これはWindow 10 上でVivado HLS を使用したときと同様の結果だ。

次に、C コードの合成を行った。
Win10_Ubuntu_Vivado_22_170720.png

エラーが発生した。
詳しく見てみよう。
Win10_Ubuntu_Vivado_23_170720.png

/opt/Xilinx/Vivado_HLS/2017.2/lnx64/tools/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.6.3/../../../../include/c++/4.6.3/x86_64-unknown-linux-gnu/bits/os_defines.h で'features.h' file not found だそうだ。
自分のところのコードの問題ではなくXilinx 社のコードでの問題のようだ。

Bash on Windows 10 のVivado HLS はうまく動かいないし、C シミュレーションのコンパイラのWindow 10 と同じようなので、メリットが無い。また、C コードの合成はエラーになってしまうことがあるようだ。(ap_fixed を使用していないC ソースコードでは合成できるか?は確かめていない)
  1. 2017年07月20日 05:03 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Bash on Windows 10にVivado WebPACK 2017.2をインストールした2(日本語表示)

Bash on Windows 10にVivado WebPACK 2017.2をインストールした”の続き。

前回は、Xmingを起動してから、Bash on Windows 10 からVivado を起動したところ GUI 上でLinux バージョンのVivado を起動することができた。今回は、日本語を表示できるようにしてみた。

Xming の日本語表示についてはXfont をインストールしたり、いろいろとやってみたが、うまく行かなかった。ツィッターで聞いたところ、tethys さんが教えてくれた。ありがとうございました。

その方法は、「 [WSL]BashOnWindows(WSL)のGUIの日本語表示」の Windows10 に入ってる Windows フォントを使う方法だ。
下の2つのコマンドをBash on Windows 10 上で実行する。
sudo ln -s /mnt/c/Windows/Fonts /usr/share/fonts/WindowsFonts
sudo fc-cache -fv

Win10_Ubuntu_Vivado_14_170718.png

その後、vivado を立ち上げたところ、日本語が表示できるようになった。
Win10_Ubuntu_Vivado_15_170718.png

次に、X サーバーだが、Xming だとVivado を立ち上げてもWindow 10 のタスクバーに表示されるアイコンはXming のX のアイコンなのだが、VcXsrv というX サーバーを使用すると、Vivado のアイコンがタスクバーに表示されるようになった。(「WindowsでリモートのLinuxのGUIアプリを表示させる-Xサーバ VcXsrv」参照)
これも善し悪しで、Windows のアイコンと見分けがつかなくなるという欠点はあるのだが、VcXsrv を使うことにした。

次に日本語入力だが、結論から言うと、GUI 上での日本語入力は諦めて、Windows の方からSublime text 上で日本語入力することにした。
Bash on Windows 10 のroot は「【シェル芸人への道】Bash on Windowsを探検する」によると、

C:\Users\Masaaki\AppData\Local\lxss

にありました。
Win10_Ubuntu_Vivado_16_170719.png

Vivado のトップHDL のあるC:\Users\Masaaki\AppData\Local\lxss\home\marsee\HDL\project_1\project_1.srcs\sources_1\bd\base_zynq\hdl フォルダに行った。
Win10_Ubuntu_Vivado_17_170719.png

base_zynq_wrapper.vhd をWindow 10 上のSublime text で編集し、日本語を書きこんだ。
Win10_Ubuntu_Vivado_18_170719.png

Vivado 2017.2 上でbase_zynq_wrapper.vhd を開いてみると、Sublime text で編集した日本語が表示されている。
Win10_Ubuntu_Vivado_19_170719.png

日本語はWindow 10 上のSublime text で入力してもよいと思った。ただし、入力してもVivado には追加入力されたということを認識できないので、自分で論理合成結果をクリアする必要があるようだ。
  1. 2017年07月19日 05:06 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Bash on Windows 10にVivado WebPACK 2017.2をインストールした

Vengineerの戯言」ブログの「Bash on Windows 10でVivado 2017.2」でWindows 10のPowerShell で動作するUbuntu 16.04 上でVivado 2017.2 をインストールするという記事が載っていた。それを参照して、自分でもWindows 10 のUbuntu 16.04 にVivado WebPACK 2017.2 をインストールしてみた。

まずは、左下のウインドウアイコンを右クリックして、右クリックメニューからWindows PowerShell を起動した。
update, upgrade コマンドを入力する。
sudo apt-get update
sudo apt-get upgrade

Win10_Ubuntu_Vivado_1_170717.png

Xming は既にインストールしてあるので、Xming を立ち上げた。次に、x11-apps をインストールした。続けてJava をインストールした。
sudo apt-get install x11-apps
sudo apt-get install default_jre
sudo apt-get install default_jdk


カレント・ディレクトリにXilinx_Vivado_SDK_2017.2_0616_1_Lin64.bin を貼り付けて
sudo ./Xilinx_Vivado_SDK_2017.2_0616_1_Lin64.bin
を実行するとDISPLAY 変数をセットしないといわれてエラーだった。
export DISPLAY=:0.0
を実行して、もう一度、
sudo ./Xilinx_Vivado_SDK_2017.2_0616_1_Lin64.bin
を実行するとVivado のインストーラーが上がってきた。
Win10_Ubuntu_Vivado_3_170717.png

その後はLinuxでのインストールと同様に、インストール画面を表示されたので、WebPACKを選択して、インストールを開始した。
Win10_Ubuntu_Vivado_2_170717.png

インストール途中でエラーが出てしまった。今のインストール先は、/mnt/d/Xilinx ディレクトリだ。
Win10_Ubuntu_Vivado_4_170717.png

D: ドライブは十分に容量があるので、たぶん、行先のディレクトリが長すぎるのでは?と思う。
Win10_Ubuntu_Vivado_5_170717.png

今度はデフォルトのディレクトリパスの /opt/Xilinx にした。
Win10_Ubuntu_Vivado_6_170717.png

Win10_Ubuntu_Vivado_7_170717.png

インストール終了。成功した。
Win10_Ubuntu_Vivado_8_170717.png

Ubuntu16.04にVivado 2016.4をインストール”を参考に設定を行った。

gedit が無いのでインストールした。
sudo apt install gedit

gedit で .bashrc を編集する。
gedit .bashrc

.bashrc の下に以下の3行を追加した。
source /opt/Xilinx/Vivado/2017.2/settings64.sh
alias xsdk='env SWT_GTK3=0 xsdk'
alias vivado='env SWT_GTK3=0 vivado'

(2017/07/18:追記 export DISPLAY=:0.0 も追加しておいた方が良い)
Win10_Ubuntu_Vivado_9_170717.png

.bashrc の内容を反映。
source .bashrc

.Xilinx のオーナーを自分に変更する。
sudo chown -R marsee:marsee .Xilinx/

Vivado を起動した。
Vivado &
Win10_Ubuntu_Vivado_10_170717.png

Vivado が起動した。
Win10_Ubuntu_Vivado_11_170717.png

ZC702 のExample Project を生成してみた。
Win10_Ubuntu_Vivado_12_170717.png

論理合成、インプリメント、ビットストリームの生成も通った。
Win10_Ubuntu_Vivado_13_170718.png

ただし、日本語の表示と入力はまだできない。日本語を表示させるとトーフになってしまう。
  1. 2017年07月17日 08:00 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

手書き数字認識用畳み込みニューラルネットワーク回路の製作8(Linuxでの動作1)

手書き数字認識用畳み込みニューラルネットワーク回路の製作7(ハードとソフトの比較)”の続き。

前回はSDKを使用してベアメタル・アプリケーションでハードウェアでのMNIST手書き数字認識とソフトウェアでのMNIST手書き数字認識の実行時間を比較した。今回は、それをLinuxのアプリケーションソフトを作成してやってみようと思う。まずは、カメラ画像の表示を目指す。

なお、PYNQボードにikwzmさんのLinux システムを載せて、デバイスツリー・オーバーロード、FPGA Manager を使用して、動作させることを目指す。
過去にやったことを思い出しながらやってみよう。このためにブログのまとめをやったようなものだ。
FPGAの部屋のWeb サイトの「PYNQ」の「”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる1(FPGA-SoC-Linux のクローン)」からのブログを参考にやってみた。ほとんど「
”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を使用してカメラの画像を表示」を見ながらやってみた。
最初にデバイスツリーのpynq_mnist_cnn.dts を作成した。pynq_mnist_cnn.dts を示す。

/dts-v1/;
/ {
    fragment@0 {
        target-path = "/amba";
        __overlay__ {
            #address-cells = <0x1>;
            #size-cells = <0x1>;
            axi_gpio_0@41200000 {
                compatible = "generic-uio";
                reg = <0x41200000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            axi_iic_0@41600000 {
                compatible = "generic-uio";
                reg = <0x41600000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            axi_vdma_0@43000000 {
                compatible = "generic-uio";
                reg = <0x43000000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            axis_switch_0@43C10000 {
                compatible = "generic-uio";
                reg = <0x43C10000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            axis_switch_1@43C20000 {
                compatible = "generic-uio";
                reg = <0x43C20000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            bitmap_disp_cntrler_axi_master_0@43C00000 {
                compatible = "generic-uio";
                reg = <0x43C00000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            mnist_conv_nn_0@43C50000 {
                compatible = "generic-uio";
                reg = <0x43C50000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            mt9d111_inf_axis_0@43C40000 {
                compatible = "generic-uio";
                reg = <0x43C40000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            square_frame_gen_0@43C30000 {
                compatible = "generic-uio";
                reg = <0x43C30000 0x10000>;
                #interrupts = <0x0 0x1d 0x4>;
            };
            udmabuf4 {
                compatible = "ikwzm,udmabuf-0.10.a";
                minor-number = <4>;
                size = <0x00600000>;
            };
            fclk0 {
                compatible  = "ikwzm,fclkcfg-0.10.a";
                clocks      = <1 15>;
            };
            fclk1 {
                compatible  = "ikwzm,fclkcfg-0.10.a";
                clocks      = <1 16>;
            };
            fclk2 {
                compatible  = "ikwzm,fclkcfg-0.10.a";
                clocks      = <1 17>;
            };
        };
    };
};


pynq_mnist_cnn.dts をコンパイルして pynq_mnist_cnn.dtbo を生成しよう。
dtc -I dts -O dtb -o pynq_mnist_cnn.dtbo pynq_mnist_cnn.dts
pynq_mnist_cnn.dtbo が生成できたので、スーパーユーザーになってからdevtov コマンドでデバイスツリー・オーバーレイでデバイスツリーを設定しよう。(devtov, fpgamag, rmdevtov はこのディレクトリにコピーしてあります)
su
./devtov pynq_mnist_cnn

hand_draw_num_101_170716.png

次にクロックの周波数を設定する clock_settings.sh を作成した。なお、fclk0はデフォルトで100MHzに設定されているので、そのままとした。つまり設定は行っていない。

#!/bin/sh
# clock_settings.sh

echo 25000000 > /sys/class/fclkcfg/fclk1/rate
cat /sys/class/fclkcfg/fclk1/rate

echo 72000000 > /sys/class/fclkcfg/fclk2/rate
cat /sys/class/fclkcfg/fclk2/rate


これをスーパーユーザー・モードで実行した。
hand_draw_num_102_170716.png

fpgamag コマンドでビット・ファイルをPYNQのZynq にダウンロードする。
./fpgamag pynq_fastx_wrapper.bit
実行するとDONE ランプが点灯した。
hand_draw_num_103_170716.png

”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を使用してカメラの画像を表示」の cam_disp.c を改造してコンパイルし、実行したところ、ディスプレイにカメラ画像を表示することができた。
exit
gcc -o cam_disp cam_disp.c
./cam_disp

hand_draw_num_104_170716.png

hand_draw_num_105_170716.jpg

cam_disp.c を示す。

// cam_disp.c
// 2017/07/15 by marsee
//
// cam_disp for pynq_mnist_cnn
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

#define FASTX_THRESHOLD        20

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main()
{
    int fd1, fd2, fd3, fd4, fd5, fd7;
    int fd_udmabuf, fd_paddr;
    volatile unsigned int *axi_iic_0, *axi_vdma_0, *axis_switch_0, *axis_switch_1;
    volatile unsigned int *bitmap_disp_cntrler_axim_0, *fastx_corner_det_0;
    volatile unsigned int *mt9d111_inf_axis_0;
    volatile unsigned int *frame_buffer;
    unsigned char  attr[1024];
    unsigned long  phys_addr;

    // axi_iic_0 (uio1)
    fd1 = open("/dev/uio1", O_RDWR); // axi_iic_0
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (axi_iic_0) open errorn");
        exit(-1);
    }
    axi_iic_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (axi_iic_0 == MAP_FAILED){
        fprintf(stderr, "axi_iic_0 mmap errorn");
        exit(-1);
    }
    
    // axi_vdma_0 (uio2)
    fd2 = open("/dev/uio2", O_RDWR); // axi_vdma_0
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axi_vdma_0) open errorn");
        exit(-1);
    }
    axi_vdma_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (axi_vdma_0 == MAP_FAILED){
        fprintf(stderr, "axi_vdma_0 mmap errorn");
        exit(-1);
    }

    // axis_switch_0 (uio3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_0
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_0) open errorn");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (axis_switch_0 == MAP_FAILED){
        fprintf(stderr, "axis_switch_0 mmap errorn");
        exit(-1);
    }
    
    // axis_switch_1 (uio4)
    fd4 = open("/dev/uio4", O_RDWR); // axis_switch_1
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (axis_switch_1) open errorn");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (axis_switch_1 == MAP_FAILED){
        fprintf(stderr, "axis_switch_1 mmap errorn");
        exit(-1);
    }
    
    // bitmap_disp_cntrler_axim_0 (uio5)
    fd5 = open("/dev/uio5", O_RDWR); // bitmap_disp_cntrler_axim_0
    if (fd5 < 1){
        fprintf(stderr, "/dev/uio5 (bitmap_disp_cntrler_axim_0) open errorn");
        exit(-1);
    }
    bitmap_disp_cntrler_axim_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
    if (bitmap_disp_cntrler_axim_0 == MAP_FAILED){
        fprintf(stderr, "bitmap_disp_cntrler_axim_0 mmap errorn");
        exit(-1);
    }
    
    // mt9d111_inf_axis_0 (uio7)
    fd7 = open("/dev/uio7", O_RDWR); // mt9d111_inf_axis_0
    if (fd7 < 1){
        fprintf(stderr, "/dev/uio7 (mt9d111_inf_axis_0) open errorn");
        exit(-1);
    }
    mt9d111_inf_axis_0 = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
    if (mt9d111_inf_axis_0 == MAP_FAILED){
        fprintf(stderr, "mt9d111_inf_axis_0 mmap errorn");
        exit(-1);
    }
    
    // udmabuf4
    fd_udmabuf = open("/dev/udmabuf4", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd_udmabuf == -1){
        fprintf(stderr, "/dev/udmabuf4 open errorn");
        exit(-1);
    }
    frame_buffer = (volatile unsigned int *)mmap(NULL, (ALL_DISP_ADDRESS*3), PROT_READ|PROT_WRITE, MAP_SHARED, fd_udmabuf, 0);
    if (frame_buffer == MAP_FAILED){
        fprintf(stderr, "frame_buffer mmap errorn");
        exit(-1);
    }

    // phys_addr of udmabuf4
    fd_paddr = open("/sys/devices/soc0/amba/amba:udmabuf4/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd_paddr == -1){
        fprintf(stderr, "/sys/devices/soc0/amba/amba:udmabuf4/udmabuf/udmabuf4/phys_addr open errorn");
        exit(-1);
    }
    read(fd_paddr, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd_paddr);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);
    
    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x0// 0x40 = 0
    axis_switch_1[17] = 0x80000000// 0x44 = 0x80000000, disable
    axis_switch_1[18] = 0x80000000// 0x48 = 0x80000000, disable
    axis_switch_1[19] = 0x80000000// 0x4C = 0x80000000, disable
    axis_switch_1[0] = 0x2// Comit registers
    
    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x0// 0x40 = 0;
    axis_switch_0[0] = 0x2// Comit registers

    // AXI VDMA Initialization sequence (axi_vdma_0)
    axi_vdma_0[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4 
    while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_0[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4 
    while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_0[18] = NUMBER_OF_WRITE_FRAMES; // S2MM_FRMSTORE (0x48) register
    axi_vdma_0[12] = 0x00010002// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1)
    axi_vdma_0[41] = HORIZONTAL_PIXELS*PIXEL_NUM_OF_BYTES; // S2MM Horizontal Size Register(S2MM_HSIZE)0xc80 = 3200dec = 800 x 4
    axi_vdma_0[42] = HORIZONTAL_PIXELS*PIXEL_NUM_OF_BYTES; // S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)0xc80 = 3200dec = 800 x 4
    axi_vdma_0[43] = (unsigned)phys_addr; // S2MM Start Address (1 to 16) Start Address 1
    axi_vdma_0[44] = (unsigned)phys_addr; // S2MM Start Address (1 to 16) Start Address 2
    axi_vdma_0[45] = (unsigned)phys_addr; // S2MM Start Address (1 to 16) Start Address 3
    axi_vdma_0[12] = 0x00010003// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1, Run/stop = 1)
    while((axi_vdma_0[13] & 0x1) == 0x1) ; // Halt? (S2MM_VDMASR 0x34)
    axi_vdma_0[40] = VERTICAL_LINES; // S2MM Vertical Size (S2MM_VSIZE  Offset 0xA0) 0x258 = 600dec

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(axi_iic_0);
    
    cam_i2c_write(axi_iic_0, 0xba, 0xf00x1);        // Changed regster map to IFP page 1
    cam_i2c_write(axi_iic_0, 0xba, 0x970x20);    // RGB Mode, RGB565

    mt9d111_inf_axis_0[1] = 0;
    mt9d111_inf_axis_0[0] = (unsigned int)phys_addr;

    bitmap_disp_cntrler_axim_0[0] = (unsigned int)phys_addr;
        
    munmap((void *)axi_iic_0, 0x10000);
    munmap((void *)axi_vdma_0, 0x10000);
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)bitmap_disp_cntrler_axim_0, 0x10000);
    munmap((void *)mt9d111_inf_axis_0, 0x10000);
    munmap((void *)frame_buffer, (ALL_DISP_ADDRESS*3));
    
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    close(fd5);
    close(fd7);
    close(fd_udmabuf);
}

  1. 2017年07月16日 04:00 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2017年7月14日)

FPGAの部屋のまとめサイトを更新しました。
DNNAWS-FPGA を追加して、その他のカテゴリーの記事を更新しました。
なお、以前あったDeep Learning はDNN とマージしました。
  1. 2017年07月14日 03:58 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

aws/aws-fpgaをやってみた3

aws/aws-fpgaをやってみた2”の続き。

前回は、デザインをビルドしてみたが、失敗してしまった。今回はシミュレーションを試みてみよう。なお、AWSは使用していないで、ローカルのパソコンで行っている。

今回は、「AWS EC2 F1について、みんなでワイワイ調べる会 サンプルデザインのテストベンチ&テストプログラムを開発するチーム 活動報告 2017.07.08」に基づいてやってみた。
また、元になったマニュアルは、「RTL Simulation for Verilog/VHDL Custom Logic Design with AWS HDK」だ。

まずは、~/aws-fpga/cl/examples/cl_hello_world/verif/scripts ディレクトリのMakefile.vivado とwaves.tcl を修正する。
aws-fpga_12_170710.png

Makefile.vivado のxsim に -g オプションを追加して、GUI を立ち上げる。
aws-fpga_13_170710.png

waves.tcl の quit をコメントアウトした。こうしないとxsim が終了してしまうそうだ。
aws-fpga_14_170710.png

make をしてもエラーだった。
aws-fpga_15_170710.png

そういえば、source hdk_setup.sh を実行した後で、VirtualBox のVM を落としてしまったので、パスなどの設定が無くなってしまったようだ。
もう一度、~/aws-fpga に戻って source hdk_setup.sh を実行した。
、~/aws-fpga/cl/examples/cl_hello_world/verif/scripts ディレクトリに行って、make を実行した。
aws-fpga_17_170710.png

Vivado が立ち上がったが、internal exception が発生してしまった。。。
aws-fpga_16_170710.png

シミュレーションも失敗してしまった。
結局、ビルドもシミュレーションもうまく行かなかった。残念だが、AWS で試したほうが良さそうだ。
  1. 2017年07月12日 04:27 |
  2. AWS-FPGA
  3. | トラックバック:0
  4. | コメント:0

aws/aws-fpgaをやってみた2

aws/aws-fpgaをやってみた1”の続き。

コメント欄で教えて頂いた

expected_memory_usage=30000000

を変更する方法でもう一度やってみた。値は、

expected_memory_usage=16000000

とした。

まずは、~/aws-fpga/hdk/common/shell_stabel/build/scripts/aws_build_dcp_from_cl.sh の45行目の

expected_memory_usage=30000000

expected_memory_usage=16000000

に変更した。
aws-fpga_18_170711.png

「AWS EC2 F1についえ、みんなでワイワイ調べる会 カスタムロジックサンプル解析 CLサンプル解析班」の資料の14ページを参考に記述を変更した。

~/aws-fpga/hdk/common/shell_stabel/build/scripts/aws_build_dcp_from_cl.sh の42 行目の foreground を 1 に変更した。
aws-fpga_19_170711.png

同じく、aws_build_dcp_from_cl.sh の 218 行目の -mode batch を削除した。
aws-fpga_20_170711.png

~/aws-fpga/cl/examples/cl_hello_world/build/scripts/encrypt.tcl の encrypt -k で始まる行をコメントアウトした。
aws-fpga_22_170711.png

これは資料には書いていなかったが、CL_DIR 環境変数を ~/aws-fpga/cl/examples/cl_hello_world に指定した。
aws-fpga_21_170711.png

./aws_build_dcp_from_cl.sh
を起動した。
aws-fpga_24_170711.png

Vivado は立ち上がったがライセンス・エラーになった。xcvu9p-flgb2104 のライセンスはあるのだが?
aws-fpga_23_170711.png

エラー・メッセージを示す。

[Common 17-348] Failed to get the license for feature 'Synthesis' and/or device 'xcvu9p-flgb2104'. Explanation: The license feature Synthesis could not be found.
Resolution: Check the status of your licenses in the Vivado License Manager. For debug help search Xilinx Support for "Licensing FAQ".


Vivado 2017.1 を立ち上げて、xcvu9p-flgb2104 のプロジェクトも作ることができる。
aws-fpga_25_170711.png

Ubuntu 14.04 にVivado 2017.1 をインストールするのは仕様外なので仕方ないかもしれない?
おかしなことに、ライセンスは入れたのだが、Vivado License Manager ではライセンスは見えないのだ?
やはり、サポート対象のUbuntu 16.04 にVivado 2017.1 を入れる必要があるだろう。通常はVivado Design Editionをインストールすることができないので、”Ubuntu 16.04 にVivado Design Edition がインストールできない”のコメント欄を参照のこと。

やはり、AWSを使ってやった方が良さそうだ。。。

これ以上は面倒になったので、詳しくは、「AWS EC2 F1についえ、みんなでワイワイ調べる会 カスタムロジックサンプル解析 CLサンプル解析班」の資料の「回路図を表示させてみよう(4)」以降のページをご覧ください。。。(資料を作ってくれてありがとうございました)
  1. 2017年07月11日 04:50 |
  2. AWS-FPGA
  3. | トラックバック:0
  4. | コメント:0

aws/aws-fpgaをやってみた1

2017年7月8日(土)に、「AWS EC2 F1について、みんなでワイワイ調べる会」に参加して、「サンプルデザインのHDLコードを解析するチーム(Hello World & DMA)」になったのだが、「Ubuntu 16.04 にVivado Design Edition がインストールできない」という理由でVirtualBox 上のUbuntu 16.04 にVivado WebPACK Edition しかインストールしていなくて、たいして貢献できなくて申し訳ないので、Ubuntu 14.04 上にVivado をインストールしてリベンジしてみた。

最初に、VirtualBox 上に最新版の Vivado 2017.2 をインストールしてみた。
次に、aws/aws-fpga からgit clone した。詳しくはWeb サイトを見てほしい。
git clone https://github.com/aws/aws-fpga
aws-fpga_1_170709.png

cd aws-fpga
source hdk_setup.sh

HostID_all0_2_170709.png

やはり、指定では、Vivado 2017.1 なのに、2017.2 をインストールしたので、エラーが出てしまった。
~/aws-fpga/hdk/supported_vivado_versions.txt を見ると 2017.1 と書いてあったので、2017.2 に書き換えた。
aws-fpga_3_170709.png

もう一度、
source hdk_setup.sh
を実行すると、curl がインストールされていないというエラーだった。
aws-fpga_4_170709.png

sudo apt-get install curl でインストールした。
もう一度、source hdk_setup.shを実行した。良い感じで実行されていたが。。。
aws-fpga_4_170709.png

IP Catalog の revision が違うというエラーになってしまった。Vivado のバージョンが違うので仕方がない。。。
aws-fpga_6_170709.png

と言う訳で、せっかくインストールしたVivado Design Edition 2017.2 をアンインストールして、Vivado Design Edition 2017.2 をインストールした。
再再度、source hdk_setup.shを実行した。今度は通った。図は始まりと終わりを示す。
aws-fpga_7_170709.png
aws-fpga_8_170709.png

全部のログを示す。

masaaki@masaaki-VirtualBox:~/aws-fpga$ source hdk_setup.sh 
INFO: Using Vivado v2017.1 (64-bit)
INFO: Setting up environment variables
INFO: Using HDK shell version shell_v04151701
INFO: HDK shell is up-to-date
INFO: DDR4 model files in /home/masaaki/aws-fpga/hdk/common/verif/models/ddr4_model/ do NOT exist. Running model creation step.
INFO:   Building in /home/masaaki/aws-fpga/ddr4_model_build
INFO:   This could take 5-10 minutes, please be patient!
/home/masaaki/aws-fpga/hdk/common/verif/scripts/init.sh: 18: /home/masaaki/aws-fpga/hdk/common/verif/scripts/init.sh: [[: not found
/home/masaaki/aws-fpga/hdk/common/verif/scripts/init.sh: 23: /home/masaaki/aws-fpga/hdk/common/verif/scripts/init.sh: [[: not found
/home/masaaki/aws-fpga/hdk/common/verif/scripts/init.sh: 29: /home/masaaki/aws-fpga/hdk/common/verif/scripts/init.sh: [[: not found

****** Vivado v2017.1 (64-bit)
  **** SW Build 1846317 on Fri Apr 14 18:54:47 MDT 2017
  **** IP Build 1846188 on Fri Apr 14 20:52:08 MDT 2017
    ** Copyright 1986-2017 Xilinx, Inc. All Rights Reserved.

source /home/masaaki/aws-fpga/hdk/common/verif/scripts/init.tcl
# set_msg_config -severity INFO -suppress
# set_msg_config -severity STATUS -suppress
# set_msg_config -severity WARNING -suppress
CRITICAL WARNING: [Common 17-1355] You are suppressing all messages of type 'WARNING'. You may potentially disregard important DRC, CDC, and implementation messages that can negatively impact your design.  If this is not desired, please run 'reset_msg_config -suppress -severity {WARNING}' to undo this change.
# set_msg_config -string {exportsim} -suppress
# set_msg_config -string {IP_Flow} -suppress
# create_project -force tmp_ddr ./tmp -part xcvu9p-flgb2104-2-i 
# add_files -norecurse $::env(HDK_COMMON_DIR)/shell_stable/design/ip/ddr4_core/ddr4_core.xci
INFO: [IP_Flow 19-234] Refreshing IP repositories
INFO: [IP_Flow 19-1704] No user IP repositories specified
INFO: [IP_Flow 19-2313] Loaded Vivado IP repository '/opt/Xilinx/Vivado/2017.1/data/ip'.
add_files: Time (s): cpu = 00:00:05 ; elapsed = 00:00:07 . Memory (MB): peak = 1308.211 ; gain = 213.969 ; free physical = 474 ; free virtual = 18367
# export_ip_user_files -of_objects  [get_files  $::env(HDK_COMMON_DIR)/shell_stable/design/ip/ddr4_core/ddr4_core.xci] -force -quiet
# open_example_project -force -dir ./tmp/tmp_ddr_ex [get_ips  ddr4_core]
INFO: [IP_Flow 19-1686] Generating 'Examples' target for IP 'ddr4_core'...
INFO: [Device 21-403] Loading part xcvu9p-flgb2104-2-i

****** Vivado v2017.1 (64-bit)
  **** SW Build 1846317 on Fri Apr 14 18:54:47 MDT 2017
  **** IP Build 1846188 on Fri Apr 14 20:52:08 MDT 2017
    ** Copyright 1986-2017 Xilinx, Inc. All Rights Reserved.

source /home/masaaki/aws-fpga/hdk/common/shell_stable/design/ip/ddr4_core/ddr4_core_ex.tcl -notrace
INFO: [open_example_project] Creating new example project...
INFO: [open_example_project] Importing original IP ...
INFO: [IP_Flow 19-234] Refreshing IP repositories
INFO: [IP_Flow 19-1704] No user IP repositories specified
INFO: [IP_Flow 19-2313] Loaded Vivado IP repository '/opt/Xilinx/Vivado/2017.1/data/ip'.
import_ip: Time (s): cpu = 00:00:05 ; elapsed = 00:00:06 . Memory (MB): peak = 1316.215 ; gain = 8.012 ; free physical = 219 ; free virtual = 17375
INFO: [open_example_project] Generating the example project IP ...
INFO: [open_example_project] Adding example synthesis HDL files ...
INFO: [open_example_project] Adding example XDC files ...
INFO: [open_example_project] Adding simulation HDL files ...
INFO: [open_example_project] Sourcing example extension scripts ...
Post processing the example_design
update_compile_order: Time (s): cpu = 00:00:08 ; elapsed = 00:00:09 . Memory (MB): peak = 1316.645 ; gain = 0.418 ; free physical = 311 ; free virtual = 17369
INFO: [open_example_project] Rebuilding all the top level IPs ...
INFO: [exportsim-Tcl-35] Exporting simulation files for "XSIM" (Xilinx Vivado Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/xsim/ddr4_core.sh'
Generating merged BMM file for the design top 'sim_tb_top'...
Generating merged BMM file for the design top 'sim_tb_top'...
INFO: [exportsim-Tcl-35] Exporting simulation files for "MODELSIM" (Mentor Graphics ModelSim Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/modelsim/ddr4_core.sh'
INFO: [exportsim-Tcl-35] Exporting simulation files for "QUESTA" (Mentor Graphics Questa Advanced Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/questa/ddr4_core.sh'
INFO: [exportsim-Tcl-35] Exporting simulation files for "IES" (Cadence Incisive Enterprise Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/ies/ddr4_core.sh'
INFO: [exportsim-Tcl-35] Exporting simulation files for "VCS" (Synopsys Verilog Compiler Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/vcs/ddr4_core.sh'
INFO: [exportsim-Tcl-35] Exporting simulation files for "RIVIERA" (Aldec Riviera-PRO Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/riviera/ddr4_core.sh'
INFO: [exportsim-Tcl-35] Exporting simulation files for "ACTIVEHDL" (Aldec Active-HDL Simulator)...
INFO: [exportsim-Tcl-29] Script generated: '/home/masaaki/aws-fpga/ddr4_model_build/tmp/tmp_ddr_ex/ddr4_core_ex/ddr4_core_ex.ip_user_files/sim_scripts/ddr4_core/activehdl/ddr4_core.sh'
INFO: [open_example_project] Open Example Project completed
INFO: [Common 17-206] Exiting Vivado at Sun Jul  9 18:03:27 2017...
open_example_project: Time (s): cpu = 00:00:36 ; elapsed = 00:00:44 . Memory (MB): peak = 2018.074 ; gain = 678.875 ; free physical = 531 ; free virtual = 17600
# exit
INFO: [Common 17-206] Exiting Vivado at Sun Jul  9 18:03:28 2017...
Copying files to /home/masaaki/aws-fpga/hdk/common/verif/models/ddr4_model
Copying files to /home/masaaki/aws-fpga/hdk/common/verif/models/ddr4_rdimm_wrapper
INFO: DDR4 model build passed.
INFO: ATTENTION: Don't forget to set the CL_DIR variable for the directory of your Custom Logic.
INFO: AWS HDK setup PASSED.
masaaki@masaaki-VirtualBox:~/aws-fpga$ 


何がどうなっているか、よくわからないがとにかく通った。

~/aws-fpga/hdk/cl/examples を見ると、cl_dram_dma, cl_hello_world, common のディレクトリがある。
そのうちの cl_hello_world をやってみることにする。
aws-fpga_9_170709.png

~/aws-fpga/hdk/cl/examples/cl_hello_world/build/scripts ディレクトリに行ってみた。
aws-fpga_10_170709.png

Vivado のプロジェクトはないので、「How to build and submit your Custom Logic (CL) to AWS」を参考に、とりあえず、~/aws-fpga/hdk/cl/examples/cl_hello_world/build/scripts ディレクトリで
./aws_build_dcp_from_cl.sh
をやってみたが、エラーになってしまった。
aws-fpga_11_170710.png

エラーの内容は、

ERROR: YOUR INSTANCE has less memory than is necessary for certain builds. This means that your builds will take longer than expected.
To change to an instance type with more memory, please check our instance resize guide: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-resize.html

で、メモリは10GB 程度割り当てているのだが、だめだそうだ。
やはり、この辺りはAWS EC2 F1 インスタンスを使ってビルドするしかないのかもしれない?
  1. 2017年07月10日 04:36 |
  2. AWS-FPGA
  3. | トラックバック:0
  4. | コメント:2

「メアリと魔女の花」(映画)を見てきました

今日は、「メアリと魔女の花」(映画)を見てきました。良くも悪くもジブリらしい映画でした。
良かったのですが、もうちょっと、新機軸のアニメ映画を見てみたい気もしました。
  1. 2017年07月09日 20:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ubuntu 16.04 にVivado Design Edition がインストールできない

Ubuntu 16.04 にVivado のDesign Edition がインストールできない。(現在のバージョンは、2017.2)

理由は、HostID が ”000000000000”になってしまうからだ。
HostID_all0_1_170709.png

原因は、Ubuntu 16 では、イーサネットの名前が enp0s3 とかになってしまって、eth0 が無くなってしまったからのようだ。
HostID_all0_2_170709.png

AR# 60510 ライセンス - Vivado License Manager (VLM) に使用するマシンの HostID が「000000000000」と表示される”を見つけてやってみたが、私のUbuntu 16.04 ではファイルが無いと言われてダメだった。

Vivado のライセンス・マネージャーがUbuntu 16.04 に対応してくれることを望む。
(2017/07/10:まっちゃんさんのアドバイスのおかげで eth0 にできました。ありがとうございました。詳しくはコメント欄をご覧ください。)

なお、WebPACKはライセンスが必要ないので、問題なくインストールすることができた。
Ubuntu16.04にVivado 2016.4をインストール”を参照。
  1. 2017年07月09日 08:48 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:3

手書き数字認識用畳み込みニューラルネットワーク回路の製作7(ハードとソフトの比較)

手書き数字認識用畳み込みニューラルネットワーク回路の製作6(PYNQボードで動作確認)”の続き。

前回は、mnist_conv_nn_test.c を作成して、手書き数字を認識してみたところ、今のところ 100 % の精度で手書き数字を認識することができた。今回は、ハードウェアのMNISTの手書き数字を認識する時間とソフトウェアでMNISTの手書き数字を認識する時間を比較してみようと思う。

ハードウェアの手書き数字を認識時間とソフトウェアの手書き数字を認識時間を比べるためにmnist_conv_soft_test.c を作成した。ソフトウェアの手書き数字の認識は、float で演算している。更に、カーソルを動かすのが面倒なため、それぞれの方向キーをシフトキーを押したときに、5ピクセルずつ移動できるように改良した。なお、時間の計測には、”SDKのベアメタル・アプリケーションで時間を計測する方法(Zynq)”で試したXTime_GetTime() を使用している。
hand_draw_num_100_170708.png

mnist_conv_soft_test.elf を起動して、1 を認識してみた。
hand_draw_num_90_170706.png

ハードウェアの実行時間は 12.9 ms 程度、ソフトウェアの実行時間は 34.2 ms 程度だった。ハードウェアの方がソフトウェアより、約 2.66 倍速い。

2 を認識してみた。
hand_draw_num_91_170706.png

3 を認識してみた。
hand_draw_num_92_170706.png

4 を認識してみた。
hand_draw_num_93_170706.png

5 を認識してみた。
hand_draw_num_94_170706.png

6 を認識してみた。
hand_draw_num_95_170706.png

7 を認識してみた。
hand_draw_num_96_170706.png

8 を認識してみた。
hand_draw_num_97_170706.png

9 を認識してみた。
hand_draw_num_98_170706.png

0 を認識してみた。
hand_draw_num_99_170706.png

ハードウェアの実行時間はほとんど変動はない。ソフトウェアの実行時間にもそれほど変動はないので、約 2.7 倍ハードウェアの方が速いという結果だった。ハードウェア、ソフトウェア共に精度は今のところ 100 % だった。
ソフトウェアの方が float というハンデはあるが、ハードウェアの方が速かった。だが、ソフトウェアもチューニングするとどうなるかわからないと思う。まあ、ハードウェアにオフロードして、仕様を満足できたので良かったと思う。

最後に、mnist_conv_soft_test.c を貼っておく。
なお、

float buf[28][28];
float conv_out[10][24][24];
float pool_out[10][12][12];
float dot1[100];
float dot2[10];

をグローバル変数にしたのは、ローカル変数にしていては動作がおかしかったからだ。スタックに積むことができる大きさに制限があるのかもしれない?

/* * mnist_conv_soft_test.c * *  Created on: 2017/07/06 *      Author: ono */

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#include "xgpio.h"
#include "xtime_l.h"

#include "xmnist_conv_nn.h"
#include "xsquare_frame_gen.h"
#include "af1_bias_float.h"
#include "af1_weight_float.h"
#include "af2_bias_float.h"
#include "af2_weight_float.h"
#include "conv1_bias_float.h"
#include "conv1_weight_float.h"

#define FRAME_BUFFER_ADDRESS 0x10000000
#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

int max_int(int out[10]);
int max_float(float out[10]);
int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]);
float conv_rgb2y_soft(int rgb);

static XAxiVdma_DmaSetup Vdma0_WriteCfg;
float buf[28][28];
float conv_out[10][24][24];
float pool_out[10][12][12];
float dot1[100];
float dot2[10];

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XMnist_conv_nn mcnn;
    XSquare_frame_gen sf_gen;
    int inbyte_in;
    int xval, yval;
    int i, res;
    int result[10];
    float result_float[10];
    static XGpio GPIOInstance_Ptr;
    int XGpio_Status;
    int max_id;
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;
    int result_disp = 0;
    int conv_addr;
    int max_id_float;
    XTime start_time, end_time;

    // AXI VDMA Initialization sequence
    XAxiVdma0_Config = XAxiVdma_LookupConfig(XPAR_CAMERA_INTERFACE_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
    if (XAxiVdma0_Config == NULL){
        fprintf(stderr, "No AXI VDMA found\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() failed\n");
        return(-1);
    }

    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.

    Vdma0_WriteCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_WriteCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_WriteCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_WriteCfg.FrameDelay = 0// Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_WriteCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_WriteCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_WriteCfg.PointNum = 0// No Gen-Lock
    Vdma0_WriteCfg.EnableFrameCounter = 0// Endless transfers
    Vdma0_WriteCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
        return(-1);
    }

    // Frame buffer address set
    unsigned int frame_addr = (unsigned int)FRAME_BUFFER_ADDRESS;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma0_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        //frame_addr += HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * VERTICAL_LINES;
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed\n");
        return(-1);
    }

    // Mnist_conv_nn, Square_frame_gen Initialize
    XMnist_conv_nn_Initialize(&mcnn, 0);
    XSquare_frame_gen_Initialize(&sf_gen, 0);

    // square_frame_gen initialize
    XSquare_frame_gen_Set_x_pos(&sf_gen, HORIZONTAL_PIXELS/2);
    xval = HORIZONTAL_PIXELS/2;
    XSquare_frame_gen_Set_y_pos(&sf_gen, VERTICAL_LINES/2);
    yval = VERTICAL_LINES/2;
    XSquare_frame_gen_Set_width(&sf_gen, 28);
    XSquare_frame_gen_Set_height(&sf_gen, 28);
    XSquare_frame_gen_Set_off_on(&sf_gen, 1); // on

    // XSquare_frame_gen start
    XSquare_frame_gen_DisableAutoRestart(&sf_gen);
    while(!XSquare_frame_gen_IsIdle(&sf_gen)) ;
    XSquare_frame_gen_Start(&sf_gen);
    XSquare_frame_gen_EnableAutoRestart(&sf_gen);

    // mnist_conv_nn initialize
    XMnist_conv_nn_Set_addr_offset(&mcnn, HORIZONTAL_PIXELS/2);
    XMnist_conv_nn_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*(VERTICAL_LINES/2)*sizeof(int));

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x0); // square_frame_gen enable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x1);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers

    // VDMA start
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed\n");
        return(-1);
    }

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cntrler_axi_master_0
    volatile unsigned int *bmdc_axi_lites;
    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    bmdc_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;

    bmdc_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller start
    mt9d111_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(mt9d111_i2c_axi_lites);

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf00x1);      // Changed regster map to IFP page 1
    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x970x20);        // RGB Mode, RGB565

    mt9d111_axi_lites[1] = 0// One_shot_mode is disabled

    // AXI GPIO Initialization
    XGpio_Status = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID);
    if(XST_SUCCESS != XGpio_Status)
        print("GPIO INIT FAILED\n\r");
    // AXI GPIO Set the Direction(output setting)
    XGpio_SetDataDirection(&GPIOInstance_Ptr, 10);

    while(1){
        printf("mnist_conv_nn_test, <h> : left, <k> : up, <j> : down, <l> : right, <q> : exit\n");
        inbyte_in = inbyte();
        switch(inbyte_in) {
            case 'h' : // left
            case 'H' : // left -5
                if(inbyte_in == 'h' && xval > 0)
                    --xval;
                else if(inbyte_in == 'H' && xval >= 5)
                    xval -= 5;
                XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                XMnist_conv_nn_Set_addr_offset(&mcnn, xval);
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'l' : // right
            case 'L' : // right +5
                if(inbyte_in == 'l' && xval < HORIZONTAL_PIXELS-28)
                    xval++;
                else if(inbyte_in == 'L' && xval <= HORIZONTAL_PIXELS-28-5)
                    xval += 5;
                XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                XMnist_conv_nn_Set_addr_offset(&mcnn, xval);
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'k' : // up
            case 'K' : // up -5
                if(inbyte_in == 'k' && yval > 0)
                    --yval;
                else if(inbyte_in == 'K' && yval >= 5)
                    yval -= 5;
                XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                XMnist_conv_nn_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int));
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'j' : // down
            case 'J' : // down +5
                if(inbyte_in == 'j' && xval < VERTICAL_LINES-28)
                    yval++;
                else if(inbyte_in == 'J' && xval <= VERTICAL_LINES-28-5)
                    yval += 5;
                XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                XMnist_conv_nn_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int));
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'r' : // result check
                result_disp = 1;
                break;
            case 'q' : // exit
                return(0);
        }

        if(result_disp){
            printf("\nHardware\n");
            // XMnist_conv_nn start
            XMnist_conv_nn_DisableAutoRestart(&mcnn);
            while(!XMnist_conv_nn_IsIdle(&mcnn));
            XTime_GetTime(&start_time);
            XMnist_conv_nn_Start(&mcnn);
            while(!XMnist_conv_nn_IsIdle(&mcnn));
            XTime_GetTime(&end_time);
            printf("conv_time = %f ms\n", (float)((long)end_time-(long)start_time)/325000.0);

            // mnist cnn result check
            for(i=0; i<5; i++){
                XMnist_conv_nn_Read_out_V_Words(&mcnn, i, &res, 1);
                result[i*2] = res & 0x0fff;
                if(result[i*2] & 0x800// minus
                    result[i*2] = 0xfffff000 | result[i*2]; // Sign extension

                result[i*2+1] = (res & 0x0fff0000) >> 16;
                if(result[i*2+1] & 0x800// minus
                    result[i*2+1] = 0xfffff000 | result[i*2+1]; // Sign extension
            }

            max_id = max_int(result);
            XGpio_DiscreteWrite(&GPIOInstance_Ptr, 1, max_id);

            for(i=0; i<10; i++){
                printf("result[%d] = %x\n", i, result[i]);
            }
            printf("max_id = %d\n", max_id);

            printf("\nSoftware\n");
            conv_addr = FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int);
            XTime_GetTime(&start_time);
            mnist_conv_nn_float((int *)conv_addr, xval, result_float);
            XTime_GetTime(&end_time);
            max_id_float = max_float(result_float);
            printf("conv_time = %f ms\n", (float)((long)end_time-(long)start_time)/325000.0);
            for(i=0; i<10; i++){
                printf("result_float[%d] = %f\n", i, result_float[i]);
            }
            printf("max_id_float = %d\n", max_id_float);

            result_disp = 0;
        }
    }
}

int max_int(int out[10]){
    int max_id;
    int max, i;

    for(i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]){

    // 手書き数字の値を表示
    /*for (int i=0; i<28; i++){        for (int j=0; j<800; j++){            if (j>=addr_offset && j<addr_offset+28)                printf("%2x, ", (int)(conv_rgb2y_soft(in[i*800+j])*256.0));        }        printf("\n");    } */

    buf_copy1: for(int i=0; i<28; i++){
        buf_copy2: for(int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                buf[i][j-addr_offset] = (float)0.99609375 - (float)conv_rgb2y_soft(in[i*800+j]);
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<10; i++){    // カーネルの個数
        CONV2: for(int j=0; j<24; j++){
            CONV3: for(int k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_fweight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_fbias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<10; i++){
        POOL2: for(int j=0; j<24; j += 2){
            POOL3: for(int k=0; k<24; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<10; i++){
            af1_dot3: for(int j=0; j<12; j++){
                af1_dot4: for(int k=0; k<12; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<10; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_fweight[row][col];
        }
        dot2[col] += af2_fbias[col];

        out[col] = dot2[col];
    }

    return(0);
}

int max_float(float out[10]){
    int max_id;
    float max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}


// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
// 2017/06/30 : retval を float にした
float conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;
    float y_float;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    if (y >= 256)
        y = 255;

    y_float = (float)y/256.0;

    return(y_float);
}

  1. 2017年07月08日 04:50 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

SDKのベアメタル・アプリケーションで時間を計測する方法(Zynq)

SDKのベアメタル・アプリケーションで時間を計測する方法とPYNQボードでのテストについて書いておく。

なお、”ZYBOでのベアメタルの時刻取得方法について”を参照させて頂いた。ありがとうございます。

ZYBOでのベアメタルの時刻取得方法について”によると、XTime_GetTime() を使用するそうだ。そして、Zynq のCortex-A9 プロセッサのクロックの1/2 の周波数でタイマーが動作しているとのことだった。
PYNQボードの動作クロックを見てみたが、650 MHz だったので、325 MHz で動作しているということで間違いないようだ。

私もアプリケーションソフトの xttime_test を作成して、XTime_GetTime() についてテストしてみた。使用した基板はPYNQボードだ。
XTtime_test_1_170707.png

xttime_test.elf を起動すると、1.000246 ms と表示された。
XTtime_test_2_170707.png

usleep(1000) を行っているので、1 ms のはずだ。大体合っている。

次に、usleep(1000); をコメントアウトして、sleep(10); のコメントアウトを外した。
XTtime_test_3_170707.png

10000.000252 ms なので、10 秒だ。別にストップウォッチでも計ってみたが、合っている。大丈夫そうだ。
XTime_GetTime() は経過時間の計測に使えるということが分かった。

xttime_test.c を貼っておく。

/* * xttime_test.c * *  Created on: 2017/07/06 *      Author: Ono */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "xtime_l.h"

int main(){
    XTime start_time, end_time;

    printf("Start\n");
    XTime_GetTime(&start_time);
    usleep(1000);
    //sleep(10);
    XTime_GetTime(&end_time);
    printf("end\n");

    printf("usleep_time = %lf ms\n", (double)((long long int)end_time-(long long int)start_time)/325000.0);
}

  1. 2017年07月07日 04:35 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

手書き数字認識用畳み込みニューラルネットワーク回路の製作6(PYNQボードで動作確認)

手書き数字認識用畳み込みニューラルネットワーク回路の製作5(SDK)”の続き。

前回は、カメラで撮影した画像の内の四角枠の領域の手書き数字を認識するPYNQボード用のVivado 2017.2プロジェクトで、SDKを使用してカメラ画像を表示した。今回は、mnist_conv_nn_test.c を作成して、手書き数字を認識してみよう。

まずは、SDK でベアメタル・アプリケーションソフトの mnist_conv_nn_test.c を作成した。
hand_draw_num_89_170706.png

PYNQボードにMT9D111カメラモジュールを搭載したシステムで、手書きの数字を撮影した。
hand_draw_num_78_170705.jpg

画像にピンクの四角枠が表示され、PYNQボードのシリアルインターフェイスに接続されたTera Term の k キーを押すと1ピクセル左に、j キーを押すと1ピクセル下に、k キーを押すと1ピクセル上に、l キーを押すと1ピクセル右に移動する。 r キーを押すと、0 ~ 10 までの値が表示され、最大値 (max_id) の値が表示される。 q キーでexit する。
更に、GPIOに接続されたLEDが、最大値 (max_id) の値を2進数で表示する。

さて、キー操作で、ピンクの四角枠を移動して、数字を指定する。
まずは、1 を認識してみよう。
hand_draw_num_79_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。result[0] ~ result[9] はそれぞれの値の手書き数字の値を示す。その最大値 (max_id) は 1 なので、1 と判定された。なお、max_id はint で 2 の補数表示となっている。
hand_draw_num_68_170705.png

つぎは、2 を認識してみよう。
hand_draw_num_80_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 2 と認識されている。
hand_draw_num_69_170705.png

3 を認識してみよう。
hand_draw_num_81_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 3 と認識されている。
hand_draw_num_70_170705.png

4 を認識してみよう。
hand_draw_num_82_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 4 と認識されている。
hand_draw_num_71_170705.png

5 を認識してみよう。
hand_draw_num_83_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 5 と認識されている。
hand_draw_num_72_170705.png

6 を認識してみよう。
hand_draw_num_84_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 6 と認識されている。
hand_draw_num_73_170705.png

7 を認識してみよう。
hand_draw_num_85_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 7 と認識されている。
hand_draw_num_74_170705.png

8 を認識してみよう。
hand_draw_num_86_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 8 と認識されている。
hand_draw_num_75_170705.png

9 を認識してみよう。
hand_draw_num_87_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 9 と認識されている。
hand_draw_num_76_170705.png

0 を認識してみよう。
hand_draw_num_88_170705.jpg

パソコンで立ち上げたTera Term の画面を示す。 0 と認識されている。
hand_draw_num_77_170705.png

今のところ精度は 100 % だった。うまく行ったようだ。
手書き数字を認識する領域であるピンクの四角枠をキーで移動できるので、カメラの位置を細かく合わせる必要がなく、とってもやりやすい。

最後に mnist_conv_nn_test.c を貼っておく。

/* * mnist_conv_nn_test.c * *  Created on: 2017/07/03 *      Author: Masaaki */

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#include "xgpio.h"

#include "xmnist_conv_nn.h"
#include "xsquare_frame_gen.h"

#define FRAME_BUFFER_ADDRESS 0x10000000
#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

int max_int(int out[10]);

static XAxiVdma_DmaSetup Vdma0_WriteCfg;

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XMnist_conv_nn mcnn;
    XSquare_frame_gen sf_gen;
    int inbyte_in;
    int xval, yval;
    int i, res;
    int result[10];
    static XGpio GPIOInstance_Ptr;
    int XGpio_Status;
    int max_id;
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;
    int result_disp = 0;

    // AXI VDMA Initialization sequence
    XAxiVdma0_Config = XAxiVdma_LookupConfig(XPAR_CAMERA_INTERFACE_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
    if (XAxiVdma0_Config == NULL){
        fprintf(stderr, "No AXI VDMA found\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() failed\n");
        return(-1);
    }

    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.

    Vdma0_WriteCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_WriteCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_WriteCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_WriteCfg.FrameDelay = 0// Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_WriteCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_WriteCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_WriteCfg.PointNum = 0// No Gen-Lock
    Vdma0_WriteCfg.EnableFrameCounter = 0// Endless transfers
    Vdma0_WriteCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
        return(-1);
    }

    // Frame buffer address set
    unsigned int frame_addr = (unsigned int)FRAME_BUFFER_ADDRESS;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma0_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        //frame_addr += HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * VERTICAL_LINES;
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed\n");
        return(-1);
    }

    // Mnist_conv_nn, Square_frame_gen Initialize
    XMnist_conv_nn_Initialize(&mcnn, 0);
    XSquare_frame_gen_Initialize(&sf_gen, 0);

    // square_frame_gen initialize
    XSquare_frame_gen_Set_x_pos(&sf_gen, HORIZONTAL_PIXELS/2);
    xval = HORIZONTAL_PIXELS/2;
    XSquare_frame_gen_Set_y_pos(&sf_gen, VERTICAL_LINES/2);
    yval = VERTICAL_LINES/2;
    XSquare_frame_gen_Set_width(&sf_gen, 28);
    XSquare_frame_gen_Set_height(&sf_gen, 28);
    XSquare_frame_gen_Set_off_on(&sf_gen, 1); // on

    // XSquare_frame_gen start
    XSquare_frame_gen_DisableAutoRestart(&sf_gen);
    while(!XSquare_frame_gen_IsIdle(&sf_gen)) ;
    XSquare_frame_gen_Start(&sf_gen);
    XSquare_frame_gen_EnableAutoRestart(&sf_gen);

    // mnist_conv_nn initialize
    XMnist_conv_nn_Set_addr_offset(&mcnn, HORIZONTAL_PIXELS/2);
    XMnist_conv_nn_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*(VERTICAL_LINES/2)*sizeof(int));

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x0); // square_frame_gen enable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x1);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers

    // VDMA start
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed\n");
        return(-1);
    }

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cntrler_axi_master_0
    volatile unsigned int *bmdc_axi_lites;
    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    bmdc_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;

    bmdc_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller start
    mt9d111_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(mt9d111_i2c_axi_lites);

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf00x1);      // Changed regster map to IFP page 1
    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x970x20);        // RGB Mode, RGB565

    mt9d111_axi_lites[1] = 0// One_shot_mode is disabled

    // XMnist_conv_nn start
    XMnist_conv_nn_DisableAutoRestart(&mcnn);
    while(!XMnist_conv_nn_IsIdle(&mcnn));
    XMnist_conv_nn_Start(&mcnn);
    XMnist_conv_nn_EnableAutoRestart(&mcnn);

    // AXI GPIO Initialization
    XGpio_Status = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID);
    if(XST_SUCCESS != XGpio_Status)
        print("GPIO INIT FAILED\n\r");
    // AXI GPIO Set the Direction(output setting)
    XGpio_SetDataDirection(&GPIOInstance_Ptr, 10);

    while(1){
        printf("mnist_conv_nn_test, <h> : left, <k> : up, <j> : down, <l> : right, <q> : exit\n");
        inbyte_in = inbyte();
        switch(inbyte_in) {
            case 'h' : // left
                if(xval > 0){
                    --xval;
                    XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                    XMnist_conv_nn_Set_addr_offset(&mcnn, xval);
                    printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                }
                break;
            case 'l' : // right
                if(xval < HORIZONTAL_PIXELS-28){
                    xval++;
                    XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                    XMnist_conv_nn_Set_addr_offset(&mcnn, xval);
                    printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                }
                break;
            case 'k' : // up
                if(yval > 0){
                    --yval;
                    XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                    XMnist_conv_nn_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int));
                    printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                }
                break;
            case 'j' : // down
                if(yval < VERTICAL_LINES-28){
                    yval++;
                    XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                    XMnist_conv_nn_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int));
                    printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                }
                break;
            case 'r' : // result check
                result_disp = 1;
                break;
            case 'q' : // exit
                return(0);
        }

        // mnist cnn result check
        for(i=0; i<5; i++){
            XMnist_conv_nn_Read_out_V_Words(&mcnn, i, &res, 1);
            result[i*2] = res & 0x0fff;
            if(result[i*2] & 0x800// minus
                result[i*2] = 0xfffff000 | result[i*2]; // Sign extension

            result[i*2+1] = (res & 0x0fff0000) >> 16;
            if(result[i*2+1] & 0x800// minus
                result[i*2+1] = 0xfffff000 | result[i*2+1]; // Sign extension
        }

        max_id = max_int(result);
        XGpio_DiscreteWrite(&GPIOInstance_Ptr, 1, max_id);

        if(result_disp){
            for(i=0; i<10; i++){
                printf("result[%d] = %x\n", i, result[i]);
            }
            printf("max_id = %d\n", max_id);
            result_disp = 0;
        }
    }
}

int max_int(int out[10]){
    int max_id;
    int max, i;

    for(i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

  1. 2017年07月06日 05:03 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

SDK における inbyte() の使用

Vivado のSDK でベアメタルのアプリケーションソフトを作っているときに、キー入力を使用するが、その際にfgetc() , scanf() などを使用してキー入力すると、リターンキーが押されるまで処理が戻ってこなかったりする。それだと都合が悪い場合は、fflush(stdin) を使用すると思う。

Xilinx のSDKでは inbyte() という、1バイトのキー入力ルーチンがある。ブロックされて、1文字入力するまで戻ってこないが、リターンキーを待ってはいないので、一文字入力すると関数コールから帰ってくる。(ベアメタルのみでLinuxでは使えません。Linuxでのノンブロッキングのキー入力については、「Linux の C 言語でノンブロッキングキー入力をする」を参照してください)

    while(1){
        print("********************** LED4 TEST Start ***********************\n\r");
        print("TeraTerm: Please Set Local Echo Mode.\n\r");
        print("Press '1' to show all registers\n\r");
        print("Press '2' to set LED4 Enable or Disable(Toggle, Command Register)\n\r");
        print("Press '3' to set LED Counter Load Register (4bits, Please input hexadecimal)\n\r");
        print("Press '4' to set LED Interval Register (32bits, Please input decimal)\n\r");
        print("Press '5' to exit\n\r");
        print("Selection : ");
        inbyte_in = inbyte();
        print(" \r\n");
        print(" \r\n");

        switch(inbyte_in) {
            case '1' : // Show all registers
                val = (int)Xil_In32((u32)XPAR_LED4IP_0_S_AXI_BASEADDR);
                printf("Command Register is %x\r\n", val);
                val = (int)Xil_In32((u32)(XPAR_LED4IP_0_S_AXI_BASEADDR+4));
                printf("LED Counter Load Register is %x\r\n", val);
                val = (int)Xil_In32((u32)(XPAR_LED4IP_0_S_AXI_BASEADDR+8));
                printf("LED Monitor Register is %x\r\n", val);
                val = (int)Xil_In32((u32)(XPAR_LED4IP_0_S_AXI_BASEADDR+0xc));
                printf("LED Interval Register is %d (decimal)\r\n", val);
                break;
            case '2' : // Set LED4 Enable or Disable(Toggle, Command Register)


メニューを表示して、inbyte() でキー入力を待つ。1文字の数字を押してすぐに、その処理ルーチンに飛ぶようになっている。数字を入力して、リターンキーを押さなくて済むので便利だ。
  1. 2017年07月04日 05:15 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

手書き数字認識用畳み込みニューラルネットワーク回路の製作5(SDK)

手書き数字認識用畳み込みニューラルネットワーク回路の製作4(Vivadoプロジェクト)”の続き。

前回は、手書き数字認識用四角枠表示回路(IP)と、手書き数字を認識する畳み込みニューラルネットワークIP を使用してカメラで撮影した画像の内の四角枠の領域の手書き数字を認識するPYNQボード用のVivado 2017.2プロジェクトを作成した。今回は、SDKを使用してカメラ画像を表示してみよう。

Vivado プロジェクトのインプリメントが成功したので、ハードウェアをエクスポートして、SDK を立ち上げた。

FASTX コーナー検出の時に使用していた cam_disp_axis.c はそのまま使用できるので、cam_disp_axis アプリケーション・プロジェクトを作成して、cam_disp_axis.c をソースコードとして、src フォルダにコピーした。
hand_draw_num_66_170702.png

SDK のXilinx Tools メニューから、Program FPGAを選択して、Zynq をコンフィギュレーションした。
cam_disp_axis.elf を起動したらカメラ画像が表示された。
hand_draw_num_67_170704.jpg

次回は、アプリケーションソフトを作成して、四角枠を表示して、その枠内の手書き数字の値をLED に表示してみたい。
  1. 2017年07月04日 05:03 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

手書き数字認識用畳み込みニューラルネットワーク回路の製作4(Vivadoプロジェクト)

手書き数字認識用畳み込みニューラルネットワーク回路の製作3(畳み込みNN)”の続き。

前回は、カメラのフレームバッファから直接DMA で画像データを持ってきて手書き数字を認識する畳み込みニューラルネットワークで手書き数字を認識するIP を作成した。
今回は、手書き数字認識用四角枠表示回路(IP)と、手書き数字を認識する畳み込みニューラルネットワークIP を使用してカメラで撮影した画像の内の四角枠の領域の手書き数字を認識するPYNQボード用のVivado 2017.2プロジェクトを作成する。

ペースとなるVivado プロジェクトとしては、PYNQ用のFASTX コーナー検出プロジェクトを使用する。その画像フィルタの代わりに、手書き文字認識用四角枠表示回路を挿入する。手書き数字を認識する畳み込みニューラルネットワークIPはAXI_HP0 のAXI Interconnect に接続することにしよう。

PYNQ_MNIST_CMM_172 フォルダのVivado 2017.2 プロジェクトを示す。プロジェクト名は、FASTX コーナー検出jのPYNQ_FASTX_164 のままだ。
hand_draw_num_62_170702.png

ブロックデザインを示す。mnist_conv_nn_0 が中央付近にあるのが分かる。
hand_draw_num_63_170702.png

camera_interface モジュールを示す。
hand_draw_num_64_170702.png

論理合成、インプリメント、ビットストリームの生成を行った。
hand_draw_num_65_170702.png

成功した。
ちなみに、Linux版Vivado HLS 2016.4 のIP を使用しているが、Estimated が 10.07 ns のWindowsのVivado HLS 2016.4 では、タイミングがメットしなかった。論理合成のストラテジーを変えてもだめだった。いろいろと微妙のようだ。結構、Vivado HLS のタイミングの予測が正しいみたいだ。
  1. 2017年07月03日 04:52 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

手書き数字認識用畳み込みニューラルネットワーク回路の製作3(畳み込みNN)

手書き数字認識用畳み込みニューラルネットワーク回路の製作2(手書き数字認識用四角枠表示回路)”の続き。

前回は、手書き数字認識用四角枠表示回路が完成した。これで画像中に認識する四角枠を表示することができた。この四角枠の中に手書き数字を入れれば認識することができる。今回は、四角枠の中の手書き数字を認識する畳み込みニューラルネットワークを作成しよう。
この畳み込みニューラルネットワークは、画像中の四角枠の中の手書き数字をDMA で持ってきて、畳み込みニューラルネットワークを通すことになる。するとDMA はストライド付きのDMA となる。
下の図で画像は 800 ピクセル x 600 行なので、0 の手書き数字の領域は最初の行で 28 ピクセルを読み込んだら次の行の手書き数字のピクセルは 800 - 28 個目にあることになる。よって、畳み込みニューラルネットワークには、下の図の緑色の領域のピクセルを渡して、ストライドを付けてDMAすることにする。
hand_draw_num_52_170630.png

C シミュレーションができないため、VirtualBox 上のUbuntu 16.04 でVivado HLS 2016.4 を起動してmnist_conv_nn10_sDMA プロジェクトを作成した。なお、カメラ・インターフェース回路からDDR3 メモリ上にDMA Write されたデータを直接DMA でRead するため入力ポートになる引数の型はap_ufixed からint に変更した。
hand_draw_num_53_170630.png

最初に C シミュレーションを行った。
最初に表示される 28 x 28 の数字は画像から切り出された 28 x 28 の手書き数字のピクセル値を表している。これは手書き数字の 8 だ。他にも0, 5, 7 について同様にC シミュレーションを行ったが正解だった。
その後で、ハードウエアでの認識結果(max_id_hw)とソフトウェアでの認識結果(max_id_sw)が表示されている。両方とも正しい。
hand_draw_num_61_170701.jpg

hand_draw_num_54_170630.png

C コードの合成を行った。
hand_draw_num_55_170630.png
hand_draw_num_56_170630.png

最低限の最適化だが、100 MHz 動作で 12.8 ms 程度なので、 60 fps は満足している。
なお、WindowsのVivado HLS 2016.4 でもC コードの合成を行ってみた。すると、Estimated が違って、こちらは 10 nsをオーバーしてしまった。リソース使用量も微妙に違う。Windowsの結果とLinuxでの結果が一致しないようだ。
hand_draw_num_59_170630.png

C/RTL協調シミュレーションを行った。
hand_draw_num_57_170630.png

Export RTL を行って、IP化した。Place and Route を行って結果を見たが、問題なさそうだ。
hand_draw_num_58_170630.png

Windowsでもやってみたがやはり結果が微妙に違う。
hand_draw_num_60_170630.png

Linux の結果を使用することにした。

mnist_conv_nn10_sDMA.cpp を貼っておく。

// mnist_conv_nn10_sDMA.cpp
// 2017/06/12 by marsee
// 畳み込み層のカーネル数 10
// 2017/06/29 : アドレスオフセット導入 800x600 画像中の 28x28 を切り取ってDMAする
// |      アドレスオフセット      |
// *************************-手書き数字1行目-****************
// *************************-手書き数字2行目-****************
//

#include <ap_fixed.h>

#include "conv1_weight.h"
#include "conv1_bias.h"
#include "af1_weight.h"
#include "af1_bias.h"
#include "af2_weight.h"
#include "af2_bias.h"

ap_ufixed<80, AP_TRN_ZERO, AP_SAT> conv_rgb2y(int rgb);

int mnist_conv_nn(int in[22400], int addr_offset, ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[10]){
#pragma HLS INTERFACE s_axilite port=addr_offset
#pragma HLS INTERFACE s_axilite register port=out
#pragma HLS INTERFACE m_axi depth=22400 port=in  offset=slave
#pragma HLS INTERFACE s_axilite port=return
    ap_ufixed<80, AP_TRN_ZERO, AP_SAT> buf[28][28];
    ap_fixed<103, AP_TRN_ZERO, AP_SAT> conv_out[10][24][24];
    ap_fixed<103, AP_TRN_ZERO, AP_SAT> pool_out[10][12][12];
    ap_fixed<137, AP_TRN_ZERO, AP_SAT> dot1[100];
    ap_fixed<137, AP_TRN_ZERO, AP_SAT> dot2[10];

    buf_copy1: for(int i=0; i<28; i++){
        buf_copy2: for(int j=0; j<800; j++){
#pragma HLS PIPELINE II=1
            if (j>=addr_offset && j<addr_offset+28)
                buf[i][j-addr_offset] = (ap_ufixed<80, AP_TRN_ZERO, AP_SAT>)0.99609375 - conv_rgb2y(in[i*800+j]);
                // 1.0 にならないように 1/256を引いておく
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<10; i++){    // カーネルの個数
        CONV2: for(int j=0; j<24; j++){
            CONV3: for(int k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_weight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_bias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<10; i++){
        POOL2: for(int j=0; j<24; j += 2){
            POOL3: for(int k=0; k<24; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<10; i++){
            af1_dot3: for(int j=0; j<12; j++){
                af1_dot4: for(int k=0; k<12; k++){
#pragma HLS PIPELINE II=3
                    dot1[col] += pool_out[i][j][k]*af1_weight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_bias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<10; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_weight[row][col];
        }
        dot2[col] += af2_bias[col];

        out[col] = dot2[col];
    }

    return(0);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
// 2017/06/30 : ap_ufixed<8, 0, AP_TRN_ZERO, AP_SAT> 出力とした
ap_ufixed<80, AP_TRN_ZERO, AP_SAT> conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;
    ap_ufixed<168, AP_TRN_ZERO, AP_SAT> y_ap_ufixed;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    if (y >= 256)
        y = 255;

    y_ap_ufixed = (ap_ufixed<168, AP_TRN_ZERO, AP_SAT>)y / 256;

    return((ap_ufixed<80, AP_TRN_ZERO, AP_SAT>)y_ap_ufixed);
}


mnist_conv_nn_sDMA_tb.cpp を貼っておく。

// mnist_conv_nn_sDMA_tb.cpp
// 2017/06/14 by marsee
// 畳み込み層のカーネル数 10
// 2017/06/29 : ストライドDMAのためのテストベンチ
//

#include <stdio.h>
#include <ap_fixed.h>

#include "conv1_weight.h"
#include "conv1_bias.h"
#include "af1_weight.h"
#include "af1_bias.h"
#include "af2_weight.h"
#include "af2_bias.h"

#include "bmp_header.h"

int mnist_conv_nn(int in[22400], int addr_offset, ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[10]);
int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]);
int max_ap_fixed(ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[10]);
int max_float(float out[10]);
float conv_rgb2y_soft(int rgb);

#define READ_BMP_FILE_NAME    "bmp_file0.bmp"

// 8
#define X_POS    560
#define Y_POS    183
// 7
//#define X_POS    504
//#define Y_POS    184
// 5
//#define X_POS    390
//#define Y_POS    138
// 0
//#define X_POS    390
//#define Y_POS    70
#define WIDTH    28
#define HEIGHT    28

int main(){
    ap_fixed<127, AP_TRN_ZERO, AP_SAT> result_ap_fixed[10];
    float result_float[10];
    int max_id_hw, max_id_sw, max_id_ref;
    int *in;
    int *inf;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr;
    int *rd_bmp;
    int blue, green, red;

    if ((fbmpr = fopen(READ_BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open ");
        fprintf(stderr, READ_BMP_FILE_NAME);
        fprintf(stderr, " by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

    // ピクセルを入れるメモリをアロケートする
    if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate rd_bmp memory\n");
        exit(1);
    }

    if ((in =(int *)malloc(sizeof(int) * (800 * 28))) == NULL){
        fprintf(stderr, "Can't allocate (ap_ufixed<8, 0, AP_TRN_ZERO, AP_SAT>)in memory\n");
        exit(1);
    }

    if ((inf =(int *)malloc(sizeof(int) * (800 * 28))) == NULL){
        fprintf(stderr, "Can't allocate (float)inf memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

    // rd_bmp を in と inf に入力
    for (int y=Y_POS; y<Y_POS+HEIGHT; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            in[(y-Y_POS)*bmpihr.biWidth+x] = rd_bmp[y*bmpihr.biWidth+x];
            inf[(y-Y_POS)*bmpihr.biWidth+x] = rd_bmp[y*bmpihr.biWidth+x];
        }
    }

    mnist_conv_nn(in, X_POS, result_ap_fixed);
    mnist_conv_nn_float(inf, X_POS, result_float);

    max_id_hw = max_ap_fixed(result_ap_fixed);
    max_id_sw = max_float(result_float);

    printf("max_id_hw = %d\n", max_id_hw);
    printf("max_id_sw = %d\n", max_id_sw);

    return(0);
}

int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]){
    float buf[28][28];
    float conv_out[10][24][24];
    float pool_out[10][12][12];
    float dot1[100];
    float dot2[10];

    // 手書き数字の値を表示
    for (int i=0; i<28; i++){
        for (int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                printf("%2x, ", (int)(conv_rgb2y_soft(in[i*800+j])*256.0));
        }
        printf("\n");
    }

    buf_copy1: for(int i=0; i<28; i++){
        buf_copy2: for(int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                buf[i][j-addr_offset] = (float)0.99609375 - (float)conv_rgb2y_soft(in[i*800+j]);
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<10; i++){    // カーネルの個数
        CONV2: for(int j=0; j<24; j++){
            CONV3: for(int k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_fweight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_fbias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<10; i++){
        POOL2: for(int j=0; j<24; j += 2){
            POOL3: for(int k=0; k<24; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<10; i++){
            af1_dot3: for(int j=0; j<12; j++){
                af1_dot4: for(int k=0; k<12; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<10; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_fweight[row][col];
        }
        dot2[col] += af2_fbias[col];

        out[col] = dot2[col];
    }

    return(0);
}

int max_ap_fixed(ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[10]){
    int max_id;
    ap_fixed<127, AP_TRN_ZERO, AP_SAT> max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

int max_float(float out[10]){
    int max_id;
    float max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}


// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
// 2017/06/30 : retval を float にした
float conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;
    float y_float;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    if (y >= 256)
        y = 255;

    y_float = (float)y/256.0;

    return(y_float);
}

  1. 2017年07月01日 04:53 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0