FC2カウンター FPGAの部屋 2017年12月

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

FPGAの部屋

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

2017年のFPGAの部屋のブログのまとめ(7月 ~ 12月)

”2017年のFPGAの部屋のブログのまとめ(1月 ~ 6月)”の続き。

7月
手書き数字認識用畳み込みニューラルネットワーク回路の製作3(畳み込みNN) 四角枠の中の手書き数字を認識する畳み込みニューラルネットワークを作成しよう。
手書き数字認識用畳み込みニューラルネットワーク回路の製作6(PYNQボードで動作確認)
・SDKのベアメタル・アプリケーションで時間を計測する方法(Zynq)
手書き数字認識用畳み込みニューラルネットワーク回路の製作7(ハードとソフトの比較) ハードウェアのMNISTの手書き数字を認識する時間とソフトウェアでMNISTの手書き数字を認識する時間を比較してみようと思う。
aws/aws-fpgaをやってみた1
手書き数字認識用畳み込みニューラルネットワーク回路の製作8(Linuxでの動作1) ハードウェアでのMNIST手書き数字認識とソフトウェアでのMNIST手書き数字認識の実行時間を比較した。今回は、それをLinuxのアプリケーションソフトを作成してやってみようと思う。まずは、カメラ画像の表示を目指す。
Bash on Windows 10にVivado WebPACK 2017.2をインストールした
ルンバ622を買いました
白線追従走行用畳み込みニューラルネットワークの製作1(概要) MNIST手書き数字認識用ニューラルネットワークが完成したので、今度は本命のミニ・ロボットカーを白線間を走らせるための白線追従走行用畳み込みニューラルネットワーク(白線追従走行用CNN)を製作しよう。
HLS ビデオライブラリの hls::LineBuffer のVivado HLS 2015.4 以前とその後での変更点1(メモリ・ライン・バッファー) Vivado HLS 2016.1 から hls::LineBuffer と hls::Window のクラス・メソッドが大きく変更になった。Vivado HLS 2015.4 までは、 hls::LineBuffer と hls::Window の配列の並びは、列はインデックス 0 からなのだが、行はインデックス「行の配列の最大数」になっていた。
Ubuntu 16.04 にOpenCV 3.3.0 rc をインストールした Ubuntu 16.04 にOpenCV 3.1.0 をインストールしようとしたのだが、make でエラーになってしまった。どうやらCUDA 8.0 が悪さしているようだというのがわかった。dandelion さんからOpenCV 3.2 だったら大丈夫と教えていただいたので、OpenCV 3.2 以降をインストールすることにした。
Ubuntu 16.04 上のVivado HLS 2017.2 でOpenCV を使用したプロジェクトでエラー発生 Ubuntu 16.04 上のVivado HLS 2017.2 でOpenCV を使用したプロジェクトで libjpeg.so.62 と libtiff.so.3 が無いと言われてコンパイルできなかったので、解決方法を書いておく。
Pmod Shield: Adapter Board for Uno R3 Standard to Pmod

8月
白線追従走行用畳み込みニューラルネットワークの製作2(画像縮小、切り出し) 
MNIST手書き数字のデータフォーマット
白線追従走行用畳み込みニューラルネットワークの製作3(トレーニング、ラベル・ファイルの作成) 本格的に56 x 10 ピクセルの白線の画像を切り出すとともに、MNISTデータセットと同じフォーマットでトレーニング・ファイルとラベル・ファイルを生成しよう。
白線追従走行用畳み込みニューラルネットワークの製作5(テストデータの作成)
MFT2017 に行って来ました
白線追従走行用畳み込みニューラルネットワークの製作7(学習2) テストデータの正解率が 71 % になってしまう。もう一度、やり直した方が良いかもしれない。
Vivado シミュレータのDPI-C その1 Vivado シミュレータでDPI (Direct Programming Interface)をやってみることにした。
Vivado シミュレータでDPI-C を使用してZynq VIPを使う1
ソニーのNeural Network Console をやってみた1 「Neural Network Console」という学習・評価だけでなく、ニューラルネットワークの設計までも可能なディープラーニング・ツールをソニーが無償提供したので、やってみることにした。
白線追従走行用畳み込みニューラルネットワークの製作8(再度トレーニング、ラベル・ファイルの作成) ”白線追従走行用畳み込みニューラルネットワークの製作7(学習2)”で、精度が 71 % だったので、もう一度、白線追従直進走行用の画像データをもう一度取得して、再度トレーニング・ファイルとラベル・ファイルを作成することにした。しかし、やはり、精度は 70 % 程度だった。
白線追従走行用畳み込みニューラルネットワークの製作10(画像を増やす) 精度が上がらなかったので、画像を増やしてトレーニングしてみようということになった。今回はimagemagic を使って画像を増やしてみよう。9,075 枚に増やすことができた。
白線追従走行用畳み込みニューラルネットワークの製作13(9075枚のトレーニング用画像データで学習) 9075 個のトレーニング用画像データを使用して、学習したところ、フィルタ数が 2 でも、93 % 程度の精度が確保できた。
白線追従走行用畳み込みニューラルネットワークの製作14(固定小数点用に量子化) 9075 個のトレーニング用画像データと4125 個のテスト用画像データを使用して学習を行った。その結果、CONV数が 2 の畳み込みニューラルネットワークで、93.1 % の精度を得ることができた。今回は、その畳み込みニューラルネットワークを固定小数点用に量子化し、Vivado HLS に使用する重みやバイアスのヘッダファイルを生成しよう。
白線追従走行用畳み込みニューラルネットワークの製作16(白線追従走行用の画像データをCの配列に出力)
白線追従走行用畳み込みニューラルネットワークの製作19(Cコードの合成、IP化) Cコードの合成を行って、レイテンシやリソース使用量を確認する。
・白線追従走行用畳み込みニューラルネットワークの製作20(CNN IPの戦略を考える) 直進のみだけど白線追従走行用畳み込みニューラルネットワークの推論用Vivado HLSのプロジェクトは完成した。ただしまだ畳み込みニューラルネットワークを固定小数点数で作って性能を確認しただけで、どのようにFPGA上の回路にするかの検討はまだしていない。今回は、どのようにFPGA上の回路にするかの検討を行っていこう。

9月
Vivado HLS で画像のサイズを縮小して白黒変換(resize_gray)
画像をリサイズするためにDMA Read IPをVivado HLSで製作した1(dmar4resize_gray)
AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその1(C シミュレーション) ”白線追従走行用畳み込みニューラルネットワークの製作19(Cコードの合成、IP化)”
で作成した白線追従走行用畳み込みニューラルネットワークをAXI4 Streamで入力するように変更した。これは、”Vivado HLS で画像のサイズを縮小して白黒変換2(resize_gray)”のAXI4 Stream 入力を受けて、白線追従走行用畳み込みニューラルネットワークにそのAXI4 Stream データを入力して処理する。
CNNのVivado HLS実装のstraight_conv_nn2 の演算精度を変更する straight_conv_nn2 の精度が良かったのは画像が良かったからという結論が出たので、精度の悪そうな画像でもう一度、straight_conv_nn2 のC シミュレーションを行った。そうすると、ハードウェアの精度は56.7 % だった。これでは精度が悪すぎるので、演算の精度、つまりビット幅を見直すことにした。演算のビット幅を変えながら誤差を見ていこう。
dmar4resize_gray, resize_gray, straight_conv_nn2_axis2 をVivado HLS 2017.2 で IP化
白線追従走行用畳み込みニューラルネットワーク・システムの製作1 白線追従走行用畳み込みニューラルネットワークを搭載して、カメラ画像から進む方向(左旋回、直進、右旋回)を決定し、モーターを駆動して、ミニ・ロボットカーに白線間を走行させるシステムである。
白線追従走行用畳み込みニューラルネットワーク・システムの製作7(白線間を走行) ZYBO のUbuntu 14.04 上でアプリケーションソフトを作り、白線間を走行させた。白線間を走行できた。動画あり。
Xilinx reVISION、xfOpenCV のExampleをやってみた1(of2) Xilinx 社から機械学習やコンピュータ・ビジョン・ツールの reVision と、OpenCVをハードウェア化する xfOpenCV が出た。これらのExample をやってみることにした。
・「RTLを語る会(14) ~FPGAの現実~」で発表してきました 「RTLを語る会(14) ~FPGAの現実~」で「「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化」という題で1時間発表してきました。
ZYBO Z7-20 が届きました
ZYBO Z7-20 のボードファイルをVivado 2017.2 にインストールする
ZYBO Z7-20 の u-boot.elf と devicetree.dtb を作る

10月
Zybo Z7-20でLinux を起動しようとしたが失敗 ”ZYBO Z7-20 の u-boot.elf と devicetree.dtb を作る”で作ったdevicetree.dtb と”ZYBO_Z7_0 のVivado 2017.2 プロジェクトでBOOT.bin を作成”で作ったBOOT.bin をZYBO Linux 用のMicro SD カードに入れてZybo Z7-20 で起動してみた。なお、LinuxカーネルはZYBO で使用してたものとした。結果は、TTYPS0 までは行くのだが、その後の文字が化け化けになってしまった。
Ultra-Zed-EGのデモをやってみた
Zybo Z7-20 上でUbuntu 14.04 が動作したがネットワークがつながらない
Zybo Z7-20 上でUbuntu 14.04 が動作し、ネットワークもつながった
ビットマップ・ディスプレイ・コントローラIPとカメラ・インタフェースIPのAXI4 Lite Slaveのバグをフィックス ”Zybo Z7-20上の白線間走行CNNシステムのプロジェクトが動作しないバグ”で、ビットマップ・ディスプレイ・コントローラIPとカメラ・インタフェースIPのAXI4 Lite Slave インターフェース回路にバグがあることが分かった。
Vivado 2017.3 をインストールした
ZYBO Z7-20上のUbuntu 14.04でカメラ画像を表示
Github で現在使用しているZYBO Z7-20用のBOOT.bin, devicetree.dtb, u-boot, uImage などを公開しました
ZYBO Z7-20上のUbuntu 14.04でカメラ画像にガボール・フィルタを動作させる
2017年度Zynq+Vivado HLS勉強会概要 全 8 回になってしまったので、まだ、1回分残っています。
ZYBO Z7-20上のUbuntu 14.04で白線間走行用畳み込みニューラルネットワークを動作させる
Vivado HLS 2015.4と2017.2の合成時の違い
Windows 10 fall creators update のWindows Subsystem for Linuxを試してみた

11月
ZYBOでのxfOpenCVライブラリの使用1
Vivado HLS 2017.3.1 における識別子の違いによる任意精度固定小数点データ型の動作の違い1
Vivado HLSで#define と プラグマ指示子の使用
intel HLS コンパイラを試してみる
intel HLS コンパイラを試してみる2(counterサンプルが動いた)
UltraZed-EG Starter Kit のチュートリアル1
intel HLS コンパイラのレポート
Windows 10 Fall Creators Update をかけるとVivado 2017.3 が起動しない
intel HLS コンパイラを試してみる11(mm_slave その1)
カーブ、直線用白線間走行用畳み込みニューラルネットワーク1(データ) ”白線追従走行用畳み込みニューラルネットワーク・システムの製作7(白線間を走行)”で、ミニ・ロボットカーが直線の白線を走行することができた。次はカーブを曲がれるようにしたい。そこで、曲がってい角度が 23 度のカーブと 48 度のカーブを用意して、曲がれるかどうかを試してみた。(注:カーブを曲がる学習はまだしていません。直線を走る学習のみです)
FPGA+SoC+Linux実践勉強会用のZYBO Z7用MicroSDカードの準備
PetaLinux 2017.3 をインストールする
UltraZed-EG Starter Kit でPetaLinux 2017.3 をブートする

12月
FPGA+SoC+Linux実践勉強会での課題をやってみた1(Vivado HLS編)
intel HLS の pointer_mm_master を試してみた1
Vivado HLS の合成でEstimated がTarget の制約を満たせなかったときの処置 Vivado HLS の合成でEstimated の値がTarget を満たせなかったときの処置を@hiyuh さんに教わったので書いておこう。
FPGA+SoC+Linux実践勉強会での課題をやってみた6(udmabuf、実機テスト)
カーブ、直線用白線間走行用畳み込みニューラルネットワーク5(トレーニング用データの生成)
カーブ、直線用白線間走行用畳み込みニューラルネットワーク11(Vivado HLS でCNN を実装)
ZYBOでUbuntu を起動したらネットワークがつながらない
カーブ、直線用白線間走行用畳み込みニューラルネットワーク13(AXI4 Stream版CNN IP 1) AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIP と入れ替えるためにカーブと直線走行用のAXI4 Stream 版畳み込みニューラルネットワーク IP を作成しよう。
UltraZed-EG Starter Kit でDebian が起動した
カーブ、直線用白線間走行用畳み込みニューラルネットワーク18(ミニ・ロボットカーでの走行テスト) ミニ・ロボットカーがカーブを自動走行することができた。動画あり。
Pcam 5Cカメラが届きました

今年もいろいろな記事を書いたが、やはり「ゼロから作るDeep Learning」を読んで、Python コードを使わせてもらって、自分で、畳み込みニューラルネットワークを学習させて、ミニ・ロボットカーに実装して、白線間を自動走行したが嬉しかった。5月に「ゼロから作るDeep Learning」を読んで、6月からMNIST手書き数字認識をFPGA実装してから弾みついた気がする。

今年もたくさんの方に見て頂いたし、また、いろいろな方に助けられてブログ記事を書くことができた。本当にありがたい。また来年もよろしくお願いいたします。

それではよいお年をお迎えください。。。
  1. 2017年12月31日 04:56 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

2017年のFPGAの部屋のブログのまとめ(1月 ~ 6月)

2017年のFPGAの部屋のブログ記事をまとめてみよう。

1月
SDSoC のプラットフォームのお勉強6(ハードウェア・プラットフォームの完成) 2017年の最初のFPGA関連記事は、SDSoC の記事だった。SDSoC を勉強しようとして、いろいろとやってみていた。また再開したいな。reVISION とかもあるし。
SDx 2016.3 のプラグマによるハードウェアと性能の違い1 おなじみのSDx 用ラプラシアンフィルタのプロジェクトを使用して、SDx 2016.3 のデータに関するプラグマを入れて、ハードウェアがどう変更されたのか?性能がどうなったのかを検証してみよう。
Zybot をステレオカメラにする2(カメラ・マウントの作製) Zybot に取り付ける、カメラ拡張ボード用のマウントをFreeCAD で設計して、3D プリンタで作成した。
Vivado HLS のソースコードをSDx で試す1(memcpy() を使った第2段階のコード)
AXI4-Stream向きのコードで書いたラプラシアンフィルタをVivado HLSでテスト1 ”Vivado HLS のソースコードをSDx で試す4(AXI4-Stream向きのコード)”でAXI4-Stream向きのコードをAXI4 Master として実装して性能を評価したところ、とても高い性能だった。それは、DMAのWrite とRead が重なり合って実行しているとしか考えらない性能だった。となると、そのコードはVivado HLS で合成したときにDMAのWrite とRead が重なり合って実行されるのだろう。そのような状況には出会ったことがないので、さっそくVivado HLS でやってみた。
SDSoCのチュートリアルをやってみた1(システムのデバック) SDSoCのデバック方法やパフォーマンス測定のただし方法などを知らなかったので、SDSoCのチュートリアルをやってみることにした。
Zybot をステレオカメラにする3(Zybot 改造中)
Xilinx/PYNQのプロジェクトを生成した1 ikwzm さんの”PYNQ-Z1 の ビットストリームを再ビルドしたときのタイミング違反を無くす”を見ながら、Xilinx/PYNQのプロジェクトを生成してみた。
SDSoC 勉強会 SDSoC 勉強会に行ったけ。。。
FPGAマガジン No.16にVivado HLSのAXI4 Masterアクセス編を書きました

1月の記事はどれも長かったな。。。良く書けたもんだ。。。

2月
FASTXコーナー検出による物体の形状検出1(Vivado 2016.4 プロジェクト) 以前、”FASTX コーナー検出の改良3(threshold をソフトウェアで変更可能にする)”で、Vivado HLS のOpenCV 機能の一部であるFASTX コーナー検出を使用して、CMOS カメラで撮影した画像のコーナー検出を行った。今回は、FASTX コーナー検出のプロジェクトを Vivado 2016.4 に変換して動作を確かめた。
守谷ハーフマラソンの5kmの部に出場しました 結果は26分31秒でした。
Zybotの障害物検知と回避1(超音波距離センサの性能) Zybotの障害物検知と回避で使用するために、超音波距離センサの指向性を計ってみた。Zybot の改造を行っている。
PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出1 このところ実装しているVivado HLS のFASTX コーナー検出IP をPYNQ ボードにも実装してカメラ画像からリアルタイムにFASTX コーナー検出を行った。
バイキュービック法のFPGAへの適用 バイキュービック(BiCubic)法をFPGA に適用できるように固定小数点に直して演算する方法。
Vivado HLS 2016.4 における assert() 文の効果 Vivado HLS 2016.4 で変域を指定することができる assert() 文の効果を確かめてみた。
Zybot による障害物回避 Zybot による障害物回避が曲がりなりにもできた。

3月
PYNQ祭りに参加してきました 「PYNQでカメラ画像をリアルタイムFASTX コーナー検出」という題で発表してきました。スライドはSlideShareにアップしました。
XilinxのBNN-PYNQをやってみる1(インストール編) XilinxのBNN-PYNQをやって見たいということで、やってみました。BNN-PYNQはBinarized Neural Network (BNN) on PYNQ だそうです。
・Ubuntu16.04にVivado 2016.4をインストール Ubuntu16.04にVivado 2016.4をインストールする覚書を書いておこうと思う。
「Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)」を使って合成後の機能シミュレーション 前回は絶対アドレス指定のDMA Read IPをVivado HLS 2016.4 で作成した。今回は、そのDMA Read IPをVivado で論理シミュレーションと合成後の機能シミュレーションを行った。
Vivado 2016.4 のSDKでデバイスツリーのソース(DTS)を生成する Windows 10 上で、Vivado 2016.4 のSDKでデバイスツリーのソース(DTS)を生成してみよう。
・”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる1(FPGA-SoC-Linux のクローン) ikwzm さんの”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみようと思う。

4月
PYNQのLED表示プロジェクト1(ブロックデザインの作成) ikwzm さんのFPGA Manager と デバイスツリー・オーバーレイを確かめてみるために、簡単な例としてPYNQボードのLED表示プロジェクトを作ることにした。
”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる8(入れ替え1) 前回は、デバイスツリー・オーバーレイとFPGA Manager を使いやすいようにShell スクリプトを作成した。今回は、2つのFPGA回路とデバイスツリーをLinux 起動しながら入れ替えてみようと思う。
Raspberry Pi Zero にLinux をインストール ”Raspberry Pi Zero インストール(2016/07/02)”のほぼその通りにRaspberry Pi Zero のSDカードにLinux をインストールした。
技術書典2に行ってきました
ikwzm さんの構築したPYNQ ボード用DebianでのPS出力クロックfclkの設定方法
かすみがうらマラソン2017に出場しました
Thinkpad 13が届きました ”「PYNQ祭り」延長戦 : FPGAディープラーニング実践懇親会”でがっつり実装するために購入しました。
”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を使用してカメラの画像を表示 
Vivado 2017.1 の新機能1(概要) Vivado 2017.1 がリリースされて、新機能が多かったので、その解説をした。
Vivado 2017.1 の新機能2(AXI Verification IPの概要)
FPGAマガジンNo.17にVivado HLS の記事を書きました(ソースコードをGitHubで公開)
AXI4マスタ版ラプラシアン・フィルタ最速の条件 この記事はFPGAマガジンNo.17 に載るはずだったけど、ページが足りなくて載せることができなかったコラムです。

5月
Vivado 2017.1 の新機能8(Zynq-7000 VIP)
Vivado HLSで stdint.h を使用する taksei さんに教えて頂いたように、stdint.h を使用して、uintX_t や intX_t を使用することにした。
「ゼロから作る Deep Learning」をやってみる1(Numpyと matplotlib の使い方) オライリーの「ゼロから作る Deep Learning」をやってみたのは5月からだったんだ、これ以降はこのCNN の話題がブログの中心となった。7か月位で、ミニ・ロボットカーを走らせるまでになったのはとっても良かった。
・DnnWeaverをやってみる1 結局、うまく行かなかった。
BNN-PYNQ のトレーニングを試してみる1
Vivado HLS の符号付 C++の任意精度固定小数点型について
ニューラルネットワークの推論のハードウェア化1(概要編) 「ゼロから作る Deep Learning」を使用して、ニューラルネットワークをFPGA で実装しようという試みが始まった。まずはMNISTの手書き数字認識をFPGA に実装してみることにした。

6月
Vivado HLS の任意精度固定小数点型を使用した内積の計算 配列の内積をVivado HLS の任意精度固定小数点型を使用して計算してみよう。ニューラルネットワークを実装するためのテストだった。
「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化1 「ゼロから作るDeep Learning」の5章 誤差逆伝播法の2層のニューラルネットワークをハードウェア化してFPGA に実装してみようと思う。浮動小数点数を量子化して固定小数点化する方法を書いた。
マウスコンピューターのパソコンにHDDとGPUを追加してUbuntuをインストールした
「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化3 Vivado HLSに持っていくための重みとバイアスのC の配列を生成するPython コードを紹介した。
BNN-PYNQ のトレーニングを試してみる3 GPUを使用してCIFAR-10をトレーニングしてみた。
「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化4(Vivado HLS) 前回作成した重みやバイアス、MNISTデータセットの一部のヘッダファイルを使用して、Vivado HLS でMNISTの手書き数字を判定するハードウェアを作る。ただし、Softmax は実装が難しいし、最大値を取れば数字は推定できるので、実装していない。
「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化6(指示子を入れる) IP として使用できるようにVivado HLS に指示子を入れた。
「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1 「ゼロから作るDeep Learning」の7章 畳み込みニューラルネットワークをハードウェア化してFPGA に実装してみることにした。
「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化4(Vivado HLS1) 畳み込みニューラルネットワークのC ソースコードを作成してVivado HLSでハードウェア化した。
MNISTの畳み込みニューラルネットワークで自分の手書き数字を認識する1 自分で手描きの数字を書いてVivado HLS のC シミュレーションによって、認識させてみた。
MNISTの畳み込みニューラルネットワークで自分の手書き数字を認識する3(カメラ画像) 手書き数字をカメラで撮影した画像を切り出して認識させたところ、精度はいまいちだが、一応、カメラで撮影した手書き数字を認識できているようだ。本格的にPYNQボードに組み込んで、カメラで撮影した画像から手書き数字を認識させてみよう。
手書き数字認識用畳み込みニューラルネットワーク回路の製作1(概要) 手書き数字認識用畳み込みニューラルネットワークができたので、カメラで撮影した画像の中の手書き数字を認識してみようと思う。使用するボードはPYNQボードとする。以前に、PYNQボードでFASTX コーナー検出IP を使用したプロジェクトがあるので、それをベースとする。
手書き数字認識用畳み込みニューラルネットワーク回路の製作2(手書き数字認識用四角枠表示回路) 手書き数字認識用畳み込みニューラルネットワーク回路のパーツとなる手書き数字認識用四角枠表示回路をVivado HLS を使用して作ってみよう。

6月は怒涛の進行だった。今読むと凄かったと思う。
  1. 2017年12月30日 04:37 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

Pcam 5Cカメラが届きました

昨日、Pcam 5Cカメラが届きました。
Pcam5C_171229.jpg

リソース・センターです。OmniVision 社の OV5640 のマニュアルもあります。
Pcam 5Cカメラは、Zybo Z7: Zynq-7000 ARM/FPGA SoC Development Board のコネクタに接続して使用します。

Zybo Z7 Pcam 5C Demo もあります。後でやってみる予定です。
  1. 2017年12月29日 05:19 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク18(ミニ・ロボットカーでの走行テスト)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク17(BOOT.bin と devicetree.dtb の生成)”の続き。

前回は、SDK でBOOT.bin を作成し、zynq-zybo.dts から devicetree.dtb を作成して、Ubuntu にマウントした、MicroSDカードの第1パーティションにSFTPで書き込んだ。今回は、カーブと直線の白線間走行用のアプリケーションソフト(wl_tracing_cnn.cpp)を作成して、ミニ・ロボットカーで実際に白線間を走行させてみる。

ZYBO のZybot ディレクトリに wl_tracing_cnn_curve ディレクトリを作成して、Vivado HLS で作成したIP のドライバや、”白線追従走行用畳み込みニューラルネットワーク・システムの製作7(白線間を走行)”で作成した wl_tracing_cnn.cpp や Makefile をコピーした。

次に、wl_tracing_cnn.cpp を curve_conv_nn2_axi3 用に修正した。
curve_tracing_cnn_94_171228.png

Makefile もそれに合わせて修正した。
curve_tracing_cnn_95_171228.png

wl_tracing_cnn_curve ディレクトリを示す。
curve_tracing_cnn_96_171228.png

make コマンドを実行した。
curve_tracing_cnn_97_171228.png

make コマンド後の wl_tracing_cnn_curve ディレクトリを示す。
curve_tracing_cnn_98_171228.png

wl_tracing_cnn 実行ファイルができている。

./udmabuf_insmod を実行して、カメラのフレームバッファを確保してから、
./wl_tracing_cnn を実行する。
curve_tracing_cnn_99_171228.png

./wl_tracing_cnn の実行結果を示す。
curve_tracing_cnn_100_171228.png

実際にミニ・ロボットカーがカーブを走っているところを動画で示す。
まずは、48 度のカーブでのミニ・ロボットカーの走行動画を示す。






23度のカーブでのミニ・ロボットカーの走行動画を示す。




時々、左旋回、右旋回を迷うことがあるが、概ね安定して走行している。

wl_tracing_cnn.cpp を貼っておく。

// wl_tracing_cnn.cpp
// 2017/12/27 by marsee
//

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

#include "xpwm.h"
#include "xdmar4resize_gray.h"
#include "xresize_gray.h"
#include "xcurve_conv_nn2_axis3.h"

#define CMA_START_ADDRESS 0x17800000
#define VIDEO_BUFFER_START_ADDRESS  0x18000000  // Limit 0x18800000, 800*600*4 = 2MBytes * 2

#define HORIZONTAL_PIXEL    800
#define ALL_CHAR_OF_1LINE   (HORIZONTAL_PIXEL/8)
#define VERTICAL_PIXEL      600
#define ALL_CHAR_OF_ROW     (VERTICAL_PIXEL/8)
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXEL*VERTICAL_PIXEL*4)
#define ALL_DISP_CHARACTOR  (HORIZONTAL_PIXEL*VERTICAL_PIXEL)

#define DEBUG
//#define MOTOR_OFF

void cam_i2c_init(volatile unsigned *mt9d111_axi_iic) {
    mt9d111_axi_iic[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_axi_iic[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_axi_iic, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_axi_iic[66] = 0x100 | (device_addr & 0xfe); // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_axi_iic[66] = write_addr;
    mt9d111_axi_iic[66] = (write_data >> 8)|0xff;           // first data
    mt9d111_axi_iic[66] = 0x200 | (write_data & 0xff);      // second data
    cam_i2x_write_sync();
}

// Motor
//
void motor_settings(XPwm *motorLp, XPwm *motorRp){
    XPwm_DisableAutoRestart(motorLp);
    while(!XPwm_IsIdle(motorLp)) ;
    XPwm_Start(motorLp);
    XPwm_EnableAutoRestart(motorLp);
    
    XPwm_DisableAutoRestart(motorRp);
    while(!XPwm_IsIdle(motorRp)) ;
    XPwm_Start(motorRp);
    XPwm_EnableAutoRestart(motorRp);
}

void Stopped_Zybot(XPwm *motorLp, XPwm *motorRp){
    XPwm_Set_sw_late_V(motorLp, 0);
    XPwm_Set_sw_late_V(motorRp, 0);
}


int main()
{
    int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9, fd10;
    volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
    volatile unsigned *dmaw4gabor_0;
    volatile unsigned *axis_switch_0, *axis_switch_1;
    volatile unsigned *mt9d111_inf_axis_0;
    volatile unsigned *mt9d111_axi_iic;
    volatile unsigned *axi_gpio_0;
    volatile unsigned *frame_buffer_bmdc;
    char  attr[1024];
    unsigned long  phys_addr;
    int i;
    XDmar4resize_gray xdmar;
    XResize_gray resg;
    XCurve_conv_nn2_axis3 stcnn;
    XPwm motorL, motorR;
    XPwm *motorLp, *motorRp;
    
    motorLp = &motorL;
    motorRp = &motorR;

    // Bitmap Display Controller 0 AXI4 Lite Slave (UIO6)
    fd6 = open("/dev/uio6", O_RDWR); // bitmap_display_controller 0 axi4 lite
    if (fd6 < 1){
        fprintf(stderr, "/dev/uio6 (bitmap_disp_cntrler_axi_master_0) open error\n");
        exit(-1);
    }
    bmdc_axi_lites0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
    if (!bmdc_axi_lites0){
        fprintf(stderr, "bmdc_axi_lites0 mmap error\n");
        exit(-1);
    }
    
    // Bitmap Display Controller 1 AXI4 Lite Slave (UIO7)
    fd7 = open("/dev/uio7", O_RDWR); // bitmap_display_controller axi4 lite
    if (fd7 < 1){
        fprintf(stderr, "/dev/uio7 (bitmap_disp_cntrler_axi_master_0) open error\n");
        exit(-1);
    }
    bmdc_axi_lites1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
    if (!bmdc_axi_lites1){
        fprintf(stderr, "bmdc_axi_lites1 mmap error\n");
        exit(-1);
    }

    // dmaw4gabor_0 (UIO1)
    fd1 = open("/dev/uio1", O_RDWR); // dmaw4gabor_0 interface AXI4 Lite Slave
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (dmaw4gabor_0) open error\n");
        exit(-1);
    }
    dmaw4gabor_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!dmaw4gabor_0){
        fprintf(stderr, "dmaw4gabor_0 mmap error\n");
        exit(-1);
    }
    
    // mt9d111 i2c AXI4 Lite Slave (UIO0)
    fd0 = open("/dev/uio0", O_RDWR); // mt9d111 i2c AXI4 Lite Slave
    if (fd0 < 1){
        fprintf(stderr, "/dev/uio0 (mt9d111_axi_iic) open error\n");
        exit(-1);
    }
    mt9d111_axi_iic = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, 0);
    if (!mt9d111_axi_iic){
        fprintf(stderr, "mt9d111_axi_iic mmap error\n");
        exit(-1);
    }

    // mt9d111 inf axis AXI4 Lite Slave (UIO5)
    fd5 = open("/dev/uio5", O_RDWR); // mt9d111 inf axis AXI4 Lite Slave
    if (fd5 < 1){
        fprintf(stderr, "/dev/uio5 (mt9d111_inf_axis_0) open error\n");
        exit(-1);
    }
    mt9d111_inf_axis_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
    if (!mt9d111_inf_axis_0){
        fprintf(stderr, "mt9d111_inf_axis_0 mmap error\n");
        exit(-1);
    }

    // axis_switch_0 (UIO2)
    fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axis_switch_0){
        fprintf(stderr, "axis_switch_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1 (UIO3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!axis_switch_1){
        fprintf(stderr, "axis_switch_1 mmap error\n");
        exit(-1);
    }
    
    // axi_gpio_0 (UIO8)
    fd8 = open("/dev/uio8", O_RDWR); // axi_gpio_0 interface AXI4 Lite Slave
    if (fd8 < 1){
        fprintf(stderr, "/dev/uio8 (axi_gpio_0) open error\n");
        exit(-1);
    }
    axi_gpio_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
    if (!axi_gpio_0){
        fprintf(stderr, "axi_gpio_8 mmap error\n");
        exit(-1);
    }
    
    // udmabuf0
    fd9 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd9 == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    frame_buffer_bmdc = (volatile unsigned *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
    if (!frame_buffer_bmdc){
        fprintf(stderr, "frame_buffer_bmdc mmap error\n");
        exit(-1);
    }

    // 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
    
    // phys_addr of udmabuf0
    fd10 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd10 == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd10, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd10);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    // DMAW4Gabor Initialization sequence
    dmaw4gabor_0[6] = (unsigned int)phys_addr; // Data signal of frame_buffer0
    dmaw4gabor_0[8] = (unsigned int)phys_addr+ALL_DISP_ADDRESS; // Data signal of frame_buffer1
    dmaw4gabor_0[0] = 0x1// ap_start = 1
    dmaw4gabor_0[0] = 0x80// auto_restart = 1

    // bitmap display controller settings
    bmdc_axi_lites0[0] = (unsigned int)phys_addr; // Bitmap Display Controller 0 start
    bmdc_axi_lites1[0] = (unsigned int)phys_addr; // Bitmap Display Controller 1 start
    mt9d111_inf_axis_0[0] = (unsigned int)phys_addr; // Camera Interface start (Address is dummy)

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

    mt9d111_inf_axis_0[1] = 0;

    // Initialization of xdmar4resize_gray, xresize_gray, XCurve_conv_nn2_axis3
    if(XDmar4resize_gray_Initialize(&xdmar, "dmar4resize_gray_0") != XST_SUCCESS){
        fprintf(stderr, "dmar4resize_gray_0 open error\n");
        exit(-1);
    }
    if(XResize_gray_Initialize(&resg, "resize_gray_0") != XST_SUCCESS){
        fprintf(stderr, "resize_gray_0 open error\n");
        exit(-1);
    }
    if(XCurve_conv_nn2_axis3_Initialize(&stcnn, "curve_conv_nn2_axis3_0") != XST_SUCCESS){
        fprintf(stderr, "curve_conv_nn2_axis3 open error\n");
        exit(-1);
    }

    XDmar4resize_gray_Set_frame_buffer0(&xdmar ,(unsigned int)phys_addr);
    XDmar4resize_gray_Set_frame_buffer1(&xdmar ,(unsigned int)phys_addr+ALL_DISP_ADDRESS);
    XDmar4resize_gray_Start(&xdmar);
    XDmar4resize_gray_EnableAutoRestart(&xdmar);

    XResize_gray_Start(&resg);
    XResize_gray_EnableAutoRestart(&resg);

    XCurve_conv_nn2_axis3_Start(&stcnn);
    XCurve_conv_nn2_axis3_EnableAutoRestart(&stcnn);

    // Initialization of motor
    if (XPwm_Initialize(motorLp, "pwm_0") != XST_SUCCESS){
        fprintf(stderr,"pwm_0 (Left) open error\n");
        exit(-1);
    }
    if (XPwm_Initialize(motorRp, "pwm_1") != XST_SUCCESS){
        fprintf(stderr,"pwm_1 (Right) open error\n");
        exit(-1);
    }
    // The Motors is rotated in the forward direction.
    XPwm_Set_sw_late_V(motorLp, 0);
    XPwm_Set_dir_V(motorLp, 1);

    XPwm_Set_sw_late_V(motorRp, 0);
    XPwm_Set_dir_V(motorRp, 0);

    motor_settings(motorLp, motorRp);

    // main loop
    printf("White line Tracking start. \n");
    while(1){
        usleep(10000); // 10 ms Wait

        while(!XCurve_conv_nn2_axis3_Get_outs_V_vld(&stcnn)) ;
        switch((int)XCurve_conv_nn2_axis3_Get_outs_V(&stcnn)){
            case 0 : // left turn
#ifndef MOTOR_OFF
                XPwm_Set_sw_late_V(&motorL, 10);
                XPwm_Set_sw_late_V(&motorR, 25);
#endif
#ifdef DEBUG
                printf("Left turn\n"); fflush(stdout);
#endif
                break;
            case 1 : // straight
#ifndef MOTOR_OFF
                XPwm_Set_sw_late_V(&motorL, 20);
                XPwm_Set_sw_late_V(&motorR, 20);
#endif
#ifdef DEBUG
                printf("Go straight\n"); fflush(stdout);
#endif
                break;
            default : // 2, right turn
#ifndef MOTOR_OFF
                XPwm_Set_sw_late_V(&motorL, 25);
                XPwm_Set_sw_late_V(&motorR, 10);
#endif
#ifdef DEBUG
                printf("Right turn\n"); fflush(stdout);
#endif
        }
    }


    munmap((void *)bmdc_axi_lites0, 0x10000);
    munmap((void *)bmdc_axi_lites1, 0x10000);
    munmap((void *)dmaw4gabor_0, 0x10000);
    munmap((void *)mt9d111_inf_axis_0, 0x10000);
    munmap((void *)mt9d111_axi_iic, 0x10000);
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)axi_gpio_0, 0x10000);
    munmap((void *)frame_buffer_bmdc, 576000);
    
    close(fd0);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    close(fd5);
    close(fd6);
    close(fd7);
    close(fd8);
    close(fd9);
    
    return(0);
}


Makefile を貼っておく。

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

PROGRAM = wl_tracing_cnn
OBJS = wl_tracing_cnn.o xpwm_linux.o xpwm.o xdmar4resize_gray_linux.o xdmar4resize_gray.o xresize_gray_linux.o xresize_gray.o xcurve_conv_nn2_axis3_linux.o xcurve_conv_nn2_axis3.o

CC = gcc
CFLAGS = -Wall -O2

.SUFFIXES: .c .o

.PHONY: all

all: wl_tracing_cnn

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

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

  1. 2017年12月28日 05:51 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク17(BOOT.bin と devicetree.dtb の生成)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク16(SDK)”の続き。

前回は、ハードウェアをエクスポートして、SDKを立ち上げ、アプリケーションソフトを作成して動作を確認した。今回は、SDK でBOOT.bin を作成し、zynq-zybo.dts から devicetree.dtb を作成してみよう。

まずは、BOOT.bin から作成する。
SDK で、File メニューからNew -> Application Project を選択する。
Application project ダイアログで、Project name にFSBL と入力して、Next > ボタンをクリックする。
curve_tracing_cnn_82_171227.png

Templates で Zynq FSBL を選択して、Finish ボタンをクリックする。
curve_tracing_cnn_83_171227.png

FSBL と FSBL_bsp フォルダができた。
curve_tracing_cnn_89_171227.png

FSBL フォルダを右クリックし、右クリックメニューからCreate Boot Image を選択する。
Create Boot Image ダイアログが表示された。
Boot image partitions のAdd ボタンをクリックして、u-boot.elf を追加した。
Create Image ボタンをクリックして、BOOT.bin を作成した。
curve_tracing_cnn_84_171227.png

BOOT.bin が作成された。
curve_tracing_cnn_85_171227.png

次に、devicetree.dtb を作成する。
今度は、Ubuntu 16.04 上で作業する。
白線追従走行用畳み込みニューラルネットワーク・システムの製作4(BOOT.binとデバイスツリー)”の zynq_zybo.dts で straight_conv_nn2_axis2 のエントリを編集して、curve_conv_nn2_axi3_0 を追加した。
curve_tracing_cnn_86_171227.png

zynq_zybo.dts を dtc でコンパイルする。
dtc -I dts -O dtb -o devicetree.dtb zynq-zybo.dts
コマンドでコンパイルして、devicetree.dtb を生成した。
curve_tracing_cnn_87_171227.png

curve_tracing_cnn_88_171227.png

今回は、ZYBO のMicroSDカードの第1パーティションをマウントして、WinSCP を使ってSFTP でファイルを書き込んでみよう。

まずはマウント・ポイントの ZYBO_BOOT ディレクトリを /media ディレクトリに作成する。
sudo mkdir /media/ZYBO_BOOT
次に、ZYBOのFAT32の第1パーティションをすべてのユーザー読み書き可でLinuxにマウントする。
sudo mount -t vfat /dev/mmcblk0p1 /media/ZYBO_BOOT -o rw,umask=000
ls /media/ZYBO_BOOT/ でZYBO_BOOT ディレクトリを見るとmount コマンドが成功している。
curve_tracing_cnn_90_171227.png

ZYBO の /media/ZYBO_BOOT/ に WinSCP で SFTP をして、先ほど作成した BOOT.bin と devicetree.dtb をアップロードした。
curve_tracing_cnn_91_171227.png

もう一度、ls /media/ZYBO_BOOT/ でZYBO_BOOT ディレクトリを見るとファイルが増えているのが分かる。元々あったBoot.bin と devicetree.dtb は、それぞれ _temp を名前に追加してリネームしてある。
curve_tracing_cnn_92_171227.png

これで、ZYBO のMicroSDカードの第1パーティション(ブート用FAT32 フォーマット)を書き換えることができたので、reboot すれば今コピーしたBoot.bin と devicetree.dtb が反映される。
sudo reboot コマンドでリブートを行った。

/sys/devices/amba.0 を見ると、43cf0000.curve_conv_nn2_axis3_0 があるのが分かる。
curve_tracing_cnn_93_171227.png

これで、ハードウェアの準備は終了した。次はアプリケーション・ソフトを作成して、ミニ・ロボットカーを走らせてみよう。

最後に zynq-zybo.dts を貼っておく。

/*
 * Device Tree for Zybo board
 * Partially generated by Device Tree Generator 1.1
 *
 * (C) Copyright 2007-2013 Xilinx, Inc.
 * (C) Copyright 2007-2013 Michal Simek
 * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd
 * (C) Copyright 2014 Digilent, Inc. 
 *
 * Michal SIMEK <monstr@monstr.eu>
 * Tinghui Wang <steven.wang@digilentinc.com> 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

/dts-v1/;
/ {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "xlnx,zynq-7000";
    model = "Xilinx Zynq";
    aliases {
        ethernet0 = &ps7_ethernet_0;
        serial0 = &ps7_uart_1;

        spi0 = &ps7_qspi_0;
    } ;
    chosen {
/*        bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; */
        bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1 coherent_pool=16M";
        linux,stdout-path = "/amba@0/serial@e0001000";
    } ;
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        ps7_cortexa9_0: cpu@0 {
            bus-handle = <&ps7_axi_interconnect_0>;
            clock-latency = <1000>;
            clocks = <&clkc 3>;
            compatible = "arm,cortex-a9";
            device_type = "cpu";
            interrupt-handle = <&ps7_scugic_0>;
            /* operating-points = <666667 1000000 333334 1000000 >; */
            operating-points = <650000 1000000 >;
            reg = <0x0>;
        } ;
        ps7_cortexa9_1: cpu@1 {
            bus-handle = <&ps7_axi_interconnect_0>;
            clocks = <&clkc 3>;
            compatible = "arm,cortex-a9";
            device_type = "cpu";
            interrupt-handle = <&ps7_scugic_0>;
            reg = <0x1>;
        } ;
    } ;
    pmu {
        compatible = "arm,cortex-a9-pmu";
        interrupt-parent = <&ps7_scugic_0>;
        interrupts = <0 5 4>, <0 6 4>;
        reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>;
        reg-names = "cpu0", "cpu1";
    } ;
    ps7_ddr_0: memory@0 {
        device_type = "memory";
        reg = <0x0 0x20000000>;
    } ;
    ps7_axi_interconnect_0: amba@0 {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus";
        ranges ;
        ps7_afi_0: ps7-afi@f8008000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf8008000 0x1000>;
        } ;
        ps7_afi_1: ps7-afi@f8009000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf8009000 0x1000>;
        } ;
        ps7_afi_2: ps7-afi@f800a000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf800a000 0x1000>;
        } ;
        ps7_afi_3: ps7-afi@f800b000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf800b000 0x1000>;
        } ;
        ps7_ddrc_0: ps7-ddrc@f8006000 {
            compatible = "xlnx,zynq-ddrc-1.0";
            reg = <0xf8006000 0x1000>;
            xlnx,has-ecc = <0x0>;
        } ;
        ps7_dev_cfg_0: ps7-dev-cfg@f8007000 {
            clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
            clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;
            compatible = "xlnx,zynq-devcfg-1.0";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 8 4>;
            reg = <0xf8007000 0x100>;
        } ;
        ps7_dma_s: ps7-dma@f8003000 {
            #dma-cells = <1>;
            #dma-channels = <8>;
            #dma-requests = <4>;
            clock-names = "apb_pclk";
            clocks = <&clkc 27>;
            compatible = "arm,primecell", "arm,pl330";
            interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
                "dma4", "dma5", "dma6", "dma7";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>;
            reg = <0xf8003000 0x1000>;
        } ;
        ps7_ethernet_0: ps7-ethernet@e000b000 {
            #address-cells = <1>;
            #size-cells = <0>;
            clock-names = "ref_clk", "aper_clk";
            clocks = <&clkc 13>, <&clkc 30>;
            compatible = "xlnx,ps7-ethernet-1.00.a";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 22 4>;
            phy-handle = <&phy0>;
            phy-mode = "rgmii-id";
            reg = <0xe000b000 0x1000>;
            xlnx,eth-mode = <0x1>;
            xlnx,has-mdio = <0x1>;
            xlnx,ptp-enet-clock = <108333336>;
            mdio {
                #address-cells = <1>;
                #size-cells = <0>;
                phy0: phy@1 {
                    compatible = "realtek,RTL8211E";
                    device_type = "ethernet-phy";
                    reg = <1>;
                } ;
            } ;
        } ;
        ps7_globaltimer_0: ps7-globaltimer@f8f00200 {
            clocks = <&clkc 4>;
            compatible = "arm,cortex-a9-global-timer";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <1 11 0x301>;
            reg = <0xf8f00200 0x100>;
        } ;
        ps7_gpio_0: ps7-gpio@e000a000 {
            #gpio-cells = <2>;
            clocks = <&clkc 42>;
            compatible = "xlnx,zynq-gpio-1.0";
            emio-gpio-width = <64>;
            gpio-controller ;
            gpio-mask-high = <0xc0000>;
            gpio-mask-low = <0xfe81>;
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 20 4>;
            reg = <0xe000a000 0x1000>;
        } ;
        ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 {
            compatible = "xlnx,ps7-iop-bus-config-1.00.a";
            reg = <0xe0200000 0x1000>;
        } ;
        ps7_ocmc_0: ps7-ocmc@f800c000 {
            compatible = "xlnx,zynq-ocmc-1.0";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 3 4>;
            reg = <0xf800c000 0x1000>;
        } ;
        ps7_pl310_0: ps7-pl310@f8f02000 {
            arm,data-latency = <3 2 2>;
            arm,tag-latency = <2 2 2>;
            cache-level = <2>;
            cache-unified ;
            compatible = "arm,pl310-cache";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 2 4>;
            reg = <0xf8f02000 0x1000>;
        } ;
        ps7_qspi_0: ps7-qspi@e000d000 {
            clock-names = "ref_clk", "pclk";
            clocks = <&clkc 10>, <&clkc 43>;
            compatible = "xlnx,zynq-qspi-1.0";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 19 4>;
            is-dual = <0>;
            num-cs = <1>;
            reg = <0xe000d000 0x1000>;
            xlnx,fb-clk = <0x1>;
            xlnx,qspi-mode = <0x0>;
            #address-cells = <1>;
            #size-cells = <0>;
            flash@0 {
                compatible = "n25q128";
                reg = <0x0>;
                spi-tx-bus-width = <1>;
                spi-rx-bus-width = <4>;
                spi-max-frequency = <50000000>;
                #address-cells = <1>;
                #size-cells = <1>;
                partition@qspi-fsbl-uboot {
                    label = "qspi-fsbl-uboot";
                    reg = <0x0 0x400000>;
                };
                partition@qspi-linux {
                    label = "qspi-linux";
                    reg = <0x400000 0x500000>;
                };
                partition@qspi-device-tree {
                    label = "qspi-device-tree";
                    reg = <0x900000 0x20000>;
                };
                partition@qspi-user {
                    label = "qspi-user";
                    reg = <0x920000 0x6E0000>;
                };
            };

        } ;
        ps7_qspi_linear_0: ps7-qspi-linear@fc000000 {
            clock-names = "ref_clk", "aper_clk";
            clocks = <&clkc 10>, <&clkc 43>;
            compatible = "xlnx,ps7-qspi-linear-1.00.a";
            reg = <0xfc000000 0x1000000>;
        } ;
        ps7_scugic_0: ps7-scugic@f8f01000 {
            #address-cells = <2>;
            #interrupt-cells = <3>;
            #size-cells = <1>;
            compatible = "arm,cortex-a9-gic", "arm,gic";
            interrupt-controller ;
            num_cpus = <2>;
            num_interrupts = <96>;
            reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>;
        } ;
        ps7_scutimer_0: ps7-scutimer@f8f00600 {
            clocks = <&clkc 4>;
            compatible = "arm,cortex-a9-twd-timer";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <1 13 0x301>;
            reg = <0xf8f00600 0x20>;
        } ;
        ps7_scuwdt_0: ps7-scuwdt@f8f00620 {
            clocks = <&clkc 4>;
            compatible = "xlnx,ps7-scuwdt-1.00.a";
            device_type = "watchdog";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <1 14 0x301>;
            reg = <0xf8f00620 0xe0>;
        } ;
        ps7_sd_0: ps7-sdio@e0100000 {
            clock-frequency = <50000000>;
            clock-names = "clk_xin", "clk_ahb";
            clocks = <&clkc 21>, <&clkc 32>;
            compatible = "arasan,sdhci-8.9a";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 24 4>;
            reg = <0xe0100000 0x1000>;
            xlnx,has-cd = <0x1>;
            xlnx,has-power = <0x0>;
            xlnx,has-wp = <0x1>;
        } ;
        ps7_slcr_0: ps7-slcr@f8000000 {
            #address-cells = <1>;
            #size-cells = <1>;
            compatible = "xlnx,zynq-slcr", "syscon";
            ranges ;
            reg = <0xf8000000 0x1000>;
            clkc: clkc@100 {
                #clock-cells = <1>;
                clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x",
                    "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci",
                    "lqspi", "smc", "pcap", "gem0", "gem1",
                    "fclk0", "fclk1", "fclk2", "fclk3", "can0",
                    "can1", "sdio0", "sdio1", "uart0", "uart1",
                    "spi0", "spi1", "dma", "usb0_aper", "usb1_aper",
                    "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper",
                    "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper",
                    "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper",
                    "swdt", "dbg_trc", "dbg_apb";
                compatible = "xlnx,ps7-clkc";
                fclk-enable = <0xf>;
                ps-clk-frequency = <50000000>;
                reg = <0x100 0x100>;
            } ;
        } ;
        ps7_ttc_0: ps7-ttc@f8001000 {
            clocks = <&clkc 6>;
            compatible = "cdns,ttc";
            interrupt-names = "ttc0", "ttc1", "ttc2";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
            reg = <0xf8001000 0x1000>;
        } ;
        ps7_uart_1: serial@e0001000 {
            clock-names = "uart_clk", "pclk";
            clocks = <&clkc 24>, <&clkc 41>;
            compatible = "xlnx,xuartps", "cdns,uart-r1p8";
            current-speed = <115200>;
            device_type = "serial";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 50 4>;
            port-number = <0>;
            reg = <0xe0001000 0x1000>;
            xlnx,has-modem = <0x0>;
        } ;
        ps7_usb_0: ps7-usb@e0002000 {
            clocks = <&clkc 28>;
            compatible = "xlnx,ps7-usb-1.00.a", "xlnx,zynq-usb-1.00.a";
            dr_mode = "host";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 21 4>;
            phy_type = "ulpi";
            reg = <0xe0002000 0x1000>;
            xlnx,usb-reset = "MIO 46";
        } ;
        ps7_xadc: ps7-xadc@f8007100 {
            clocks = <&clkc 12>;
            compatible = "xlnx,zynq-xadc-1.00.a";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 7 4>;
            reg = <0xf8007100 0x20>;
        } ;
        
        mt9d111_axi_iic@0x41600000 {
            compatible = "generic-uio";
            reg = < 0x41600000 0x10000>;
        };
        dmaw4gabor_0@43cb0000 {
            compatible = "generic-uio";
            reg = < 0x43cb0000 0x10000 >;
        };
        axis_switch_0@0x43c10000 {
            compatible = "generic-uio";
            reg = < 0x43c10000 0x10000 >;
        };
        axis_switch_1@0x43c20000 {
            compatible = "generic-uio";
            reg = < 0x43c20000 0x10000 >;
        };
        lap_filter_axis_0@0x43c30000 {
            compatible = "generic-uio";
            reg = < 0x43c30000 0x10000>;
        };    
        mt9d111_inf_axis_0@0x43C40000 {
            compatible = "generic-uio";
            reg = < 0x43C40000 0x10000>;
        };
        bitmap_disp_cntrler_axi_master_0@0x43c00000 {
            compatible = "generic-uio";
            reg = < 0x43c00000 0x10000>;
        };
        bitmap_disp_cntrler_axi_master_1@0x43c50000 {
            compatible = "generic-uio";
            reg = < 0x43c50000 0x10000>;
        };
        axi_gpio_0@0x41200000 {
            compatible = "generic-uio";
            reg = < 0x41200000 0x10000>;
        };
        frame_buffer_bmdc@0x17800000 {
            compatible = "generic-uio";
            reg = < 0x17800000 0x1000000>;
        };
        pwm_0@0x43c60000 {
            compatible = "generic-uio";
            reg = < 0x43c60000 0x10000>;
        };
        pwm_1@0x43c70000 {
            compatible = "generic-uio";
            reg = < 0x43c70000 0x10000>;
        };
        motor_monitor_0@0x43c80000 {
            compatible = "generic-uio";
            reg = < 0x43c80000 0x10000>;
        };
        motor_monitor_1@0x43c90000 {
            compatible = "generic-uio";
            reg = < 0x43c90000 0x10000>;
        };
        dmar4resize_gray_0@0x43ca0000 {
            compatible = "generic-uio";
            reg = < 0x43ca0000 0x10000>;
        };
        rgb2hsv_0@0x43cc0000 {
            compatible = "generic-uio";
            reg = < 0x43cc0000 0x10000>;
        };
        ultrasoninc_sensor_inf_0@0x43cd0000 {
            compatible = "generic-uio";
            reg = < 0x43cd0000 0x10000>;
        };
        resize_gray_0@0x43ce0000 {
            compatible = "generic-uio";
            reg = < 0x43ce0000 0x10000>;
        };
        curve_conv_nn2_axis3_0@0x43cf0000 {
            compatible = "generic-uio";
            reg = < 0x43cf0000 0x10000>;
        };
    } ;
} ;

  1. 2017年12月27日 05:37 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク16(SDK)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク15(Vivadoプロジェクト)”の続き。

前回は、 curve_conv_nn2_axis3 IP を使用し、直線用のVivado 2017.3 のプロジェクトを修正して、カーブと直線対応のミニ・ロボットカーの走行システムをVivado 2017.3 で作成した。今回は、ハードウェアをエクスポートして、SDKを立ち上げ、アプリケーションソフトを作成して動作を確認してみよう。

まずは、Vivado で File メニューからExport → Export Hardware... を選択して、ハードウェアをエクスポートした。

File メニューから Launch SDK を選択して、SDK を立ち上げた。

SDK で wl_tracing_cnn アプリケーション・プロジェクトを作成した。

wl_tracing_cnn.c を修正して、 wl_tracing_cnn アプリケーション・プロジェクトにコピーした。
curve_tracing_cnn_80_171226.png

ZYBO の電源をONした。コンフィギュレーション・モードはJTAG だ。

SDK の Xilinx メニューから Program FPG を選択して、FPGA にビット・ファイルをコンフィギュレーションした。

wl_tracing_cnn.elf を起動した。
VGA ポートに接続したディスプレイにカメラ画像が表示された。
シリアル・ポートに接続されたTera Term の画面に結果と 3 出力の値が表示された。
curve_tracing_cnn_81_171226.png

成功だ。

wl_tracing_cnn.c を貼っておく。

/* * wl_tracing_cnn.c * *  Created on: 2017/09/18 *      Author: Masaaki */
// ベアメタル・アプリケーションでは、CNN がきちんと動作しているを確認するのみとする
// なお、このアプリケーションはcam_disp3_axis.c を起動してカメラを表示状態にした後で起動する
// 2017/09/19 : 直進、左旋回、右旋回の各出力の値を表示するように変更
// 2017/12/12 : カーブ対応に更新
//

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

#include "xdmaw4gabor.h"
#include "xdmar4resize_gray.h"
#include "xresize_gray.h"
#include "xcurve_conv_nn2_axis3.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 FRAME_BUFFER_ADDRESS 0x10000000
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

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(){
    XDmar4resize_gray xdmar;
    XResize_gray resg;
    XCurve_conv_nn2_axis3 stcnn;
    XDmaw4gabor xdma4g;
    int i;
    uint32_t res;
    int result[4];

    // 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), 0x0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x48), 0x80000000); // disable
    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), 0x0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers

    XDmaw4gabor_Initialize(&xdma4g, 0);
    XDmaw4gabor_Set_frame_buffer0(&xdma4g, FRAME_BUFFER_ADDRESS);
    XDmaw4gabor_Set_frame_buffer1(&xdma4g, FRAME_BUFFER_ADDRESS+ALL_DISP_ADDRESS);
    XDmaw4gabor_Start(&xdma4g);
    XDmaw4gabor_EnableAutoRestart(&xdma4g);

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

    bmdc0_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    bmdc1_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_1_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;

    bmdc0_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 0 start
    bmdc1_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 1 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

    XDmar4resize_gray_Initialize(&xdmar, 0);
    XResize_gray_Initialize(&resg, 0);
    XCurve_conv_nn2_axis3_Initialize(&stcnn, 0);

    XDmar4resize_gray_Set_frame_buffer0(&xdmar ,FRAME_BUFFER_ADDRESS);
    XDmar4resize_gray_Set_frame_buffer1(&xdmar ,FRAME_BUFFER_ADDRESS+ALL_DISP_ADDRESS);
    XDmar4resize_gray_Start(&xdmar);
    XDmar4resize_gray_EnableAutoRestart(&xdmar);

    XResize_gray_Start(&resg);
    XResize_gray_EnableAutoRestart(&resg);

    XCurve_conv_nn2_axis3_Start(&stcnn);
    XCurve_conv_nn2_axis3_EnableAutoRestart(&stcnn);

    while(1){
        sleep(1);

        while(!XCurve_conv_nn2_axis3_Get_outs_V_vld(&stcnn)) ;
        printf("out = %d\n", (int)XCurve_conv_nn2_axis3_Get_outs_V(&stcnn));
        for(i=0; i<2; i++){
            XCurve_conv_nn2_axis3_Read_dot2_V_Words(&stcnn, i, &res, 1);
            result[i*2] = res & 0xffff;
            if(result[i*2] & 0x8000// minus
                result[i*2] = 0xffff0000 | result[i*2]; // Sign extension

            result[i*2+1] = (res & 0xffff0000) >> 16;
            if(result[i*2+1] & 0x8000// minus
                result[i*2+1] = 0xffff0000 | result[i*2+1]; // Sign extension
        }
        for(i=0; i<3; i++)
            printf("result[%d] = %x ", i , result[i]);
        printf("\n");
    }

    return(0);
}


  1. 2017年12月26日 05:14 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

UltraZed-EG Starter Kit でDebian が起動した

@ikwzm さんの”ZynqMP-FPGA-Linux”の”UltraZed EG IOCC”を使わせてもらって、UltraZed-EG Starter Kit でDebian を動作させてみよう。

@ikwzm さん、いつもありがとうございます。使わせていただきます。

やり方は”UltraZed EG IOCC”を見ながらその通りにやってみる。

まずは、次のコマンドを実行した。
git clone git://github.com/ikwzm/ZynqMP-FPGA-Linux
cd ZynqMP-FPGA-Linux
git checkout v0.1.1

UltraZed-EG_StKit_Linux_1_171225.png

git lfs pull
UltraZed-EG_StKit_Linux_2_171225.png

ZynqMP-FPGA-Linux ディレクトリを tree コマンドでディレクトリ構造を見た結果を示す。
UltraZed-EG_StKit_Linux_3_171225.png

”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる2(Micro SDカードの準備)”の通りに 8 GB の Micro SD カードを用意した。
UltraZed-EG_StKit_Linux_4_171225.png

FAT32 のUltraZed-EG と ext3 の ROOT_FS をマウントした。
UltraZed-EG_StKit_Linux_5_171225.png

~/ZynqMP-FPGA-Linux/target/UltraZed-EG-IOCC/boot ディレクトリのファイルを /media/ono/UltraZed-EG ディレクトリにコピーした。
cp ZynqMP-FPGA-Linux/target/UltraZed-EG-IOCC/boot/* /media/ono/UltraZed-EG/
UltraZed-EG_StKit_Linux_6_171225.png

/media/ono/UltraZed-EG ディレクトリのファイルを示す。
UltraZed-EG_StKit_Linux_7_171225.png

sudo tar xfz ZynqMP-FPGA-Linux/debian9-rootfs-vanilla.tgz -C /media/ono/ROOT_FS/
UltraZed-EG_StKit_Linux_8_171225.png

/media/ono/ROOT_FS ディレクトリを示す。
UltraZed-EG_StKit_Linux_9_171225.png

sudo mkdir /media/ono/ROOT_FS/fpga
sudo mkdir /media/ono/ROOT_FS/fpga/debian
sudo cp ZynqMP-FPGA-Linux/linux-image-4.9.0-xlnx-v2017.3-zynqmp-fpga_4.9.0-xlnx-v2017.3-zynqmp-fpga-1_arm64.deb /media/ono/ROOT_FS/fpga/debian/
sudo cp ZynqMP-FPGA-Linux/linux-headers-4.9.0-xlnx-v2017.3-zynqmp-fpga_4.9.0-xlnx-v2017.3-zynqmp-fpga-1_arm64.deb /media/ono/ROOT_FS/fpga/debian/

UltraZed-EG_StKit_Linux_10_171225.png

/media/ono/ROOT_FS/fpga/debian ディレクトリを示す。
UltraZed-EG_StKit_Linux_11_171225.png

これで、Micro SDカードが完成したので、UltraZed-EG Starter Kit に挿入して電源ONした。
Debian が無事に起動した。
UltraZed-EG_StKit_Linux_12_171225.png

起動メッセージを貼っておく。

Xilinx Zynq MP First Stage Boot Loader
Release 2017.2   Dec 24 2017  -  11:06:15
NOTICE:  ATF running on XCZU3EG/silicon v4/RTL5.1 at 0xfffea000, with PMU firmware
NOTICE:  BL31: Secure code at 0x0
NOTICE:  BL31: Non secure code at 0x8000000
NOTICE:  BL31: v1.4(release):development build
NOTICE:  BL31: Built : 11:44:32, Dec 24 2017
PMUFW:  v0.3


U-Boot 2017.01 (Dec 25 2017 - 00:11:15 +0900) Xilinx ZynqMP UltraZed-EG-IOCC

I2C:   ready
DRAM:  2 GiB
EL Level:       EL2
Chip ID:        xczu3eg
MMC:   sdhci@ff160000: 0 (eMMC), sdhci@ff170000: 1 (SD)
reading uboot.env

** Unable to read "uboot.env" from mmc0:1 **
Using default environment

In:    serial@ff000000
Out:   serial@ff000000
Err:   serial@ff000000
Bootmode: SD_MODE1
Net:   ZYNQ GEM: ff0e0000, phyaddr 9, interface rgmii-id

Warning: ethernet@ff0e0000 (eth0) using random MAC address - 9a:5e:bc:78:ef:9c
eth0: ethernet@ff0e0000
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc1 is current device
Device: sdhci@ff170000
Manufacturer ID: 74
OEM: 4a60
Name: USDU1
Tran Speed: 50000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 7.3 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
reading uEnv.txt
461 bytes read in 11 ms (40 KiB/s)
Loaded environment from uEnv.txt
Importing environment from SD ...
Running uenvcmd ...
reading image-4.9.0-xlnx-v2017.3-fpga
13042176 bytes read in 880 ms (14.1 MiB/s)
reading devicetree-4.9.0-xlnx-v2017.3-fpga-zynqmp-uz3eg-iocc.dtb
34934 bytes read in 20 ms (1.7 MiB/s)
## Flattened Device Tree blob at 04000000
   Booting using the fdt blob at 0x4000000
   Loading Device Tree to 000000000fff4000, end 000000000ffff875 ... OK

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.9.0-xlnx-v2017.3-zynqmp-fpga (ichiro@sphinx-vm-ubuntu) (gcc version 5.4.0 20160609 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.4) ) #1 SMP Thu Dec 21 13:06:41 JST 2017
[    0.000000] Boot CPU: AArch64 Processor [410fd034]
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] cma: Reserved 256 MiB at 0x0000000070000000
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: PSCIv1.1 detected in firmware.
[    0.000000] psci: Using standard PSCI v0.2 function IDs
[    0.000000] psci: MIGRATE_INFO_TYPE not supported.
[    0.000000] percpu: Embedded 21 pages/cpu @ffffffc06ff74000 s47384 r8192 d30440 u86016
[    0.000000] Detected VIPT I-cache on CPU0
[    0.000000] CPU features: enabling workaround for ARM erratum 845719
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 517120
[    0.000000] Kernel command line: console=ttyPS0,115200 root=/dev/mmcblk1p2 rw rootwait uio_pdrv_genirq.of_id=generic-uio
[    0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
[    0.000000] Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.000000] Inode-cache hash table entries: 131072 (order: 8, 1048576 bytes)
[    0.000000] Memory: 1789496K/2097152K available (8892K kernel code, 576K rwdata, 2732K rodata, 512K init, 389K bss, 45512K reserved, 262144K cma-reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     modules : 0xffffff8000000000 - 0xffffff8008000000   (   128 MB)
[    0.000000]     vmalloc : 0xffffff8008000000 - 0xffffffbebfff0000   (   250 GB)
[    0.000000]       .text : 0xffffff8008080000 - 0xffffff8008930000   (  8896 KB)
[    0.000000]     .rodata : 0xffffff8008930000 - 0xffffff8008be0000   (  2752 KB)
[    0.000000]       .init : 0xffffff8008be0000 - 0xffffff8008c60000   (   512 KB)
[    0.000000]       .data : 0xffffff8008c60000 - 0xffffff8008cf0200   (   577 KB)
[    0.000000]        .bss : 0xffffff8008cf0200 - 0xffffff8008d5163c   (   390 KB)
[    0.000000]     fixed   : 0xffffffbefe7fd000 - 0xffffffbefec00000   (  4108 KB)
[    0.000000]     PCI I/O : 0xffffffbefee00000 - 0xffffffbeffe00000   (    16 MB)
[    0.000000]     vmemmap : 0xffffffbf00000000 - 0xffffffc000000000   (     4 GB maximum)
[    0.000000]               0xffffffbf00000000 - 0xffffffbf01c00000   (    28 MB actual)
[    0.000000]     memory  : 0xffffffc000000000 - 0xffffffc080000000   (  2048 MB)
[    0.000000] Hierarchical RCU implementation.
[    0.000000]  Build-time adjustment of leaf fanout to 64.
[    0.000000]  RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
[    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=4
[    0.000000] NR_IRQS:64 nr_irqs:64 0
[    0.000000] GIC: Adjusting CPU interface base to 0x00000000f902f000
[    0.000000] GIC: Using split EOI/Deactivate mode
[    0.000000] arm_arch_timer: Architected cp15 timer(s) running at 99.99MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x171015c90f, max_idle_ns: 440795203080 ns
[    0.000003] sched_clock: 56 bits at 99MHz, resolution 10ns, wraps every 4398046511101ns
[    0.000287] Console: colour dummy device 80x25
[    0.000307] Calibrating delay loop (skipped), value calculated using timer frequency.. 199.99 BogoMIPS (lpj=399996)
[    0.000315] pid_max: default: 32768 minimum: 301
[    0.000431] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes)
[    0.000437] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes)
[    0.001093] ASID allocator initialised with 65536 entries
[    0.001652] zynqmp_plat_init Power management API v0.3
[    0.001736] EFI services will not be available.
[    0.002118] Detected VIPT I-cache on CPU1
[    0.002149] CPU1: Booted secondary processor [410fd034]
[    0.002452] Detected VIPT I-cache on CPU2
[    0.002472] CPU2: Booted secondary processor [410fd034]
[    0.002761] Detected VIPT I-cache on CPU3
[    0.002780] CPU3: Booted secondary processor [410fd034]
[    0.002819] Brought up 4 CPUs
[    0.002834] SMP: Total of 4 processors activated.
[    0.002841] CPU features: detected feature: 32-bit EL0 Support
[    0.002847] CPU: All CPU(s) started at EL2
[    0.002862] alternatives: patching kernel code
[    0.003642] devtmpfs: initialized
[    0.009113] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.015329] xor: measuring software checksum speed
[    0.052049]    8regs     :  2048.000 MB/sec
[    0.092080]    8regs_prefetch:  1882.000 MB/sec
[    0.132112]    32regs    :  2500.000 MB/sec
[    0.172145]    32regs_prefetch:  2182.000 MB/sec
[    0.172149] xor: using function: 32regs (2500.000 MB/sec)
[    0.172249] pinctrl core: initialized pinctrl subsystem
[    0.172979] NET: Registered protocol family 16
[    0.190620] cpuidle: using governor menu
[    0.190848] Failed to initialise IOMMU /amba/smmu@fd800000
[    0.191041] vdso: 2 pages (1 code @ ffffff8008937000, 1 data @ ffffff8008c64000)
[    0.191053] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[    0.191658] DMA: preallocated 256 KiB pool for atomic allocations
[    0.206145] reset_zynqmp reset-controller: Xilinx zynqmp reset driver probed
[    0.206799] ARM CCI_400_r1 PMU driver probed
[    0.210336] zynqmp-pinctrl ff180000.pinctrl: zynqmp pinctrl initialized
[    0.238939] HugeTLB registered 2 MB page size, pre-allocated 0 pages
[    0.304416] raid6: int64x1  gen()   374 MB/s
[    0.372346] raid6: int64x1  xor()   399 MB/s
[    0.440410] raid6: int64x2  gen()   613 MB/s
[    0.508452] raid6: int64x2  xor()   548 MB/s
[    0.576501] raid6: int64x4  gen()   950 MB/s
[    0.644540] raid6: int64x4  xor()   689 MB/s
[    0.712598] raid6: int64x8  gen()  1007 MB/s
[    0.780633] raid6: int64x8  xor()   666 MB/s
[    0.848700] raid6: neonx1   gen()   662 MB/s
[    0.916766] raid6: neonx1   xor()   695 MB/s
[    0.984811] raid6: neonx2   gen()  1069 MB/s
[    1.052857] raid6: neonx2   xor()   949 MB/s
[    1.120907] raid6: neonx4   gen()  1382 MB/s
[    1.188942] raid6: neonx4   xor()  1083 MB/s
[    1.256982] raid6: neonx8   gen()  1443 MB/s
[    1.325034] raid6: neonx8   xor()  1103 MB/s
[    1.325038] raid6: using algorithm neonx8 gen() 1443 MB/s
[    1.325042] raid6: .... xor() 1103 MB/s, rmw enabled
[    1.325046] raid6: using intx1 recovery algorithm
[    1.325882] SCSI subsystem initialized
[    1.326101] usbcore: registered new interface driver usbfs
[    1.326142] usbcore: registered new interface driver hub
[    1.326187] usbcore: registered new device driver usb
[    1.326265] media: Linux media interface: v0.10
[    1.326297] Linux video capture interface: v2.00
[    1.326327] pps_core: LinuxPPS API ver. 1 registered
[    1.326331] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    1.326348] PTP clock support registered
[    1.326381] EDAC MC: Ver: 3.0.0
[    1.326708] FPGA manager framework
[    1.326858] fpga-region fpga-full: FPGA Region probed
[    1.326958] Advanced Linux Sound Architecture Driver Initialized.
[    1.327304] Bluetooth: Core ver 2.22
[    1.327331] NET: Registered protocol family 31
[    1.327335] Bluetooth: HCI device and connection manager initialized
[    1.327345] Bluetooth: HCI socket layer initialized
[    1.327352] Bluetooth: L2CAP socket layer initialized
[    1.327375] Bluetooth: SCO socket layer initialized
[    1.328020] clocksource: Switched to clocksource arch_sys_counter
[    1.328102] VFS: Disk quotas dquot_6.6.0
[    1.328150] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    1.333325] NET: Registered protocol family 2
[    1.333729] TCP established hash table entries: 16384 (order: 5, 131072 bytes)
[    1.333847] TCP bind hash table entries: 16384 (order: 6, 262144 bytes)
[    1.334137] TCP: Hash tables configured (established 16384 bind 16384)
[    1.334209] UDP hash table entries: 1024 (order: 3, 32768 bytes)
[    1.334254] UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes)
[    1.334406] NET: Registered protocol family 1
[    1.334641] RPC: Registered named UNIX socket transport module.
[    1.334646] RPC: Registered udp transport module.
[    1.334649] RPC: Registered tcp transport module.
[    1.334653] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    1.335102] hw perfevents: enabled with armv8_pmuv3 PMU driver, 7 counters available
[    1.335862] futex hash table entries: 1024 (order: 5, 131072 bytes)
[    1.335945] audit: initializing netlink subsys (disabled)
[    1.335972] audit: type=2000 audit(1.324:1): initialized
[    1.336515] workingset: timestamp_bits=62 max_order=19 bucket_order=0
[    1.337189] NFS: Registering the id_resolver key type
[    1.337207] Key type id_resolver registered
[    1.337211] Key type id_legacy registered
[    1.337220] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[    1.337241] jffs2: version 2.2. (NAND) (SUMMARY)  c 2001-2006 Red Hat, Inc.
[    1.342073] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 247)
[    1.342080] io scheduler noop registered
[    1.342085] io scheduler deadline registered
[    1.342095] io scheduler cfq registered (default)
[    1.343355] xilinx-dpdma fd4c0000.dma: Xilinx DPDMA engine is probed
[    1.343741] Write failed gate address:1000f02
[    1.343846] xilinx-zynqmp-dma fd500000.dma: ZynqMP DMA driver Probe success
[    1.343980] xilinx-zynqmp-dma fd510000.dma: ZynqMP DMA driver Probe success
[    1.344135] xilinx-zynqmp-dma fd520000.dma: ZynqMP DMA driver Probe success
[    1.344269] xilinx-zynqmp-dma fd530000.dma: ZynqMP DMA driver Probe success
[    1.344405] xilinx-zynqmp-dma fd540000.dma: ZynqMP DMA driver Probe success
[    1.344540] xilinx-zynqmp-dma fd550000.dma: ZynqMP DMA driver Probe success
[    1.344679] xilinx-zynqmp-dma fd560000.dma: ZynqMP DMA driver Probe success
[    1.344815] xilinx-zynqmp-dma fd570000.dma: ZynqMP DMA driver Probe success
[    1.345086] xilinx-zynqmp-dma ffa80000.dma: ZynqMP DMA driver Probe success
[    1.345224] xilinx-zynqmp-dma ffa90000.dma: ZynqMP DMA driver Probe success
[    1.345363] xilinx-zynqmp-dma ffaa0000.dma: ZynqMP DMA driver Probe success
[    1.345498] xilinx-zynqmp-dma ffab0000.dma: ZynqMP DMA driver Probe success
[    1.345638] xilinx-zynqmp-dma ffac0000.dma: ZynqMP DMA driver Probe success
[    1.345777] xilinx-zynqmp-dma ffad0000.dma: ZynqMP DMA driver Probe success
[    1.345921] xilinx-zynqmp-dma ffae0000.dma: ZynqMP DMA driver Probe success
[    1.346058] xilinx-zynqmp-dma ffaf0000.dma: ZynqMP DMA driver Probe success
[    1.346232] zynqmp_pm firmware: Power management API v0.3
[    1.378801] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[    1.380299] ff000000.serial: ttyPS0 at MMIO 0xff000000 (irq = 40, base_baud = 6249999) is a xuartps
[    2.344446] console [ttyPS0] enabled
[    2.348408] ff010000.serial: ttyPS1 at MMIO 0xff010000 (irq = 41, base_baud = 6249999) is a xuartps
[    2.357593] [drm] Initialized
[    2.360846] [drm] load() is defered & will be called again
[    2.366757] xilinx-drm-dp-sub fd4aa000.dp_sub: Xilinx DisplayPort Subsystem is probed
[    2.374677] Unable to detect cache hierarchy from DT for CPU 0
[    2.385879] brd: module loaded
[    2.392174] loop: module loaded
[    2.396117] ahci-ceva fd0c0000.ahci: ceva,p1-cominit-params property not defined
[    2.403459] ahci-ceva: probe of fd0c0000.ahci failed with error -22
[    2.409810] mtdoops: mtd device (mtddev=name/number) must be supplied
[    2.417060] m25p80 spi0.0: found n25q256a, expected n25q512a
[    2.422760] m25p80 spi0.0: n25q256a (65536 Kbytes)
[    2.427481] 3 ofpart partitions found on MTD device spi0.0
[    2.432934] Creating 3 MTD partitions on "spi0.0":
[    2.437710] 0x000000000000-0x000000100000 : "boot"
[    2.443043] 0x000000100000-0x000000140000 : "bootenv"
[    2.448532] 0x000000140000-0x000001740000 : "kernel"
[    2.454850] libphy: Fixed MDIO Bus: probed
[    2.460085] tun: Universal TUN/TAP device driver, 1.6
[    2.465055] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
[    2.471360] CAN device driver interface
[    2.475757] macb ff0e0000.ethernet: Not enabling partial store and forward
[    2.483104] libphy: MACB_mii_bus: probed
[    2.488789] macb ff0e0000.ethernet eth0: Cadence GEM rev 0x50070106 at 0xff0e0000 irq 30 (9a:5e:bc:78:ef:9c)
[    2.498530] TI DP83867 ff0e0000.etherne:09: attached PHY driver [TI DP83867] (mii_bus:phy_addr=ff0e0000.etherne:09, irq=-1)
[    2.510135] usbcore: registered new interface driver asix
[    2.515491] usbcore: registered new interface driver ax88179_178a
[    2.521549] usbcore: registered new interface driver cdc_ether
[    2.527362] usbcore: registered new interface driver net1080
[    2.533003] usbcore: registered new interface driver cdc_subset
[    2.538906] usbcore: registered new interface driver zaurus
[    2.544473] usbcore: registered new interface driver cdc_ncm
[    2.550693] usbcore: registered new interface driver uas
[    2.555960] usbcore: registered new interface driver usb-storage
[    2.562234] mousedev: PS/2 mouse device common for all mice
[    2.568170] rtc_zynqmp ffa60000.rtc: rtc core: registered ffa60000.rtc as rtc0
[    2.575343] i2c /dev entries driver
[    2.579070] cdns-i2c ff030000.i2c: 400 kHz mmio ff030000 irq 32
[    2.585917] usbcore: registered new interface driver uvcvideo
[    2.591578] USB Video Class driver (1.1.1)
[    2.596212] cdns-wdt fd4d0000.watchdog: Xilinx Watchdog Timer at ffffff8008ed9000 with timeout 10s
[    2.605306] Bluetooth: HCI UART driver ver 2.3
[    2.609671] Bluetooth: HCI UART protocol H4 registered
[    2.614795] Bluetooth: HCI UART protocol BCSP registered
[    2.620081] Bluetooth: HCI UART protocol LL registered
[    2.625201] Bluetooth: HCI UART protocol ATH3K registered
[    2.630583] Bluetooth: HCI UART protocol Three-wire (H5) registered
[    2.636876] Bluetooth: HCI UART protocol Intel registered
[    2.642252] Bluetooth: HCI UART protocol Broadcom registered
[    2.647857] Bluetooth: HCI UART protocol QCA registered
[    2.653102] usbcore: registered new interface driver bcm203x
[    2.658741] usbcore: registered new interface driver bpa10x
[    2.664296] usbcore: registered new interface driver bfusb
[    2.669767] usbcore: registered new interface driver btusb
[    2.675200] Bluetooth: Generic Bluetooth SDIO driver ver 0.1
[    2.680895] usbcore: registered new interface driver ath3k
[    2.686436] EDAC MC: ECC not enabled
[    2.690090] EDAC DEVICE0: Giving out device to module zynqmp-ocm-edac controller zynqmp_ocm: DEV ff960000.memory-controller (INTERRUPT)
[    2.702697] cpufreq: cpufreq_online: CPU0: Running at unlisted freq: 1099999 KHz
[    2.710100] cpufreq: cpufreq_online: CPU0: Unlisted initial frequency changed to: 1199999 KHz
[    2.718960] sdhci: Secure Digital Host Controller Interface driver
[    2.725050] sdhci: Copyright(c) Pierre Ossman
[    2.729388] sdhci-pltfm: SDHCI platform and OF driver helper
[    2.735564] ledtrig-cpu: registered to indicate activity on CPUs
[    2.741619] usbcore: registered new interface driver usbhid
[    2.747110] usbhid: USB HID core driver
[    2.752738] fpga_manager fpga0: Xilinx ZynqMP FPGA Manager registered
[    2.759786] pktgen: Packet Generator for packet performance testing. Version: 2.75
[    2.767483] Netfilter messages via NETLINK v0.30.
[    2.772234] ip_tables: (C) 2000-2006 Netfilter Core Team
[    2.777511] Initializing XFRM netlink socket
[    2.781768] NET: Registered protocol family 10
[    2.786635] ip6_tables: (C) 2000-2006 Netfilter Core Team
[    2.791993] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[    2.798243] NET: Registered protocol family 17
[    2.802609] NET: Registered protocol family 15
[    2.807037] bridge: filtering via arp/ip/ip6tables is no longer available by default. Update your scripts to load br_netfilter if you need this.
[    2.819959] Ebtables v2.0 registered
[    2.823567] can: controller area network core (rev 20120528 abi 9)
[    2.829716] NET: Registered protocol family 29
[    2.834109] can: raw protocol (rev 20120528)
[    2.838359] can: broadcast manager protocol (rev 20161123 t)
[    2.844004] can: netlink gateway (rev 20130117) max_hops=1
[    2.849544] Bluetooth: RFCOMM TTY layer initialized
[    2.854350] Bluetooth: RFCOMM socket layer initialized
[    2.859470] Bluetooth: RFCOMM ver 1.11
[    2.863197] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[    2.868491] Bluetooth: BNEP filters: protocol multicast
[    2.873700] Bluetooth: BNEP socket layer initialized
[    2.878644] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
[    2.884549] Bluetooth: HIDP socket layer initialized
[    2.889652] 9pnet: Installing 9P2000 support
[    2.893848] Key type dns_resolver registered
[    2.898539] registered taskstats version 1
[    2.902987] Btrfs loaded, crc32c=crc32c-generic
[    2.918499] [drm] load() is defered & will be called again
[    2.924699] xilinx-psgtr fd400000.zynqmp_phy: Lane:3 type:8 protocol:4 pll_locked:yes
[    2.932734] xilinx-drm-dp fd4a0000.dp: device found, version 4.010
[    2.938839] xilinx-drm-dp fd4a0000.dp: Display Port, version 1.0200 (tx)
[    2.946521] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    2.951939] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 1
[    2.959810] xhci-hcd xhci-hcd.0.auto: hcc params 0x0238f625 hci version 0x100 quirks 0x02010010
[    2.968448] xhci-hcd xhci-hcd.0.auto: irq 220, io mem 0xfe200000
[    2.974542] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[    2.981248] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.988449] usb usb1: Product: xHCI Host Controller
[    2.993308] usb usb1: Manufacturer: Linux 4.9.0-xlnx-v2017.3-zynqmp-fpga xhci-hcd
[    3.000773] usb usb1: SerialNumber: xhci-hcd.0.auto
[    3.005958] hub 1-0:1.0: USB hub found
[    3.009642] hub 1-0:1.0: 1 port detected
[    3.013703] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    3.019114] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 2
[    3.026797] usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
[    3.034895] usb usb2: New USB device found, idVendor=1d6b, idProduct=0003
[    3.041599] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    3.048801] usb usb2: Product: xHCI Host Controller
[    3.053661] usb usb2: Manufacturer: Linux 4.9.0-xlnx-v2017.3-zynqmp-fpga xhci-hcd
[    3.061126] usb usb2: SerialNumber: xhci-hcd.0.auto
[    3.066274] hub 2-0:1.0: USB hub found
[    3.069957] hub 2-0:1.0: 1 port detected
[    3.120025] mmc0: SDHCI controller on ff160000.sdhci [ff160000.sdhci] using ADMA 64-bit
[    3.176026] mmc1: SDHCI controller on ff170000.sdhci [ff170000.sdhci] using ADMA 64-bit
[    3.184642] OF: graph: no port node found in /xilinx_drm
[    3.189876] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    3.196467] [drm] No driver support for vblank timestamp query.
[    3.243768] mmc0: new HS200 MMC card at address 0001
[    3.248926] mmcblk0: mmc0:0001 Q2J55L 7.09 GiB
[    3.253492] mmcblk0boot0: mmc0:0001 Q2J55L partition 1 16.0 MiB
[    3.259446] mmcblk0boot1: mmc0:0001 Q2J55L partition 2 16.0 MiB
[    3.265390] mmcblk0rpmb: mmc0:0001 Q2J55L partition 3 4.00 MiB
[    3.271930]  mmcblk0: p1
[    3.285962] mmc1: new high speed SDHC card at address 59b4
[    3.291577] mmcblk1: mmc1:59b4 USDU1 7.31 GiB
[    3.296619]  mmcblk1: p1 p2
[    3.339460] random: fast init done
[    7.324783] xilinx-drm xilinx_drm: No connectors reported connected with modes
[    7.331928] [drm] Cannot find any crtc or sizes - going 1024x768
[    7.344608] Console: switching to colour frame buffer device 128x48
[    7.355861] xilinx-drm xilinx_drm: fb0:  frame buffer device
[    7.380030] [drm] Initialized xilinx_drm 1.0.0 20130509 on minor 0
[    7.386366] rtc_zynqmp ffa60000.rtc: setting system clock to 2016-11-03 17:20:55 UTC (1478193655)
[    7.395160] of_cfs_init
[    7.397604] of_cfs_init: OK
[    7.401677] ALSA device list:
[    7.404554]   No soundcards found.
[    7.409324] EXT4-fs (mmcblk1p2): mounting ext3 file system using the ext4 subsystem
[    7.429639] EXT4-fs (mmcblk1p2): mounted filesystem with ordered data mode. Opts: (null)
[    7.437663] VFS: Mounted root (ext3 filesystem) on device 179:34.
[    7.447709] devtmpfs: mounted
[    7.450810] Freeing unused kernel memory: 512K (ffffffc000be0000 - ffffffc000c60000)
[    7.922171] systemd[1]: systemd 232 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN)
[    7.940358] systemd[1]: Detected architecture arm64.

Welcome to Debian GNU/Linux 9 (stretch)!

[    7.956544] systemd[1]: Set hostname to <debian-fpga>.
[    8.248911] systemd[1]: Reached target Swap.
[  OK  ] Reached target Swap.
[    8.264225] systemd[1]: Listening on udev Kernel Socket.
[  OK  ] Listening on udev Kernel Socket.
[    8.280172] systemd[1]: Listening on Journal Socket (/dev/log).
[  OK  ] Listening on Journal Socket (/dev/log).
[    8.296139] systemd[1]: Listening on /dev/initctl Compatibility Named Pipe.
[  OK  ] Listening on /dev/initctl Compatibility Named Pipe.
[    8.320166] systemd[1]: Listening on udev Control Socket.
[  OK  ] Listening on udev Control Socket.
[    8.336086] systemd[1]: Reached target Remote File Systems.
[  OK  ] Reached target Remote File Systems.
[    8.352264] systemd[1]: Created slice System Slice.
[  OK  ] Created slice System Slice.
         Mounting POSIX Message Queue File System...
[  OK  ] Started Dispatch Password Requests to Console Directory Watch.
[  OK  ] Listening on Journal Socket.
         Starting Nameserver information manager...
         Starting Remount Root and Kernel File Systems...
         Mounting Debug File System...
[  OK  ] Created slice system-getty.slice.
[  OK  ] Started Forward Password Requests to Wall Directory Watch.
[  OK  ] Reached target Encrypted Volumes.
[  OK  ] Reached target Paths.
         Starting Create Static Device Nodes in /dev...
[  OK  ] Created slice User and Session Slice.
[  OK  ] Reached target Slices.
[  OK  ] Listening on Journal Audit Socket.
         Starting Load Kernel Modules...
[  OK  ] Listening on Syslog Socket.
         Starting Journal Service...
[  OK  ] Created slice system-serial\x2dgetty.slice.
[  OK  ] Mounted Debug File System.
[  OK  ] Mounted POSIX Message Queue File System.
[  OK  ] Started Remount Root and Kernel File Systems.
[  OK  ] Started Create Static Device Nodes in /dev.
[  OK  ] Started Load Kernel Modules.
[  OK  ] Started Nameserver information manager.
[  OK  ] Started Journal Service.
         Starting Apply Kernel Variables...
         Mounting Configuration File System...
         Starting udev Kernel Device Manager...
         Starting Load/Save Random Seed...
         Starting Flush Journal to Persistent Storage...
[  OK  ] Reached target Local File Systems (Pre).
         Mounting /config...
         Starting udev Coldplug all Devices...
[  OK  ] Mounted Configuration File System.
[  OK  ] Mounted /config.
[  OK  ] Started Apply Kernel Variables.
[  OK  ] Started Load/Save Random Seed.
[    8.889501] systemd-journald[1607]: Received request to flush runtime journal from PID 1
[  OK  ] Started Flush Journal to Persistent Storage.
[  OK  ] Started udev Kernel Device Manager.
[  OK  ] Found device /dev/ttyPS0.
[  OK  ] Started udev Coldplug all Devices.
[  OK  ] Listening on Load/Save RF Kill Switch Status /dev/rfkill Watch.
[    9.341732] random: crng init done
[  OK  ] Found device /dev/mmcblk0p1.
         Mounting /boot...
[    9.740992] FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[  OK  ] Mounted /boot.
[  OK  ] Reached target Local File Systems.
         Starting Create Volatile Files and Directories...
[  OK  ] Started ifup for eth0.
         Starting Raise network interfaces...
[  OK  ] Started Create Volatile Files and Directories.
[  OK  ] Reached target System Time Synchronized.
         Starting Update UTMP about System Boot/Shutdown...
[  OK  ] Started Update UTMP about System Boot/Shutdown.
[  OK  ] Reached target System Initialization.
[  OK  ] Started Daily Cleanup of Temporary Directories.
[  OK  ] Listening on Avahi mDNS/DNS-SD Stack Activation Socket.
[  OK  ] Started Daily apt download activities.
[  OK  ] Started Daily apt upgrade and clean activities.
[  OK  ] Reached target Timers.
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Reached target Sockets.
[  OK  ] Reached target Basic System.
         Starting System Logging Service...
         Starting Login Service...
[  OK  ] Started Regular background program processing daemon.
[  OK  ] Started D-Bus System Message Bus.
[   10.131541] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
         Starting Avahi mDNS/DNS-SD Stack...
[  OK  ] Started System Logging Service.
[  OK  ] Started Login Service.
[  OK  ] Started Avahi mDNS/DNS-SD Stack.
[  OK  ] Started Raise network interfaces.
[  OK  ] Reached target Network.
         Starting OpenBSD Secure Shell server...
         Starting Permit User Sessions...
[  OK  ] Reached target Network is Online.
         Starting Samba NMB Daemon...
         Starting LSB: Start NTP daemon...
[  OK  ] Started Permit User Sessions.
[  OK  ] Started Getty on tty1.
[  OK  ] Started Serial Getty on ttyPS0.
[  OK  ] Reached target Login Prompts.
[  OK  ] Started OpenBSD Secure Shell server.
[  OK  ] Started LSB: Start NTP daemon.
[   11.140381] macb ff0e0000.ethernet eth0: link up (1000/Full)
[   11.146000] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
         Starting Samba SMB Daemon...
[  OK  ] Started Samba SMB Daemon.

Debian GNU/Linux 9 debian-fpga ttyPS0

debian-fpga login:

  1. 2017年12月26日 04:26 |
  2. UltraZed-EG
  3. | トラックバック:0
  4. | コメント:0

スター・ウォーズ/最後のジェダイ(映画)を見てきました

昨日、スター・ウォーズ/最後のジェダイ(映画)を見てきました。
スターウォーズは最初にエピソード4 を大学1年生の時に映画館で見たときからのファンです。確か、友人に連れられて行ったのですが、その迫力にびっくりして、ファンになりました。これから、欠かさずに新作が出ると映画館で見ています。今回スターウォーズも面白かったです。皆さん、見ましょう。
  1. 2017年12月25日 04:55 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク15(Vivadoプロジェクト)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク14(AXI4 Stream版CNN IP 2)”の続き。

前回で、カーブと直線での出力を学習した畳み込みニューラルネットワークをVivado HLS 2017.3 で IP にすることができた。今回はその curve_conv_nn2_axis3 IP を使用し、直線用のVivado 2017.3 のプロジェクトを修正して、カーブと直線対応のミニ・ロボットカーの走行システムを作成してみよう。

直線走行の時のVivado プロジェクトがあるので、それをVivado 2017.3 に変換して、 ZYBO_0_173_9 フォルダとした。

straight_conv_nn2_axis2 IP を削除して、代わりに curve_conv_nn2_axis3 IP を追加 した。
curve_tracing_cnn_68_171224.png

ZYBO_0_173_9 フォルダのZYBO_0_153 プロジェクトを示す。
curve_tracing_cnn_69_171224.png

ZYBO_0 ブロック・デザインを示す。
curve_tracing_cnn_70_171224.png

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

Address Editor を示す。最後に curve_conv_nn2_axi3_0 があるのが分かる。
curve_tracing_cnn_72_171224.png

これで、論理合成、インプリメント、ビットストリームの生成を行ったが、Timing エラーだった。
curve_tracing_cnn_73_171224.png

Timing エラーを探るために、Open Implement Degin をクリックした。
Timing を見ると、Intra-Clock Paths の clk_fpga_0 クロック領域内で、curve_conv_nn2_axis3 IP 内のパスがタイミング・エラーを起こしている。
curve_tracing_cnn_74_171224.png

やはり、Vivado HLS に戻って制約をきつくする必要がある。
Vivado HLS に戻って、curve_conv_nn2_axis3 プロジェクトを開いた。
Soulution メニューからSolution Settings を開く。
Solution Settings (solution1) ダイアログで、Uncertainty に 2 (ns) を設定した。(”Vivado HLS の合成でEstimated がTarget の制約を満たせなかったときの処置”を参照のこと)
curve_tracing_cnn_75_171224.png

C コードの合成を行った。結果を示す。
curve_tracing_cnn_76_171224.png
curve_tracing_cnn_77_171224.png

前の合成結果と比較すると、Latency が 100 クロック増えた。増えた場所は af1_dot1 で Iteration Latency が 956 から 957 になって、Trip Count が 100 なので、100 クロック増えている。これで一番のクリティカルパスをつぶしたのだろう。
Estimated は 8.38 ns が 8.77 ns になってしまったが、実質的な性能はExport RTL で確認しよう。

Export RTL を行った。結果を示す。
curve_tracing_cnn_78_171224.png

Final Timing のCP achieved post-implemetation は、8.944 ns になっていて、前回の 9.934 ns よりも大分改善してる。
この IP をZYBO_0_173_9 フォルダのVivado プロジェクトの curve_conv_nn2_axis3 フォルダにコピーした。

IP をUpgrade して、論理合成、インプリメント、ビットストリームの生成を行った。結果を示す。
curve_tracing_cnn_79_171224.png

今度は、タイミング・エラーは発生しなかった。成功だ。
  1. 2017年12月25日 04:47 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク14(AXI4 Stream版CNN IP 2)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク13(AXI4 Stream版CNN IP 1)”の続き。

前回は、カーブと直線走行用のAXI4 Stream 版畳み込みニューラルネットワーク IP を作成するために、curve_conv_nn2_axis3 プロジェクトを作成し、C シミュレーションを行った。今回は、C コードの合成を行い、Export RTL で IP にする。

C Synthesis ボタンをクリックして、C コードの合成を行った。結果を示す。
curve_tracing_cnn_64_171224.png
curve_tracing_cnn_65_171224.png

Estimated は 8.38 ns で Target の 10 ns を満たしている。Latency は 194433 クロックで、クロックが 100 MHz なので、約 1.94 ms となり十分に仕様を満たしている。
BRAM_18K は 18 個、DSP48E は 9 個、FF は 1031 個、LUT は 1680 個使用している。やはり、全体的にFF とLUT の使用数が少ない。

C/RTL コシミュレーションは、今回は飛ばすことにする。

Export RTL を行った。
Export RTL のダイアログで、Place and Route にチェックを入れて OK ボタンをクリックした。
curve_tracing_cnn_66_171224.png

Export RTL の結果を示す。
curve_tracing_cnn_67_171224.png

Resource Usage では、各リソース使用量がさらに下がっている。
気になるのは、Final Timing のCP achieved post-implemetation が 9.934 ns となっていることだ。これは実際にVivado 2017.3 で IP をインプリメントしたときにタイミングが実際に間に合わないという状況になってしまった。
ともかく、IP は完了できたので、Vivado のプロジェクトに持っていってインプリメントを行っていこう。
  1. 2017年12月24日 05:00 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク13(AXI4 Stream版CNN IP 1)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク12(直線走行用の重みとバイアスでカーブのテストデータを検証)”の続き。

AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIP と入れ替えるためにカーブと直線走行用のAXI4 Stream 版畳み込みニューラルネットワーク IP を作成しよう。
AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIP についての情報は以下の記事を参照のこと。
AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその1(C シミュレーション)
AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその2(C シミュレーション2)
AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその3(C シミュレーション、合成)

curve_conv_nn2_axis3 プロジェクトを作成した。
curve_tracing_cnn_62_171223.png

curve_conv_nn2_axis3.cpp を示す。
60 ピクセル x 45 行の画像から、56 ピクセル x 10 行を切り出して、畳み込みニューラルネットワークにかける。

// curve_conv_nn2_axis3.cpp
// 2017/09/09 by marsee
// 畳み込み層のカーネル数 2
// AXI4 Stream入力 番号出力
// 2017/09/18 : dot2[3]の出力も追加
// 2017/12/13 : 直線に加えてカーブのデータも使用して学習した
//

#include <ap_fixed.h>
#include <hls_stream.h>
#include <ap_axi_sdata.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"

#define REDUSED_ROW        45
#define REDUSED_COULMN    60
#define NUM_OF_KERNELS    2
#define COULMN_PIXELS    56
#define ROW_PIXELS        10
#define ALL_PIXELS        560
#define NUM_OF_OUTPUT    3

int max_ap_fixed(ap_fixed<167, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT], ap_uint<2> &out_num);

int curve_conv_nn2_axis3(hls::stream<ap_axiu<32,1,1,1> >& ins, ap_uint<2> &outs,
        ap_fixed<167, AP_TRN_ZERO, AP_SAT> dot2[NUM_OF_OUTPUT]){
#pragma HLS INTERFACE s_axilite port=dot2
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=outs
#pragma HLS INTERFACE axis register both port=ins
    ap_ufixed<80, AP_TRN_ZERO, AP_SAT> buf[ROW_PIXELS][COULMN_PIXELS];
    ap_fixed<136, AP_TRN_ZERO, AP_SAT> conv_out[NUM_OF_KERNELS][ROW_PIXELS-4][COULMN_PIXELS-4];
    ap_fixed<136, AP_TRN_ZERO, AP_SAT> pool_out[NUM_OF_KERNELS][(ROW_PIXELS-4)/2][(COULMN_PIXELS-4)/2];
    ap_fixed<167, AP_TRN_ZERO, AP_SAT> dot1[100];
    ap_axiu<32,1,1,1> pix;

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

    // 10 x 56 に整形
    buf_copy1: for(int i=0; i<REDUSED_ROW; i++){
        buf_copy2: for(int j=0; j<REDUSED_COULMN; j++){
            if (!(i==0 && j==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            if((i>=33 && i<33+ROW_PIXELS) && (j>=2 && j<2+COULMN_PIXELS)){
                buf[i-33][j-2] = (ap_ufixed<80, AP_TRN_ZERO, AP_SAT>)((ap_ufixed<168, AP_TRN_ZERO, AP_SAT>)(pix.data & 0xff) / 256);
            }
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<NUM_OF_KERNELS; i++){    // カーネルの個数
        CONV2: for(int j=0; j<ROW_PIXELS-4; j++){
            CONV3: for(int k=0; k<COULMN_PIXELS-4; 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<NUM_OF_KERNELS; i++){
        POOL2: for(int j=0; j<ROW_PIXELS-4; j += 2){
            POOL3: for(int k=0; k<COULMN_PIXELS-4; 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<NUM_OF_KERNELS; i++){
            af1_dot3: for(int j=0; j<(ROW_PIXELS-4)/2; j++){
                af1_dot4: for(int k=0; k<(COULMN_PIXELS-4)/2; k++){
                    dot1[col] += pool_out[i][j][k]*af1_weight[i*((ROW_PIXELS-4)/2)*((COULMN_PIXELS-4)/2)+j*((COULMN_PIXELS-4)/2)+k][col];
                }
            }
        }
        dot1[col] += af1_bias[col];

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

    af2_dot1: for(int col=0; col<NUM_OF_OUTPUT; 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];
    }

    max_ap_fixed(dot2, outs);

    return(0);
}

int max_ap_fixed(ap_fixed<167, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT], ap_uint<2> &out_num){
    int max_id;
    ap_fixed<167, AP_TRN_ZERO, AP_SAT> max;

    for(int i=0; i<NUM_OF_OUTPUT; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    out_num = (ap_uint<2>)max_id;

    return(0);
}


curve_conv_nn2_axis3_tb.cpp を示す。
このテストベンチは、800 ピクセル x 600 行の BMP 画像を白黒変換し、60 ピクセル x 45 行にサイズ・ダウンした後にで、curve_conv_nn2_axis3 をコールする。 curve_conv_nn2_axis3 の判定が間違っていたら表示する。

// curve_conv_nn2_axis3_tb.cpp
// 2017/09/09 by marsee
//
// 2017/09/18 : straight_conv_nn2_axis3.cpp に dot2[3]の出力も追加
// 2017/12/13 : 直線に加えてカーブのデータも使用して学習した
//

#include <iostream>
#include "hls_opencv.h"
#include "ap_axi_sdata.h"
#include "hls_video.h"

#define MAX_HEIGHT    600
#define MAX_WIDTH    800

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC1> GRAY_IMAGE;

using namespace cv;

#define NUM_OF_OUTPUT    3

//#define STRAIGHT_LOOP_COUNT    41    // train_images
//#define LR_LOOP_COUNT            18    // train_images
#define STRAIGHT_LOOP_COUNT        35    // test_images
#define LR_LOOP_COUNT            12    // test_images
//#define STRAIGHT_LOOP_COUNT    1    // for C/RTL Co-Simulation
//#define LR_LOOP_COUNT            1    // for C/RTL Co-Simulation

//#define STRAIGHT_IMAGE_NAME     "train_images_171129/straight"
//#define LEFT_TURN_IMAGE_NAME    "train_images_171129/left_turn"
//#define RIGHT_TURN_IMAGE_NAME   "train_images_171129/right_turn"
#define STRAIGHT_IMAGE_NAME     "test_images_171129/straight_test"
#define LEFT_TURN_IMAGE_NAME    "test_images_171129/left_turn_test"
#define RIGHT_TURN_IMAGE_NAME   "test_images_171129/right_turn_test"

int curve_conv_nn2_axis3(hls::stream<ap_axiu<32,1,1,1> >& ins, ap_uint<2> &outs,
        ap_fixed<167, AP_TRN_ZERO, AP_SAT> dot2[NUM_OF_OUTPUT]);
int resize_gray(AXI_STREAM& ins, AXI_STREAM& outs);
int main_output_loop(char *buf, int loop_count, int correct_data);

int main () {
    char buf[200];

    sprintf(buf, "%s", STRAIGHT_IMAGE_NAME);
    main_output_loop(buf, STRAIGHT_LOOP_COUNT, 1);

    sprintf(buf, "%s", LEFT_TURN_IMAGE_NAME);
    main_output_loop(buf, LR_LOOP_COUNT, 0);

    sprintf(buf, "%s", RIGHT_TURN_IMAGE_NAME);
    main_output_loop(buf, LR_LOOP_COUNT, 2);

    return(0);
}

int main_output_loop(char *buf, int loop_count, int correct_data){
    char bmp_file_name[200];
    ap_uint<2> outs;
    AXI_STREAM src_axi, dst_axi;
    Mat src;
    ap_fixed<167, AP_TRN_ZERO, AP_SAT> dot2[NUM_OF_OUTPUT];
    int err_num = 0;

    for(int i=0; i<loop_count; i++){
        sprintf(bmp_file_name, "%s%d.bmp", buf, i);

        // OpenCV で 画像を読み込む
        src = imread(bmp_file_name);

        // BGR から RGBへ変換
        Mat src_rgb;
        cvtColor(src, src_rgb, CV_BGR2RGB);

        // Mat フォーマットから AXI4 Stream へ変換
        cvMat2AXIvideo(src_rgb, src_axi);

        // resize_gray() 関数をコール
        resize_gray(src_axi, dst_axi);

        curve_conv_nn2_axis3(dst_axi, outs, dot2);

        if((int)outs != correct_data){
            printf("*%s\n", bmp_file_name);
            printf("correct data = %d, outs = %d\n", correct_data, (int)outs);
            for(int i=0; i<NUM_OF_OUTPUT; i++)
                printf("dot2[%d] = %f ", i, (float)dot2[i]);
            printf("\n");
            err_num++;
        }
    }
    if(correct_data == 1)
        printf("Straight error is %d\n\n", err_num);
    else if(correct_data == 0)
        printf("Left error is %d\n\n", err_num);
    else // if(correct_data == 2)
        printf("Right error is %d\n\n", err_num);

    return(0);
}

int resize_gray(AXI_STREAM& ins, AXI_STREAM& outs){

    RGB_IMAGE org_img(600800);
    GRAY_IMAGE org_img_g(600800);
    GRAY_IMAGE resize_img_g(4560);
    RGB_IMAGE resize_img(4560);

    hls::AXIvideo2Mat(ins, org_img);
    hls::CvtColor<HLS_RGB2GRAY>(org_img, org_img_g);
    hls::Resize(org_img_g, resize_img_g);
    hls::CvtColor<HLS_GRAY2RGB>(resize_img_g, resize_img);
    hls::Mat2AXIvideo(resize_img, outs);

    return(0);
}


C シミュレーションを行った。結果を示す。
curve_tracing_cnn_63_171223.png

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
   Compiling ../../../curve_conv_nn2_axis3_tb.cpp in debug mode
   Generating csim.exe
Straight error is 0

*test_images_171129/left_turn_test8.bmp
correct data = 0, outs = 1
dot2[0] = -0.435547 dot2[1] = 1.232422 dot2[2] = -4.697266 
Left error is 1

Right error is 0

INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************


エラーは左旋回の時の1個だけだった。59 個のテスト画像で判別しているので、58 / 59 x 100 ≒ 98.3 % になった。十分だと思う。
  1. 2017年12月23日 04:36 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

ZYBOでUbuntu を起動したらネットワークがつながらない

Zynq+Vivado HLS勉強会は 7 回から 8 回に変更になった。最後の回は、任意精度固定小数点データ型とVivado HLS のOpenCV対応を追加した。今日はZYBO でUbuntu 14.04 を立ち上げて、その上で、Vivado HLS で生成したAXI4 Lite Slave インターフェースのIP を使う方法をやる予定だ。
その下準備をしていたところ、ZYBO のボード・ファイルを使用して作成したブロック・デザインで、ネットワークが動作しなかった。いろいろとやってみたが、どうにも動作しない。もしかしてということで、ZYBO Z7-20のネットワークがつながらなかった例を思い出した。

まずは、VIvado 2017.3 で作成した multi_ex2 プロジェクトを示す。
ZYBO_BF_Bug_1_171221.png

multi_bd ブロック・デザインを開くと、MDIO_ETHERNT_0 が processing_system7_0 にあるのが分かる。これは EMIO にマップされているということだ。
ZYBO_BF_Bug_2_171221.png

processing_system7_0 をダブルクリックして開き、Page Navigatorで Peripheral I/O Pinsをクリックする。
Ethernet0 を展開すると、MDIO が EMIO にマップされている。
ZYBO_BF_Bug_3_171221.png

EMIO の脇の MDIO をクリックして選択する。

MDIO がハイライトされて、選択された。
ZYBO_BF_Bug_4_171221.png

OKボタンをクリックした。
すると、MDIO_ETHERNT_0 が無くなったのが分かる。これは、EMIO から MIO にマップが変更されたからだ。
ZYBO_BF_Bug_5_171221.png

これでブロック・デザインをセーブして、論理合成、インプリメント、ビットストリームの生成を行った。
ハードウェアをエクスポートして、SDK を立ち上げた。
FSBL を生成して、u-boot.elf を追加しながら、BOOT.bin を作成した。
ZYBO_BF_Bug_6_171222.png

これで、ZYBO 上でUbuntu 14.04 を起動したときにネットワークがつながるようになった。

ZYBO や ZYBO Z7 のボード・ファイルを早く直してほしいものだ。今のところ、ZYBO/B.3、ZYBO-Z7-10/A.0、ZYBO Z7-20/A.0 のボード・ファイルでは、今回の様に修正する必要があると思う。
  1. 2017年12月22日 04:51 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク12(直線走行用の重みとバイアスでカーブのテストデータを検証)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク11(Vivado HLS でCNN を実装)”の続き。

前回は、Vivado HLS 2017.3 で畳み込みニューラルネットワークを実装した。カーブと直線のテストデータでの精度は、ハードウェアで、約 97.7 % 、96.3 % 、95.3 % だった。今回は、この精度が、直線のみの重みとバイアスでどの程度になるか?を検証してみよう。

畳み込みニューラルネットワークの C ソースコードが同じなので、なんか違う畳み込みニューラルネットワークを作った気がしないので、違うということを自分の胸に刻んでおきたいということでやってみることにした。

さて、straigtht_conv_nn2_4CurveData プロジェクトを作成し、curve_conv_nn2.cpp 、 curve_data_0_100.h と curve_data_2500_2600.h 、 curve_data_5000_5100.h 、curve_conv_nn_tb.cpp はそのままプロジェクトに入れて、 af1_bias.h、af1_weight.h、af2_bias.h、af2_weight.h、conv1_bias.h、conv1_weight.h を”白線追従走行用畳み込みニューラルネットワークの製作18(Vivado HLSでCシミュレーション)”の時の重みとバイアスに入れ替えた。

straigtht_conv_nn2_4CurveData プロジェクトを示す。af_weight.h の日付が 2017/08/24 になっているのが分かる。直線走行用の重みだ。
curve_tracing_cnn_58_171221.png

最初に、テストデータの 0 番目から 100 番目までの画像データで検証する。直線、左旋回、右旋回の画像にそれぞれについて 100 枚づつなので、合計 300 枚の画像について推論精度を確かめている。
curve_tracing_cnn_59_171221.png

C シミュレーションを行った。結果を示す。

hw_err_cnt = 8, sw_err_cnt = 10
hw accuracy = 97.333336%, sw accuracy = 96.666664%


カーブと直線走行用のの重みとバイアスの時のC シミュレーションでの精度を示す。

hw_err_cnt = 7, sw_err_cnt = 20
hw accuracy = 97.666669%, sw accuracy = 93.333334%


ここでは、精度はあまり変わらない。画像の前の方は、直線走行用のデータをそのまま使用しているので、双方の精度はあまり変わらなくなっていると言えると思う。

次に、テストデータの 2500 番目から 2600 番目までの画像データで検証する。直線、左旋回、右旋回の画像にそれぞれについて 100 枚づつなので、合計 300 枚の画像について推論精度を確かめている。
curve_tracing_cnn_60_171221.png

C シミュレーションを行った。結果を示す。

hw_err_cnt = 26, sw_err_cnt = 34
hw accuracy = 91.333336%, sw accuracy = 88.666666%


やはり、この辺りのテストデータは、カーブの画像が入っているので、直線走行用の重みとバイアスでは、精度が悪くなっているのだろう。

カーブと直線走行用の重みとバイアスの時のC シミュレーションでの精度を示す。

hw_err_cnt = 11, sw_err_cnt = 9
hw accuracy = 96.333331%, sw accuracy = 97.000003%


こちらは、同じ画像でもカーブの画像で学習されているので、高い精度を保っていると言える。やはり、学習は効いている。

最後に、テストデータの 5000 番目から 5100 番目までの画像データで検証する。直線、左旋回、右旋回の画像にそれぞれについて 100 枚づつなので、合計 300 枚の画像について推論精度を確かめている。
curve_tracing_cnn_61_171221.png

C シミュレーションを行った。結果を示す。

hw_err_cnt = 25, sw_err_cnt = 25
hw accuracy = 91.666669%, sw accuracy = 91.666669%


この辺りのテストデータも 2500 ~ 2600 番目と同様に、カーブの画像が入っているので、直線走行用の重みとバイアスでは、精度が悪くなっているようだ。

カーブと直線走行用の重みとバイアスの時のC シミュレーションでの精度を示す。

hw_err_cnt = 14, sw_err_cnt = 6
hw accuracy = 95.333332%, sw accuracy = 98.000002%


2500 ~ 2600 番目と同様に、直線走行用の重みとバイアスを使用した結果よりも明らかに精度が良い。

カーブと直線走行用の重みとバイアスの学習の効果を実感することができた。これで安心してIP として実装することができる。
  1. 2017年12月21日 05:04 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク11(Vivado HLS でCNN を実装)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク10(重みとバイアスをC のヘッダファイルに変換)”の続き。

前回は、カーブと直線の白線間を走行するためのデータセットで畳み込みニューラルネットワークを学習したときの重みとバイアスを C のヘッダファイルに変換して、Vivado HLS で使用できるようにした。これでVivado HLS でカーブと直線の白線間走行用畳み込みニューラルネットワークを実装する準備が整ったので、今回は、Vivado HLS 2017.3 で畳み込みニューラルネットワークを実装しよう。

Vivado HLS 2017.3 で curve_conv_nn2 プロジェクトを作成した。
curve_tracing_cnn_51_171220.png

カーブ、直線用白線間走行用畳み込みニューラルネットワーク10(重みとバイアスをC のヘッダファイルに変換)”で作成した重みとバイアスの C ヘッダ・ファイルの af1_bias.h、af1_weight.h、af2_bias.h、af2_weight.h、conv1_bias.h、conv1_weight.h がプロジェクトの source ディレクトリに追加されている。更に、畳み込みニューラルネットワークを C で実装した curve_conv_nn2.cpp も source ディレクトリに追加している。
Test Bench ディレクトリには、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク11(画像データをCのヘッダファイルに変換)”で作成した curve_data_0_100.h と curve_data_2500_2600.h 、 curve_data_5000_5100.h を追加してある。そして、テストベンチ・ファイルの curve_conv_nn_tb.cpp も追加されている。

curve_conv_nn2.cpp を貼っておく。なお、ビット精度が大きくなっているが、”CNNのVivado HLS実装のstraight_conv_nn2 の演算精度を変更する”で検証したビット幅を使用している。

// curve_conv_nn2.cpp
// 2017/12/06 by marsee
// 畳み込み層のカーネル数 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"

#define NUM_OF_KERNELS 2
#define COULMN_PIXELS 56
#define ROW_PIXELS 10
#define ALL_PIXELS 560
#define NUM_OF_OUTPUT 3

int curve_conv_nn(ap_ufixed<80, AP_TRN_ZERO, AP_SAT> in[ALL_PIXELS], ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT]){
    ap_ufixed<80, AP_TRN_ZERO, AP_SAT> buf[ROW_PIXELS][COULMN_PIXELS];
    ap_fixed<166, AP_TRN_ZERO, AP_SAT> conv_out[NUM_OF_KERNELS][ROW_PIXELS-4][COULMN_PIXELS-4];
    ap_fixed<166, AP_TRN_ZERO, AP_SAT> pool_out[NUM_OF_KERNELS][(ROW_PIXELS-4)/2][(COULMN_PIXELS-4)/2];
    ap_fixed<197, AP_TRN_ZERO, AP_SAT> dot1[100];
    ap_fixed<197, AP_TRN_ZERO, AP_SAT> dot2[NUM_OF_OUTPUT];

    buf_copy1: for(int i=0; i<ROW_PIXELS; i++)
        buf_copy2: for(int j=0; j<COULMN_PIXELS; j++)
            buf[i][j] = in[i*COULMN_PIXELS+j];

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<NUM_OF_KERNELS; i++){    // カーネルの個数
        CONV2: for(int j=0; j<ROW_PIXELS-4; j++){
            CONV3: for(int k=0; k<COULMN_PIXELS-4; 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<NUM_OF_KERNELS; i++){
        POOL2: for(int j=0; j<ROW_PIXELS-4; j += 2){
            POOL3: for(int k=0; k<COULMN_PIXELS-4; 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<NUM_OF_KERNELS; i++){
            af1_dot3: for(int j=0; j<(ROW_PIXELS-4)/2; j++){
                af1_dot4: for(int k=0; k<(COULMN_PIXELS-4)/2; k++){
                    dot1[col] += pool_out[i][j][k]*af1_weight[i*((ROW_PIXELS-4)/2)*((COULMN_PIXELS-4)/2)+j*((COULMN_PIXELS-4)/2)+k][col];
                }
            }
        }
        dot1[col] += af1_bias[col];

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

    af2_dot1: for(int col=0; col<NUM_OF_OUTPUT; 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);
}


curve_conv_nn_tb.cpp を貼っておく。

// curve_conv_nn_tb.cpp
// 2017/12/06 by marsee
// 畳み込み層のカーネル数 2
//

#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 "curve_data_0_100.h"
//#include "curve_data_2500_2600.h"
//#include "curve_data_5000_5100.h"

#define ALL_DATA_NUM   300
#define NUM_OF_KERNELS 2
#define COULMN_PIXELS 56
#define ROW_PIXELS 10
#define ALL_PIXELS 560
#define NUM_OF_OUTPUT 3

int curve_conv_nn(ap_ufixed<80, AP_TRN_ZERO, AP_SAT> in[ALL_PIXELS], ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT]);
int curve_conv_nn_float(float in[ALL_PIXELS], float out[NUM_OF_OUTPUT]);
int max_ap_fixed(ap_fixed<127, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT]);
int max_float(float out[NUM_OF_OUTPUT]);

#define NUM_ITERATIONS    150 // C Simulation
//#define NUM_ITERATIONS    1 // C/RTL CoSimulation

int main(){
    float t_tran_float[NUM_ITERATIONS][ALL_PIXELS];
    ap_fixed<127, AP_TRN_ZERO, AP_SAT> result_ap_fixed[NUM_ITERATIONS][NUM_OF_OUTPUT];
    float result_float[NUM_ITERATIONS][NUM_OF_OUTPUT];
    int max_id_hw, max_id_sw, max_id_ref;

    for(int i=0; i<NUM_ITERATIONS; i++)
        for(int j=0; j<ALL_PIXELS; j++)
            t_tran_float[i][j] = (float)t_train[i][j];

    for(int i=0; i<NUM_ITERATIONS; i++){
        curve_conv_nn(&t_train[i][0], &result_ap_fixed[i][0]);
        curve_conv_nn_float(&t_tran_float[i][0], &result_float[i][0]);
    }

    int errflag=0;
    int sw_err_cnt = 0;
    int hw_err_cnt = 0;
    for(int i=0; i<NUM_ITERATIONS; i++){
        max_id_hw = max_ap_fixed(&result_ap_fixed[i][0]);
        max_id_sw = max_float(&result_float[i][0]);
        max_id_ref = max_float(&t_test[i][0]);

        if(max_id_ref != max_id_hw){
            printf("id = %d, max_id_ref = %d, max_id_hw = %d\n", i, max_id_ref, max_id_hw);
            errflag = 1;
            hw_err_cnt++;
        }
        if(max_id_ref != max_id_sw){
            printf("id = %d, max_id_ref = %d, max_id_sw = %d\n", i, max_id_ref, max_id_sw);
            errflag = 1;
            sw_err_cnt++;
        }
    }

    if(errflag == 0){
        printf("No Error\n");
    } else {
        printf("\nhw_err_cnt = %d, sw_err_cnt = %d\n", hw_err_cnt, sw_err_cnt);
        printf("hw accuracy = %f\%, sw accuracy = %f\%\n",
                (((float)ALL_DATA_NUM-(float)hw_err_cnt)/(float)ALL_DATA_NUM)*100.0,
                (((float)ALL_DATA_NUM-(float)sw_err_cnt)/(float)ALL_DATA_NUM)*100.0);
    }
    printf("\n");

    return(0);
}

int curve_conv_nn_float(float in[ALL_PIXELS], float out[NUM_OF_OUTPUT]){
    float buf[ROW_PIXELS][COULMN_PIXELS];
    float conv_out[NUM_OF_KERNELS][ROW_PIXELS-4][COULMN_PIXELS-4];
    float pool_out[NUM_OF_KERNELS][(ROW_PIXELS-4)/2][(COULMN_PIXELS-4)/2];
    float dot1[100];
    float dot2[NUM_OF_OUTPUT];

    buf_copy1: for(int i=0; i<ROW_PIXELS; i++)
        buf_copy2: for(int j=0; j<COULMN_PIXELS; j++)
            buf[i][j] = in[i*COULMN_PIXELS+j];

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<NUM_OF_KERNELS; i++){    // カーネルの個数
        CONV2: for(int j=0; j<ROW_PIXELS-4; j++){
            CONV3: for(int k=0; k<COULMN_PIXELS-4; 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<NUM_OF_KERNELS; i++){
        POOL2: for(int j=0; j<ROW_PIXELS-4; j += 2){
            POOL3: for(int k=0; k<COULMN_PIXELS-4; 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<NUM_OF_KERNELS; i++){
            af1_dot3: for(int j=0; j<(ROW_PIXELS-4)/2; j++){
                af1_dot4: for(int k=0; k<(COULMN_PIXELS-4)/2; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*((ROW_PIXELS-4)/2)*((COULMN_PIXELS-4)/2)+j*((COULMN_PIXELS-4)/2)+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

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

    af2_dot1: for(int col=0; col<NUM_OF_OUTPUT; 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[NUM_OF_OUTPUT]){
    int max_id;
    ap_fixed<127, AP_TRN_ZERO, AP_SAT> max;

    for(int i=0; i<NUM_OF_OUTPUT; 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[NUM_OF_OUTPUT]){
    int max_id;
    float max;

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


curve_conv_nn_tb.cpp のカーブと直線の画像データ・セットを curve_data_0_100.h と curve_data_2500_2600.h 、 curve_data_5000_5100.h にコメントアウトしている文を切り替えて 3 回 C シミュレーションしてみよう。
curve_tracing_cnn_52_171220.png

最初に、 curve_data_0_100.h で C シミュレーションを実行した。
curve_tracing_cnn_53_171220.png

ハードウェアの固定小数点演算では、300 画像の内で 7 個間違って、その精度は (300 - 7) / 300 X 100 = 97.666669% だった。
ソフトウェアの浮動小数点演算では、 300 画像の内で 20 個間違って、その精度は、93.333334% だった。

hw_err_cnt = 7, sw_err_cnt = 20
hw accuracy = 97.666669%, sw accuracy = 93.333334%



次に、curve_data_2500_2600.h で C シミュレーションを実行した。
curve_tracing_cnn_54_171220.png

ハードウェアの固定小数点演算では、300 画像の内で 11 個間違って、その精度は 96.333331% だった。
ソフトウェアの浮動小数点演算では、 300 画像の内で 9 個間違って、その精度は、97.000003% だった。

hw_err_cnt = 11, sw_err_cnt = 9
hw accuracy = 96.333331%, sw accuracy = 97.000003%



次に、curve_data_5000_5100.h で C シミュレーションを実行した。
curve_tracing_cnn_55_171220.png

ハードウェアの固定小数点演算では、300 画像の内で 14 個間違って、その精度は 95.333332% だった。
ソフトウェアの浮動小数点演算では、 300 画像の内で 6 個間違って、その精度は、98.000002% だった。

hw_err_cnt = 14, sw_err_cnt = 6
hw accuracy = 95.333332%, sw accuracy = 98.000002%



C コードの合成を行った。結果を示す。
curve_tracing_cnn_56_171220.png
curve_tracing_cnn_57_171220.png

Estimated は 8.68 ns で Target の 10 ns を満足している。
Latency は約 1.72 ms で 30 fps のカメラ画像を解析するには十分だ。

DSP48E は 8 使用されている。FF と LUT 使用量は割と少ない。BRAM_18K は 16 個使用している。

大体これで行けそうだ。後は、DMAエンジンを組み込んで、実際に使う状態でのVivado HLS プロジェクトを作成しよう。
  1. 2017年12月20日 06:39 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク11(画像データをCのヘッダファイルに変換)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク10(重みとバイアスをC のヘッダファイルに変換)”の続き。

前回は、学習した重みとバイアスを C のヘッダファイルに変換した。その配列は、float と固定小数点数の2つの配列がある。今回は、画像データの一部をCのヘッダファイルに変換する。

直進の白線間走行の場合は、”白線追従走行用畳み込みニューラルネットワークの製作16(白線追従走行用の画像データをCの配列に出力)”で画像データの一部をCのヘッダファイルに変換するPython コードを公開してあるが、それはあくまで、直進、左旋回、右旋回の画像数が同じ数という前提がある。今回は、直進の画像数が多いため、修正を行った。その、image_data2c_wt.py を下に示す。

# 白線追従走行用のテスト用画像データをCの配列に出力し、ファイルに書き込み
# image_data2c_wt.py
# 2017/12/20 :直進と左旋回、右旋回の画像数が違う場合の対応を追加した。 by marsee

# coding: utf-8
import sys, os
sys.path.append(os.pardir)

import numpy as np
from dataset_curve.curve_dataset import load_mnist
import datetime

OUTPUT_DATA_NUM = 100 # 出力する白線追従走行のテストデータ数 直進、左旋回、右旋回で x 3
OFFSET = 0 # 白線追従走行用データセットのオフセット、100だったら100番目からOUTPUT_DATA_NUM個を出力する

STRAIGHT_DATA_NUM = 15750 # 直進の総画像数
L_R_TURN_DATA_NUM = 5400 # 左旋回、右旋回の総画像数

def normal_image(offset, output_data_num, x_test, end):
    for i in range(offset, offset+output_data_num):
        f.write("\t{")
        for j in range(x_test.shape[1]):
            f.write(str(x_test[i][j]))
            if (j==x_test.shape[1]-1):
                if (i==offset+output_data_num-1 and end==1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")

def no_normal_image(offset, output_data_num, x_test, end):
    for i in range(offset, offset+output_data_num):
        f.write("\t{")
        for j in range(x_test.shape[1]):
            f.write(str(int(x_test[i][j]*256)))
            if (j==x_test.shape[1]-1):
                if (i==offset+output_data_num-1 and end==1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")

def normal_label(offset, output_data_num, t_test, end):
    for i in range(offset, offset+output_data_num):
        f.write("\t{")
        for j in range(t_test.shape[1]):
            f.write(str(t_test[i][j]))
            if (j==t_test.shape[1]-1):
                if (i==offset+output_data_num-1 and end==1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")

# データの読み込み
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

all_x_test = x_test.shape[0];
all_go_direction = int(all_x_test/3);
print(all_x_test)
print(all_go_direction)

f = open("curve_data.h", 'w')
todaytime = datetime.datetime.today()
f.write('// curve_data.h\n')
strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
f.write('// {0} by marsee\n'.format(strdtime))
f.write("\n")

f.write('ap_ufixed<8, 0, AP_TRN_ZERO, AP_SAT> t_train['+str(OUTPUT_DATA_NUM*3)+']['+str(x_test.shape[1])+'] = {\n')
normal_image(OFFSET, OUTPUT_DATA_NUM, x_test, 0) # 直進
normal_image(OFFSET+STRAIGHT_DATA_NUM, OUTPUT_DATA_NUM, x_test, 0) # 左旋回
normal_image(OFFSET+STRAIGHT_DATA_NUM+L_R_TURN_DATA_NUM, OUTPUT_DATA_NUM, x_test, 1) # 右旋回
f.write("};\n")

f.write('int t_train_256['+str(OUTPUT_DATA_NUM*3)+']['+str(x_test.shape[1])+'] = {\n')
no_normal_image(OFFSET, OUTPUT_DATA_NUM, x_test, 0) # 直進
no_normal_image(OFFSET+STRAIGHT_DATA_NUM, OUTPUT_DATA_NUM, x_test, 0) # 左旋回
no_normal_image(OFFSET+STRAIGHT_DATA_NUM+L_R_TURN_DATA_NUM, OUTPUT_DATA_NUM, x_test, 1) # 右旋回
f.write("};\n")

f.write("\n")
f.write('float t_test['+str(OUTPUT_DATA_NUM*3)+']['+str(t_test.shape[1])+'] = {\n')
normal_label(OFFSET, OUTPUT_DATA_NUM, t_test, 0) # 直進
normal_label(OFFSET+STRAIGHT_DATA_NUM, OUTPUT_DATA_NUM, t_test, 0) # 左旋回
normal_label(OFFSET+STRAIGHT_DATA_NUM+L_R_TURN_DATA_NUM, OUTPUT_DATA_NUM, t_test, 1) # 右旋回
f.write("};\n")
f.close() 


image_data2c_wt.py で出力した curve_data.h の一部を示す。
curve_tracing_cnn_49_171220.png

0 番目から 100 番目の直進、左旋回、右旋回の画像データ curve_data_0_100.h と 2500 番目から 2600 番目の直進、左旋回、右旋回の画像データ curve_data_2500_2600.h と 5000 番目から 5100 番目の直進、左旋回、右旋回の画像データ curve_data_5000_5100.h を作成した。
curve_tracing_cnn_50_171220.png

なぜ、このように後ろの方の画像データを作ったかというと、最初は、以前の直進の白線走行用の画像データが入っているので、カーブの学習データも織り交ぜるために、このように後ろからも学習データをC のヘッダファイルに変換している。

これで、カーブ、直進用白線走行用畳み込みニューラルネットワークをVivado HLS で実装する準備が整った。
  1. 2017年12月20日 04:08 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク10(重みとバイアスをC のヘッダファイルに変換)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク9(量子化)”の続き。

前回は、カーブと直線の白線間を走行するためのデータセットで畳み込みニューラルネットワークを学習したときの重みとバイアスを量子化してどのくらいの精度が出るのか?を検証した。今回は、その重みとバイアスを C のヘッダファイルに変換して、Vivado HLS で使用できるようにしてみよう。

畳み込み層の重みをCヘッダファイルに書き出すPython コードの fwrite_conv_weight() 関数や畳み込み層と全結合層のバイアスをCヘッダファイルに書き出すPython コードの fwrite_bias() 関数、全結合層の重みをCヘッダファイルに書き出すPython コードの fwrite_af_weight() 関数は”「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化3”コードそのままなのだが、全結合層の重みの小数部が 10 ビット取ってあるので、重みとバイアスの定義を畳み込み層用(MAGNIFICATION_CONV)と全結合層用(MAGNIFICATION_AF)用に分けた。
それで畳み込み層と全結合層 2 層分の重みとバイアスを C のヘッダファイルに変換した。そのPython コードを示す。

MAGNIFICATION_CONV = 2 ** (9-1)
fwrite_conv_weight(network.params['W1'], 'conv1_weight.h', 'conv1_fweight', 'conv1_weight', MAGNIFICATION_CONV)

fwrite_bias(network.params['b1'], 'conv1_bias.h', 'conv1_fbias', 'conv1_bias', MAGNIFICATION_CONV)
MAGNIFICATION_AF = 2 ** (11-1)
fwrite_bias(network.params['b2'], 'af1_bias.h', 'af1_fbias', 'af1_bias', MAGNIFICATION_AF)
fwrite_bias(network.params['b3'], 'af2_bias.h', 'af2_fbias', 'af2_bias', MAGNIFICATION_AF)

fwrite_af_weight(network.params['W2'], 'af1_weight.h', 'af1_fweight', 'af1_weight', MAGNIFICATION_AF)
fwrite_af_weight(network.params['W3'], 'af2_weight.h', 'af2_fweight', 'af2_weight', MAGNIFICATION_AF)


curve_tracing_cnn_48_171219.png

実行結果として、af1_bias.h、af1_weight.h、af2_bias.h、af2_weight.h、conv1_bias.h、conv1_weight.h が生成された。
curve_tracing_cnn_46_171219.png

af1_weight.h などはかなり大きいので、 conv1_weight.h を例として示す。
curve_tracing_cnn_47_171219.png
  1. 2017年12月19日 04:31 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク9(量子化)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク8(学習)”の続き。

前回は、カーブと直線の白線間を走行するためのデータセットで畳み込み層 - ReLU - プーリング層 - 全結合層 - ReLU - 全結合層 - SoftMax の畳み込みニューラルネットワークを学習した。今回は、学習した重みとバイアスを量子化してどの程度の精度が出るかを確かめてみよう。

すでにいろいろと量子化のパラメータを試してみて、直線の白線間を走行するときの量子化よりも、全結合層の重みの小数部を 2 ビット増やして、10 ビットとすることにした。
curve_tracing_cnn_44_171218.png

この時のデバックモードの出力を示す。

(100, 1, 10, 56)
Conv col.shape = (31200, 25)
Conv col_W.shape = (25, 2)
Conv np.max(x) = 0.8705882430076599
Conv np.min(x) = 0.32549020648002625
(2, 1, 5, 5)
Conv np.max(self.W_int) = 0.79296875
Conv np.min(self.W_int) = -0.23828125
(2,)
Conv np.max(self.b_int) = 0.0
Conv np.min(self.b_int) = -1.0
Conv out.shape = (31200, 2)
Conv np.max(out) = 8.476914929691702
Conv np.min(out) = -0.03768382431007922
Conv np.max(out2) = 8.5
Conv np.min(out2) = 0.0
Conv out.reshape = (100, 2, 6, 52)
Pooling x.shape = (100, 2, 6, 52)
Pooling out.shape = (100, 2, 3, 26)
x shape =(100, 2, 3, 26)
np.max(self.W) = 0.5351036345618255
np.max(self.W) = 0.5351036345618255
np.max(self.b) = 0.30059633490491805
x reshape =(100, 156)
np.max(x) = 8.5
np.min(x) = 0.0
(156, 100)
np.max(self.W_int) = 0.53515625
np.min(self.W_int) = -0.357421875
(100,)
np.max(self.b_int) = 0.30078125
np.min(self.b_int) = -0.4248046875
(100, 100)
np.max(out) = 20.33831787109375
np.min(out) = -13.0367431640625
np.max(out2) = 20.34375
np.min(out2) = -13.0
x shape =(100, 100)
np.max(self.W) = 0.8667410516980987
np.max(self.W) = 0.8667410516980987
np.max(self.b) = 0.29596798816137226
x reshape =(100, 100)
np.max(x) = 20.34375
np.min(x) = 0.0
(100, 3)
np.max(self.W_int) = 0.8671875
np.min(self.W_int) = -0.98046875
(3,)
np.max(self.b_int) = 0.2958984375
np.min(self.b_int) = -0.3017578125
(100, 3)
np.max(out) = 7.79901123046875
np.min(out) = -16.07855224609375
np.max(out2) = 7.8125
np.min(out2) = -16.0625


量子化したときのテスト用データでの精度は 0.947495291902 となった。量子化していないときは 0.95472693032 なので、こんなものかな?と思う。
curve_tracing_cnn_45_171219.png
  1. 2017年12月19日 04:01 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク8(学習)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク7(テスト用データの作成)”の続き。

前回は、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク2(本格的なデータ収集)”で収集したテスト用の画像を 1062 枚に増やした。そして、それを 白黒変換し、白線の部分だけを 56 ピクセル X 10 行の画像を一枚の画像から 25 個切り出して、MNISTデータ形式のテスト用画像ファイルとテスト用ラベル・ファイルを作成した。今回はこれで、トレーニング用とテスト用のデータセットがそろったので、Jupyter Notebook を使用して学習してみよう。

なお、”ゼロから作るDeep Learning ――Pythonで学ぶディープラーニングの理論と実装”のPython コードを全面的に使わせて頂いている。畳み込みニューラルネットワークの層構成は、畳み込み層 - ReLU - プーリング層 - 全結合層 - ReLU - 全結合層 - SoftMax だった。

まずは、”白線追従走行用畳み込みニューラルネットワークの製作6(学習1)”を参考にして、dataset_straight をコピーしてdataset_curve フォルダを作成した。更に、ch7_straight をコピーして、ch7_curve フォルダを作成した。
curve_tracing_cnn_39_171218.png

dataset_curve フォルダの直線走行用のMNISTデータセットを削除して、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク5(トレーニング用データの生成)”で作成した train_curve_run_image と train_curve_run_label をコピーした。
また、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク7(テスト用データの作成)”で作成した test_curve_run_image と test_curve_run_label をコピーした。
curve_tracing_cnn_40_171218.png

白線追従走行用畳み込みニューラルネットワークの製作6(学習1)”の straight_dataset.py を curve_dataset.py に変更し、train_num と test_num を書き換えた。
curve_tracing_cnn_41_171218.png

次に、Jupyter Notebook を立ち上げて、deep-learning-from-scratch/ch07_curve に移動して、DLFS_Chap7_integer.ipynb を起動した。
curve_tracing_cnn_42_171218.png

DLFS_Chap7_integer.ipynb を編集して、

from dataset_curve.curve_dataset import load_mnist

に変更した。
curve_tracing_cnn_43_171218.png

Jupyter Notebook 上の train_convnet.py を貼っておく。畳み込み層のフィルタ数は 2 となっている。

# train_convnet.py
# 2017/08/08 白線追従走行用CNNに変更 by marsee
# 元になったコードは、https://github.com/oreilly-japan/deep-learning-from-scratch にあります。
# 改変したコードもMITライセンスとします。 2017/08/08 by marsee
# カーブ・データ用に修正 2017/12/18 by marsee

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import matplotlib.pyplot as plt
from dataset_curve.curve_dataset import load_mnist
from simple_convnet import SimpleConvNet
from common.trainer import Trainer

# データの読み込み
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)

all_x_train = x_train.shape[0];
all_x_test = x_test.shape[0];
print(all_x_train)
print(all_x_test)

# 処理に時間のかかる場合はデータを削減 
#x_train, t_train = x_train[:5000], t_train[:5000]
#x_test, t_test = x_test[:1000], t_test[:1000]

max_epochs = 20

network = SimpleConvNet(input_dim=(1,10,56), 
                        conv_param = {'filter_num': 2, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        #conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        hidden_size=100, output_size=3, weight_init_std=0.01)
                        
trainer = Trainer(network, x_train, t_train, x_test, t_test,
                  epochs=max_epochs, mini_batch_size=100,
                  optimizer='Adam', optimizer_param={'lr': 0.001},
                  evaluate_sample_num_per_epoch=100)
trainer.train()

# パラメータの保存
network.save_params("params.pkl")
print("Saved Network Parameters!")


これで、Jupyter Notebook 上の train_convnet.py で学習したところ、0.95472693032 の精度が確保できた。

train_convnet.py を実行した結果の最初と最後を貼っておく。

Converting train_curve_run_image to NumPy Array ...
Done
Converting train_curve_run_label to NumPy Array ...
Done
Converting test_curve_run_image to NumPy Array ...
Done
Converting test_curve_run_label to NumPy Array ...
Done
Creating pickle file ...
Done!
34650
26550
pool_output_size =156
train loss:1.0981899475
=== epoch:1, train acc:1.0, test acc:1.0 ===
train loss:1.0980374466
train loss:1.0966096818
train loss:1.09627088932
train loss:1.09695438209


train loss:0.12427020397
train loss:0.0725574218453
train loss:0.0593783238407
train loss:0.0805719249781
train loss:0.0529893267479
train loss:0.0247235638705
train loss:0.0481303088163
train loss:0.0534950709832
train loss:0.10404449012
train loss:0.082864550859
train loss:0.091640690661
train loss:0.102096129491
train loss:0.0732472519834
train loss:0.068286296823
train loss:0.0726208094243
train loss:0.0522118761663
=============== Final Test Accuracy ===============
test acc:0.95472693032
Saved Network Parameters!

  1. 2017年12月18日 04:43 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク7(テスト用データの作成)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク6(テスト用画像を増やす)”の続き。

前回は、学習画像をMNISTのデータ形式に変換した。テスト用の画像を”カーブ、直線用白線間走行用畳み込みニューラルネットワーク2(本格的なデータ収集)”で収集した画像を 1062 枚に増やした。今回は、それを 白黒変換し、白線の部分だけを 56 ピクセル X 10 行の画像を一枚の画像から 25 個切り出して、MNISTデータ形式のテスト用画像ファイルとテスト用ラベル・ファイルを作成する。

Vivado HLS 2017.3 で curve_test_data3 プロジェクトを作成した。
curve_tracing_cnn_34_171217.png

curve_test_data.h を貼っておく。

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

#ifndef __CURVE_DATASET_BMP_H__
#define __CURVE_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    10
#define DATASET_WIDTH    56

#define STRAIGHT_NUM_OF_IMAGE        630
#define LEFT_TURN_NUM_OF_IMAGE        216
#define    RIGHT_TURN_NUM_OF_IMAGE        216

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


curve_test_data.cpp を貼っておく。

// curve_test_data.cpp
// 2017/11/30 by marsee
//

#include <iostream>
#include "hls_opencv.h"
#include "curve_test_data.h"
#include <arpa/inet.h>

const char IMAGE_DIR[] = "test_images_171130";

int main(){
    char straight_fn[256] = "straight_test";
    char left_turn_fn[256] = "left_turn_test";
    char right_turn_fn[256] = "right_turn_test";
    char bmp_file[256];
    FILE *ftin, *ftln;
    char test_image_name[256] = "test_curve_run_image";
    char test_label_name[256] = "test_curve_run_label";
    uint32_t buf[5];
    uint8_t bufchar[100];


    if ((ftin = fopen(test_image_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", test_image_name);
        exit(1);
    }
    if ((ftln = fopen(test_label_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", test_label_name);
        exit(1);
    }

    // Writed header
    buf[0] = htonl(0x803); // magic number
    buf[1] = htonl((STRAIGHT_NUM_OF_IMAGE+LEFT_TURN_NUM_OF_IMAGE+RIGHT_TURN_NUM_OF_IMAGE)*25); // number of image
    buf[2] = htonl(10); // number of rows (10)
    buf[3] = htonl(56); // number of columns (56)
    fwrite(buf, sizeof(uint32_t), 4, ftin);

    buf[0] = htonl(0x801); // magic number
    buf[1] = htonl((STRAIGHT_NUM_OF_IMAGE+LEFT_TURN_NUM_OF_IMAGE+RIGHT_TURN_NUM_OF_IMAGE)*25); // number of image
    fwrite(buf, sizeof(uint32_t), 2, ftln);

    // refereed to http://opencv.jp/cookbook/opencv_img.html
    // straight
    for(int i=0; i<STRAIGHT_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s/%s%d.bmp", IMAGE_DIR, straight_fn, i);
        cv::Mat straight_img = cv::imread(bmp_file,1);
        if(straight_img.empty()){
            fprintf(stderr,"Error: %s\n", bmp_file);
            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_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        //sprintf(bmp_file, "%s_RED%d.bmp", straight_fn, i);
        //cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", straight_fn, i, y, x);
                //cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x1;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    // left turn
    for(int i=0; i<LEFT_TURN_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s/%s%d.bmp", IMAGE_DIR, left_turn_fn, i);
        cv::Mat left_trun_img = cv::imread(bmp_file,1);
        if(left_trun_img.empty()){
            fprintf(stderr,"Error: %s\n", bmp_file);
            return(-1);
        }
        cv::Mat reduct_img(left_trun_img.rows*0.075, left_trun_img.cols*0.075, left_trun_img.type());
        cv::resize(left_trun_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        //sprintf(bmp_file, "%s_RED%d.bmp", left_turn_fn, i);
        //cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", left_turn_fn, i, y, x);
                //cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x0;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    // right turn
    for(int i=0; i<RIGHT_TURN_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s/%s%d.bmp", IMAGE_DIR, right_turn_fn, i);
        cv::Mat right_trun_img = cv::imread(bmp_file,1);
        if(right_trun_img.empty()){
            fprintf(stderr,"Error: %s\n", bmp_file);
            return(-1);
        }
        cv::Mat reduct_img(right_trun_img.rows*0.075, right_trun_img.cols*0.075, right_trun_img.type());
        cv::resize(right_trun_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        //sprintf(bmp_file, "%s_RED%d.bmp", right_turn_fn, i);
        //cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", right_turn_fn, i, y, x);
                //cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x2;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    fclose(ftin);
    fclose(ftln);

    return(0);
}


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

curve_tracing_cnn_36_171217.png

test_curve_run_image のテスト用画像ファイルと test_curve_run_label のテスト用ラベル・ファイルを作成することができた。

test_curve_run_image をバイナリ・エディタで見た。
curve_tracing_cnn_37_171217.png

最初の 0x0000 0803 が画像ファイルのマジック・ナンバーだ。その次の 0x0000 67b6 は16進数なので、10進数に直すと26,550 となって学習画像の数を表す。0x0000 000a は10 進数にすると 10 で、画像の縦のピクセル数を表す。次の 0000 0038 は、10進数に直すと 56 で画像の横のピクセル数を表す。

test_curve_run_label を示す。
curve_tracing_cnn_38_171217.png

最初の 0x0000 0801 はラベル・ファイルのマジック・ナンバーだ。その次の 0x0000 67b6 は16進数なので、10進数に直すと 26,550 となってトレーニング・ラベルの数を表す。

これで、テスト用画像ファイルとテスト用ラベル・ファイルを作成することができた。
  1. 2017年12月17日 05:55 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク6(テスト用画像を増やす)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク5(トレーニング用データの生成)”の続き。

前回は、学習画像をMNISTのデータ形式に変換した。テスト用の画像を”カーブ、直線用白線間走行用畳み込みニューラルネットワーク2(本格的なデータ収集)”で収集した。今回は、それの画像を増やすことにした。

カーブ、直線用白線間走行用畳み込みニューラルネットワーク4(学習画像を増やす)”と同様に imagemagic を使ってバッチ・ファイルを起動して、画像を増やしていて、17倍に増やしている。元の画像が1組あるので、直進が 35 X 18 = 630 枚になる。右旋回と左旋回は 12 X 18 = 216 枚になる予定だ。合計のテスト用画像は 1062 枚になるはずだ。

imagemagic を使ったバッチ・ファイル increase_image_test2 を示す。

#!/bin/bash
# increase_images2

straight_max=35
lr_turn_max=12

# contrast
for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -contrast straight_test$(expr $i + $straight_max).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -contrast left_turn_test$(expr $i + $lr_turn_max).bmp
    convert right_turn_test$i.bmp -contrast right_turn_test$(expr $i + $lr_turn_max).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -contrast -contrast straight_test$(expr $i + $straight_max \* 2).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -contrast -contrast left_turn_test$(expr $i + $lr_turn_max \* 2).bmp
    convert right_turn_test$i.bmp -contrast -contrast right_turn_test$(expr $i + $lr_turn_max \* 2).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -contrast -contrast -contrast straight_test$(expr $i + $straight_max \* 3).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -contrast -contrast -contrast left_turn_test$(expr $i + $lr_turn_max \* 3).bmp
    convert right_turn_test$i.bmp -contrast -contrast -contrast right_turn_test$(expr $i + $lr_turn_max \* 3).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +contrast straight_test$(expr $i + $straight_max \* 4).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +contrast left_turn_test$(expr $i + $lr_turn_max \* 4).bmp
    convert right_turn_test$i.bmp +contrast right_turn_test$(expr $i + $lr_turn_max \* 4).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +contrast +contrast straight_test$(expr $i + $straight_max \* 5).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +contrast +contrast left_turn_test$(expr $i + $lr_turn_max \* 5).bmp
    convert right_turn_test$i.bmp +contrast +contrast right_turn_test$(expr $i + $lr_turn_max \* 5).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +contrast +contrast +contrast straight_test$(expr $i + $straight_max \* 6).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +contrast +contrast +contrast left_turn_test$(expr $i + $lr_turn_max \* 6).bmp
    convert right_turn_test$i.bmp +contrast +contrast +contrast right_turn_test$(expr $i + $lr_turn_max \* 6).bmp
done

# blur
for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -blur 10x1.5 straight_test$(expr $i + $straight_max \* 7).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -blur 10x1.5 left_turn_test$(expr $i + $lr_turn_max \* 7).bmp
    convert right_turn_test$i.bmp -blur 10x1.5 right_turn_test$(expr $i + $lr_turn_max \* 7).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -blur 10x2 straight_test$(expr $i + $straight_max \* 8).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -blur 10x2 left_turn_test$(expr $i + $lr_turn_max \* 8).bmp
    convert right_turn_test$i.bmp -blur 10x2 right_turn_test$(expr $i + $lr_turn_max \* 8).bmp
done

# gaussian-blur
for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -blur 10x1.5 straight_test$(expr $i + $straight_max \* 9).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -gaussian-blur 10x1.5 left_turn_test$(expr $i + $lr_turn_max \* 9).bmp
    convert right_turn_test$i.bmp -blur 10x1.5 right_turn_test$(expr $i + $lr_turn_max \* 9).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -blur 10x2 straight_test$(expr $i + $straight_max \* 10).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -gaussian-blur 10x2 left_turn_test$(expr $i + $lr_turn_max \* 10).bmp
    convert right_turn_test$i.bmp -blur 10x2 right_turn_test$(expr $i + $lr_turn_max \* 10).bmp
done

#gamma
for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -gamma 1.5 straight_test$(expr $i + $straight_max \* 11).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -gamma 1.5 left_turn_test$(expr $i + $lr_turn_max \* 11).bmp
    convert right_turn_test$i.bmp -gamma 1.5 right_turn_test$(expr $i + $lr_turn_max \* 11).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp -gamma 0.75 straight_test$(expr $i + $straight_max \* 12).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp -gamma 0.75 left_turn_test$(expr $i + $lr_turn_max \* 12).bmp
    convert right_turn_test$i.bmp -gamma 0.75 right_turn_test$(expr $i + $lr_turn_max \* 12).bmp
done

#noise
for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +noise Gaussian straight_test$(expr $i + $straight_max \* 13).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +noise Gaussian left_turn_test$(expr $i + $lr_turn_max \* 13).bmp
    convert right_turn_test$i.bmp +noise Gaussian right_turn_test$(expr $i + $lr_turn_max \* 13).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +noise Impulse straight_test$(expr $i + $straight_max \* 14).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +noise Impulse left_turn_test$(expr $i + $lr_turn_max \* 14).bmp
    convert right_turn_test$i.bmp +noise Impulse right_turn_test$(expr $i + $lr_turn_max \* 14).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +noise Gaussian straight_test$(expr $i + $straight_max \* 15).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +noise Gaussian left_turn_test$(expr $i + $lr_turn_max \* 15).bmp
    convert right_turn_test$i.bmp +noise Gaussian right_turn_test$(expr $i + $lr_turn_max \* 15).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +noise Impulse straight_test$(expr $i + $straight_max \* 16).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +noise Impulse left_turn_test$(expr $i + $lr_turn_max \* 16).bmp
    convert right_turn_test$i.bmp +noise Impulse right_turn_test$(expr $i + $lr_turn_max \* 16).bmp
done

for ((i=0; i < $straight_max; i++)); do
    convert straight_test$i.bmp +noise Laplacian straight_test$(expr $i + $straight_max \* 17).bmp
done
for ((i=0; i < $lr_turn_max; i++)); do
    convert left_turn_test$i.bmp +noise Laplacian left_turn_test$(expr $i + $lr_turn_max \* 17).bmp
    convert right_turn_test$i.bmp +noise Laplacian right_turn_test$(expr $i + $lr_turn_max \* 17).bmp
done


ircrease_image_test2 を実行すると、画像が 1,062 枚に増えた。テスト用として画像を切り出すときに 25 倍に増えるので、 26,550 枚になるはずだ。
curve_tracing_cnn_33_171216.jpg
  1. 2017年12月16日 05:30 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

カーブ、直線用白線間走行用畳み込みニューラルネットワーク5(トレーニング用データの生成)

カーブ、直線用白線間走行用畳み込みニューラルネットワーク4(学習画像を増やす)”の続き。

前回は、 41 + 18 + 18 = 71 枚の学習画像をコントラストを変えたり、ぼかしたり、ガンマ値を変えたり、ノイズを加えたりして、1,386 枚に増やした。今回はその学習画像をMNISTのデータ形式に変換する。

MNIST手書き数字のデータフォーマットは、”MNIST手書き数字のデータフォーマット”の記事の中で解析している。
白線追従走行用畳み込みニューラルネットワークの製作3(トレーニング、ラベル・ファイルの作成)”で直線走行用のトレーニング用データを作成したので、それを参照して、カーブ、直線用白線走行用のトレーニング用画像・ファイルとトレーニング用ラベル・ファイルを作成していこう。

トレーニング・ファイルとラベル・ファイルを作成するプラットフォームも使い慣れたVivado HLS を使用していこう。
Vivado HLS 2017.3 で curve_dataset_bmp3 プロジェクトを作成した。
curve_tracing_cnn_25_171215.png

curve_dataset_bmp.h を貼っておく。

// curve_dataset_bmp.h
// 2017/11/29 by marsee
//

#ifndef __CURVE_DATASET_BMP_H__
#define __CURVE_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    10
#define DATASET_WIDTH    56

#define STRAIGHT_BMP_FILE_NAME        straight
#define LEFT_TURN_BMP_FILE_NAME        left_turn
#define RIGHT_TURN_BMP_FILE_NAME    right_turn
#define STRAIGHT_NUM_OF_IMAGE        738
#define LEFT_TURN_NUM_OF_IMAGE        324
#define    RIGHT_TURN_NUM_OF_IMAGE        324

typedef hls::Scalar<3unsigned 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


次に、curve_dataset_bmp_nowr.cpp を貼っておく。

// curve_dataset_bmp_nowr.cpp
// 2017/11/29 by marsee
//

#include <iostream>
#include "hls_opencv.h"
#include "curve_dataset_bmp.h"
#include <arpa/inet.h>

const char IMAGE_DIR[] = "train_data_171129";

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];
    FILE *ftin, *ftln;
    char train_image_name[256] = "train_curve_run_image";
    char train_label_name[256] = "train_curve_run_label";
    uint32_t buf[5];
    uint8_t bufchar[100];


    if ((ftin = fopen(train_image_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_image_name);
        exit(1);
    }
    if ((ftln = fopen(train_label_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_label_name);
        exit(1);
    }

    // Writed header
    buf[0] = htonl(0x803); // magic number
    buf[1] = htonl((STRAIGHT_NUM_OF_IMAGE+LEFT_TURN_NUM_OF_IMAGE+RIGHT_TURN_NUM_OF_IMAGE)*25); // number of image
    buf[2] = htonl(10); // number of rows (10)
    buf[3] = htonl(56); // number of columns (56)
    fwrite(buf, sizeof(uint32_t), 4, ftin);

    buf[0] = htonl(0x801); // magic number
    buf[1] = htonl((STRAIGHT_NUM_OF_IMAGE+LEFT_TURN_NUM_OF_IMAGE+RIGHT_TURN_NUM_OF_IMAGE)*25); // number of image
    fwrite(buf, sizeof(uint32_t), 2, ftln);

    // refereed to http://opencv.jp/cookbook/opencv_img.html
    // straight
    for(int i=0; i<STRAIGHT_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s/%s%d.bmp", IMAGE_DIR, straight_fn, i);
        cv::Mat straight_img = cv::imread(bmp_file,1);
        if(straight_img.empty()){
            fprintf(stderr,"Error: %s\n", bmp_file);
            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_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        //sprintf(bmp_file, "%s_RED%d.bmp", straight_fn, i);
        //cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", straight_fn, i, y, x);
                //cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x1;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    // left turn
    for(int i=0; i<LEFT_TURN_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s/%s%d.bmp", IMAGE_DIR, left_turn_fn, i);
        cv::Mat left_turn_img = cv::imread(bmp_file,1);
        if(left_turn_img.empty()){
            fprintf(stderr,"Error: %s\n", bmp_file);
            return(-1);
        }
        cv::Mat reduct_img(left_turn_img.rows*0.075, left_turn_img.cols*0.075, left_turn_img.type());
        cv::resize(left_turn_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        //sprintf(bmp_file, "%s_RED%d.bmp", left_turn_fn, i);
        //cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", left_turn_fn, i, y, x);
                //cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x0;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    // right turn
    for(int i=0; i<RIGHT_TURN_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s/%s%d.bmp", IMAGE_DIR, right_turn_fn, i);
        cv::Mat right_turn_img = cv::imread(bmp_file,1);
        if(right_turn_img.empty()){
            fprintf(stderr,"Error: %s\n", bmp_file);
            return(-1);
        }
        cv::Mat reduct_img(right_turn_img.rows*0.075, right_turn_img.cols*0.075, right_turn_img.type());
        cv::resize(right_turn_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        //sprintf(bmp_file, "%s_RED%d.bmp", right_turn_fn, i);
        //cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", right_turn_fn, i, y, x);
                //cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x2;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    fclose(ftin);
    fclose(ftln);

    return(0);
}


curve_dataset_bmp_nowr.cpp では数が増えすぎてしまうので、学習画像をBMPファイルにしていないが、画像を出力した curve_dataset_bmp2 で出力した学習画像の一部を示す。
まずは、左旋回の学習画像を示す。
curve_tracing_cnn_26_171215.png

右旋回の画像を示す。
curve_tracing_cnn_27_171215.png

直進の画像を示す。
curve_tracing_cnn_28_171215.png

C シミュレーションを行ったところ、train_curve_run_image と train_curve_run_label ができた。
curve_tracing_cnn_29_171215.png

curve_tracing_cnn_30_171215.png

train_curve_run_image をバイナリ・エディタで見た。
curve_tracing_cnn_31_171215.png

最初の 0x0000 0803 が画像ファイルのマジック・ナンバーだ。その次の 0x0000 875a は16進数なので、10進数に直すと34,650 となって学習画像の数を表す。0x0000 000a は10 進数にすると 10 で、画像の縦のピクセル数を表す。次の 0000 0038 は、10進数に直すと 56 で画像の横のピクセル数を表す。

train_curve_run_label を示す。
curve_tracing_cnn_32_171215.png

最初の 0x0000 0801 はラベル・ファイルのマジック・ナンバーだ。その次の 0x0000 875a は16進数なので、10進数に直すと 34,650 となってトレーニング・ラベルの数を表す。

これで、トレーニング用画像・ファイルとトレーニング用ラベル・ファイルを作成することができた。
  1. 2017年12月15日 05:04 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

FPGA+SoC+Linux実践勉強会での課題をやってみた7(dma_pow2 IP のドライバを使用したアプリケーション)

前回は、Vivado HLS 2017.3 で作成した 2 乗倍するDMAIP をVivado 2017.3 のブロック・デザインでインスタンスして構成した回路で Device Tree Overlay でデバイスツリー・オーバーレイで、 FPGA Region を使用して、ビット・ファイルをコンフィギュレーションした。今回は、それに加えて udmabuf を実装し、udmabuf を使用し、更にアプリケーションソフト test_dma.c を書いて、dma_pow2 IP を動作させた。今回はその続きで、前回の test_dma.c を dma_pow2 IP のドライバを使用するコードに書きなおす。それを test_dma_wd.c とする。そして、Makefile も書いて make し、動作させてみる。

dma_pow2 IP のドライバを使用したアプリケーションソフト test_dma_wd.c を作成してテストする。
まずは、dma_pow2 IP のドライバをZYBO Z7 上のDebian に dma_pow2_drivers というディレクトリを作成してアップロードした。
FPGA-SoC-Linux4ZYBO_Z7_76_171214.png

test_dma_wd.c を作成した。test_dma_wd.c を示す。

// test_dma_wd.c
// test_dma with drivers
// 2017/12/14 by marsee
//

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

#include "xdma_pow2.h"

int main(){
    int fd1, fd2;
    
    XDma_pow2 xdma_ap;
    int Xdma_status;
    volatile unsigned int *cma_buffer;
    
    char  attr[1024];
    unsigned long  phys_addr;
    int i;
    
    // Initialize the Device
    Xdma_status = XDma_pow2_Initialize(&xdma_ap, "dma_pow2");
    if (Xdma_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XDma_pow2\n");
        return(-1);
    }
    
    // udmabuf0
    fd1 = open("/dev/udmabuf0", O_RDWR); // frame_buffer, The chache is enabled. 
    if (fd1 == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    cma_buffer = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!cma_buffer){
        fprintf(stderr, "cma_buffer mmap error\n");
        exit(-1);
    }
    
    // phys_addr of udmabuf0
    fd2 = open("/sys/class/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd2 == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd2, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd2);
    printf("phys_addr = %x\n", (int)phys_addr);

    XDma_pow2_Set_in_r(&xdma_ap, phys_addr);
    XDma_pow2_Set_out_r(&xdma_ap, phys_addr+sizeof(int)*10);
    
    for(i=0; i<10; i++)
        cma_buffer[i] = i;

    XDma_pow2_Start(&xdma_ap);
    
    while(!XDma_pow2_IsDone(&xdma_ap)) ;
    
    printf("in[] =  ");
    for(i=0; i<10; i++)
        printf("%2d ", cma_buffer[i]);
    printf("\n");
    
    printf("out[] = ");
    for(i=10; i<20; i++)
        printf("%2d ", cma_buffer[i]);
    printf("\n");
    
    munmap((void *)cma_buffer, 0x10000);
    close(fd1);
    
    return(0);
}


Makefile も作成した。貼っておく。

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

PROGRAM = test_dma_wd
OBJS = test_dma_wd.o xdma_pow2.o xdma_pow2_linux.o

CC = gcc
CFLAGS = -Wall -O2

.SUFFIXES: .c .o

.PHONY: all

all: test_dma_wd

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

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


ここまでできたので、make し、./dma_pow2_wd で実行した。
FPGA-SoC-Linux4ZYBO_Z7_77_171214.png

前回同様に、in[] を 2乗した値が out[] に出力されているのが分かる。こちらも成功だ。
  1. 2017年12月14日 05:02 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

FPGA+SoC+Linux実践勉強会での課題をやってみた6(udmabuf、実機テスト)

FPGA+SoC+Linux実践勉強会での課題をやってみた5(FPGA Region)”の続き。

前回は、Vivado HLS 2017.3 で作成した 2 乗倍するDMAIP をVivado 2017.3 のブロック・デザインでインスタンスして構成した回路で Device Tree Overlay でデバイスツリー・オーバーレイで、 FPGA Region を使用して、ビット・ファイルをコンフィギュレーションした。今回は、それに加えて udmabuf を実装し、udmabuf を使用し、更にアプリケーションソフトを書いて、dma_pow2 IP を動作させてみよう。

FPGA+SoC+Linux実践勉強会資料”の 94 ページの「デバイスの追加 - DMA バッファの確保 (1)」のコードを fpga_dma_pwo2.dts にコピー&ペーストして、fpga_udma_dma_pow2.dts とした。そして、size を 64 Kバイトの領域に変更した。
fpga_udma_dma_pow2.dts を示す。

/dts-v1/; /plugin/;
/ {
  fragment@1 {
    target-path = "/amba/fpga-region0";
    #address-cells = <1>;
    #size-cells = <1>;
    __overlay__ {
      #address-cells = <1>;
      #size-cells = <1>;
      firmware-name = "test_dma_wrapper.bin";
      dma_pow2@43c00000 { 
        compatible = "generic-uio";
        reg = <0x43c00000 0x10000>;
        #interrupts = <0x0 0x1d 0x4>;
      };
      udmabuf0@0x00 {
        compatible = "ikwzm,udmabuf-0.10.a";
        device-name = "udmabuf0";
        size = <0x00010000>;
      }; 
    };
  };
};


dtbocfg.rb を使用して、デバイスツリー・オーバーレイを行う。ZYBO Z7 のPL にtest_dma_wrapper.bin がダウンロードされて、dma_pow2 の uio ドライバが実装され、udmabuf0 も実装されるはずだ。
コマンドとしては、
sudo dtbocfg.rb -i test_dma --dts fpga_udma_dma_pow2.dts
を実行した。
ls /config/device-tree/overlays
を実行すると test_dma ディレクトリが生成されていた。
ls /sys/devices/soc0/amba/amba\:fpga-region0/
を実行すると、43c00000.dma_pow2 が生成されているのが分かった。
FPGA-SoC-Linux4ZYBO_Z7_73_171214.png

ls /dev を実行すると uio0 と udmabuf0 が見えた。
FPGA-SoC-Linux4ZYBO_Z7_74_171214.png

dma_pow2 IP を使用するためのアプリケーションソフト test_dma.c を作成した。
test_dma.c を示す。

// test_dma.c
// 2017/12/12 by marsee
//

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

int main(){
    int fd0, fd1, fd2;
    
    volatile unsigned int *dma_pow2_0;
    volatile unsigned int *cma_buffer;
    
    char  attr[1024];
    unsigned long  phys_addr;
    int i;
    
    // dma_pow2_0 (UIO0)
    fd0 = open("/dev/uio0", O_RDWR); // dma_pow2_0 interface AXI4 Lite Slave
    if (fd0 < 1){
        fprintf(stderr, "/dev/uio0 (dma_pow2_0) open error\n");
        exit(-1);
    }
    dma_pow2_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, 0);
    if (!dma_pow2_0){
        fprintf(stderr, "dma_pow2_0 mmap error\n");
        exit(-1);
    }
    
    // udmabuf0
    fd1 = open("/dev/udmabuf0", O_RDWR); // frame_buffer, The chache is enabled. 
    if (fd1 == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    cma_buffer = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!cma_buffer){
        fprintf(stderr, "cma_buffer mmap error\n");
        exit(-1);
    }
    
    // phys_addr of udmabuf0
    fd2 = open("/sys/class/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd2 == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd2, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd2);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    dma_pow2_0[6] = phys_addr;    // 0x18 Data signal of in_r
    dma_pow2_0[8] = phys_addr+sizeof(int)*10;    // 0x20 Data signal of out_r
    
    for(i=0; i<10; i++)
        cma_buffer[i] = i;
    
    dma_pow2_0[0] = 1// Start
    
    while(!(dma_pow2_0[0] & 0x2));    // wait done signal
    
    printf("in[] =  ");
    for(i=0; i<10; i++)
        printf("%2d ", cma_buffer[i]);
    printf("\n");
    
    printf("out[] = ");
    for(i=10; i<20; i++)
        printf("%2d ", cma_buffer[i]);
    printf("\n");
    
    munmap((void *)dma_pow2_0, 0x10000);
    munmap((void *)cma_buffer, 0x10000);

    close(fd0);
    close(fd1);
    
    return(0);
}


PS からのPL のクロックはFCLK_CLK0 は 100 MHz で出力されるように設定されているということなので、test_dma を実行してみよう。
最初に gcc でコンパイルを行った。
gcc -o test_dma test_dma.c
エラーは無かった、というかエラーが発生しないようにデバックしたのだ。
./test_dma で実行したところ、/dev/uio0 が開けなかった。
しまった、uio0 と udmabuf のパーミッションの設定で、ユーザーには開けなかったんだった。
sudo chmod 666 /dev/uio0 /dev/udmabuf0
を実行して、uio0 と udmabuf のパーミッションを設定して、ユーザーでも開けるように変更した。
もう一度、./test_dma を実行した。
FPGA-SoC-Linux4ZYBO_Z7_75_171214.png

in[] を 2乗した値が out[] に出力されているのが分かる。成功だ。ACP ポートを使用しているので、udmabuf をキャッシュ・オンにしているのだが、きちんとARMプロセッサが読めているようだ。
  1. 2017年12月14日 04:57 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS の合成でEstimated がTarget の制約を満たせなかったときの処置

Vivado HLS の合成でEstimated の値がTarget を満たせなかったときの処置を@hiyuh さんに教わったので書いておこう。

今まで、Vivado HLS の合成でEstimated の値がTarget を満たせなかったときは、Solution メニューからSolution Settings ダイアログの Synthesis でClock Period を 短い周期にしていた。それだとタイミング制約が変更されてしまうので、Uncertainty を変更したほうが良いということだ。

ラプラシアンフィルタの lap_filter4_axim でVivado HLS 2017.3 を使用して、C コードの合成を行うと、Target が 10.00 ns に対して、Estimated が 11.31 ns とタイミング違反になってしまう。
Vivado_HLS_4_171213.png

これを修正するために、Solution メニューからSolution Settings ダイアログの Synthesis でClock Period を 8 ns に設定していた。
Vivado_HLS_5_171213.png

すると、Target が 8.00 ns となるものの、Estimated は 9.40 ns となり、10 ns を満たすので、これでVivado に持っていっての合成も問題なかった。
Vivado_HLS_6_171213.png

しかし、C/RTL コシミュレーションのクロック周期は 8 ns となってしまうのと、IP にしたときのタイミング制約 lap_filter_axim_ooc.xdc を見ると、クロック周期の制約が 8.000 ns になってしまっている。実際は、Vivado での制約は 10 ns であるので、オーバーなタイミング制約になっているということが言えると思う。
Vivado_HLS_7_171213.png

Vivado_HLS_8_171213.png

これをツィーターで@hiyuh さんに指摘してもらった。解決方法としては、Solution メニューからSolution Settings ダイアログの Synthesis でClock Period を 短い周期に変更するのではなく、Uncertainty を増やすということだ。

Uncertainty はクロック周期のマージンでクロックのばらつき具合を示す。よって、これを増やすと、結果的にタイミング制約の周期の制約の値が小さくなる。つまり、10 ns では、Uncertainty のデフォルト値は 12.5 % の 1.25 ns だが、これを増やすと実質的にクロックのタイミング制約がきつくなる。

さてここで、Solution メニューからSolution Settings ダイアログの Synthesis でUncertainty の値を 3 ns にしてみよう。
Vivado_HLS_9_171213.png

このC コードの合成結果は、Target が 10.00 ns で、Estimated が 9.40 ns、Uncertainty が 3.00 ns になって、タイミング制約を満たすようになった。
Vivado_HLS_10_171213.png

これだと、C/RTL コシミュレーションでもクロック周期が 10 ns で本来の値となっている。
IP にしたときのタイミング制約 lap_filter_axim_ooc.xdc を見ても、クロックのタイミング制約は 10.000 ns となっていて、問題が無い。
Vivado_HLS_11_171213.png

Vivado HLS の合成でEstimated の値がTarget を満たせなかったときは、Solution メニューからSolution Settings ダイアログの Synthesis でUncertainty を大きくすることにしよう。
  1. 2017年12月13日 05:25 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

FPGA+SoC+Linux実践勉強会での課題をやってみた5(FPGA Region)

FPGA+SoC+Linux実践勉強会での課題をやってみた4(Device Tree Overlay)”の続き。

前回は、Vivado HLS 2017.3 で作成した 2 乗倍するDMAIP をVivado 2017.3 のブロック・デザインでインスタンスして構成した回路で Device Tree Overlay を試した。今回は、それの回路で FPGA Region を使用して、ビット・ファイルをコンフィギュレーションしてみよう。

まずは、”FPGA+SoC+Linux実践勉強会資料”の38 ページの sample.dts を参照しながら fpga_dma_pow2.dts を作成した。
FPGA-SoC-Linux4ZYBO_Z7_63_171211.png

/dts-v1/; /plugin/;
/ {
  fragment@1 {
    target-path = "/amba/fpga-region0";
    #address-cells = <1>;
    #size-cells = <1>;
    __overlay__ {
      #address-cells = <1>;
      #size-cells = <1>;
      firmware-name = "test_dma_wrapper.bin";
      dma_pow2@43c00000 { 
        compatible = "generic-uio";
        reg = <0x43c10000 0x10000>;
        #interrupts = <0x0 0x1d 0x4>;
      };
    };
  };
};


Windows 10のUbuntu を使用して、”Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法”の fpga-bit-to-bin.py をコピーした。
FPGA-SoC-Linux4ZYBO_Z7_64_171211.png

python fpga-bit-to-bin.py -f test_dma_wrapper.bit test_dma_wrapper.bin
コマンドで、test_dma_wrapper.bit を test_dma_wrapper.bin に変換した。この際に、-f オプションを付け忘れて、ツィーターで指摘してもらった。ありがとうございました。
FPGA-SoC-Linux4ZYBO_Z7_65_171211.png

cd /mnt/e で e ドライブに行って、sudo cp ~/test_dma_wrapper.bin . で test_dma_wrapper.bin をコピーした。
FPGA-SoC-Linux4ZYBO_Z7_66_171211.png

Windows の E: ドライブにコピーできた。
FPGA-SoC-Linux4ZYBO_Z7_67_171211.png

WinSCP で ZYBO Z7-20 のDebianにコピーした。
FPGA-SoC-Linux4ZYBO_Z7_68_171211.png

sudo cp test_dma_wrapper.bin /lib/firmware/ で test_dma_wrapper.bin を /lib/firmware ディレクトリにコピーした。
FPGA-SoC-Linux4ZYBO_Z7_69_171211.png

sudo dtbocfg.rb -i test_dma --dts fpga_dma_pow2.dts
を実行するとZYBO Z7 のDONE LED が点灯した。コンフィギュレーションが成功したようだ。
ls /config/device-tree/overlays を実行すると test_dma ができているのが分かった。
ls /sys/devices/soc0/amba/amba\:fpga-region0/ を見ると、 43c00000.dma_pow2 がいるのが分かった。
FPGA-SoC-Linux4ZYBO_Z7_70_171211.png

ls /dev コマンドを実行すると uio0 がいるのが分かった。
FPGA-SoC-Linux4ZYBO_Z7_71_171211.png

sudo dtbocfg.rb -r test_dma を実行して、test_dma を取り外した。
ls /config/device-tree/overlays を実行すると test_dma が無くなっているのが分かった。
ls /sys/devices/soc0/amba/amba\:fpga-region0/ を見ても、43c00000.dma_pow2 が無くなっていた。
FPGA-SoC-Linux4ZYBO_Z7_72_171212.png
  1. 2017年12月12日 04:29 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

映画「DESTINY 鎌倉ものがたり」を見てきました

昨日、映画「DESTINY 鎌倉ものがたり」(動画、音注意です)を見てきました。久しぶりの映画でした。やはり三丁目の夕日のスタッフだけあってファンタジーでもどこかほのぼのとした雰囲気で良かったです。
  1. 2017年12月11日 04:59 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

FPGA+SoC+Linux実践勉強会での課題をやってみた4(Device Tree Overlay)

FPGA+SoC+Linux実践勉強会での課題をやってみた3(Vivado 編2 ACPポートを使用)”の続き。

前回は、Vivado HLS 2017.3 で作成した 2 乗倍するDMAIP をVivado 2017.3 のブロック・デザインでインスタンスして、回路を構成した。その際には、ACP ポートを使用した。SDK のベアメタル・アプリケーションソフトで動作を確認した。今回は、ikwzm さんの Device Tree Overlay を試してみよう。

PYNQ ボードで Device Tree Overlay を試した時の記事は、””FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる5(デバイスツリー・オーバーレイ)”だ。これと、”FPGA+SoC+Linux実践勉強会資料”を参照している。
なお、”FPGA+SoC+Linux実践勉強会用のZYBO Z7用MicroSDカードの準備”で準備したMicroSDカードを使用している。

まずは、dma_pow2.dts を作成した。
Vivado の Address Editor を見ると、アサインされたアドレスが分かる。
FPGA-SoC-Linux4ZYBO_Z7_54_171209.png

これを見ると、DMA_pow2_0 が 0x43C0_0000 からの 64 kバイトを使用することが分かる。
これを元に、”FPGA+SoC+Linux実践勉強会資料”の 26 ページのDevice Tree Overlay のサンプルを参考にデバイスツリーを書いてみた。
FPGA-SoC-Linux4ZYBO_Z7_55_171209.png

/dts-v1/;
/ {
  fragment@0 {
    target-path = "/amba";
    __overlay__ {
      #address-cells = <0x1>;
      #size-cells = <0x1>;
      dma_pow2@43c00000 {
        compatible = "generic-uio";
        reg = <0x43c00000 0x10000>;
        #interrupts = <0x0 0x1d 0x4>;
      };
    };
  };
};


デバイスツリー・オーバーレイを実行するには、””FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる5(デバイスツリー・オーバーレイ)”だと、/config/device-tree/overlays で uio_gpio_0 ディレクトリを作成して、status に書いたりして実装していたが、”FPGA+SoC+Linux実践勉強会資料”の 32 ページに dtbocfg.rb があるので使ってみよう。これは拡張子で分かるように Ruby スクリプトだ。
まず、dtbocfg.rb -h を実行してコマンドを見た。
FPGA-SoC-Linux4ZYBO_Z7_61_171209.png

-i を使えばよいのかな?
sudo dtbocfg.rb -i --dts dma_pow2.dts dma_pow2
を実行した。
FPGA-SoC-Linux4ZYBO_Z7_56_171209.png

ワーニングが出た。それは、

/config/device-tree/overlays/dma_pow2/dtbo: Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property

だった。

試しに、ls /config/device-tree/overlays を実行すると、dma_pow2 があったので、うまく行っているみたいだ。
FPGA-SoC-Linux4ZYBO_Z7_57_171209.png

dma_pow2 ディレクトリの下には、dtbo と status の 2 つのファイルがあった。

次に、/sys/devices/soc0/amba/ に行ってみよう。
cd /sys/devices/soc0/amba/
FPGA-SoC-Linux4ZYBO_Z7_58_171209.png

ls すると、43c00000.dma_pow2 があった。デバイスツリー・オーバーレイで dma_pow2 を実装できているようだ。

43c00000.dma_pow2 を tree コマンドで構造を見た。
FPGA-SoC-Linux4ZYBO_Z7_59_171209.png
FPGA-SoC-Linux4ZYBO_Z7_60_171209.png

次にインストールしたデバイスツリー・オーバーレイを削除してみよう。
sudo dtbocfg.rb -r dma_pow2
を実行した。
FPGA-SoC-Linux4ZYBO_Z7_62_171210.png

ls /config/device-tree/overlays をしても dma_pow2 は無くなっていた。
ls /sys/devices/soc0/amba/ をしても、43c00000.dma_pow2 は無くなっていた。
  1. 2017年12月10日 05:16 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

intel HLS の pointer_mm_master を試してみた2

intel HLS の pointer_mm_master を試してみた1”の続き。

前回は、intel HLS の F:\intelFPGA_lite\17.1\hls\examples\tutorials\interfaces\pointer_mm_master を試してみた。
ここには、part_1_pointers.cpp、part_2_masters.cpp、part_3_ddr_masters.cpp、part_4_ddr_masters_coalesce.cpp、part_5_ddr_masters_align.cpp の 5 つのAvalon-MM master のサンプルがあった。そして、それぞれの実装の違いをHDLのポート宣言を見ることで確認した。
今回は、それらの転送波形をModelSim で見てみよう。

part_1_pointers.cpp
part_1_pointers.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(int* a,
                          int* b,
                          int* c,
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];
  }
}


ModelSim の全体波形を示す。
Intel_HLS_135_171208.png

done が出るまでの時間は約 17.03 us だった。

1つのトランザクションが見えるように拡大波形を示す。
Intel_HLS_136_171208.png

それぞれ 1 回ずつReadが 2 回、Write が 1 回のアクセルがある。 1 回の転送の周期は、17 ns だった。これを 1000 回やっているので、17 us となり計算は合う。

part_2_masters.cpp
part_2_masters.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<16>, ihc::dwidth<32> >& a,
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<16>, ihc::dwidth<32> >& b,
                          ihc::mm_master<int, ihc::aspace<3>, ihc::awidth<16>, ihc::dwidth<32> >& c,
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


part_1_pointers.cpp と比べると、32 ビット幅のバスを 3 つにした。つまりスループットが大きくなる要素がそろった。
ModelSim の全体波形を示す。
Intel_HLS_137_171208.png

3つのバスとも、アドレスとデータの幅は 32 ビットだ。
part_2_masters.cpp の done が出るまでに時間は約 1.04 ms となった。part_1_pointers.cpp との性能差は17 倍弱だ。

拡大してみよう。
Intel_HLS_138_171208.png

この実装では、Read と Write はパイプライン実行されている。クロックごとに 1 ns で Write されているので、1 回の転送の周期は 1 ns となる。

part_2_masters.cpp がなぜエラーになるかだが、演算の最初を拡大してみると、最初の演算の答えが avmm_3_rw_writedata に 0000464c と出ているが、まだ avmm_3_rw_write は 1 にアサートされていない。avmm_3_rw_write が 1 にアサートされるのはその 2 クロック後であるので、データが 2 個ずれているようだ。この、avmm_3_rw_write が 1 にアサートされるのを 2 クロック前にずらせれば良さそうだ。

part_3_ddr_masters.cpp
part_3_ddr_masters.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& a, // bank 1
                          ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& b, // bank 1
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& c, // bank 2
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


データバスの幅が 256 ビットになって、Read が 1 つのバス、Write も 1 つのバスの合計 2 つのバスになった。
ModelSim の全体波形を示す。
Intel_HLS_139_171208.png

まばらにアクセスがあるが、ビット幅が 256 ビット幅なので、done が出るまでの時間は、約 1.63 us だった。part_1_pointers.cpp との性能差は約10.4 倍だった。

拡大してみてみよう。
Intel_HLS_140_171208.png

Write の幅を見ると 8 ns になっているのが分かる。これは、32ビット幅の演算器しか持っていないので、256 ビット幅のデータを満たすには、 256 / 32 = 8 クロック分(1クロックは 1 ns)かかるためだと思われる。

part_4_ddr_masters_coalesce.cpp
part_4_ddr_masters_coalesce.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& a, // bank 1
                          ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& b, // bank 1
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& c, // bank 2
                          int N) {
  #pragma unroll 8
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


part_4_ddr_masters_coalesce.cpp では、#pragma unroll 8 のプラグマが追加されているので、part_3_ddr_masters.cpp での 8 クロックに 1 回のデータ Write が改善されていると思われる。
ModelSim の全体波形を示す。
Intel_HLS_141_171208.png

done が出るまでの時間は、384 ns だった。アクセスがきちんと並んでいて、転送のスループットが大きいのが分かる。part_1_pointers.cpp との性能差は約 44.3 倍だった。

波形を拡大してみよう。
Intel_HLS_142_171208.png

Read のアドレスが飛んでいるので、a[i] をRead しているアドレスと b[i] をRead しているアドレスがあると考えられる。よって、Write の転送は、半分のスループットになっているのが分かる。つまり、2 つデータを読んで 1 つデータを書いているわけだ。

part_5_ddr_masters_align.cpp
part_5_ddr_masters_align.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::align<32>, ihc::waitrequest<true> >& a, // bank 1
                          ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::align<32>, ihc::waitrequest<true> >& b, // bank 1
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::align<32>, ihc::waitrequest<true> >& c, // bank 2
                          int N) {
  #pragma unroll 8
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


part_5_ddr_masters_align.cpp では、part_4_ddr_masters_coalesce.cpp に ihc::align<32> が追加されている。これでデータバスの 256 ビット幅にアラインされているということにしている。

ModelSim の全体波形を示す。
Intel_HLS_143_171208.png

done が出るまでの時間は、380 ns だった。part_4_ddr_masters_coalesce.cpp とほとんど同じようだ。part_1_pointers.cpp との性能差は約 44.8 倍だった。

波形を拡大してみた。
Intel_HLS_144_171208.png

part_4_ddr_masters_coalesce.cpp と同様だ。 ihc::align<32> を付けるとリソース使用量が減るのではないか?と思う。


最後に part_2_masters.cpp のエラーの対処方法を押しててもらったので、やってみよう。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<16>, ihc::dwidth<32>, ihc::latency<0> >& a,
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<16>, ihc::dwidth<32>, ihc::latency<0> >& b,
                          ihc::mm_master<int, ihc::aspace<3>, ihc::awidth<16>, ihc::dwidth<32>, ihc::latency<0> >& c,
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


このように、ihc::latency<0> を追加して build clean してから build default を行ったところ、PASSED になった。なお、mm_A, mm_B, mm_C の宣言の部分にも ihc::latency<0> を追加している。
Intel_HLS_145_171209.png

ModelSim の波形を示す。
Intel_HLS_146_171209.png

これは、ihc::latency<0> を付加する前に比べてスループットが下がっている。以前は、done が出るまでに時間は約 1.04 ms だったが、今回は、約 1.33 ms になった。

拡大してみた。
Intel_HLS_147_171209.png
  1. 2017年12月08日 05:13 |
  2. intel HLS
  3. | トラックバック:0
  4. | コメント:0

FPGA+SoC+Linux実践勉強会での課題をやってみた3(Vivado 編2 ACPポートを使用)

FPGA+SoC+Linux実践勉強会での課題をやってみた2(Vivado 編)”の続き。

「”FPGA+SoC+Linux実践勉強会”でZYBO Z7 を使用し、Vivado HLS でDMA IPを作成して、Vivado で回路にして、SDK でベアメタル・アプリケーションでDMA IP を動作させようとしたら動作しなかった。
そこで、DMA IP を仕上げてデバイツリー・オーバーレイやudmabuf などを確かめてみよう。」ということで、前回はPS のHP ポートを使用して、Vivado HLS で作成したDMA_pow2 IP を接続して使用することができた。今回は、ACP ポートにDMA_pow2 IP を接続して使用してみようと思う。

FPGA+SoC+Linux実践勉強会での課題をやってみた2(Vivado 編)”をプロジェクト・フォルダごとコピー&ペーストして、フォルダの名前をtest_dma_ACP に変更した。
FPGA-SoC-Linux4ZYBO_Z7_41_171206.png

PS をダブルクリックして、ダイアログを開き、HP ポートを削除し、ACP ポートをTie off AxUSER 付きで追加した。
FPGA-SoC-Linux4ZYBO_Z7_43_171206.png

ブロック・デザインを示す。
FPGA-SoC-Linux4ZYBO_Z7_42_171206.png

Address Editor 画面を示す。
FPGA-SoC-Linux4ZYBO_Z7_54_171209.png

論理合成、インプリメント、ビットストリームの生成を行った。結果を示す。
FPGA-SoC-Linux4ZYBO_Z7_44_171206.png
FPGA-SoC-Linux4ZYBO_Z7_45_171206.png

成功した。
ビットストリーム付きで、ハードウェアをエクスポートし、SDK を立ち上げた。
FPGA-SoC-Linux4ZYBO_Z7_46_171206.png

Vivado Analyzer で波形を観測するためにHello_World を起動してから、Vivado Analyzer を起動して、その後、test_dma.elf を十個したところ、成功した。
FPGA-SoC-Linux4ZYBO_Z7_40_171206.png

Vivado Analyzer の波形を示す。
Read 波形を示す。
FPGA-SoC-Linux4ZYBO_Z7_39_171206.png

Write 波形を示す。
FPGA-SoC-Linux4ZYBO_Z7_40_171206.png

ここで、最後にBVALID が 1 になっていることに注目してほしい。
ここまでは昨日の夜やっていたのだが、一夜明けて、朝もう一度やってみたところ、Tera Termに全く表示されなくなった。
その時の波形を示す。

Read から示す。
FPGA-SoC-Linux4ZYBO_Z7_47_171207.png

一見普通のトランザクションに見えるのだが、最後の 9 をRead するところで、データのRead が 1 買いだけになってしまっているのが分かると思う。つまり、トランザクションが足りない。

次にWrite を見てみよう。
FPGA-SoC-Linux4ZYBO_Z7_48_171207.png

こちらも 64 はWrite できているが、91 が無い。しかもBVALID のアサートもない。
つまり、Write 応答チャネルに反応が無いようなのだ。メモリに書けていないようなのだ。しかし、一回はうまく行ったのに、一夜明けると失敗するのだろう?不可解だ。。。
なお、HP ポートはいつでも成功していて安定している。

(追記)
ACPポートが使えるようになりました。ikzwm さんに教えてもらったのですが、AWCACHEとARCACHE はXilinxのデフォルトでは 0011 のCacheable and bufferable, do not allocate だが、これではL2 キャッシュには書かれないそうだ。(”Zynq の ACP を使う時の AxCACHE 信号とAxUSER 信号の値”参照)

Zynq の ACP を使う時の AxCACHE 信号とAxUSER 信号の値”によるとAxCACHE 信号とAxUSER 信号の値は、Cacheable write-back, allocate on both read and write の 1111 ということで、これを設定してやってみた。

DMA_pow2 IP をダブルクリックして、設定ダイアログを表示させた。
CACHE value を ”1111”に変更した。
FPGA-SoC-Linux4ZYBO_Z7_49_171207.png

これで、論理合成、インプリメント、ビットストリームの生成を行って、成功した。

ハードウェアをエクスポートして、SDK を立ち上げた。
FPGA-SoC-Linux4ZYBO_Z7_50_171207.png

HP ポートでも result[] が 0 になるコードを実行したが、きちんと二乗の計算ができてる。
FPGA-SoC-Linux4ZYBO_Z7_51_171207.png

Vivado Analyzer でAXI4 Master の波形を取ってみたので貼っておく。
Read
FPGA-SoC-Linux4ZYBO_Z7_52_171207.png

Write
FPGA-SoC-Linux4ZYBO_Z7_53_171207.png

これで、デバイスツリー・オーバーレイや udmabuf を試してみよう。
  1. 2017年12月07日 04:57 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

FPGA+SoC+Linux実践勉強会での課題をやってみた2(Vivado 編)

FPGA+SoC+Linux実践勉強会での課題をやってみた1(Vivado HLS編)”の続き。

「”FPGA+SoC+Linux実践勉強会”でZYBO Z7 を使用し、Vivado HLS でDMA IPを作成して、Vivado で回路にして、SDK でベアメタル・アプリケーションでDMA IP を動作させようとしたら動作しなかった。
そこで、DMA IP を仕上げてデバイツリー・オーバーレイやudmabuf などを確かめてみよう。」ということで、前回はVivado HLS 2017.3 でDMA_pow プロジェクトを作成し、10 個のデータをReadし、 2 乗して出力するIP にした。今回は、そのDMA_pow2 IP を使用して、Vivado 2017.3 の IPI で ZYBO Z7 のPS と接続して、SDK でアプリケーションソフトを作って実機で試してみよう。

Vivado 2017.3 で test_dma プロジェクトを作成した。

IP Catalog を開いて、右クリックメニューからAdd Repository... を選択して、DMA_pow2 IP を加えた。

test_dma ブロック・デザインを作成し、回路を構成した。
FPGA-SoC-Linux4ZYBO_Z7_23_171206.png

ブロック・デザインを示す。
FPGA-SoC-Linux4ZYBO_Z7_24_171206.png

PS のHP ポートを使用している。ACP ポートを使用すると、SDK のtest_dma アプリケーションソフトを実行したときに、どうしても

while(!XDma_pow2_IsDone(&XMluti_ap)) ;

から抜けてこなかったのだ。どうしてか分からないが、ACP ポートではVivado HLS で作成した Dma_pow2 IP がDone にならないようだ?

HDL Wapper を作成し、論理合成、インプリメント、ビットストリームの生成を行って、成功した。結果を示す。
FPGA-SoC-Linux4ZYBO_Z7_25_171206.png
FPGA-SoC-Linux4ZYBO_Z7_26_171206.png

ハードウェアをビットストリームごとエクスポートし、SDK を立ち上げた。

Hello_World アプリケーション・プロジェクトを作成した。

test_dma アプリケーション・プロジェクトを作成した。
FPGA-SoC-Linux4ZYBO_Z7_28_171206.png

test_dma.c を示す。

/* * test_dma.c * *  Created on: 2017/12/02 *      Author: masaaki */


#include <stdio.h>
#include "xdma_pow2.h"
#include "xparameters.h"

volatile int data[10] = {0123456789};
volatile int result[10] = {0123456789};

int main(){
    XDma_pow2 XMluti_ap;
    XDma_pow2_Config *XMulti_apPtr;
    int i;

    // Look Up the device configuration
    XMulti_apPtr = XDma_pow2_LookupConfig(0);
    if (!XMulti_apPtr){
        fprintf(stderr, "XMulti_apuint configuration failed.\n");
        return(-1);
    }

    // Initialize the Device
    int Xlap_status = XDma_pow2_CfgInitialize(&XMluti_ap, XMulti_apPtr);
    if (Xlap_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XMulti_apuint\n");
        return(-1);
    }

    XDma_pow2_Set_in_r(&XMluti_ap, (u32)&data[0]);
    XDma_pow2_Set_out_r(&XMluti_ap, (u32)&result[0]);

    XDma_pow2_Start(&XMluti_ap);

    while(!XDma_pow2_IsDone(&XMluti_ap)) ;

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

    return 0;

}


Hello_World を実行してから、test_dma を実行した結果を示す。
FPGA-SoC-Linux4ZYBO_Z7_29_171206.png

date[] の 2 乗倍が result[] になっている。

result[] の結果はresult[] 配列の宣言によっても影響を受ける。

volatile int result[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

volatile int result[10];

にしてみよう。
FPGA-SoC-Linux4ZYBO_Z7_30_171206.png

これで実行してみた結果を示す。
FPGA-SoC-Linux4ZYBO_Z7_31_171206.png

result[] はすべて 0 だ。。。DMAは成功していてもARM プロセッサはデータを読めていない。これで、”FPGA+SoC+Linux実践勉強会”の時はうまく行かなかったようだ。
これは、.bss 領域と .data 領域のキャッシュのON, OFF の違いが影響しているのかもしれない?
ちなみに、現在は、volatile でグローバルに data 配列と reseult 配列を宣言しているが、main() の中で、data 配列と reseult 配列を宣言していた時は、Vivado Analyzer で見たときのRead アクセス(つまり in[i] のRead )のデータも正しくなかった。つまり、物理アドレスと仮想アドレスが違っていたのではないか?と思う。
いろいろと難しいですね。。。ホントに。。。

Vivado Analyzerの波形を貼っておく。

まずは、全体のトランザクション波形から。
FPGA-SoC-Linux4ZYBO_Z7_32_171206.png

Slot_0 がAXI4 Master で、Slot_1 が AXI4 Lite Slave だ。
AXI4 Lite Slave でレジスタを設定してるので、AXI4 Master よりも先にトランザクションがあるのが分かる。AXI4 Master のトランザクションが発生してからのAXI4 Lite Slave はAXI4 Master のDone 待ちループに入っている。

次に、AXI4 Lite Slave のレジスタ設定部分を拡大してみた。
FPGA-SoC-Linux4ZYBO_Z7_33_171206.png

最初の0x18 へのWrite が in[] のアドレスを書いている。それが 0x0010e3fc だ。次に、0x20 に out[] のアドレスの 0x0010e424 を書いている。最後のWrite はスタートで、0x00 に 1 を書いている。

次にAXI4 Master を見てみよう。
最初のRead とWrite を拡大した。最初にRead から。
FPGA-SoC-Linux4ZYBO_Z7_34_171206.png

これは、最初の二乗の 0 の二乗をやっているところだ。RVALID が 2 回 1 になっているのが分かる。これは、Vivado HLS でのC/RTL コシミュレーションと同様だ。RDATA の値は 0 になっているのが分かる。

次に、同じ時間のWrite を示す。
FPGA-SoC-Linux4ZYBO_Z7_35_171206.png

WVALID が 1 になっているところが 1 個のデータ(WDATAが 0 )をWrite したところだ。なお、Read のバースト長は 1 だが、Write のバースト長は 10 で、すべてのデータをバーストで書く。しかし、データが用意できないので、Write もまばらなトランザクションになってしまう。

データが 0 では寂しいので、最後の二乗を示す。 9 X 9 = 81 の演算だ。まずはRead を示す。
FPGA-SoC-Linux4ZYBO_Z7_36_171206.png

次にWrite を示す。
FPGA-SoC-Linux4ZYBO_Z7_37_171206.png

ここでは、バーストの最後なので、RVALID と一緒にRLAST が 1 にアサートされているのが分かると思う。そして、BVALID がアサートされているのも分かる。
  1. 2017年12月06日 05:22 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0
»