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

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

FPGAの部屋

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

ZYBO 上のOpenCV で白線検出3(Canny フィルタのみの場合)

ZYBO 上のOpenCV で白線検出2(equalizeHist() を使用した場合2)”の続き。

今回は前回のコードはそのままに、10行目の”#define HIST”をコメントアウトして、equalizeHist() を使用しないで、Canny フィルタのみで白線検出を行うことにする。なお、Canny フィルタのスレッショルドは、試行錯誤して、最適化したつもりだ。

最初に、test_1080p.bmp からやってみた。
Lane-Detecting_75_160529.png

白線検出の経過時間は 0.221 sec 程度だった。前回よりも 0.057 sec 速かった。
白線検出結果を示す。
Lane-Detecting_76_160529.jpg

白線検出ができてる。なお、source ウインドウは今回はカラーで取り込んでいる。

次に road_1.jpg の結果を示す。
Lane-Detecting_77_160529.png

白線検出の経過時間は 0.416 sec 程度だった。前回は、source ウインドウは白黒だが、0.638 sec 程度だった。
白線検出結果を示す。
Lane-Detecting_78_160529.jpg

次に road_2.jpg の結果を示す。
Lane-Detecting_79_160529.png

白線検出の経過時間は 0.414 sec 程度だった。前回は、source ウインドウは白黒だが、1.290 sec 程度だった。大幅に速くなっている。これだったら使えそうだ。1秒回に 2 回は判定できる。
白線検出結果を示す。
Lane-Detecting_80_160529.jpg

次に road_3.jpg の結果を示す。
Lane-Detecting_81_160529.png

白線検出の経過時間は 0.394 sec 程度だった。前回は、source ウインドウは白黒だが、1.300 sec 程度だった。こちらも大幅に速くなっている。
白線検出結果を示す。
Lane-Detecting_82_160529.jpg

最後に、road_4.jpg の結果を示す。
Lane-Detecting_83_160529.png

白線検出の経過時間は 0.320 sec 程度だった。前回は、source ウインドウは白黒だが、0.604 sec 程度だった。
白線検出結果を示す。
Lane-Detecting_84_160529.jpg

全体に白線検出の速度は上がっている。equalizeHist() を外したおかげもあるが、HoughLines() で検出する直線の数が経過時間に影響するようだ。
  1. 2016年05月29日 05:31 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

パソコンをWindows 10 にしました

2016年5月27日(金)にパソコンをWindows 7 からWindows10にアップグレードしました。
ほかのパソコンをWindows10にアップグレードして、FPGAの環境に影響しないことを確認したので、無料アップグレード期間が終了する前にアップグレードしました。

最新のVivado 2016.1はWindows 10 対応で問題ないです。ISE は”Windows8以降のOSでISE WebPACKを動かす”を参考にさせていただいて、DLLを取り換えると動作に問題ないようです。

Xming なども問題なく動作して、今のところ、不具合はないですね。
  1. 2016年05月29日 04:49 |
  2. パソコン関連
  3. | トラックバック:0
  4. | コメント:0

Z-turn Board が届きました

Z-turn Board が昨日届きました。注文してから足掛け3日で届きました。

箱の中には、Z-turn BoardZ-turn IO Cape とデータが入ったDVDが入っていました。
Z_turn_Board_1_160528.jpg

袋を開けるとZ-turn Board には、Micro SDカードが入っていました。
Z_turn_Board_2_160528.jpg

Z-turn IO Cape のコネクタにZ-turn Board を挿入しました。
Z_turn_Board_3_160528.jpg

これでPmod やIOピンが使いやすくなりました。上の写真ではZYNQ の型番も見えます。 XC7Z020CLG400-1C です。

DVD の中身です。マニュアルやツール、ソースなどが入っています。
Z_turn_Board_4_160528.png
  1. 2016年05月28日 07:22 |
  2. Z-turn Board
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出2(equalizeHist() を使用した場合2)

”ZYBO 上のOpenCV で白線検出1(equalizeHist() を使用した場合)”の続き。

前回は、equalizeHist() を使用し、Canny フィルタを掛けて、HoughLine 変換で道路の白線検出を行った。しかし、画像を読み込む時点で白黒画像に変換していた。ハードウェアでは、カメラで撮影した画像を白黒変換して、Canny フィルタを掛ける予定なので、白黒画像変換の部分の経過時間も測る必要がある。それでC++ ソースコードを修正した。更に、白黒画像変換+Canny フィルタの経過時間を測定した。

Hough_example.cpp を下に示す。

// Line Detection by Hough Line Transform
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <sys/time.h>

#define HIST

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat src;
    
    if (argc >= 1){
        src = imread(argv[1]);
    } else {
        printf("Usage : HoughLine_example <read_file_name>\n");
        exit(1);
    }

    Mat dst, cdst;
    Mat src_g;
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

    cvtColor(src, src_g, CV_BGR2GRAY);
#ifdef HIST
    Mat eqst;
    equalizeHist(src_g, eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    //Canny(src_g, dst, 50, 200, 3); // Normal
    Canny(src_g, dst, 2003003); // Normal2
#endif

    //gettimeofday(&end_time, NULL);
    
    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    gettimeofday(&end_time, NULL);
    
    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    
    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }

#ifdef HIST
    imshow("equalizeHist", eqst);
#endif
    imshow("Canny", dst);
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    waitKey();
    waitKey();
    waitKey();
    
    return 0;
}


./Hough_example test_1080p.bmp コマンドを実行した。
Lane-Detecting_72_160527.png

白線検出の経過時間は 0.278 sec 程度だった。前回は 0.273 sec だったので、約 5 ms 程度、白黒変換にかかることが分かった。

白線検出結果を示す。結果は前回と同じだが、source ウインドウがカラーなのが分かる。
Lane-Detecting_73_160527.jpg

次に、白黒画像変換+Canny フィルタの経過時間を測定する。
現在の”gettimeofday(&end_time, NULL);”の行をコメントアウトして、現在コメントになっている同様の行のコメントを外した。もう一度コンパイルして、やってみた。

すると、白黒画像変換+Canny フィルタの経過時間は、57 ms くらいのようだ。
Lane-Detecting_74_160527.png
  1. 2016年05月27日 04:07 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出1(equalizeHist() を使用した場合)

Vivado HLS を使用した車の白線検出9(Canny フィルタ3)”で、大体Vivado HLS による C シミュレーションでは白線検出が出来てきたと思うので、本命のZYBO のOpenCV 環境でまずはソフトウェアで、どのくらいの速度で白線検出をできるかどうかをテストしてみた。

ZYBO のUbuntu 14.04 LTS 上のOpenCV 2.4.10 で白線検出のテストを行った。
白線検出用のアプリケーションの HoughLine_example.cpp を示す。最初は、equalizeHist() を行う設定でやってみた。
Lane-Detecting_71_160526.png

// Line Detection by Hough Line Transform
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <sys/time.h>

#define HIST

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat src;
    
    if (argc >= 1){
        src = imread(argv[1], 0);
    } else {
        printf("Usage : HoughLine_example <read_file_name>\n");
        exit(1);
    }

    Mat dst, cdst;
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

#ifdef HIST
    Mat eqst;
    equalizeHist(src, eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    Canny(src, dst, 502003); // Normal
    //Canny(src, dst, 200, 300, 3); // Normal2
#endif

    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    gettimeofday(&end_time, NULL);
    
    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    
    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }

#ifdef HIST
    imshow("equalizeHist", eqst);
#endif
    imshow("Canny", dst);
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    waitKey();
    waitKey();
    waitKey();
    waitKey();
    
    return 0;
}


このアプリケーションを使用して、最初に test_1080p.bmp の白線検出をやってみた。
Lane-Detecting_61_160526.png

白線検出の経過時間は0.273 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_62_160526.jpg

良さそうだ。

次に、自分で撮影した4つの写真の白線検出結果を見た。

まずは、 road_1.jpg の白線検出を行った。
Lane-Detecting_63_160526.png

白線検出の経過時間は0.638 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_64_160526.jpg

良さそうではあるが、電線の影を検出している。

次に、road_2.jpg の白線検出を行った。
Lane-Detecting_65_160526.png

白線検出の経過時間は1.290 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_66_160526.jpg

road_1.jpg の方が逆光で、road_2.jpg の方が順光だからか?道路のちょっとした凸凹までエッジとして検出されているので、Hough変換で相当な量の直線を検出したようだ。

road_3.jpg の白線検出を行った。road_3.jpg は road_2.jpg の反対のレーンから撮影した写真なので、road_2.jpg の結果と同じような傾向になるはずだ。
Lane-Detecting_67_160526.png 

白線検出の経過時間は 1.300 sec 程度だった。下に白線検出結果を示す。
Lane-Detecting_68_160526.jpg

やはり、 road_2.jpg と同様の結果になった。

最後に、road_4.jpg の白線検出を行った。同様に、road_4.jpg は road_1.jpg と同様の写真である。
Lane-Detecting_69_160526.png

白線検出の経過時間は、0.604 程度だった。下に白線検出結果を示す。
Lane-Detecting_70_160526.jpg

road_2.jpg と road_3.jpg の白線検出が酷い気がする。equalizeHist() を使用すると、現在のパラメータでは、このカメラの順光時のアスファルト舗装の細かい凸凹がよく見えるようになってしまう。

どうやら、Hough 変換の実行時間は検出した本数が多いほど、遅くなっているのでは?と思う。
  1. 2016年05月26日 04:49 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Z-turn Boardを購入しました

Z-turn Boardを購入しました。
MYS-7Z020-C-S のZynq 7020 が搭載されたZynq ボードです。DDR3 SDRAM は1 GB 搭載されています。価格は $ 119 です。

Z-turn IO Cape も同時に購入しました。3 x Pmod interfacesが付いているのが魅力的です。CMOSカメラを接続したいです。$ 35 です。

Shipping Price は Asia (exclude Mid-East Asia and South Asia) が $25 + USD6 for each extra 0.5kg で 合計 $ 31 でした。

合計 $ 185 でした。PayPal 支払いで 21,106 円でした。

怖いのは Shopping Cart の Buy Now ボタンをクリックすると、ダイレクトにPayPal につながっちゃいます。住所や名前は入れる隙がありません。

PayPal の住所、氏名で良いのか?と思ったんですが、今見たら Shopping Cart にこう書いてありました。

Please contact MYIR after you placed the order and kindly provide us your detailed shipping address and contact phone number for shipment. Thank you!


どうやって、連絡するのでしょうか?メールかな?メール来るかもしれないので、少し待っていようと思います。

どうして、Z-turn Board を欲しかったかというと、Zynq-7010 の ZYBO では、リソースが足りなそうと思ったからです。 Z-turn Board はHDMI 入力がないので、Z-turn Board HDMI 出力 -> ZYBO HDMI 入力で使いたいと思っています。

(追記)
MYIR Tech Limited の Sales Manager から午前8時40分ころメールが来て、住所と名前のコンファームと電話番号教えてくれという内容でした。住所と名前はOKなので、電話番号をお知らせしました。

(2016/06/07:追記)
今日、Z-turn Board の消費税が1,500円+特別取扱手数料(Fedexの?)が500円の合計2,000円追加で、請求書が来ました。
合計金額は 23,106 円になりました。
  1. 2016年05月25日 07:26 |
  2. Z-turn Board
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出9(Canny フィルタ3)

Vivado HLS を使用した車の白線検出8(Canny フィルタ2)”の続き。

前回、ガウシアンフィルタの 5x5 では、DSP リソース使用量が ZYBO で使用できる DSP 数をオーバーしてしまうため、3x3 に変更した。しかし、よくよく考えてみると、ガウシアンフィルタや Sobel フィルタなどは、現在はカラーでファイルを掛けているが、グレー変換して1色でやっても同じことだと気がついたので、それでやってみたら、案の定、5x5 のガウシアンフィルタでもリソース使用量が減って、ZYBO に入るようになった。

canny_filter() 関数の変数宣言部を下に示す。

RGB_IMAGE src(rows, cols);
RGBSINGLE_IMAGE src_bw(rows, cols);
RGBSINGLE_IMAGE src_blur(rows, cols);
RGBSINGLE_IMAGE src1(rows, cols);
RGBSINGLE_IMAGE src2(rows, cols);
RGBSINGLE_IMAGE sobel_gx_g(rows, cols);
RGBSINGLE_IMAGE sobel_gy_g(rows, cols);
RGB_IMAGE sobel_gx(rows, cols);
RGB_IMAGE sobel_gy(rows, cols);
RGB_IMAGE_16 grad_gd(rows, cols);
RGB_IMAGE suppressed(rows, cols);
RGB_IMAGE canny_edges(rows, cols);


hls::AXIvideo2Mat() した後で、

hls::CvtColor<HLS_RGB2GRAY>( src, src_bw );

を行って、”HLS_8UC1”に変換し、5x5 のガウシアンフィルタを行い、Sobel フィルタ処理が終了した後で、

hls::CvtColor( sobel_gx_g, sobel_gx );
hls::CvtColor( sobel_gy_g, sobel_gy );

を行い、”HLS_8UC3”に戻している。

この修正を加えて、

hls::GaussianBlur<5,5>( src_bw, src_blur );

を使用して C コードの合成を行った。結果を示す。
Lane-Detecting_53_160524.png

Lane-Detecting_54_160524.png

DSP48E の使用数が 38 個になって、ZYBO のリソースで収まるようになった。

更に自分で撮影した写真で白線検出をやってみた。C シミュレーションの結果を示す。
まずは元の写真を示す。
Lane-Detecting_55_160524.jpg

HLS ビデオライブラリを使用した Canny フィルタを使用して、OpenCV でHough 変換を実行した結果を示す。白線検出はできているようだ。
Lane-Detecting_56_160524.jpg

OpenCV を使って、白線検出した結果を示す。こちらも白線検出できているようだ。
Lane-Detecting_57_160524.jpg

次に C/RTL コシミュレーションを行った。
Lane-Detecting_58_160525.png

640 x 480 ピクセルの画像を Canny フィルタ処理するのに 318060 クロックかかている。318060 / (640x480) ≒ 1.035 となり、1 倍近いので、1 クロックで 1 ピクセルを Canny フィルタ処理できていることになる。

Vivado で C/RTL コシミュレーションの波形を表示した。
Lane-Detecting_60_160525.png

波形を拡大してみると、、input_r_TVALID, input_r_TREADY, output_r_TVALID, output_r_TREADY がほとんど 1 になっているのが分かる。
Lane-Detecting_59_160525.png
  1. 2016年05月24日 04:49 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出8(Canny フィルタ2)

Vivado HLS を使用した車の白線検出7(Canny フィルタ1)”の続き。

前回は、ZYBOのリソース使用量をオーバーしてしまった。今回は、その一番大きな原因であるガウシアンフィルタを 5x5 から 3x3 にしてみよう。

まずは、5x5 のガウシアンフィルタを 3x3 に変更した。
Lane-Detecting_43_160521.png

C シミュレーションを行った。 5x5 のガウシアンフィルタよりも 3x3 の方がノイズが増えてしまった。左に 3x3 のガウシアンフィルタ結果、右に 5x5 のガウシアンフィルタ結果を示す。
Lane-Detecting_44_160522.jpgLane-Detecting_38_160522.jpg

これでも大丈夫かもしれないということで、 3x3 のガウシアンフィルタで行ってみることにした。

次にC コードの合成を行った。
Lane-Detecting_45_160521.png
Lane-Detecting_46_160521.png
これでやっとZYBO のリソースで足りるようになった。

次に性能を向上させたいのだが、あまりリソースが増えるとまた入らなくなってしまう。とりあえず、DATAFLOW ディレクティブを入れてみた。
Lane-Detecting_47_160521.png

C コードを合成した結果を示す。
Lane-Detecting_48_160521.png
Lane-Detecting_49_160521.png

DSPが 3 個ほど増えたが許容範囲内だ。Latency の max が 4353075 から 487634 に約 1/9 になった。

C/RTL コシミュレーションを行った。ちなみにテストベンチを書き換えて、エラーは出ないようにしないとシミュレーションがエラーになってしまった。
Lane-Detecting_50_160522.png

Latency は 315960 クロックだった。これで、640 ピクセル x 480 ラインの画像を処理しているので、315960 / (640 x 480) ≒ 1.03
よって、1ピクセルを大体 1 クロックで処理できている。

シミュレーション波形を示す。
Lane-Detecting_51_160522.png

拡大して見ると、input_r_TVALID, input_r_TREADY, output_r_TVALID, output_r_TREADY がほとんど 1 になっているのが分かる。
Lane-Detecting_52_160522.png
  1. 2016年05月22日 04:49 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出7(Canny フィルタ1)

Vivado HLS を使用した車の白線検出6(hls::HoughLine2() その2)”の続き。

前回、白線検出ハードウェアはとてもZYBO には入らないということがよく分かった。それでも Canny フィルタだけはハードウェアにしたいということでやってみた。

白線検出はグレー変換して、Canny フィルタを掛けているので、Hough 変換とその後の赤いラインを書く部分を削除する。
テストベンチはOpenCV 2.x 形式で書き換えた。

テストベンチの Canny_filter_tb.cpp を示す。

// Canny_fiter_tb.cpp
// 2016/05/20 by marsee
// OpenCV 2 の Mat を使用したバージョン
// 

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

using namespace cv;

void canny_filter(AXI_STREAM& input, AXI_STREAM& output, int rows, int cols, int threshold_low, int threshold_high);
void opencv_canny_filter(Mat& src, Mat& dst, int threshold_low, int threshold_high, int sobel_size);

int main (int argc, char** argv) {
    //const int threshold_low = 50;
    //const int threshold_high = 200;
    const int threshold_low = 20;
    const int threshold_high = 30;
    const int sobel_size = 3;

    // OpenCV で 画像を読み込む
    Mat src = imread(INPUT_IMAGE);
    AXI_STREAM src_axi, dst_axi;

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

    // image_filter() 関数をコール
    canny_filter(src_axi, dst_axi, src.rows, src.cols, threshold_low, threshold_high);

    // AXI4 Stream から Mat フォーマットへ変換
    // dst は宣言時にサイズとカラー・フォーマットを定義する必要がある
    Mat dst(src.rows, src.cols, CV_8UC3);
    AXIvideo2cvMat(dst_axi, dst);

    // Mat フォーマットからファイルに書き込み
    imwrite(OUTPUT_IMAGE, dst);

    // opencv_image_filter() をコール
    Mat dst_cv(src.rows, src.cols, CV_8UC3);
    opencv_canny_filter(src, dst_cv, 50200, sobel_size);
    imwrite(OUTPUT_IMAGE_GOLDEN, dst_cv);

    // dst と dst_cv が同じ画像かどうか?比較する
    for (int y=0; y<src.rows; y++){
        Vec3b* dst_ptr = dst.ptr<Vec3b>(y);
        Vec3b* dst_cv_ptr = dst_cv.ptr<Vec3b>(y);
        for (int x=0; x<src.cols; x++){
            Vec3b dst_bgr = dst_ptr[x];
            Vec3b dst_cv_bgr = dst_cv_ptr[x];

            // bgr のどれかが間違っていたらエラー
            if (dst_bgr[0] != dst_cv_bgr[0] || dst_bgr[1] != dst_cv_bgr[1] || dst_bgr[2] != dst_cv_bgr[2]){
                printf("x = %d, y = %d,  Error dst=%d,%d,%d dst_cv=%d,%d,%d\n", x, y,
                        dst_bgr[0], dst_bgr[1], dst_bgr[0], dst_cv_bgr[0], dst_cv_bgr[1], dst_cv_bgr[2]);
                //return 1;
            }
        }
    }
    printf("Test with 0 errors.\n");

    return 0;
}

void opencv_canny_filter(Mat& src, Mat& dst, int threshold_low, int threshold_high, int sobel_size){
    Canny(src, dst, (double)threshold_low, (double)threshold_high, sobel_size);
}



Canny_fiter プロジェクトを作製した。
Lane-Detecting_36_160521.png

C シミュレーションを行った。パラメータも違うし、値を比較するのが無理のようだ。
Lane-Detecting_37_160521.png

Vivado HLS のHLS ビデオライブラリを使用したCanny フィルタの結果を示す。
Lane-Detecting_38_160522.jpg

OpenCV の Canny フィルタの結果を示す。流石に綺麗だ。
Lane-Detecting_39_160522.jpg

C コードの合成結果を示す。
Lane-Detecting_40_160521.png
Lane-Detecting_41_160521.png

DSP48E のリソース使用量がZYBO のリソース限界を超えている。。。orz

Analysis 表示を示す。
Lane-Detecting_42_160521.png

最初の Filter2D のDSP 使用量が多い。これは、

hls::GaussianBlur<5,5>( src_bw, src_blur, 1.4, 1.4 );

だ。
5x5のガウシアンフィルタなので、大きい様だ。3x3 のガウシアンフィルタにしてみよう。
  1. 2016年05月21日 06:51 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出6(hls::HoughLine2() その2)

Vivado HLS を使用した車の白線検出5(hls::HoughLine2())”の続き。

前回は、HLS ビデオライブラリを使用した Hough 変換による白線検出が上手く行ったが、合成したらZYBO のリソース使用量が 2200 % 程度になってしまった。今回はリソース使用量を削減してみた。

リソース使用量を削減するのに、PIPELINE ディレクティブを外してみよう。
top_2.cpp のすべてのPIPELINE ディレクティブを外した。
Lane-Detecting_33_160519.png

これで C コードの合成を行うと、リソース使用量が 736 %になった。まだ 700 %台だけどだいぶましになった。最初に今回のPIPELINE ディレクティブをすべて外した場合のC コードの合成結果、次に前回の合成結果を示す。
Lane-Detecting_34_160519.pngLane-Detecting_29_160518.png

リソース使用量が減った代わりに、Latency の最大が 12505280 から 24123409002 に増えてしまった。これは、100 MHz で動作させたとしたら、125 ms と 241 sec に相当する。これではハードウェア化する意味が無い。

Analysis 表示を確認した。
Lane-Detecting_35_160519.png

Hough_plotting() の FF 使用量が前回の 203094 から 5519 に、LUT 使用量が 276508 から 7871 に劇的に減っている。
劇的に減ってはいるが、HoughLines2() さえDSP を 386 個使用するので、Z-7010 はもとより Z-7020 にさえ入らないという結果だった。がっくり。。。

仕方がないので、Canny フィルタのハードウェア実装をやってみようと思う。
  1. 2016年05月19日 04:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出5(hls::HoughLine2())

Vivado HLS を使用した車の白線検出4(ヒストグラム均一化)”の続き。

前回はヒストグラムの均一化を行ってから、グレー変換、Canny フィルタ、Hough 変換を行うと白線検出をすることができた。今回は、”Vivado HLS を使用した車の白線検出1(初めに)”で使用した”ka367/Lane-Detecting-Using-Hough-Transform”が動作して、C シミュレーションとC コードの合成をすることができた。

どうやって、C シミュレーションとC コードの合成をすることができたか?なのだが、ひたすら他力本願当事になってしまった。
まずは、”Vivado HLS を使用した車の白線検出1(初めに)”に、Xilinx の Community Forums の”Vivado HLS Video Libraries - HoughLines2 - Unable to synthesize”の”Hough_Top.zip ‏9 KB”をダウンロードして、top.cpp と top.h を入れ替えた。そのファイル名を top_2.cpp と top_2.h に変更した。 top_2.cpp と top_2.h の画像サイズが 320 x 240 ピクセルだったので、640 x 480 ピクセルに変更した。top_2.cpp のコード内にも 240 ラインを直接書いてある部分があったので、それを 480 ラインに変更した。
top_2.cpp の 464 行目を

hls::Polar_< ap_fixed<16,3>, ap_fixed<12,12> >lines[50];

にした。つまり line[500] から line[50] に変更した。この値は、合成時に効いてくるようだ。リソース使用量が増えてしまうし、合成時のメモリ使用量が極端に増えてしまう。
それに伴って、468行目の Hough_plotting<500> も Hough_plotting<50>に変更した。
Lane-Detecting_26_160518.png

これで、C シミュレーションを行った。HLS ビデオライブラリを使用した結果と OpenCV の結果の比較結果はエラーだったが、result_1080p.bmp と result_1080p_golden.bmp が生成された。
result_1080p.bmp と result_1080p_golden.bmp を示す。左が result_1080p.bmp で、右が result_1080p_golden.bmp だ。
Lane-Detecting_27_160518.jpgLane-Detecting_28_160518.jpg

全く違うが、result_1080p.bmp が HLS ビデオライブラリを使用した結果で、 result_1080p_golden.bmp はOpenCV で白線検出を行った結果だ。OpenCV の方はCanny フィルタの出力に白線検出の結果を表示している(白線検出はされていない)。 HLS ビデオライブラリの方は、原画像に白線検出した結果の赤い線を載せている。白線検出ができているようだ。

次にC コードの合成を行った。結果を示す。
Lane-Detecting_29_160518.png

動作周波数が満足していないし、ZYBO のZynq 7010 のリソースではまったくもって足りない。LUT は 2262 % 必要だった。つまり、今のZynq の 22 倍以上大きな FPGA が必要ということだ。
ちなみに、C:\Users\Masaaki\Documents\Vivado_HLS\ZYBO\test\Lane-Detecting\Lane-Detecting_HLS_16_1\solution1\syn\verilog フォルダを示す。ファイル数は 126 ファイルあった。
Lane-Detecting_30_160518.png

なんとか Canny フィルタだけでもZYBO のFPGA 部分に乗らないだろうか?Hough 変換は諦めて ARM プロセッサで動作させることも考えたい。
この HLS ビデオライブラリを使用した top_2.cpp は、Canny フィルタがHLS ビデオライブラリに無いので、Canny フィルタを作っているようだ。

hls::GaussianBlur<5,5>()
hls::Sobel<1,0,3>()
hls::Sobel<0,1,3>()
gradient_decomposition( sobel_gx, sobel_gy, grad_gd ),
nonmax_suppression()
hysteresis()


Canny フィルタの概要は”Canny Edge Detection -アルゴリズム-”を参照のこと。

Analysis 表示を示す。
Lane-Detecting_31_160518.png

Recource Profile を見ると、各モジュールのリソース使用量が見える。
Hough_plotting_50が圧倒的にリソース使用量が多い。その他もかなりDSP を消費している。

”Zynq-7000 All Programmable SoC 概要 DS190 (v1.9) 2016 年 1 月 20 日”から表1を引用する。
Lane-Detecting_32_160518.png

このままでは、一番大きい XC7Z100 にも入らないのか。。。絶望的だが、Hough_plotting() のPIPELINE をやめれば、700% 程度にまでLUT のリソース使用量が落ちたので、結構入るZynq も増えるだろう。
この辺りは、ハードウェアにするにしてもリソース使用量が極端に増えてしまうので、注意が必要だし、CPUでやった方が良いのかもしれない?う~ん。残念。。。

Hough_plotting() は画像に検出した線を示すために必要なので、実際の白線検出は検出した線を書かなくて良いので、HoughLine2() まで実装できれば良い。しかし、ZYBO にはそれもDSP が足りなくて無理そうではある。せめてCanny フィルタだけでも実装できれば。。。
もっと大きなZynq が切実に欲しい。。。Zynq-7020 のZYBO が出ないものか。。。
  1. 2016年05月18日 04:56 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出4(ヒストグラム均一化)

Vivado HLS を使用した車の白線検出3(暗い画像での白線検出)”の続き。

前回は、cannyフィルタでエッジ検出した後でHough 変換を行って、直線検出したが、最後の暗い画像では、道路の白線を検出することはできなかった。今回は、canny フィルタの前に equalizeHist() を行うことで、ヒストグラムの均一化を図ってみよう。

Line Detection by Hough Line Transform”のC ソースコードを多少修正した。貼っておく。

// Line Detection by Hough Line TransformのC++コードを使用させて頂いて、変更を加えています
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

#define HIST

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("test_1080p_rb3.bmp"0);

    Mat dst, cdst;
#ifdef HIST
    Mat eqst;
    equalizeHist(src, eqst); // ヒストグラム平均化
    imshow("equalizeHist", eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    Canny(src, dst, 502003); // Normal
#endif
    imshow("Canny", dst);

    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }

    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    return 0;
}


equalizeHist() を行うとエッジが鮮明になるので、canny フィルタのパラメータを多少修正した。

最初に”test_1080p.bmp”の結果を示す。
Lane-Detecting_22_160516.jpg

次に、GIMP で明るさを -74 に設定した”test_1080p_rb1.bmp” の結果を示す。
Lane-Detecting_23_160516.jpg

GIMP で明るさを -127 に設定した”test_1080p_rb2.bmp” の結果を示す。
Lane-Detecting_24_160516.jpg

GIMP で明るさを -127に設定した画像を更に -100 に設定した”test_1080p_rb3 .bmp” の結果を示す。
Lane-Detecting_25_160516.jpg

すべての画像で白線検出ができているようだ。
  1. 2016年05月16日 04:37 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出3(暗い画像での白線検出)

Vivado HLS を使用した車の白線検出2(HoughLinesで直線検出)”の続き。

前回は、”Line Detection by Hough Line Transform”のOpenCVを使用した直線検出のアプリケーションを使用して、”ka367/Lane-Detecting-Using-Hough-Transform”の”test_1080p.bmp”の道路の白線を検出することができた。
今回は、暗い時の白線を検出できるかどうかを調べてみようと思う。

最初に”test_1080p.bmp” をGIMP で明るさを変えてみた。(なお、画像の”test_1080p.bmp”は、”ka367/Lane-Detecting-Using-Hough-Transform”から使用させて頂いています)
最初に元の”test_1080p.bmp” を示す。
Lane-Detecting_9_160515.jpg

次に、GIMP で明るさを -74 に設定した”test_1080p_rb1.bmp” を示す。
Lane-Detecting_10_160515.jpg

GIMP で明るさを -127 に設定した”test_1080p_rb2.bmp” を示す。
Lane-Detecting_11_160515.jpg

GIMP で明るさを -127に設定した画像を更に -100 に設定した”test_1080p_rb3 .bmp” を示す。
Lane-Detecting_12_160515.jpg

明るさを暗くした画像を白線検出を試みた。なお、今回は Canny フィルタの出力画像も追加した。
最初に、”test_1080p_rb1.bmp”の白線検出結果を示す。
Lane-Detecting_13_160515.jpgLane-Detecting_14_160515.jpgLane-Detecting_15_160515.jpg
sourceウインドウが白黒画像で、CannyウインドウがCannyフィルタを掛けた後の画像、detect linesウインドウが直線検出した線を赤い線で表した画像を示す。
白線検出は問題ない。

”test_1080p_rb2.bmp”の白線検出結果を示す。
Lane-Detecting_16_160515.jpgLane-Detecting_17_160515.jpgLane-Detecting_18_160515.jpg
こっちらも白線検出は問題ない。

”test_1080p_rb3.bmp”の白線検出結果を示す。
Lane-Detecting_19_160515.jpgLane-Detecting_20_160515.jpgLane-Detecting_21_160515.jpg
白線検出はできていない。やはり暗すぎるようだ。

  1. 2016年05月15日 05:35 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出2(HoughLinesで直線検出)

”Vivado HLS を使用した車の白線検出1(初めに)”の続き。

前回、”ka367/Lane-Detecting-Using-Hough-Transform”のコードを試してみたが、C シミュレーションは上手く行かずに、C コードの合成はZYBO に入らなかった。そこで、地道にOpenCVのHough 変換をやってみることにした。

まずは、”Line Detection by Hough Line Transform”のコードを頂いて、”ka367/Lane-Detecting-Using-Hough-Transform”の”test_1080p.bmp”で白線を検出できるかどうか?やってみた。

下にプロジェクトを示す。なお画像は、”ka367/Lane-Detecting-Using-Hough-Transform”の”test_1080p.bmp”を使用させて頂いている。
Lane-Detecting_5_160514.png

これで C シミュレーションを行った。
Lane-Detecting_8_160514.png

”source”と”detected lines”が表示された。なお画像は、先程も書いたが”ka367/Lane-Detecting-Using-Hough-Transform”の”test_1080p.bmp”を使用させて頂いている。
Lane-Detecting_6_160514.pngLane-Detecting_7_160514.png

”detected lines”ウインドウを見ると、道路のレーンの直線が検出できている。水平線と車の車内も直線検出されている。車内の線は位置で除けるし、水平線は傾きで除けると思う。但し、センターラインが出ていないが、これも検出できるようにしたい。

まだ、OpenCVをソフトウェアで動作させただけで、ハードウェアにした訳では無いが、もう少しやってみよう。
  1. 2016年05月14日 11:35 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS を使用した車の白線検出1(初めに)

車の白線検出をハードウェア化してみたいということで、OpenCVを使用して車の白線検出を行い、それをVivado HLS でハードウェア化してみることにした。

初めに見たのが、”Vivado での OpenCV および高位合成の使用 (日本語吹替)”のビデオだった。これによると、白線検出のハードウェア処理の手順は、下のように示されていた。

1.RGBからグレーへの変換
2.画像ヒストグラムのイコライゼーション
3.エッジ検出
4.ハフ変換


それを検索すると、GitHub にそのままのコードがあるようだった。”ka367/Lane-Detecting-Using-Hough-Transform”だ。
これをZIPでダウンロードして、my_hls_video_hough.h をこのように変更して、C シミュレーションを行った。(2016/05/13 変更: プロジェクトのフォルダを変更した。 C:\Users\Masaaki\Documents\Vivado_HLS\ZYBO\test\Lane-Detecting-Using-Hough-Transform-master\Lane-Detecting_HLS_16_1)
Lane-Detecting_1_160512.png

C シミュレーションはエラーで失敗した。”@E Simulation failed: SIGSEGV.”(Vivado HLS 2016.1 使用)
Lane-Detecting_2_160512.png

次に C コードの合成を行った。これは成功した。結果を示す。
Lane-Detecting_3_160512.png

Lane-Detecting_4_160512.png

リソース使用量が多すぎて、ZYBOのZynq-7010 には入らない。。。
このままではダメなようである。
Vivado での OpenCV および高位合成の使用 (日本語吹替)”のビデオで示された白線検出のハードウェア処理を検討してみようと思う。
  1. 2016年05月12日 05:00 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS勉強会資料(AXI4 Lite Slave)を更新しました

Vivado HLS勉強会資料(AXI4 Lite Slave)を更新しました。

ZYBO_zynq_def.xml を使用してZYBO のPS部分を設定していましたが、Digilent社のWebサイトにZYBO_zynq_def.xml が無くなってしまったので、ボード・ファイルを使う方法に変更しました。
細かいタイポを修正しました。
  1. 2016年05月12日 04:19 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:2

KiCad-4.0.2 と FreeRouter インストール覚書

KiCad-4.0.2 と FreeRouter をインストールした時の覚書です。

KiCadのホームページ
ダウンロード
ドキュメント、綺麗な日本語のドキュメントがあります。読みやすいです。翻訳して頂いた方に感謝します。

私はWindows版の最新安定版 KiCad 4.0.2 をインストールしました。

FreeRouter は付いていなかったので、freerouting/freerouting から「Download ZIP」ボタンをクリックして、”freerouting-master.zip”をダウンロードします。

freerouting-master.zip の中の freerouting-master フォルダを適当なフォルダに解凍します。

freerouting-master\binaries フォルダの下の”FreeRouting.exe”を起動するとFreeRouter が起動します。(スタートメニューに入れてあります)
KiCad402_1_160510.png

KiCadとの連帯です。

KiCad の「ツール」メニューの「FreeRouter」 を選択すると「Freerouter のエクスポートとインポート」ダイアログが出ます。

FreeRouter にパッド、配線データを渡すには、「現在のボードを”Specctra DSN“ファイルへエクスポート」ボタンをクリックして、”.dsn”ファイルにセーブします。
KiCad402_2_160510.png

FreeRouter で「Open Your Own Design」ボタンをクリックして、先ほどセーブした”.dsn”ファイルを指定してロードします。

FreeRouter にパッド、配線データがロードされました。
KiCad402_3_160510.png

FreeRouter で Autorouter ボタンをクリックするとオートルートが始まり、しばらくすると終了します。
KiCad402_4_160510.png

FreeRouter で 「File」メニューから、「Export Specctra Session File」を選んで、”.ses”ファイルをエクスポートします。

KiCad の「Freerouter のエクスポートとインポート」ダイアログから、「スペクトラ セッション ファイル(*.ses)のパックインポート」ボタンをクリックして、”.ses”ファイルを KiCad にインポートします。

すると、Freerouter で配線した配線データが読み込まれます。
KiCad402_5_160510.png

なお、基板の図はKiCad のサンプルの test_xil_95108 を使用させて頂いています。
  1. 2016年05月10日 14:42 |
  2. CADツール
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力9(プロジェクト休止)

AXI VDMAのMM2Sを使用してビデオ出力8(シミュレーション4)”の続き。

前回、シミュレーションで、AXI GPIO をVTC の aresetn に追加して、1 フレーム目にAXI VMDA のMM2S が出力された。
今回は実機でVivado Analyzer を使って実際にどうなっているかを確かめてみた。

ZYBO ででVivado Analyzer を使って波形を見てみたが、MM2S は当然ながら、プロジェクトの元にしたS2MM も全く動いていなかった。VTC のビデオ信号も出ていない。VTC は v_axi4s_vid_out_0 の vtg_ce から VTC の gen_clken に行く線を削除して、VTC の gen_clken を 1 固定にするとVTC のビデオ信号は出力された。

やはり、どうにもAXI VDMA は相性が悪いみたいで、どうもうまく行かない。”AXI VDMA を使用したカメラ表示システムのフレームレートを 5 fps から 15 fps にする”で自作のビットマップ・ディスプレイ・コントローラを使って、15 fps にはできているので、これで良いことにする。但し、シングル・フレーム・バッファなので、どうしてもジャギーは出てしまうのだが。。。
これは、後で、トリプル・フレーム・バッファ・バージョンを作ることにする。 s2mm_frame_ptr_out(5:0) があるので、どのフレーム・バッファを使用してるか分かるようなので、それを使えば、自作ビットマップ・ディスプレイ・コントローラでもフレーム同期ができるだろう。”AXI Video Direct Memory Access v6.2 LogiCORE IP Product Guide Vivado Design Suite PG020 November 18, 2015 ”参照
AXI VDMA をもう一度やるときは、S2MM 専用AXI VDMA とMM2S 専用AXI VDMA を用意することにする。

次からは自動車の白線検出をOpenCV で実装してからVivado HLS でハードウェア化してみようと思う。
  1. 2016年05月10日 05:21 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

映画「64‐ロクヨン‐前編」を見てきました

今日は映画「64‐ロクヨン‐前編」(音注意)を見てきました。
佐藤浩市が迫真の演技をしていました。面白かったです。後編も絶対見ます。
小説は家に買ってあって、2回読みました。こちらも心理描写が凄くて、良かったです。
  1. 2016年05月08日 20:04 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力8(シミュレーション4)

AXI VDMAのMM2Sを使用してビデオ出力7(実機でテスト)”の続き。

前回はZYBOを使って実機でテストしてみたが、画像は出力されなかった。今回はシミュレーションをもう一度やってみた。

前回のシミュレーションでは、AXI VDMA の設定がVTC のfsync_out (これが、AXI VDMA の mm2s_fsync に接続されている)が出た後だったので、MM2S のスタートが 1 フレーム後になってしまった。今回は、VTC のリセットにAXI GPIO を接続して、AXI VDMA の設定が終了してからVTC のリセットを外すことにする。

video_module にAXI GPIO を追加して、出力をVTC の resetn に入力した。
全体のブロックデザインを示す。
AXI_VDMA_MM2S_42_160507.png

video_module を示す。なお、camera_module は変更がない。
AXI_VDMA_MM2S_43_160507.png

アドレスマップを示す。
AXI_VDMA_MM2S_44_160507.png

AXI GPIO は 0x40000000 番地からマップされている。

これでシミュレーションを行った。AXI GPIO の出力を 1 にするのは、AXI VDMA が設定終了後にしてある。

gpio_io_o が 1 になった時に、AXI VDMA の mm2s_fsync にパルスが入っているのが分かる。
AXI_VDMA_MM2S_39_160507.png

これで、1 フレーム目から MM2S もスタートした。S2MM もスタートしている。画像データ転送が両方向とも問題ない。
AXI_VDMA_MM2S_40_160507.png

でもVGA 出力は出ていない。
AXI_VDMA_MM2S_41_160507.png

AXI4-Stream to Video Out v4.0 LogiCORE IP Product Guide Vivado Design Suite PG044 November 18, 2015
の 32 ページによると locked は 4 フレームかかるらしいので、シミュレーションでは見えないかもしれない?

最後にレジスタの設定リスト vdma_reg_set.txt を示す。

44a00000
0000008B
44a0005c
00000000
44a00060
00000000
44a00064
00000000
44a00058
00000c80
44a00054
00000c80
44a00050
00000258
44a00030
00000003
44a000ac
00000000
44a000B0
00000000
44a000B4
00000000
44a000a8
00000c80
44a000a4
00000c80
44a000a0
00000258
44a20040
00000000
44a20044
80000000
44a20000
00000002
44a10040
00000000
44a10000
00000002
44a40000
00000000
44a40004
00000000
40000000
00000001
ffffffff

  1. 2016年05月07日 20:21 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力7(実機でテスト)

AXI VDMAのMM2Sを使用してビデオ出力6(インプリメントしたがエラー)”の続き。

前回はビットストリームの生成まで出来たので、今回は、アプリケーションを作って、ZYBOの実機でテストした。

ビットストリームの生成ができたので、ハードウェアをエクスポートして、SDKを立ち上げた。

cam_disp_axis.c を AXI VDMA の MM2S を使う仕様に変更して、ZYBO実機でテストしてみたが、何も表示されない。ビデオ信号が出ていない感じだ。もう一度、シミュレーションに戻ってやり直してみようと思う。その場合は、VTC のリセットにGPIO を入れて、任意のタイミングでVTC のリセットを外せるようにして、最初のフレームからAXI VDMA のMM2S が動作する状況にしたいと思う。

SDK を示す。
AXI_VDMA_MM2S_38_160506.png

修正した cam_disp_axis.c を示す。

// cam_disp_axis.c
// 2015/06/14 by marsee
// 2016/05/06 : Supporting to the MM2S of AXI VDMA
//
// Refered to Xilinx\SDK\2015.1\data\embeddedsw\XilinxProcessorIPLib\drivers\axivdma_v5_1\doc\html\api
// Refered to https://github.com/elitezhe/Atyls-VDMA-one-in-one-out/blob/master/SDK/colorbar/src/helloworld.c
// Refered to http://www.xilinx.com/support/documentation/ip_documentation/axi_vdma/v6_2/pg020_axi_vdma.pdf
// Refered to http://forums.xilinx.com/t5/Embedded-Processor-System-Design/Axi-VDMA-on-Digilent-Atlys/td-p/297019/page/2
// Refered to https://forums.xilinx.com/xlnx/attachments/xlnx/zaps/5096/1/helloworld.c
//
// normal camera out
//

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.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

static XAxiVdma_DmaSetup Vdma0_WriteCfg, Vdma0_ReadCfg;

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(){
    // malloc frame buffer
    // unsigned int *frame_buffer = (unsigned int *)malloc(HORIZONTAL_PIXELS * VERTICAL_LINES * PIXEL_NUM_OF_BYTES * NUMBER_OF_WRITE_FRAMES);

    // AXI VDMA Initialization sequence
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;

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

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

    // AXI VDMA Write Settings
    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

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

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

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

    // AXI VDMA Read Settings
    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_READ);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_READ)) ;

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

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

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

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

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

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

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_MODULE_AXIS_SWITCH_1_BASEADDR+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_MODULE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_MODULE_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_MODULE_AXIS_SWITCH_1_DEVICE_ID+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_MODULE_AXIS_SWITCH_1_DEVICE_ID), 0x2); // Commit registers

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

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

    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_MODULE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_MODULE_AXI_IIC_0_BASEADDR;

    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

    return(0);
}

  1. 2016年05月06日 06:13 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力6(インプリメントしたがエラー)

AXI VDMAのMM2Sを使用してビデオ出力5(シミュレーション3)”の続き。

前回、v_axis_vid_out IP が出力していないのが不安ではあるが、AXI VDMA からは出力が出ているので、ZYBO 実機で試してみようということで、ブロックデザインを修正して論理合成、インプリメントしてみたが、エラーが出てしまった。

シミュレーションを元にブロックデザインを修正した。ブロックデザインを示す。
AXI_VDMA_MM2S_27_160505.png

AXI_VDMA_MM2S_28_160505.png

AXI_VDMA_MM2S_29_160505.png

これでビットストリームの生成を行ったところ、route_design でエラーが出てしまった。
AXI_VDMA_MM2S_30_160505.png

MMCM のVCO の周波数が 200 MHz で動作範囲の 600 MHz ~ 1200 MHz に入らないというエラーだった。

rgb2dvi IP の設定を見てみた。TDMS clock range は >= 120 MHz になっているが、< 120 MHz でも同様にダメだった。
AXI_VDMA_MM2S_31_160505.png

rgb2dvi を右クリックして、右クリックメニューから Edit in IP Packager を選択して、IP を編集した。

rgb2dvi のプロジェクトを開いて、rgb2dvi.vhd を開くと、kClkRange には >= 40 MHz の設定があるけど、これが表に出ていないことが分かった。ちなみに、kClkRange の値は5倍されて、入力クロックの動作周波数に掛けられるので、40 MHz x ( 3 x 5) = 600 MHz で MMCM の VCO の動作範囲に入る。
AXI_VDMA_MM2S_32_160505.png

Package IP の Customization Parameters を見ると、kClkRange の Value Validation List に 40 MHz が無いので、追加すればよい。
AXI_VDMA_MM2S_33_160505.png

kClkRange の Value Validation List をダブルクリックするとダイアログが開いたので、 >= 40 MHz (SVGA の 3 を追加した。
AXI_VDMA_MM2S_34_160505.png

Package IP の Customization Parameters に戻ると、 >= 40 MHz (SVGA が増えていた。
AXI_VDMA_MM2S_35_160505.png

rgb2dvi IP を再パッケージして、元のプロジェクトに戻った。

Tool メニュー -> Report -> Report IP Status を選択して、IP Status を表示して、IP をアップグレードした。

rgb2dvi IP をダブルクリックすると、設定画面が開いたので、>= 40 MHz (SVGA のラジオボタンをクリックして選択した。
AXI_VDMA_MM2S_36_160505.png

もう一度ビットストリームの生成を行った。今度は成功した。
AXI_VDMA_MM2S_37_160505.png
  1. 2016年05月05日 06:27 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

定期戦に行ってきました

今日は娘と奥さんの高校と私の母校との定期戦に行ってきました。今回は娘の高校で行われました。
定期戦とは、娘の高校と私の母校の分校として100年以上前に誕生したという縁で、昭和22年から全運動部の対抗戦が年一回5月に行われています。全生徒が相手の高校に行って、運動部は対抗戦を行い、運動部に入っていない生徒は応援をします。開催する高校は一年おきに交代します。

私と奥さんは、石下駅までサイクリングで行って、久しぶりに常総線で行ってきました。
午前9時30分から陸上競技なので、それに間に合うように行きました。陸上部の美しい走りを見たかったからです。皆さん頑張っていました。
teikisen_1_160504.jpgteikisen_2_160504.jpg

陸上競技では、やり投げもやってました。

その後は、甥もいる弓道の様子をみました。弓道もキリッとしていて良いですね。

奥さんが高校の時にバスケ部だったので、男子バスケの試合も見ましたが、私の母校のほうが強かったです。

食事のために野球場へ。観客席が階段状にコンクリートで作ってあって良い感じに座れました。奥さんが作ってくれたオムライスおにぎりを食べました。これは、オムライスの卵焼きがチキンライスのおにぎりの中に入っているというおにぎりで美味しかったです。

さて、次は野球を観戦しました。最初は良い試合だったんですが、9回表に大量点が入って、私の母校が勝ちました。
teikisen_3_160504.jpgteikisen_4_160504.jpg

高校時代の事を思い出したりして、楽しかったです。

そいういえば、応援は私の母校では、応援練習をしていて、今でも校歌や応援歌を歌えるんですが、娘と奥さんの母校では応援練習をしないそうです。それで、応援に勢いが無かったんですね。私にとっては応援練習をしないことは信じられないことですが、高校によって違うんですね。。。新鮮な驚きでした。。。

今日は一日楽しかったです。
  1. 2016年05月03日 20:33 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力5(シミュレーション3)

AXI VDMAのMM2Sを使用してビデオ出力4(シミュレーション2)”の続き。

(2016/05/03:修正 MM2S の設定も入っていたので、ブログ記事を書き換えました)

reg_set_axi_lite_master IP のレジスタ設定ファイル vdma_reg_set.txt にアドレスと設定値を入れて、シミュレーションを行った。
最初はAXI VDMA の MM2S の設定で、その後は、AXI4-Stream Switcher の設定がある。
試しなので、現在動作している MM2S のみで、S2MM の設定はまだない。
AXI VDMA の設定値は”AXI VDMAのレジスタ設定(Triple Frame Buffer)”を参照した。
vdma_reg_set.txt を示す。

44a00000
0000008B
44a0005c
00000000
44a00060
00000000
44a00064
00000000
44a00058
00000c80
44a00054
00000c80
44a00050
00000258
44a00030
00000003
44a000ac
00000000
44a000B0
00000000
44a000B4
00000000
44a000a8
00000c80
44a000a4
00000c80
44a000a0
00000258
44a20040
00000000
44a20044
80000000
44a20000
00000002
44a10040
00000000
44a10000
00000002
44a40000
00000000
44a40004
00000000
ffffffff


これで論理シミュレーションを行った。
reg_set_axi_lite_master IP の波形を示す。 reg_set_axi_lite_master のAXI4 Lite Master の波形を示す。
AXI_VDMA_MM2S_20_160502.png

正常に設定できるようだ。

次に、AXI VDMA の S2MM のAXI インターフェースの信号を見た。正常に画像データをフレームバッファにWrite できているようだ。
AXI_VDMA_MM2S_21_160502.png

AXI VDMA の S2MMのAXI インターフェースの信号を拡大してみたが、8 バーストのバースト転送が行われているようだ。
AXI_VDMA_MM2S_22_160502.png

AXI VDMA の MM2S が最初のフレームにスタートしないのは、VTC の fsync_out が AXI VDMA の設定を行う前にアサートされているからのようだ。VTC の fsync_out は AXI VDMA の mm2s_fsync に入っている。 mm2s_fsync が入っていないので、DMA がスタートしないようだ。
AXI_VDMA_MM2S_23_160503.png

従って、 AXI VDMA の mm2s_fsync が適切に入る2フレーム目では、AXI VDMA の mm2s 転送が行われている。
AXI_VDMA_MM2S_24_160503.png

AXI VDMA の mm2s 転送のはじめの部分を拡大してみた。
AXI_VDMA_MM2S_25_160503.png

これで、AXI VDMA の mm2s 転送は動作しているが、まだ、VGA出力には画像が出力されていない。
それは、v_axis_vid_out IP が出力していないからのようだ。 locked が 0 のままだ。
AXI_VDMA_MM2S_26_160503.png

これはもっとシミュレーションしないと出力が出ないのかもしれない?
以前は、同様の回路で出力が出ていたので、インプリメントしてやってみようと思う。

なお、AXI VDMA の mm2s のアプリケーションの書き方は、Xilinx フォーラムの AXI VDMA 設定アプリケーションのサンプルを参考にしようと思う。
  1. 2016年05月03日 04:55 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ズートピア(映画)を見てきました

今日は奥さんとズートピア(映画)を見てきました。面白かったですよ。大人も楽しめたと思います。
きつねさんも良かったですね。でも、以外な犯人でした。

ふと思ったのですが、うさぎさんがやはり人参食べているということは、ライオンさんなどはお肉を食べているんではないでしょうか?でも何の肉なんでしょうね~?その辺りが気になりました。
  1. 2016年05月01日 21:02 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

AXI VDMA を使用したカメラ表示システムのフレームレートを 5 fps から 15 fps にする

AXI VDMA の S2MMで、3 フレームバッファ以上しか設定できないので、カメラの画像を 3 つのフレームバッファに入力していた。それを 1 つのフレームバッファしか扱えない自作のビットマップ・ディスプレイ・コントローラで画像を表示したので、3 つのフレームバッファの内の 1 つのフレームバッファしか表示用に使用できないので、フレームレートが 1/3 になっていた。
カメラのフレームレートは 15 fps なので、実質、5 fps になっていたわけだ。

今のところ、3 つのフレームバッファは連続的にアドレスを割り振っている。今日、シミュレーション用の設定定義ファイルを書いていた時に、気がついた。3 つのフレームバッファのアドレスをビットマップ・ディスプレイ・コントローラのアドレスだけにすればフレームレートは 1/1 じゃないか?と。。。つまり、3 つのフレームバッファのアドレスを同一にする訳だ。
それはフレームバッファのアドレスセットの文のアドレスを計算する部分をコメントアウトすれば良い。
AXI_VDMA_MM2S_16_160501.png

これでやってみたら、上手く行った。
AXI VDMA の S2MM を使わないでフレームレートが 3 倍になった。
しかし、今まで思いつかなかったところがどうしょうもない。。。

これで、AXI VDMA の S2MM を使うモチベーションは無くなったが、AXI VDMA の S2MM を使うと画像にジャギーが出ないはずので、シミュレーションだけでもやってみたいと思う。
  1. 2016年05月01日 06:00 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0