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

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

FPGAの部屋

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

ガーデンシュレッダーを買いました

昨日、柿の木を切って大量の枝を廃棄する必要が出てきました。
紐で縛ると燃えるゴミの日に出せるのですが、何分にも大量です。
garden_shredder_1_151231.jpg

どうしようか?少しずつ燃えるゴミに出そうか?と考えていましたが、ふと、枝の粉砕機を見たことがあるのを思い出して検索してみました。
検索すると、ガーデンシュレッダーという名前であることが分かりました。ガーデンシュレッダーには2種類あって、ギア式とディスクカッター方式があるようです。
ギア式は音が静かで、35mm程度の太い枝まで粉砕可能ですが、粉砕後のウッドチップが大きい様です。庭にウッドチップとして撒くならば、25mm程度の枝まで、騒音が大きいですが、ディスクカッター式のほうが細かくなるようです。

そこで、グランステージつくばに行ったところ、ガーデンシュレッダー EL-007 があったので、買ってきました。約2万円でした。アマゾンの方が安いです。ですが、よ~く説明して頂いて満足して買ってきました。アマゾンの評価は低いですが、今のところ問題無いです。

早速、家に持って帰って組み立てました。
garden_shredder_3_151231.jpg

garden_shredder_4_151231.jpg
後ろには、電源スイッチとブレーカーボタンがあります。

枝を一束やってみると、やはり音はうるさいですね。後、ディスクカッターなので、枝が回って手を弾かれるので、付属の革手袋したほうが手が痛くないです。軍手だと枝に弾かれて痛いです。
garden_shredder_5_151231.jpg

結構太いと思う枝もウッドチップになって、嬉しいです。
こんな感じでウッドチップになりました。細い枝は、短くなってますが、そのままの形で出てきました。これは仕方ないですね。。。
garden_shredder_6_151231.jpg

畑に撒くか、ウッドチップとして庭に撒きたいと思っています。
正月明けに本格的にウッドチップ製造をやってみたいと思っています。
  1. 2015年12月31日 17:59 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 と Vivado HLS 2015.4 の性能差(ソフトウェア的に書いたラプラシアンフィルタで検証)

明日、1月1日(金)にVivado HLS勉強会4 (AXI4 Master)を公開する予定だが、Vivado HLS勉強会4 (AXI4 Master)をVivado HLS 2014.4 対応から Vivado HLS 2015.4 対応に変更した時に、ソフトウェア的に書いたラプラシアンフィルタのCソースコードを高位合成した結果が異なったので、書いておく。

まずは、Vivado HLS 2014.4 で、ソフトウェア的に書いたラプラシアンフィルタのCソースコードを高位合成した結果を示す。
Vivado_HLS_2014_4_vs_2015_4_1_151231.png

Vivado_HLS_2014_4_vs_2015_4_2_151231.png

次に、同じCソースコードをVivado HLS 2015.4 で高位合成した結果を示す。
Vivado_HLS_2014_4_vs_2015_4_3_151231.png

Vivado_HLS_2014_4_vs_2015_4_4_151231.png

Timing のEstimated は同じ 8.75 ns だった。
Latency は2015.4の方が短くなっている。
使用リソースは、BRAM_18K とDSP48E は同じだが、FFとLUT は2015.4の方が多い。

C/RTL コシミュレーションの結果を示す。
最初に、Vivado HLS 2014.4 の C/RTL コシミュレーションの波形全体を示す。
Vivado_HLS_2014_4_vs_2015_4_5_151231.png
C/RTL コシミュレーションは、約 1.14 ms かかっている。

次に、Vivado HLS 2015.4 の C/RTL コシミュレーションの波形全体を示す。
Vivado_HLS_2014_4_vs_2015_4_8_151231.png
C/RTL コシミュレーションは、約 859 us で、短くなった。

Vivado HLS 2014.4 の C/RTL コシミュレーションのAXI4 Master Read 波形を示す。
Vivado_HLS_2014_4_vs_2015_4_6_151231.png
バースト長 1 で、AXI4 Master Read 間の間隔は 380 ns だった。

Vivado HLS 2015.4 の C/RTL コシミュレーションのAXI4 Master Read 波形を示す。
Vivado_HLS_2014_4_vs_2015_4_10_151231.png
バースト長 1 で、AXI4 Master Read 間の間隔は 290 ns だった。

Vivado HLS 2014.4 の C/RTL コシミュレーションのAXI4 Master Write 波形を示す。
Vivado_HLS_2014_4_vs_2015_4_7_151231.png
バースト長 1 で、AXI4 Master Write 間の間隔は 380 ns だった。

Vivado HLS 2015.4 の C/RTL コシミュレーションのAXI4 Master Write 波形を示す。
Vivado_HLS_2014_4_vs_2015_4_9_151231.png
バースト長は 64 で、AXI4 Master Write のデータ転送間の間隔は 290 ns だった。

データを見てきたように、ソフトウェア的に書いたラプラシアンフィルタのCソースコードを高位合成した結果においては、Vivado HLS 2014.4 よりも Vivado HLS 2015.4 の方が結果が良いようだ。
なお、他の2つのラプラシアンフィルタのCソースコードを高位合成した結果はほとんど変化がなかったので、Vivado HLS 2015.4 の方が、よりソフトウェア的に書いたコードでも性能が良くなるのかもしれない?

最後に、ラプラシアンフィルタのCソースコードを貼っておく。

// laplacian_filter_soft.c
// m_axi offset=slave Version
// lap_filter_axim()
// 2015/08/26 by marsee
//

#include <stdio.h>
#include <string.h>

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48
//#define HORIZONTAL_PIXEL_WIDTH    800
//#define VERTICAL_PIXEL_WIDTH    600

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=return

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb

    int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                if (y == 1 && x == 1){ // 最初のラインの最初のピクセルでは2ライン分の画素を読み出す
                    for (a=0; a<2; a++){ // 2ライン分
                        for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
                            line_buf[a][b] = cam_fb[(a*HORIZONTAL_PIXEL_WIDTH)+b];
                            line_buf[a][b] = conv_rgb2y(line_buf[a][b]);
                        }
                    }
                }
                if (x == 1) {    // ラインの最初なので、2つのピクセルを読み込む
                    for (b=0; b<2; b++){ // ライン
                        line_buf[(y+1)%3][b] = cam_fb[((y+1)*HORIZONTAL_PIXEL_WIDTH)+b];
                        // (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
                        line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);
                    }
                }

                // 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
                line_buf[(y+1)%3][x+1] = cam_fb[((y+1)*HORIZONTAL_PIXEL_WIDTH)+(x+1)];
                // (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
                line_buf[(y+1)%3][x+1] = conv_rgb2y(line_buf[(y+1)%3][x+1]);

                fl = (y-1)%3;    // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
                sl = y%3;        // 2番めのライン
                tl = (y+1)%3;    // 3番目のライン
                lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            // ラプラシアンフィルタ・データの書き込み
            lap_fb[(y*HORIZONTAL_PIXEL_WIDTH)+x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
            // printf("x = %d  y = %d", x, y);
        }
     }
     return(1);
}

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

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

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

    return(y);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}

  1. 2015年12月31日 05:24 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

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

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

7月
ラプラシアンフィルタのソフトウェアとハードウェアの速度の比較3
ZynqのSIMDエンジンNEONについての資料 ARMプロセッサのSIMDエンジンのNEON を使用して、ソフトウェアの高速化を図った。
gcc の最適化と自動ベクトル化を使用した時の性能 自動ベクトル化を行う gcc のオプションを使用してラプラシアンフィルタをコンパイルし、その性能を確認した。
clang の最適化と自動ベクトル化を使用した時の性能
OpenMPでのラプラシアンフィルタの実行速度
新しいラプラシアンフィルタのソフトウェア実装 OpenMP用のラプラシアンフィルタの新しい実装を作った。
ZYBOのHDMI入力を使用する(概要) ZYBOのHDMIはSource と Sink 両方使用することができる。つまりHDMI入力にもなれば、HDMI出力にすることもできる。これは、HDMIの信号がバッファを通したのみで Zynq-7010 チップに接続されているからなのだが、この性質を利用して、ZYBO同士を通信させようと思っている。
SDSoC 2015.2 のチュートリアルをやってみた1(新規プロジェクトの作製) SDSoC もやってみることにした。

8月
SDSoC 2015.2 のZYBO用サンプルデザインをやってみる2(Matrix Multiplication) SWの cpu cycles が 944230 に対して、HW のcpu cycles が 32554だった。HW の方が SW よりも 29 倍速いという結果になった。
SDSoC 2015.2 でハードウェアとソフトウェアのラプラシアンフィルタの性能を比較した1(ソースの公開) SDSoC のチュートリアルをある程度やってきて、大体、雰囲気が分かったので、いつものラプラシアンフィルタを題材にハードウェアとソフトウェアの性能差を測ってみることにした。
SDSoC 2015.2 でハードウェアとソフトウェアのラプラシアンフィルタの性能を比較した8(ハードウェア化5) ハードウェアでのラプラシアンフィルタ処理時間は 153 us で、ソフトウェアでのラプラシアンフィルタ処理時間は299 us だった。ハードウェアでのラプラシアンフィルタ処理時間はソフトウェアでのラプラシアンフィルタ処理時間よりも 0.517 倍に短くなった。つまり性能は 1.95 倍になった。
Vivado HLS 2014.4 でHLSストリームを使用してビデオ信号を入出力する
ビデオ信号にAXI4 Stream版のラプラシアンフィルタを通して画像出力1(準備編)

9月
ZYBOのHDMI入力をVGA出力に出力する8(ラプラシアンフィルタIP付き) ノートパソコンの画像をリアルタイムに画像出力することができた。
Vivado プロジェクトを配布する方法 1つ目は、File メニュー -> Archive Project.... を選択して、プロジェクトをアーカイブする方法だ。パブリックにダウンロードさせる方法としては、2つ目の tcl スクリプトでプロジェクトやブロックデザインを生成する方法がある。
Vivado HLS勉強会第1日目 Vivado HLS勉強会第2日目
筑波山の麓までサイクリングに行ってきました 今日は筑波山の麓までサイクリングに行ってきました。自転車は電動アシスト自転車です。登りは楽ですが、急な下りが重量が重いので怖かったです。
Vivado HLS によるアンシャープマスクキング・フィルタの作製1(準備編)
Vivado HLS によるアンシャープマスクキング・フィルタの作製2(floatで実装してみた)
Vivado HLS によるアンシャープマスクキング・フィルタの作製3(固定小数点で実装してみた)

10月
Vivado HLS によるアンシャープマスクキング・フィルタの作製6(実機確認) うまいった。
DSF2015 C-6 でのVivado HLS で生成したAXI4-Master IPの簡単な例について
Vivado HLS によるアンシャープマスクキング・フィルタの作製7(C++ の任意精度固定小数点型)
Vivado HLS 2015.3 の半精度浮動小数点数でアンシャープマスキング・フィルタを作った
Vivado HLSにおける固定小数点の誤差を平均2乗誤差で算出する
DE0-Nano-SoC をやってみる
”Atlas-SoC素晴らしいんじゃないの”をやってみる1
ZYBOにHDLで書いたラプラシアンフィルタを実装する1(FIFO の生成1) 以前、ZedBoard 用にHDLで書いたラプラシアンフィルタのIP があった。(”AXI4 Master アクセスのラプラシアン・フィルタ IP9(できた。完成)”)これをZYBO用にVivado 2015.3 で再度実装してみたいと思う。

11月
フリーの高位合成ツール Synverll を試してみる1
ZYBOにHDLで書いたラプラシアンフィルタを実装する9(制御ソフトウェアを作製して実機確認) できた。
並列ステレオカメラによる距離の測定1(ブロック図)
並列ステレオカメラによる距離の測定2(ZYBO 0 のハードウェア1) ステレオカメラによる距離の測定装置のブロック図のZYBO 0 のハードウェアを作っていくことにする。
Xilinx Announces the Spartan-7 FPGA Family Spartan-7 が出るそうです。びっくりしました。
BUFR でクロックを分周する場合は制約を追加する必要がある(ビットマップ・ディスプレイ・コントローラ IP のHDMI 出力)
並列ステレオカメラによる距離の測定6(ZYBO 0 のハードウェア5)完成
Vivado 2015.4 が出ました 無料の WebPACK でもVivado HLS がつかえるようになった。後で、Vivado Analyzer も無料で使えるようになったことが分かった。Vivado 2015.4 最強。。。

12月
AXI VDMAのドライバによるレジスタの設定値(S2MMの設定) 前回解析したのは動作しなかった場合で、フレームバッファが 1 面の時だったので、動作するようになった 3 面のフレームバッファの場合の解析をしてみる。
並列ステレオカメラによる距離の測定9(Ubuntuで動作するアプリケーションを作る2)  見事、ディスプレイにカメラ画像が表示されました。
SlideShare の Vivado and zybo linux勉強会資料を更新しました yama さんから Vivado and zybo linux勉強会資料の更新情報を頂いたので、SlideShare の Vivado and zybo linux勉強会資料2 と Vivado and zybo linux勉強会資料3 を更新しました。
HDMI入力XGA表示回路1(構想編)
Vivado HLS 勉強会1(基礎編)を公開しました
Vivado HLS 勉強会2(レジスタの挿入とPIPELINEディレクティブ)を公開しました
Vivado のImplemented Design で Report CDC を確認する
Vivado HLSでクロック周期を2.5ns で合成した掛け算回路は本当に400MHzで動作するのか? DSP48E1 のみを使っていたため約600MHzで動作するという結果になった。
Vivado HL WebPACK 2015.4 で Vivado Analyzer や Vivado Serial IO Analyzer が使えるようになりました 無料で使用できるVivado HL WebPACK 2015.4 で Vivado Analyzer や Vivado Serial IO Analyzer が使えるようになった。
Vivado HLS勉強会3(AXI4-Lite Slave)を公開しました
ZYBO_0 と ZYBO_1_XGA_test との接続テスト ZYBO_0 とZYBO_1_XGA_test を接続して動作できた。

今年もよくブログ記事を書いたものだ。この記事を入れて、2015年に書いたブログは 321 記事だった。
FPGAの部屋のブログが 10 週年を迎えたことと、Vivado 2015.4 の無料のWebPACK で、Vivado HLS とVivado Analyzer が使えるようなったことが2大ニュースだと思う。

来年もよろしくお願い致します。良いお年を。。。
  1. 2015年12月30日 05:24 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:2

ハンターマウンテン塩原スキー場に行ってきました

今日は、ハンターマウンテン塩原スキー場に行ってきました。

車でスキー場に向けて、走っていると途中から雪が降っていました。スキー場は雪です。ハンターマウンテン塩原は晴れの確率がとっても多いので、雪は珍しいです。よほど冬型が強かったんですね。。。
HunterM_1_151229.jpg

HunterM_2_151229.jpg

写真には雪が見えていないかもしれませんが、雪降っています。
滑っていると顔が寒いです。リフトに載っていると雪だらけになります。
HunterM_3_151229.jpg

そこで、リフトは2本で止めて、ゴンドラにしました。それでも1本乗ったら腹が減って、食事にしました。10時過ぎくらいですね。。。

食事後にリフトは寒いということで、ゴンドラ2本乗りました。そこで、もう年なので、十分滑ったということで、12時過ぎくらいにスキー場を出て、鬼怒川方面に降りて、鬼怒川温泉の温泉公衆浴場の鬼怒川公園岩風呂へ行きました。
HunterM_4_151229.jpg

HunterM_5_151229.jpg

スキーの後の温泉最高です。ゆっくり温まって、足を湯船の中でマッサージしていました。
風呂から出たら、マッサージ機があったので、200円払ってマッサージしてました。とっても具合が良かったですよ。。。

なお、鬼怒川公園岩風呂は12月30日と31日はお休みで、正月はやっているそうです。今日は29日なので、とってもラッキーだったと思います。
年末はやっていないようなので、ご注意下さい。
  1. 2015年12月29日 20:41 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

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

2015年のFPGAの部屋のブログを振り返ってみた。

1月
筑波山神社へ初詣
Vivado HLS 2014.4 の勉強1(高位合成の理解) Vivado HLSの勉強をしていた。
・Vivado HLS でラプラシアンフィルタを実装して、いろいろなディレクティブを試してみた。
高位合成友の会第2回目に参加
Caffe | Deep Learning Frameworkをインストール1

2月
FPGAエクストリーム・コンピューティング 第6回でLTしてきました
ハンターマウンテンスキー場に行ってきました
Zynq勉強会 7番目の資料”7 AXI4 バス説明、AXI4バスを使用したカスタムIPの作成方法”を公開2
Vivado and ZYBO Linux勉強会を開催 slideshare で Vivado and ZYBO Linux勉強資料3 を公開しました。
食器洗い洗浄機を買い替えました

3月
・Vivado HLSで生成したラプラシアンフィルタIPを使って、いろいろとやってます。
Vivado HLS 2014.4で生成したラプラシアンフィルタIPをシミュレーション3(原因が分かった) で おるさんのおかげで、1ヶ月半くらいの間、悩んできた Vivado HLS 2014.4 で生成したラプラシアンフィルタIP の原因が分かりました。
・Vivado HLS 2014.4で生成したラプラシアンフィルタIPの高速化をいろいろとやってます。
娘の学位記授与式(卒業式)に行ってきました 今は大学院に行っています。
Vivado HLS 2014.4 で合成したラプラシアンフィルタIPの高速化4(tu1978さんのCソースコード) tu1978 さん、いつもありがとうございます。

4月
Vivado HLS 2014.4 で合成したラプラシアンフィルタIPの高速化14(性能が最大になる設定を探る7、まとめ) Vivado HLS 2014.4 で合成したラプラシアンフィルタIPでの性能差をまとめた。
・だいぶミスしていたな。気をつけないと。。。
Vivado HLS 2014.4 で AXI4-Stream をテストする1(準備編)  AXI4-Stream を使って実装してみることにした。
Vivado 2014.4 でインプリメント時にStrategy を変更してインプリメント結果を改善する Vivado にもタイミング制約エラーを改善する方法があった。
FPGAマガジンNo.9 に記事を書きました FPGAマガジンNo.9 に、”【365日間の評価ライセンスが取得できる!】 C言語からFPGAを開発できる高位合成ツールが無償で使える! Vivado WebPACK EditionとVivado HLS評価版のインストール手順”という記事を書きました。今では、Vivado HLS が無料で使えるので、もっと良くなりましたね。
Vivado HLS 2014.4 でサイドチャネル付き AXI4-Stream をテストする1(C++ソースコードの公開)

5月
1x4 材で本棚を作ります1 1x4 材で本棚を作ります2
AXI4-Stream版ラプラシアンフィルタIPのカメラ表示システム1(構想編)
さくらんぼ狩りとさくらんぼジャム2
今日でFPGAの部屋のブログは10週年を迎えました ブログ始めて10週年、めでたい。。。
Vivado HLSの高位合成結果をHDLとして利用する1(準備編)
Vivado HLSの高位合成結果をHDLとして利用する5(sqrt())
藤沢邸バラ園に行ってきました
Vivado HLS で cos() を高位合成
Parallella Technical Conference in Tokyo に行ってきました

6月
Vivado HLS 2014.4 でディスプレイ・コントローラを作る1(高位合成、C/RTLコシミュレーション)
古い実家を壊しました 生まれた家を壊しました。
AXI VDMAのドライバによるレジスタの設定値
AXI4-Stream版ラプラシアンフィルタIPのカメラ表示システム9(カメラ画像表示は完成) やっと、AXI VDMAが動作した。画像のフレームは3以上でないと動作しないようだ。
ラプラシアンフィルタのソフトウェアとハードウェアの速度の比較

ほとんどVivado HLS 関連の記事だな~。。。というのが感想だ。
FPGAの部屋のブログ、10週年、ほんとうに嬉しい。。。
  1. 2015年12月29日 04:42 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

ZYBO_0 と ZYBO_1_XGA_test との接続テスト

HDMI入力XGA表示回路7(完成)”で、ZYBO_1_XGA_test が完成したので、”並列ステレオカメラによる距離の測定9(Ubuntuで動作するアプリケーションを作る2)”で完成したZYBO_0 をHDMI ケーブルで接続してテストすることにした。

ZYBO_0 はカメラが付いていて、カメラの画像をHDMI出力して、 ZYBO_1_XGA_test でHDMIから画像を入力して、VGAポートに出力する。
ZYBO_1_XGA_test_18_151216.jpg

ZYBO_0 のMicro SDカードからUbuntu 14.04 LTS をブートして、コマンドを実行し、HDMI端子にXGA 解像度の画像を出力した。それをSDKからアプリケーションを起動した ZYBO_1_XGA_test が受けて、SVGA解像度の画像をVGAポートに出力する。

早速やってみたが、どうも色がおかしい。
送り元のZYBO_0 で VGAポートから出力した画像はこれだ。
ZYBO_1_XGA_test_72_151228.jpg

それをZYBO_1_XGA_test で表示すると、こんな色になる。それに左端に白い線が見えている。
ZYBO_1_XGA_test_73_151228.jpg

どうやら、黄色がピンク、ピンクが黄色になってしまうようだ。となると、緑と青が入れ替わっているっぽい。

そこで、ZYBO_1_XGA_test の v_vid_axi4s_0 のAXI4 Steram のデータバスのバイト・レーンの内のビット7~0 とビット15~8 を入れ替えた。
ZYBO_1_XGA_test_71_151227.png

これで、ビットストリームの生成を行い、SDKでビットストリームのダウンロード、アプリケーションを起動を行うと正常に表示された。
ZYBO_1_XGA_test_74_151228.jpg

う~ん、なんで、最下位 8 ビットとその上の 8 ビットがひっくり返っているか?わからない?
取りあえず、成功したのだが、すっきりしない。調査をしてみたい。

(2016/01/02:追記)
Green とBlue の入れ替えの原因は、dvi2rgb IP の pData (23:0) が”Video pixel data packed as RBG. ”だったのが原因だった。
私が作製したIP では、RGB の順にパックされているので、Green とBlue を入れ替える必要があったようだ。
  1. 2015年12月28日 05:09 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路7(完成)

HDMI入力XGA表示回路6(デバック2)”の続き。

v_vid_in_axi4s_0 の AXI4-Stream の aclk クロックとaxi_vdama_0 の s_axis_s2mm_aclk をPS のFCLK_CLK0 に接続してビットストリームを生成した。

SDKでビットストリームをZYBO にダウンロードして、アプリケーションを走らせたが、うまく行かない。。。
(現在は、ノートパソコンのXGA解像度の2nd 画面をHDMI 経由でZYBO で受けて、それをVGA解像度でVGA端子に出力しています)

そう言えば、アプリケーションを走らせるまで、PSの設定が行われずにクロックが出ないんだったと思い直して、数回、ビットストリームをダウンロード、アプリケーションの起動の手順を繰り返したら、うまくいくことがあった。

これは、ZYBO のPL をコンフィギュレーションしても、PSからのクロックが供給されずにDDC がうまく動かないためだと思った。

PL に接続された125 MHz の水晶発信器からのクロックをPLL を介して200 MHz に変換したクロックを dvi2rgb IP の RefClk に接続することにした。
ZYBO_1_XGA_test_63_151227.png

なおMMCM は残り 0 なので、PLL を使用した。
ZYBO_1_XGA_test_64_151227.png

ZYBO_1_XGA_test_65_151227.png

ZYBO_1_XGA_test_66_151227.png

ZYBO_1_XGA_test_67_151227.png

これで、XDC に clk125 の制約を追加して、ビットストリームの生成を行った。
SDK でビットストリームをダウンロードした所、DDC が働いて、HDMI 出力を行っているノートパソコンにディスプレイ 2 が追加された。ディスプレイ 2 は予め、1024 x 768 の XGA 解像度に設定してある。
ZYBO_1_XGA_test_68_151227.jpg

ZYBO のVGA 端子に接続されたSVGA 解像度のディスプレイの表示を示す。
ZYBO_1_XGA_test_69_151227.jpg

画像がちゃんと表示されていないが、これは、XGA解像度のHDMI 画像にSVGA 解像度の画像を載せているのを前提にしているからだ。つまり、フレームバッファ上に展開された画像はそのままSVGA 画像のイメージとなっている画像が対象なので、普通のXGA 画像をノートパソコンから送られるとこうなる。(たぶん。。。)

次に、ノートパソコンの画面に右端に表示されているエクスプローラーをディスプレイ 2 に移動させた時の画像はこうなる。
ZYBO_1_XGA_test_70_151227.jpg

きちんとAXI VDMA が連続してDMA しているようだ。
これで、HDMI 入力 XGA 表示回路のデバックは終了だ。
もう一度、ZYBO からのHDMI 出力を入力して確かめてみよう。
  1. 2015年12月27日 07:28 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado のIP Integrator のちょっとしたTips

・VivadoのIP Integrator のブロックデザインのMark Debugを一挙に外す方法
Mark Debug でVivado Analyzerで見た後で、1本1本ちまちまとUnmark Debug 設定していますか?私もそうしていたんですが、ぱっと思いついてやってみたらうまく行きました。

その方法は、というと、Ctrl + A ですべて選択した後で、Unmark Debug を選択するとすべて消えました。


・VivadoのIP Integrator のブロックデザインでクロック配線などの多数に供給される配線の1本だけを削除する方法
今まで、IPのピンへの配線を繋ぎ変えようとして配線を消去すると、その配線ネットが全て消えちゃってました。これはクロック配線を繋ぎ変えようとした時に、他への配線が全て消えてしまって、とっても痛いです。そこで、そのIPの配線だけを削除する方法です。

IPのピンを選択して、右クリックし、右クリックメニューからDisconnect Pin を選択すると、そのIPの配線だけを消すことができます。
IPI_disconnect_pin_151226.png
  1. 2015年12月26日 07:25 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路6(デバック2)

HDMI入力XGA表示回路5(デバック1)”の続き。

前回は、v_vid_in_axi4s_0 の AXI4-Stream の aclk クロックは FCLK_CLK_0 だが、axi_vdama_0 の s_axis_s2mm_aclk は dvi2rgb_0 の PixelClk だった。AXI4-Stream のMaster とSlave でクロックが違っていた。
それで、v_vid_in_axi4s_0 の AXI4-Stream の aclk クロックを dvi2rgb_0 の PixelClk に接続し、ビットストリームを生成し、実機で確かめてみる。

ビットストリームの生成を行って、成功した。

Vivado 2015.4 のProject Manager -> Program and Debug -> Open Hardware Manager -> Open Target -> Auto Connect でZynq と接続した。
ZYBO_1_XGA_test_58_151226.png

Hardware Manager が立ち上がった。
Program device をクリックして、xc7z010_1 を選択して、Zynq にビットストリームをダウンロードする。
ZYBO_1_XGA_test_59_151226.png

Program Device ダイアログが表示された。
Program ボタンをクリックした。
ZYBO_1_XGA_test_60_151226.png

なぜか?Vivado Analyzer の画面が表示されない。HDMI ケーブルを接続しているノートパソコンもセカンダリ・ディスプレイが見つからない。
ZYBO_1_XGA_test_61_151226.png

なぜ、セカンダリ・ディスプレイが見つからないのかがわからない?その部分は修正に関係ないはずなんだが?
Vivado のWarning は

WARNING: [Labtools 27-3123] The debug hub core was not detected at User Scan Chain 1 or 3.

で検索すると、

AR# 64764
Vivado Logic Analyzer - Warning: [Labtools 27-3123] The debug hub core was not detected at User Scan Chain 1 or 3

がヒットした。
結局、HDMI 入力RGB 出力IP (dvi2rgb) からクロックが出ていないようだ。

v_vid_in_axi4s_0 の AXI4-Stream の aclk クロックとaxi_vdama_0 の s_axis_s2mm_aclk をPS のFCLK_CLK0 に接続することにした。
ZYBO_1_XGA_test_62_151226.png

これで、もう一度、デバックポートを設定してから、ビットストリームを生成して試してみよう。

(追記)
Vivado の以前バージョンでは、Hardware Manager を使うとVivado が頻繁に落ちていたのだが、Vivado 2015.4 で、結構 Hardware Manager を使っているが一度も落ちていない。とっても良くなったと思う。
  1. 2015年12月26日 05:32 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS勉強会3(AXI4-Lite Slave)を公開しました

Vivado HLS 勉強会3 (AXI4 Lite Slave)をSlideShare に公開しました。

内容は、

Vivado HLS 2015.4 を使用して、今までやってきた掛け算回路をAXI4 Lite Slaveインターフェースで実装します。
Vivado HLSでIP化を行って、Vivado 2015.4のIPIを使用してZYBOに実装します。
Vivado HLSで自動的に作製されたドライバを使用して、アプリケーションを作製し、掛け算回路を制御します。
ZYBO実機で掛け算回路を動作させます。シリアル・ターミナルで掛け算を行います。

という感じです。
AXI4 バス・インターフェースの知識が必要となります。波形を見なければ問題ないんですが。。。
AXI4 バス・インターフェースの生成はディレクティブ1発でOKです。何も難しいところはありません。しかもベアメタルとLinuxのドライバを自動的に生成してくれます。自動生成されたドライバを使用してベアメタル(OS無し)で掛け算回路をシリアル・インターフェース経由で動作させます。Linux 用のドライバは、UIOを使用するのが前提になっています。Linux用のドライバは手順が複雑なので、今回は使用しません。

それでは、Vivado HLS 勉強会3 (AXI4 Lite Slave)で使用するコードを貼っておきます。

まずは、ZYBO_zynq_def.xml が必要なんですが、Digilent 社のサイトには無くなってしまいました。ですが、fpga-zynq/zybo/src/xml/ZYBO_zynq_def.xml にありました。ここのコードをコピー&ペーストして、ZYBO_zynq_def.xml として保存すれば使えると思います。

最初に、multi_apuint.cpp を貼っておきます。

// multi_apuint.cpp

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

void multi_apuint(ap_uint<8> multi_in0, ap_uint<8> multi_in1,
        ap_uint<16> *multi_out){
#pragma HLS PIPELINE
#pragma HLS INTERFACE ap_hs register port=multi_in1
#pragma HLS INTERFACE ap_hs register port=multi_in0
#pragma HLS INTERFACE ap_vld register port=multi_out
#pragma HLS INTERFACE ap_ctrl_hs port=return
    *multi_out = multi_in0 * multi_in1;
}


次に、multi_apuint_tb.cpp を貼っておきます。

#include <string.h>
#include <ap_int.h>

void multi_apuint(ap_uint<8> multi_in0, ap_uint<8> multi_in1,
        ap_uint<16> *multi_out);

int main(){
    using namespace std;

    ap_uint<8> multi_in0;
    ap_uint<8> multi_in1;
    ap_uint<16> multi_out;

    for (multi_in0=0, multi_in1=1; multi_in0<10; multi_in0++, multi_in1++){
        multi_apuint(multi_in0, multi_in1, &multi_out);
        cout << "multi_out = " << multi_out << endl;
        if (multi_out != (multi_in0 * multi_in1))
            return(1);
    }

    return(0);
}


最後に、multi_test.c を貼っておきます。

// multi_test.c
// 2015/07/24 : by marsee
// multi_in0 の入力の時に999を入力すると終了する
//

#include <stdio.h>
#include "xmulti_apuint.h"
#include "xparameters.h"
#include "xil_types.h"
#include "xil_io.h"
#include "xil_exception.h"
#include "xscugic.h"

int main(){
    XMulti_apuint XMluti_ap;
    XMulti_apuint_Config *XMulti_apPtr;
    int val;

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

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

   while(1){
       printf("\n\rmulti_in0 = ");
       scanf("%d", &val);
       if(val == 999)
           break;
       XMulti_apuint_Set_multi_in0_V(&XMluti_ap, val);

       printf("\n\rmulti_in1 = ");
       scanf("%d", &val);
       XMulti_apuint_Set_multi_in1_V(&XMluti_ap, val);

       while(!XMulti_apuint_IsIdle(&XMluti_ap)) ;

       XMulti_apuint_Start(&XMluti_ap);

       while(!XMulti_apuint_IsDone(&XMluti_ap)) ;

       printf("\n\rmulti_out = %d\n\r", (int)XMulti_apuint_Get_multi_out_V(&XMluti_ap));
   }

   return(0);
}

  1. 2015年12月25日 04:35 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路5(デバック1)

HDMI入力XGA表示回路4(実機で確認)”の続きだけど、次の記事で示す変更を行っている。
set_clock_groups -asynchronous 制約
Vivado のImplemented Design で Report CDC を確認する
ビットマップ・ディスプレイ・コントローラのReport CDC unsafe 箇所を確認し、修正する

正常に動作すれば、XGA画像をHDMI から取り込んで、VGAの画面としてディスプレイに表示するはずなんだが、表示しない。そこで、Vivado Analayzer でデバックを試みることにした。
休みの日に用事をこなしながら、デバックポートを入れて、Synthesized Design からTools -> Set Up Debug をしたので、ある程度の必要な信号線を削除してしまった。

まずは、ブロックデザインから示す。
今回は、前にうまく行った”ZYBOのHDMI入力をVGA出力に出力する8(ラプラシアンフィルタIP付き)”で使用したdvi2rgb IP をそのまま使用した。
ZYBO_1_XGA_test_54_151224.png

これで、論理合成を行い、Synthesized Design からTools -> Set Up Debug を行った。ここで、必要な信号線を幾つか削除してしまったようだ。
インプリメント、ビットストリームの生成を行った。Summary を示す。
ZYBO_1_XGA_test_55_151224.png

ハードウェアをエクスポートして、SDKを立ち上げる。
SDKはアプリケーションのビルドでエラーが出るので、Clean する必要があるようだ。
Zynq はアプリケーションを起動しないとPS からのクロックも出力されないので、デバックができない。まずはSDKでProgram FPGA とアプリケーションの起動を行った。

次に、Vivado 2015.4 で、Hardware Manager を開いてデバックを行った。
ZYBO_1_XGA_test_51_151224.png

まずはXGA のピクセルクロック関連の信号だが、HSYNC の立ち上がりでキャプチャした所、dvi2rgb IP からは画像信号が出ている。

次に、AXI4バスの信号を見た。
ZYBO_1_XGA_test_52_151224.png

信号波形の拡大を示す。AXI4 Master バスは全くデータ転送をしていないようだ。
ZYBO_1_XGA_test_53_151224.png

上の図で、AXI4-Stream のm_axis_video_tvalid だけ、AXI4バスのクロック・ドメインに入っている。これはもしかして???
v_vid_in_axi4s_0 の AXI4-Stream の aclk クロックは FCLK_CLK_0 だが、axi_vdama_0 の s_axis_s2mm_aclk は dvi2rgb_0 の PixelClk だった。AXI4-Stream のMaster とSlave でクロックが違っていた。。。失敗。
ZYBO_1_XGA_test_56_151224.png

v_vid_in_axi4s_0 の AXI4-Stream の aclk クロックを dvi2rgb_0 の PixelClk に接続した。以前とは違ってピクセルクロックに接続したがどうだろう?ダメだったら、FCLK_CLK0 に接続することにする。
ZYBO_1_XGA_test_57_151224.png
  1. 2015年12月24日 05:22 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HL WebPACK 2015.4 で Vivado Analyzer や Vivado Serial IO Analyzer が使えるようになりました

無料で使用できるVivado HL WebPACK 2015.4 で Vivado Analyzer や Vivado Serial IO Analyzer が使えるようになっているようです。

今までのVivado WebPACK では、Vivado Analyzer や Vivado Serial IO Analyzer は使えなかったのですが、Vivado HLS と共に、 Vivado Analyzer や Vivado Serial IO Analyzer が使えるようになったようです。Vivado HL WebPACK 2015.4 は使用できるデバイスは限られますが、使えるデバイスでは、System Generator for DSP 以外の機能を使えるようになったようです。

今まで初心者の方に、Xilinx と Altera のどちらのFPGA を使ったほうが良いですか?と聞かれると無料でFPGA 内蔵のロジック・アナライザが使えないので、Altera にしたら?と答えていました。今度からは、Vivado HLS という C, C++ からHDL に合成できるVivado HLS も無料で使えるので、Xilinx にしたほうが良いと答えようと思います。

趣味で使う方や、仕事に使うので家で勉強したいという方に無料のVivado HL WebPACK 2015.4 をお勧めします。

初めてFPGA を触る方にどのFPGA ボードをお勧めするか?なんですが、Digilent 社のArty 、BASYS3、ZYBO が秋月電子で購入できるので、この辺りはいかがでしょうか?

少し高価ですが、650MHz のデュアルARM CortexA9 が載っているZYBO はLinux も十分に動作して、UbuntuもOpenCV も動きますし、とても良いです。Vivado HLS でソフトをハードにオフロードすることも慣れればできるでしょう。ですが、ソフトとハードを協調して動作させようとするとAXIバスの知識が必要などのハードルもあります。初心者で、初めて動作させようとすると、どうして良いか分からないということになることもあるでしょう?
今だったら、Digilent 社のサイトからは、$132 で購入できます。但し、Shipping に費用がかかります。どの位かかるのか?はよく分かりません。

FPGA初めて見たいとか自分ですべてオリジナルでCPU作りたいとか、安いほうが良い、ハード単体で使いたいということだとArty かな?と思います。それにLAN ポートが付いています。

BASYS3 は、Arty 同様ですが、LAN ポートが無く、VGA と7セグメントLED が付いています。スイッチもたくさんあって、教育用途に向いているのかな?と思います。

Digilent Documentation にそれらのボードのマニュアルやリファレンス・プロジェクトなどがありますので、参考にされると良いと思います。
  1. 2015年12月22日 05:14 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

”スター・ウォーズ/フォースの覚醒”を見てきました

今日は、午前10時から奥さんと息子と3人で”スター・ウォーズ/フォースの覚醒”を見てきました。
懐かしいキャラが3人も出てきて懐かしかったです。スター・ウォーズは大学2年の時にエピソード4 を映画館で見て以来のファンです。新作が出てとっても嬉しいです。よりリアルにスター・ウォーズの世界を堪能できました。エピソード8 が楽しみです。
  1. 2015年12月20日 10:54 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLSでクロック周期を2.5ns で合成した掛け算回路は本当に400MHzで動作するのか?

SlideShare で公開している”Vivado hls勉強会2(レジスタの挿入とpipelineディレクティブ)”の 70 ページの Solution から Vivado HLS でクロック周期が 2.5 ns つまり 400 MHz で動作するように設定して高位合成を行っているのだが、本当に400 MHz で動作するのか?をVivado 2015.4 でプロジェクトを作製してテストしてみた。

Vivado HLS 2015.4 で multi_apuint.cpp をSolution の Synthesis Settings -> Clock Period 2.5 ns (400 MHz) で合成した。
なお、公開したコードからでは、ブロックのインターフェースを ap_ctrl_none に変更している。使用するFPGAはZYBO で使用している xc7z010clg400-1 に設定した。
multi_apuint_1_151220.png

合成後のレポート。 2.15 ns (465 MHz) 動作するとのことだ。
multi_apuint_7_151220.png

これをIP化を行った。

次に、Vivado 2015.4を起動して、multi_apint プロジェクトを作製した。

Vivado HLS 2015.4 で作製したIP をIP Catalog にインポートして、multi_apuint_bd ブロックデザインを生成した。

ブロックデザインに、multi_apuint IP をAdd IP し、外部ポートを接続した。
multi_apuint_3_151220.png

ラッパーHDL を作製して、論理合成を行った。

multi_apuint_bd.xdc を作製して、2.5 ns のタイミング制約を追加した。
multi_apuint_4_151220.png

create_clock -period 2.500 -name multi_clk -waveform {0.000 1.250} ap_clk


インプリメントを行った。ビットストリームの生成はIOピンを指定していないためエラーだった。
multi_apuint_5_151220.png

タイミング制約も満たされている。
multi_apuint_6_151220.png

Implemented Design を開いて、Timing Summary を見ると、2.5 ns のクロック周期制約は満たされていて、最大のクロック周期は 1.671 ns だった、これは、598.4 MHz に相当する。
multi_apuint_2_151220.png

凄いことだ。ZYBOで掛け算回路が約 600 MHz で動作するように出来たのだから。。。
Vivado HLS の凄い所は、同じC, C++ ソースコードが、100 MHzで動作するようにも合成できたり、約 600 MHz でも動作するようにも合成できることだと思う。それぞれ、リソース使用量とレイテンシは違うが、PIPELINEディレクティブを入れて、完全にパイプラインできていれば、1クロックで掛け算が終了することには変わりがない。ということは、600 MHz で動作する掛け算回路は、100 MHz で動作する掛け算回路よりも 6 倍のスループットがある訳だ。それを、設定1発で変更できるのは凄いことだと思う。

(追記)
どうやら4ステージのパイプラインはすべてDSP48E1で実現されているようだ。それで、約 600 MHzという動作周波数が実現できたようだ。FF と LUT で実現されている訳ではない。
multi_apuint_8_151220.png

それでも、DSP48E1がパイプラインできるって知らなかったし、Vivado HLSが合成してくれて初めて使えたことを思うと、とっても良いと思う。だから、もっと複雑な回路は400 MHzとかの動作周波数では動かないはずだと思う。但し、動作周波数を変更できるのは、とっても良いと思う。
  1. 2015年12月20日 07:05 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラのReport CDC unsafe 箇所を確認し、修正する

Vivado のImplemented Design で Report CDC を確認する”で確認されたビットマップ・ディスプレイ・コントローラのReport CDC unsafe 箇所を確認して修正してみよう。

From は ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/cs_rdg_reg[0]/C
To は ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/hv_cnt_ena_d1_reg/D
だった。

bitmap_disp_eng.v でのFrom 部分を下に示す。

    // Readデータ処理モジュール用ステートマシン
    always @(posedge clk_axi) begin
        if (reset_axi)
            cs_rdg <= idle_rdg;
        else begin
            case (cs_rdg)
                idle_rdg :
                    if (ddr_cont_init_done)
                        cs_rdg <= init_full_mode;
                init_full_mode : // 最初にcam_data_afifo をFULLにするステート、このステートではVGA信号は出力しないで、ひたすらcam_data_afifo がFULLになるのを待つ。
                    if (read_count==0)
                        cs_rdg <= wait_half_full;
                wait_half_full : // cam_data_afifo がHALF_FULLになるまでこのステートで待機
                    if (vsync_axi)
                        cs_rdg <= frame_wait_state;
                    else if (wr_data_count<=AFIFO_HALF_FULL_VAL)
                        cs_rdg <= req_burst;
                req_burst :
                    if (vsync_axi)
                        cs_rdg <= frame_wait_state;
                    else if (read_count==0) // データが全部来たら
                        cs_rdg <= wait_half_full;
                frame_wait_state : // 1フレーム終了後vsync の時にWaitする
                    if (vsyncx_rise_pulse) // vsyncx の立ち上がり
                        cs_rdg <= frame_start_full;
                frame_start_full : // 1フレームのスタートの時にFIFOをフルにする
                    if (read_count==0)
                        cs_rdg <= wait_half_full;
            endcase
        end
    end
    assign hv_count_enable = (cs_rdg==wait_half_full || cs_rdg==req_burst || cs_rdg==frame_wait_state || cs_rdg==frame_start_full) ? 1'b1 : 1'b0;


リセット後ビットマップ・ディスプレイ・コントローラがスタートする時に、画像データ用FIFO を画像データで満たしてから水平カウンタ、垂直カウンタを始動しようと思っていて、そのためのイネーブル信号 (hv_count_enable) を生成している。 hv_count_enable は組み合わせ回路で作っている。 hv_count_enable はリセット後画像データ用FIFO が満たされるまでは 0 で、フルになった時に 1 になって、その後はずーと 1 だ。

この、hv_count_enable はピクセルクロックで動作する水平カウンタ、垂直カウンタにイネーブル信号として入力するために FF 2個を使用したシンクロナイザーを通してある。その後、水平カウンタ、垂直カウンタにイネーブル信号として入ってる。

    // h_count、v_count用にclk_axi 動作のcs_rdg の値を使用するので2回clk_disp 動作のFFでラッチする
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            hv_cnt_ena_d1 <= 1'b0;
            hv_cnt_ena_d2 <= 1'b0;
        end else begin
            hv_cnt_ena_d1 <= hv_count_enable;
            hv_cnt_ena_d2 <= hv_cnt_ena_d1;
        end
    end

    // h_countの実装(水平カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            h_count <= 0;
        else if (h_count>=(H_SUM-1)) // h_count がH_SUM-1よりも大きければ0に戻す(mod H_SUM)
            h_count <= 0;
        else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
            h_count <= h_count + 1;
    end

    // v_countの実装(垂直カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            v_count <= 0;
        else if (h_count>=(H_SUM-1)) begin // 水平カウンタがクリアされるとき
            if (v_count>=(V_SUM-1)) // v_count がV_SUM-1よりも大きければ0に戻す(mode V_SUM)
                v_count <= 0;
            else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
                v_count <= v_count + 1;
        end
    end


よって、この信号が unsafe だとしても問題は無いと思うのだが、修正を試みてみよう。

Verilog HDL コードをこのまま修正することは容易だが、Vivado の修正を認知させるために、IP Integrator のブロックデザインの ZYBO_1_XGA_test を開いて、bitmap_disp_cntrler_axi_master_0 を IP Packager を起動して修正する。
ZYBO_1_XGA_test_48_151220.png

組み合わせ回路の出力を hv_count_ena_comb に変更して、それをFF に通して hv_count_enable 信号として出力した。

    assign hv_count_ena_comb = (cs_rdg==wait_half_full || cs_rdg==req_burst || cs_rdg==frame_wait_state || cs_rdg==frame_start_full) ? 1'b1 : 1'b0;
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            hv_count_enable <= 1'b0;
        end else begin
            hv_count_enable <= hv_count_ena_comb;
        end
    end


これで、再度パッケージ化を行った。
ZYBO_1_XGA_test_49_151220.png

また、ZYBO_1_XGA_test プロジェクトに戻って、論理合成、インプリメント、ビットストリームの生成を行った。タイミングも満足して成功した。
Implemented Design を開いて、Tools -> Timing -> Report DRC... を実行した。
ZYBO_1_XGA_test_50_151220.png

Unsafe が消えて、問題が無くなった。
修正を行ったが、たぶん、動作は前と変わっていないと思う。
  1. 2015年12月20日 05:02 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

”海難1890”を見てきました

今日は、日本トルコ合作映画の”海難1890”を見てきました。
なかなか良かったです。泣けました。トルコと仲良くしたいですね。。。
  1. 2015年12月19日 20:50 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado のImplemented Design で Report CDC を確認する

set_clock_groups -asynchronous 制約”で論理合成、インプリメント、ビットストリームの生成を行った後で、Report CDC (Clock Domain Crossing) を見てみよう。参考にしたのは、”Vivado Design Suite ユーザー ガイド デザイン解析およびクロージャ テクニック UG906 (v2015.3) 2015 年 9 月 30 日”の 65 ページ ”クロック乗せ換えレポート”、日本語で分けわからないときは、英語のマニュアルも見よう。

まずは、Implemented Design を開いて、Tools メニュー -> Timing -> Report CDC... を選択する。
ZYBO_1_XGA_test_39_151219.png

Report CDC ダイアログが開いた。
From の ... ボタンをクリックした。
ZYBO_1_XGA_test_40_151219.png

Choose Start Clocks ダイアログが開いた。BUFR_pixel_clk_io/O と clk_fpga_0 を選んで、右向き→を選んで、Selected に移動した。
ZYBO_1_XGA_test_41_151219.png

Report CDC ダイアログの To も同様に、BUFR_pixel_clk_io/O と clk_fpga_0 を選択した。
ZYBO_1_XGA_test_42_151219.png

BUFR_pixel_clk_io/O から clk_fpga_0 は、unsafe が無いので問題ない。
但し、clk_fpga_0 から BUFR_pixel_clk_io/O は unsafe が 1 つあるので、修正の必要がありそだ。
ZYBO_1_XGA_test_43_151219.png

unsafe の 1 をクリックすると、CDC Details が表示された。
CDC-10 の Critical warning で、Combinatorial logic detected before a synchronizer だそうだ。
ZYBO_1_XGA_test_43_151219.png

BUFR_pixel_clk_io/O から clk_fpga_0 の CDC Details を下に示す。Warning のみだった。
ZYBO_1_XGA_test_47_151219.png

clk_fpga_0 から BUFR_pixel_clk_io/O の CDC Details をよく見るためにスプレッドシートのファイルを吐き出してもらう。

Timing - Report CDC 画面で右クリックし、右クリックメニューから Export to Spreadsheet... を選択した。
ZYBO_1_XGA_test_45_151219.png

Export Table to Spreadsheet ダイアログが表示された。File name を設定して、OKボタンをクリックした。
ZYBO_1_XGA_test_46_151219.png

スプレッドシートの内容を示す。
Severity ID Description Depth Exception Source (From) Destination (To) Category
Critical CDC-10 Combinatorial logic detected before a synchronizer 2 Asynch Clock Groups ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/cs_rdg_reg[0]/C ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/hv_cnt_ena_d1_reg/D No ASYNC_REG
Info CDC-6 Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/bitmap_afifo_inst/U0/inst_fifo_gen/gconvfifo.rf/grf.rf/gntv_or_sync_fifo.gcx.clkx/wr_pntr_gc_reg[7:0]/C ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/bitmap_afifo_inst/U0/inst_fifo_gen/gconvfifo.rf/grf.rf/gntv_or_sync_fifo.gcx.clkx/gsync_stage[1].rd_stg_inst/Q_reg_reg[7:0]/D Safe
Critical CDC-10 Combinatorial logic detected before a synchronizer 2 Asynch Clock Groups ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/cs_rdg_reg[0]/C ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/hv_cnt_ena_d1_reg/D Unsafe

  1. 2015年12月19日 19:01 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

set_clock_groups -asynchronous 制約

HDMI入力XGA表示回路3(インプリメント)”で、BUFR_pixel_clk_io/O と clk_fpga_0 の 2 つのクロック間の依存関係を set_false_path で無効にしていたが、set_clock_groups -asynchronous の方が良いという情報があった。

Vivado Design Suite ユーザー ガイド 制約の使用 UG903 (v2015.1) 2015 年 4 月 1 日”の 41 ページを見るとTiming Constraints Wizard の Asynchronous Clock Domain Crossing の図があって、その下に、以下のように書いてある。

どちらの方向のタイミングも無視するのが安全な場合 - set_clock_groups (-asynchronous)
一方向のパスを無視するのが安全な場合 - set_false_path


これを見ると、set_false_path でも、set_clock_groups (-asynchronous) でも同じ気がするが、”HDMI入力XGA表示回路3(インプリメント)”で設定した set_false_path を set_clock_groups -asynchronous に変更した。

やり方を示す。なお、set_false_path をコメントアウトした状態にしてある。

Implemented Design を開いて、Edit Timing Constraints をクリックする。

Timing Constraints タブが開く。

Clocks -> Set Clock Groups をクリックする。

Double click to create a Set Clock Groups constraint をダブルクリックする。
ZYBO_1_XGA_test_34_151217.png

Set Clock Groups ダイアログが立ち上がる。

Group name を pixel_clk2clk_fpga_0 に設定して、Group 1 に BUFR_pixel_clk_io/O を、Group 2 に clk_fpga_0 を指定して、OKボタンをクリックする。
ZYBO_1_XGA_test_35_151217.png

制約ファイルに、set_clock_groups (-asynchronous) 制約が設定された。

set_clock_groups -name pixel_clk2clk_fpga_0 -asynchronous -group [get_clocks [list [get_clocks -of_objects [get_pins ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]] -group [get_clocks clk_fpga_0]


制約をセーブして、再度、論理合成、インプリメント、ビットストリームの生成を行って成功した。制約は問題無いようだ。
  1. 2015年12月19日 18:45 |
  2. 制約
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 勉強会2(レジスタの挿入とPIPELINEディレクティブ)を公開しました

Vivado HLS 勉強会1(基礎編)を公開しました”の続きです。

Vivado HLS 勉強会2(レジスタの挿入とPIPELINEディレクティブ)”を公開しました。
今回は、ディレクティブを使って、入力、そして出力にレジスタを挿入して、PIPELINEディレクティブを入れてパイプライン化します。
次にPIPELINEディレクティブの応用として、rewind オプションを使ってディスプレイ・コントローラを実装してみます。

それでは、やってみた感想をお待ちしております。コメント欄でお知らせ下さい。

PIPELINEディレクティブの時のテストベンチを貼っておきます。

#include <string.h>
#include <ap_int.h>

void multi_apuint(ap_uint<8> multi_in0, ap_uint<8> multi_in1,
        ap_uint<16> *multi_out);

int main(){
    using namespace std;

    ap_uint<8> multi_in0;
    ap_uint<8> multi_in1;
    ap_uint<16> multi_out;

    for (multi_in0=0, multi_in1=1; multi_in0<10; multi_in0++, multi_in1++){
        multi_apuint(multi_in0, multi_in1, &multi_out);
        cout << "multi_out = " << multi_out << endl;
        if (multi_out != (multi_in0 * multi_in1))
            return(1);
    }

    return(0);
}


display_cont.cpp を貼っておきます。

// display_cont.cpp
// 2015/06/03 by marsee
//
// 画面を4分割した第1象限は赤、第2象限は緑、第3象限は青、第4象限は白を表示する
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

// SVGA 解像度
#define H_ACTIVE_VIDEO    800
#define H_FRONT_PORCH    40
#define H_SYNC_PULSE    128
#define H_BACK_PORCH    88
#define H_SUM            (H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH)

#define V_ACTIVE_VIDEO    600
#define V_FRONT_PORCH    1
#define V_SYNC_PULSE    4
#define V_BACK_PORCH    23
#define V_SUM            (V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH)

void display_cont_sub(ap_uint<8> *red, ap_uint<8> *green, ap_uint<8> *blue, ap_uint<1> *display_enable, ap_uint<1> *hsyncx, ap_uint<1> *vsyncx){
#pragma HLS INTERFACE ap_none register port=red
#pragma HLS INTERFACE ap_none register port=green
#pragma HLS INTERFACE ap_none register port=blue
#pragma HLS INTERFACE ap_none register port=display_enable
#pragma HLS INTERFACE ap_none register port=hsyncx
#pragma HLS INTERFACE ap_none register port=vsyncx
#pragma HLS INTERFACE ap_ctrl_hs port=return

    ap_uint<16> h_count, v_count;

    for (v_count=0; v_count<V_SUM; v_count++){
        for (h_count=0; h_count<H_SUM; h_count++){
#pragma HLS PIPELINE rewind
            if (h_count > (H_ACTIVE_VIDEO +H_FRONT_PORCH) && h_count < (H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE))
                *hsyncx = 0;
            else
                *hsyncx = 1;

            if (v_count > (V_ACTIVE_VIDEO + V_FRONT_PORCH) && v_count < (V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE))
                *vsyncx = 0;
            else
                *vsyncx = 1;

            if (h_count < H_ACTIVE_VIDEO && v_count < V_ACTIVE_VIDEO)
                *display_enable = 1;
            else
                *display_enable = 0;

            if (v_count < V_ACTIVE_VIDEO/2){
                if (h_count < H_ACTIVE_VIDEO/2){
                    *red=0xff; *green=0; *blue=0;
                } else if (h_count < H_ACTIVE_VIDEO){
                    *red=0; *green=0xff; *blue=0;
                } else {
                    *red=0; *green=0; *blue=0;
                }
            } else if (v_count < V_ACTIVE_VIDEO){
                if (h_count < H_ACTIVE_VIDEO/2){
                    *red=0; *green=0; *blue=0xff;
                } else if (h_count < H_ACTIVE_VIDEO){
                    *red=0xff; *green=0xff; *blue=0xff;
                } else {
                    *red=0; *green=0; *blue=0;
                }
            } else {
                *red=0; *green=0; *blue=0;
            }
        }
    }
}


display_cont_tb.cpp を貼っておきます。

//
// display_cont_tb.cpp
// 2015/06/03 by marsee
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

void display_cont_sub(ap_uint<8> *red, ap_uint<8> *green, ap_uint<8> *blue, ap_uint<1> *display_enable, ap_uint<1> *hsyncx, ap_uint<1> *vsyncx);
int main(){
    ap_uint<8> redb, *red;
    ap_uint<8> greenb, *green;
    ap_uint<8> blueb, *blue;
    ap_uint<1> deb, *display_enable;
    ap_uint<1> hb, *hsyncx;
    ap_uint<1> vb, *vsyncx;

    red = &redb;
    green = &greenb;
    blue = &blueb;
    display_enable = &deb;
    hsyncx = &hb;
    vsyncx = &vb;

    display_cont_sub(red, green, blue, display_enable, hsyncx, vsyncx);

    return 0;
}

  1. 2015年12月18日 00:51 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路4(実機で確認)

HDMI入力XGA表示回路3(インプリメント)”の続き。

前回は、HDMI 端子から入力したXGAの画像をDDR3 SDRAM のフレームバッファにバッファして、SVGAで表示する回路のビットストリームを生成する事ができた。今回は、SDKでソフトウェアを作製して、実機でテストを行う。

ハードウェアをエクスポートして、SDKを立ち上る。

Vivado の File メニューから Exprot -> Export Hardware... を選択した。

Export Hardware ダイアログが表示される。Include bitstream にチェックを入れて、OKボタンをクリックした。

File メニューから Launch SDKを選択した。

SDKが立ち上がった。
ZYBO_1_XGA_test_15_151214.png

Project name に hdmi_in_disp と入力した。Next > ボタンをクリックした。OS Platform は取りあえず、ベアメタル・アプリケーションとするので、デフォルトの standalone に設定した。
Board Support Package は Create New のラジオボタンをチェックして、BSPを新しく生成する。

hdmi_in_disp.c を新しく生成して、Cソースコードを書いて、オート・ビルドした。
ZYBO_1_XGA_test_16_151214.png

ZYBO を2台用意して、1台には、”並列ステレオカメラによる距離の測定9(Ubuntuで動作するアプリケーションを作る2)”を入れた。これをZYBO_0 とする。ZYBO_0 からのHDMI ケーブルを現在作製中のプロジェクトを入れるZYBO (これをZYBO_1 とする)のHDMI 端子に接続する。
ZYBO_0 は電源をONして、HDMI 端子にXGA 画面を出力するアプリケーションを起動した。
ZYBO_1 も電源をON した。下に、2つのZYBO を接続した写真を示す。HDMI ケーブルで2つのZYBO を接続しているが、現在はデバックのために、ZYBO_0 のHDMI 出力をディスプレイに接続している。
ZYBO_1_XGA_test_18_151216.jpg

ZYBO_0 の Xilinx Tools メニューからProgram FPGA を選択して、ZYBO のコンフィギュレーションを行った。
ZYBO_1_XGA_test_17_151216.png

hdmi_in_disp.c を右クリックし、右クリックメニューから Run AS -> Launch on Hardware (GDB) を選択して、ソフトウェアを起動した。
すぐに砂嵐状の画面がディスプレイに表示されたが、すぐに下の写真の様に変化した。それ以外は変化がなかった。
たぶん、1度はHDMI から入力された画像を表示しようとしたのだと思う。
ZYBO_1_XGA_test_19_151216.jpg

ZYBO_0 のHDMI 出力は信用出来ない可能性があるので、ノートパソコンのHDMI 出力でテストしてみようと思う。

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

/*
 * hdmi_in_disp.c
 *
 *  Created on: 2015/12/15
 *      Author: marsee
 */

#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    1024
#define VERTICAL_LINES        768
#define PIXEL_NUM_OF_BYTES    4

#define FRAME_BUFFER_ADDRESS 0x10000000

static XAxiVdma_DmaSetup Vdma0_WriteCfg;

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);
    }

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

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

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

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

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

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

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

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

    bmdc_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    bmdc_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 0 start

    return(0);
}

  1. 2015年12月16日 04:50 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路3(インプリメント)

HDMI入力XGA表示回路2(Vivado プロジェクトの作製)”の続き。

前回は、ZYBO_1_XGA_test ブロックデザインを作製したところまでだったので、今回は、論理合成、インプリメント、ビットストリームの生成を行う。

前回、Address Editor の図を貼っておくのを忘れていたので、貼っておく。
ZYBO_1_XGA_test_6_151213.png

最初に、ZYBO_1_XGA_test ブロックデザインを右クリックして、右クリックメニューからCreate HDL Wapper... を選択して、トップのVerilog HDL ファイルを生成した。
ZYBO_1_XGA_test_7_151214.png

論理合成を行って、Synthesized Design を立ちあげて、ZYBO_1_XGA_test.xdc を作製し、以前作ったプロジェクトからXDCファイルを持ってきて修正を行った。
ZYBO_1_XGA_test_8_151214.png

I/O Ports を表示して確かめてみた所、I/Oのピン番号の指定漏れは無いようだ。
ZYBO_1_XGA_test_9_151214.png

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

Implemented Design を開いて、Timing を見たところ、やはり、Inter-Clock Paths のBUFR_pixel_clk_io_n_0 と clk_fpga_0 間のパスがエラーだった。
ZYBO_1_XGA_test_11_151214.png

BUFR_pixel_clk_io_n_0 と clk_fpga_0 間のパスにFalse Path を設定した。
ZYBO_1_XGA_test_12_151214.png

これで、もう一度、論理合成、インプリメント、ビットストリームの生成を行った所、成功した。
ZYBO_1_XGA_test_13_151214.png

Summary を下に示す。
ZYBO_1_XGA_test_14_151214.png

最後にZYBO_1_XGA_test.xdc を貼っておく。

set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[0]}]
set_property PACKAGE_PIN J18 [get_ports {vga_blue[3]}]
set_property PACKAGE_PIN K19 [get_ports {vga_blue[2]}]
set_property PACKAGE_PIN M20 [get_ports {vga_blue[1]}]
set_property PACKAGE_PIN P20 [get_ports {vga_blue[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[4]}]
set_property PACKAGE_PIN G19 [get_ports {vga_blue[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[0]}]
set_property PACKAGE_PIN F20 [get_ports {vga_green[5]}]
set_property PACKAGE_PIN H20 [get_ports {vga_green[4]}]
set_property PACKAGE_PIN J19 [get_ports {vga_green[3]}]
set_property PACKAGE_PIN L19 [get_ports {vga_green[2]}]
set_property PACKAGE_PIN N20 [get_ports {vga_green[1]}]
set_property PACKAGE_PIN H18 [get_ports {vga_green[0]}]
set_property PACKAGE_PIN F19 [get_ports {vga_red[4]}]
set_property PACKAGE_PIN G20 [get_ports {vga_red[3]}]
set_property PACKAGE_PIN J20 [get_ports {vga_red[2]}]
set_property PACKAGE_PIN L20 [get_ports {vga_red[1]}]
set_property PACKAGE_PIN M19 [get_ports {vga_red[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports vga_hsync]
set_property IOSTANDARD LVCMOS33 [get_ports vga_vsync]
set_property PACKAGE_PIN P19 [get_ports vga_hsync]
set_property PACKAGE_PIN R19 [get_ports vga_vsync]

set_property PACKAGE_PIN H16 [get_ports TMDS_Clk_p]
set_property PACKAGE_PIN D19 [get_ports {TMDS_Data_p[0]}]
set_property PACKAGE_PIN C20 [get_ports {TMDS_Data_p[1]}]
set_property PACKAGE_PIN B19 [get_ports {TMDS_Data_p[2]}]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_Clk_p]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[0]}]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[1]}]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[2]}]

set_property PACKAGE_PIN G18 [get_ports ddc_sda_io]
set_property PACKAGE_PIN G17 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_hpd[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN E18 [get_ports {hdmi_hpd[0]}]
set_property PACKAGE_PIN F17 [get_ports {hdmi_out_en[0]}]


set_false_path -from [get_clocks [list [get_clocks -of_objects [get_pins ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]] -to [get_clocks clk_fpga_0]
set_false_path -from [get_clocks clk_fpga_0] -to [get_clocks [list [get_clocks -of_objects [get_pins ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]]

  1. 2015年12月15日 04:43 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路2(Vivado プロジェクトの作製)

HDMI入力XGA表示回路1(構想編)”の続き。

前回はHDMIから入力したSVGA画像をDDR3 SDRAMにバッファして、そこからディスプレイに表示するという構想を示した。今回は、実際にVivado 2015.4 のプロジェクトの作製を行う。

まずは、ZYBO_1_XGA_test というプロジェクトを作製した。
ZYBO_1_XGA_test_1_151213.png

DigilentInc/vivado-library を Download ZIPして、 dvi2rgb_v1_5 に必要な修正を加えた後で、ZYBO_1_XGA_test フォルダにコピーした。(”ZYBOのHDMI入力をVGA出力に出力する9(プロジェクトの公開)”を参照下さい)

ビットマップ・ディスプレイ・コントローラのBMDispCaL をZYBO_1_XGA_test フォルダにコピーした。
ZYBO_1_XGA_test_2_151213.png

コピーした dvi2rgb と ビットマップ・ディスプレイ・コントローラを IP Catalog に追加した。
ZYBO_1_XGA_test_3_151213.png

ZYBO_1_XGA_test ブロックデザインを生成して、回路を構成した。(ZYNQ PSのコンフィギュレーションはZYBOのXMLファイルをインポートした)
ZYBO_1_XGA_test_4_151213.png

ZYBO_1_XGA_test ブロックデザインをセーブした。
ZYBO_1_XGA_test_5_151213.png
  1. 2015年12月13日 07:53 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

”杉原千畝(映画)”を見てきました

杉原千畝(映画)”(音が出ます注意)を見てきました。
第2次世界大戦直前のヨーロッパは恐怖に支配されていたようですね。人々をすくった杉原千畝さん。良く決断されたと思います。映画、良かったです。
今もいろいろと紛争が絶えませんが、平和な世の中になれば良いですね。。。
  1. 2015年12月12日 21:24 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLSで幅の異なる ap_int の演算結果を検証してみた

Vivado HLS で幅の異なる ap_int の演算結果を検証してみた。

まずは、ハードウェア化されるC++ 言語の関数の apint_test.cpp を下に示す。

// apint_test.cpp
// 2015/12/12 by marsee
//

#include <stdio.h>
#include <ap_int.h>

int apint_test(ap_uint<8> inx[2], ap_int<12> wt[2], ap_int<25> *outy){

    *outy = inx[0]*wt[0] + inx[1]*wt[1];

    return(0);
}


次に、テストベンチの apint_test_tb.cpp を下に示す。

// apint_test_tb.cpp
// 2015/12/12 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ap_int.h>

#define DECIMAL_DIGITS    6    // 小数部の桁

int apint_test(ap_uint<8> inx[2], ap_int<12> wt[2], ap_int<25> *outy);

int main(){
    ap_uint<8> inx[2];
    ap_int<12> wt[2]; // 小数部 DECIMAL_DIGITS ビット
    ap_int<25> outy; // 小数部 DECIMAL_DIGITS ビット
    int outy_temp;
    int retval;

    inx[0] = 2;
    inx[1] = 1;

    wt[0] = (ap_int<12>)((float)(1.75)*(float)(pow(2,DECIMAL_DIGITS)));
    wt[1] = (ap_int<12>)((float)(-2.0)*(float)(pow(2,DECIMAL_DIGITS)));
    printf("wt[0] = %d\n", (int)wt[0]);
    printf("wt[1] = %d\n", (int)wt[1]);

    retval = apint_test(inx, wt, &outy);

    printf("outy(hex) = %x\n", (int)outy);
    printf("outy = %f\n", (float)outy/(float)pow(2,DECIMAL_DIGITS));

    return(retval);
}


つまり、1番目のap_uint<8> と 1番目のap_int<12> を掛け算して、2番目のap_uint<8> と 2番目のap_int<12> を掛け算して、それらを足し算して ap_int<25> に入れると正しく演算できるのか?、演算結果がマイナスでも正しく符号拡張してくれるのか?を確認したかった。
ap_int<12> は固定小数点数で、小数部が 6 ビット設定してあるので、整数部は7 ビット目からとなる。
演算結果の ap_int<25> も小数部が 6 ビットの固定小数点数となる。
まずは、2 * 1.75 + (-2) * 1 = 1.5 でやってみた。下に結果を示す。
apint_test_1_151212.png

正しく、

outy = 1.500000

と出力されている。

次に、2 * 1.75 + (-2) * 3 = -2.5 でやってみた。下に結果を示す。
apint_test_2_151212.png

正しく、

outy = -2.500000

と出力されている。

高位合成を行った。使用するFPGAは、ZYBOの xc7z010clg400-1 とした。
apint_test_3_151212.png

apint_test_4_151212.png

Latency は3 クロックだった。DSP48E を 2 個と FF を使用している。

Analysis 画面を示す。
apint_test_5_151212.png

C/RTL コシミュレーションをやってみた。
apint_test_6_151212.png

正しく、

outy = -2.500000

と出力されている。

Open Wave Viewer... ボタンをクリックすると、Vivado を立ちあげて波形を表示する。
apint_test_7_151212.png

波形を拡大した。
apint_test_8_151212.png

最後から 4 クロック前が演算スタートで、最後のクロックで、outy_V[24:0] に 0x1ffff60 が出力されている。

ap_uint、ap_int 同士のビット幅の異なる演算も問題なく処理されるようだ。
  1. 2015年12月12日 05:07 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 勉強会1(基礎編)を公開しました

Vivado HLS 勉強会資料の 1 番目の”Vivado HLS 勉強会1(基礎編)”を公開しました。

歌い文句は次の通りです。

Vivado HLS勉強会資料の最初です。
掛け算回路をC言語で書いてVivado HLSでIPにします。そのIPをVivadoでZYBO用にインプリメントして、スイッチとLEDを使って動作させます。
Vivado HLSを使う時の初めの1歩として、いかがでしょうか?


Vivado HLS 勉強会資料は、5つあります。タイトルを下に示します。
  1. Vivado HLS 勉強会1 (基礎編)
  2. Vivado HLS 勉強会2 (レジスタの挿入とPIPELINEディレクティブ)
  3. Vivado HLS 勉強会3 (AXI4-Lite Slave)
  4. Vivado HLS 勉強会4 (AXI4 Master)
  5. Vivado HLS 勉強会5 (AXI4 Stream)
全部で650枚位の分量があります。Vivado HLSの入門としては結構良いのではないでしょうか?

製作に数ヶ月かかった資料を無料で公開するのは、Vivado HLS を無料で公開してくれたXilinx社に敬意を表するとともに、私も普及に少しでもお手伝いできないか?と考えたのと、Vivado HLSを皆で使うことになれば、いろいろな情報が出てきて、私も恩恵を預かれるのでは?という思惑があります。皆さん、Vivado HLSによる制作物の公開をよろしくお願いします。それに、日本のFPGA産業の発展に少しでも貢献したいです。。。

いろいろなコメントも待っています。この記事のコメントとしてお願いします。

なお、後の 4 つのVivado HLS 勉強会資料も完成しているのですが、Vivado HLS 2014.4 用なので、Vivado HLS 2015.4 に変換してから公開いたします。資料が膨大なので、修正するのが大変です。修正でき次第公開しますので、気長にお待ちください。

それでは、Vivado HLS 勉強会1 (基礎編)で使用しているファイルをこのブログに貼っておきますので、使用してください。
最初に、multi_apuint.cpp から貼っておきます。

// multi_apuint.cpp

#include <ap_int.h>

void multi_apuint(ap_uint<8> multi_in0, ap_uint<8> multi_in1,
        ap_uint<16> *multi_out){
    *multi_out = multi_in0 * multi_in1;
}


次に、multi_apuint_tb.cpp です。

// multi_apuint_tb.c

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

int multi_apuint(ap_uint<8> multi_in0, ap_uint<8> multi_in1, ap_uint<16> *multi_out);

int main(){
    using namespace std;

    ap_uint<8> multi_in0;
    ap_uint<8> multi_in1;
    ap_uint<16> multi_out;

    multi_in0 = 10;
    multi_in1 = 10;
    multi_apuint(multi_in0, multi_in1, &multi_out);
    cout << "multi_out = " << multi_out << endl;

    if (multi_out == (multi_in0*multi_in1))
        return(0);
    else
        return(1);
}


multi_bd_wrapper.xdc を貼っておきます。

# multi_bd_wrapper.xdc
# 2015/07/02 by marsee
#

##Switches
##IO_L19N_T3_VREF_35 sw0
set_property PACKAGE_PIN G15 [get_ports {In0_1[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {In0_1[0]}]

##IO_L24P_T3_34 sw1
set_property PACKAGE_PIN P15 [get_ports {In0_1[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {In0_1[1]}]

##IO_L4N_T0_34 sw2
set_property PACKAGE_PIN W13 [get_ports {In0[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {In0[0]}]

##IO_L9P_T1_DQS_34 sw3
set_property PACKAGE_PIN T16 [get_ports {In0[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {In0[1]}]

##LEDs
##IO_L23P_T3_35 Dout[0]
set_property PACKAGE_PIN M14 [get_ports {Dout[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Dout[0]}]

##IO_L23N_T3_35 Dout[1]
set_property PACKAGE_PIN M15 [get_ports {Dout[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Dout[1]}]

##IO_0_35 Dout[2]
set_property PACKAGE_PIN G14 [get_ports {Dout[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Dout[2]}]

##IO_L3N_T0_DQS_AD1N_35 Dout[3]
set_property PACKAGE_PIN D18 [get_ports {Dout[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Dout[3]}]

set_switching_activity -signal_rate 1 -static_probability .99 [get_ports]

  1. 2015年12月11日 04:57 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

HDMI入力XGA表示回路1(構想編)

並列ステレオカメラによる距離の測定9(Ubuntuで動作するアプリケーションを作る2
並列ステレオカメラによる距離の測定10(Ubuntuで動作するアプリケーションを作る3)
で、ZYBO_0 はUbuntu 14.04 LTS からも制御できるようになって、完成した。次は、ZYBO_1 の方を作る。
なお、”並列ステレオカメラによる距離の測定1(ブロック図)”に書いたブロック図をもう一度示す。
StereoCam_1_151114.png

Camera Processing Unit の内部を示す。
StereoCam_2_151114.png

いきなり、ZYBO_1 を作っても大変なので、ZYBO_0 で作ったXGA のHDMI 信号をDDR3 SDRAM のフレームバッファに入れて、SVGA で表示できるかどうか?をテストしてみたい。そのブロック図を下に示す。
XGA_disp_1_151207.png

これから、ZYBO 2 台でテストしていくことになる。1歩1歩、着実に進めていきたい。
AXI VDMA のMM2S も動かして見たい。
  1. 2015年12月09日 22:45 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

並列ステレオカメラによる距離の測定10(Ubuntuで動作するアプリケーションを作る3)

並列ステレオカメラによる距離の測定9(Ubuntuで動作するアプリケーションを作る2)”の続き。

前回は、カメラ画像を表示するアプリケーションをUbuntu 14.04 LTS 上で作製した。できたと思っていたのだが、カメラ画像が1回しか書かれていなくて、連続して表示されていなかった。昨日修正したが、原因はフレームバッファの3フレーム目のスタートアドレスを書くレジスタ (0xB4) にアドレスを間違えて書いてなかったためだった。AXI VDMAは 3 面以上のフレームバッファを使用しないと連続して画像を書けない様だ。(S2MM の場合)

今回は、ZYBO のUbuntu 14.04 LTS 上で、ラプラシアンフィルタ処理してその表示を行う lap_fil_on_axis.c とラプラシアンフィルタ表示からカメラ表示に戻す cam_return_axis.c を貼っておく。どちらも動作した。

最初に、lap_fil_on_axis.c から貼っておく。

//
// lap_fil_on.c
// Created on: 2015/12/04
//      Author: marsee
//
// Refered to http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug902-vivado-high-level-synthesis.pdf
//

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

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

int main(){
    int fd2, fd3, fd4;
    volatile unsigned *axis_switch_0, *axis_switch_1;
    volatile unsigned *lap_filter_axis_0;
    int laps_cntrl;

    // 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);
    }
    
    // lap_filter_axis_0 (UIO4)
    fd4 = open("/dev/uio4", O_RDWR); // lap_filter_axis_0 interface AXI4 Lite Slave
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (lap_filter_axis_0) open error\n");
        exit(-1);
    }
    lap_filter_axis_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!lap_filter_axis_0){
        fprintf(stderr, "lap_filter_axis_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1, 1to2 ,Select M01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x80000000// 0x40 = 0x80000000; disable
    axis_switch_1[17] = 0// 0x44 = 0;
    axis_switch_1[0] = 0x2// 0x0 = 2; Commit registers
    
    // laplacian filter AXIS Start
    laps_cntrl = lap_filter_axis_0[0] & 0x80// Auto Restart bit
    lap_filter_axis_0[0] = laps_cntrl | 0x01// Start bit set
    lap_filter_axis_0[0] = 0x80// Auto Restart bit set
    
    // axis_switch_0, 2to1, Select S01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x1// 0x40 = 0x1;
    axis_switch_0[0] = 0x2// 0x0 = 2; Commit registers
    
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)lap_filter_axis_0, 0x10000);
    
    return(0);
}


次に、cam_return_axis.c を貼っておく。

//
// cam_return.c
// Created on: 2014/11/22
//      Author: Masaaki
//

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

int main(){
    int fd2, fd3, fd4;
    volatile unsigned *axis_switch_0, *axis_switch_1;
    volatile unsigned *lap_filter_axis_0;

    // 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);
    }

    // lap_filter_axis_0 (UIO4)
    fd4 = open("/dev/uio4", O_RDWR); // lap_filter_axis_0 interface AXI4 Lite Slave
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (lap_filter_axis_0) open error\n");
        exit(-1);
    }
    lap_filter_axis_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!lap_filter_axis_0){
        fprintf(stderr, "lap_filter_axis_0 mmap error\n");
        exit(-1);
    }

    // axis_switch_1, 1to2 ,Select M01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0// 0x44 = 0;
    axis_switch_1[17] = 0x80000000// 0x40 = 0x80000000; disable
    axis_switch_1[0] = 0x2// 0x0 = 2; Commit registers
    
    // laplacian filter AXIS Start
    lap_filter_axis_0[0] = 0x00// Auto Restart Disable
    
    // axis_switch_0, 2to1, Select S01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x0// 0x40 = 0x0;
    axis_switch_0[0] = 0x2// 0x0 = 2; Commit registers
    
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)lap_filter_axis_0, 0x10000);
}

  1. 2015年12月07日 04:53 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

SlideShare の Vivado and zybo linux勉強会資料を更新しました

yama さんから Vivado and zybo linux勉強会資料の更新情報を頂いたので、SlideShare の Vivado and zybo linux勉強会資料2Vivado and zybo linux勉強会資料3 を更新しました。

元の情報は、”Vivado and ZYBO Linux勉強会を開催”にあります。

yama さん、Shin さん情報ありがとうございました。この場で、お礼をさせて頂きたいと思います。

これからもいろいろな情報がありましたら、当該記事にコメントとしてお知らせ下さい。よろしくお願いします。

私もテストして更新が確認できたら資料を変更して、アップデートしようと思っています。

2015/12/06 にもう一度更新しました。
uioがShinさんの報告通りに入らなかったので、Shinさんの方法を本文に追加させて頂きました。更に、yamaさんの報告にあったとおりに、ZYBOのUbuntu 12.10の/sys/devicesの下のuioのディレクトリ位置が変わっていたので変更しました。
  1. 2015年12月07日 03:41 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLSのI/Oプロトコル(ブロックレベルとポートレベル)

Vivado HLS 2015.4 から、WebPACKでもVivado HLS が使えるようになり、高位合成を使おうという機運が盛り上がっていると思います。Xiliinx社さんのご英断に感謝致します。

今日は、Vivado HLS のI/O プロトコルにに付いて書いてみたいと思います。
ソフトウェアの C、C++ がHDL 、つまりハードウェアになるので、時間の概念が入ってきます。つまり、ソフトウェアは関数コールで関数を呼び出して実行させますが、ハードウェアはそこに回路の実体ができちゃってます。つまり関数をコールする、しないにかかわらず、いつもお仕事をできる、しちゃえる状態にあるわけです。その回路を何らかの条件で始まりを指示する必要あります。つまり、C の関数の引数の信号線だけではなく、追加の信号も必要になるということです。
これらの信号は、Vivado HLS でHDL へ変換する過程で付加されます。ですので、C をVivado HLS で高位合成して、HDL を見ると見慣れない余計な信号があるのが見えると思います。

例えば、次のCソースコードをVivado HLS 2015.4 で高位合成してみましょう。(合成と書こうと思いましたが、Xilinx社のマニュアルで高位合成と書いてあるので、ここでも高位合成とします)

// marsee_example2.c
// 2015/12/06 by marsee
// 掛け算サンプル
//

int marsee_example1(int multi_in0, int multi_in1, int *multi_out){
    *multi_out = multi_in0 * multi_in1;
    return 0;
}


marsee_example2.c を高位合成してみました。
Vivado_HLS_IO_Protcol_1_151206.png

Clock の ap_clk はクロック周期の制約が 10 ns に対して、6.08 ns になったということです。約 164 MHz ですね。
掛け算回路のレイテンシは 5 クロックで、インターバルは 6 クロックという結果が出ました。
右のウインドウを見ると、solution1 フォルダの syn フォルダに verilg フォルダができていて、そこに、marsee_example1.v と marsee_example1_mul_32s_32s_32_6.v ができていました。
Vivado_HLS_IO_Protcol_2_151206.png

marsee_example1.v がトップファイルなので、その宣言部を見てみましょう。下に示します。

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2015.4
// Copyright (C) 2015 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="marsee_example1,hls_ip_2015_4,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=6.080000,HLS_SYN_LAT=5,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=4,HLS_SYN_FF=6,HLS_SYN_LUT=1}" *)

module marsee_example1 (
        ap_clk,
        ap_rst,
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        multi_in0,
        multi_in1,
        multi_out,
        multi_out_ap_vld,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;parameter    ap_const_logic_0 = 1'b0;
parameter    ap_ST_st1_fsm_0 = 6'b1;parameter    ap_ST_st2_fsm_1 = 6'b10;
parameter    ap_ST_st3_fsm_2 = 6'b100;parameter    ap_ST_st4_fsm_3 = 6'b1000;
parameter    ap_ST_st5_fsm_4 = 6'b10000;parameter    ap_ST_st6_fsm_5 = 6'b100000;
parameter    ap_const_lv32_0 = 32'b00000000000000000000000000000000;parameter    ap_const_lv1_1 = 1'b1;
parameter    ap_const_lv32_5 = 32'b101;parameter    ap_true = 1'b1;

input   ap_clk;
input   ap_rst;
input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [31:0] multi_in0;
input  [31:0] multi_in1;
output  [31:0] multi_out;
output   multi_out_ap_vld;
output  [31:0] ap_return;


Cソースコードでは、example_marsee() の引数はmulti_in0, multi_in1, *multi_out のみでしたが、ap_clk, ap_rst, ap_done, ap_ready, multi_out_ap_vld, ap_return が増えていまます。
ちなみに、Vivado HLS では、値渡しの引数は入力信号、参照渡しの引数は入力信号、出力信号、または入力信号と出力信号の両方に合成されます。
ap_clk, ap_rst, ap_done, ap_ready, ap_return の信号は回路ブロックの、つまりブロック・レベルのインターフェース・プロトコルの信号です。これは冒頭に書いたようにC 関数の引数以外のハードウェアの回路にするのに必要なハンドシェークの信号です。
multi_out_ap_vld だけが、ポート・レベルのインターフェース・プロトコルの信号です。ポート(C 関数の引数はハードウェア(HDL) に合成した場合はポートになります)を考えてみましょう。ポートでは、ソフトウェアと違って、値が用意されて渡されるわけではありません。ポートという実体が常に存在しています。ですから、いつから信号が有効であるのかを示す必要があります。それが、multi_out_ap_vld です。
高位合成結果でレイテンシが 5 クロックという結果でしたが、これは入力を入れてから掛け算出力が出るまでに 5 クロック掛かるという意味でした。multi_in0 と multi_in1 の正しい掛け算の値が multi_out に出力された時に、multi_out_ap_vld は 1 になります。つまり、掛け算の出来上がりを知らせる信号です。
入力の multi_in0 と multi_in1 にはポート・レベルのインターフェース・プロトコル信号が付いていませんが、これは演算の間、値を保持することになります。
インターフェース・プロトコルには名前が付いていて、今回のブロック・レベルのインターフェース・プロトコル信号は ap_ctrl_hs で、multi_in0, multi_in1 は ap_none、multi_out は ap_vld です。

実際の掛け算回路動作を C/RTL コシミュレーションで表示してみましょう。
テストベンチを作製します。marsee_example2_tb.c という名前にしました。下に示します。

// marsee_example_tb.c
// 2015/12/06 by marsee
//

#include <stdio.h>
#include <stdlib.h>

int marsee_example1(int multi_in0, int multi_in1, int *multi_out);

int main(){
    int multi_in0, multi_in1, multi_out;
    int ret_val;

    multi_in0 = 2; multi_in1 = 3;
    ret_val = marsee_example1(multi_in0, multi_in1, &multi_out);
    printf("multi_out = %d\n", multi_out);

    return(ret_val);
}


C/RTL コシミュレーションの結果を下に示します。
Vivado_HLS_IO_Protcol_3_151206.png

下のウインドウに multi_out = 6 が表示されています。
C/RTL コシミュレーションの結果の波形をVivado で見ることができるので、見てみましょう。これです。
Vivado_HLS_IO_Protcol_4_151206.png

ap_start が 1 にアサートされて、掛け算が始まり、同時に ap_idle が 0 になっているのが分かります。同時に multi_in0 には 2 が、multi_in1 には 3 が入力されています。掛け算の値 6 が multi_out に出力されると multi_out_ap_vld, ap_done が 1 になります。ap_return にも、戻り値の 0 がセットされます。

このようにソフトウェアからハードウェアになると、プロトコル信号が必要となる場合があります。いろいろな回路上の都合からデータを受け取れない場合、データを受け取ったけど演算に時間がかかり、すぐに正しい結果を出力できない場合はインターフェース・プロトコル信号を付加して、ハンドシェークする必要があります。

ブロック・レベル、ポート・レベルのインターフェース・プロトコル信号については、高位合成(UG902) V2015.3 日本語版 2015/09/30 の 133 ページを御覧下さい。
  1. 2015年12月06日 04:16 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:2

並列ステレオカメラによる距離の測定9(Ubuntuで動作するアプリケーションを作る2)

並列ステレオカメラによる距離の測定8(Ubuntuで動作するアプリケーションを作る1)”の続き。

AXI VDMAのドライバによるレジスタの設定値(S2MMの設定)”で、フレームバッファを 3 面分用意した時のAXI VDMA の設定値を確認することができた。

次は、ZYBO 上で動作するUbuntu 14.04 LTS 上でUIO ドライバを使用してカメラ画像を表示できる用にソフトウェアを書くことにする。

Xming を起動して、ZYBO のTera Term から、gedit cam_disp_vdma.c & を起動してパソコン上にgedit ウインドウを起動して編集を行う。(自分のパソコン上のウインドウでZYBO のファイルの編集ができるのでとっても便利ですよ)
StereoCam_126_151203.png

gcc cam_disp_vdam.c でコンパイルして、./a.out で起動したが、

/dev/uio6 (bitmap_disp_cntrler_axi_master_0) open error

で動作しなかった。

そう言えば、/dev/uio* のパーミッションを変更するんだった。ということで、cd /dev して、ls -l uio* を行うとやはり、全部の uio のパーミッションを 666 にできていなかった。
sudo chmod 666 uio* ですべての uio のパーミッションを 666 に変更した。
StereoCam_125_151203.png 

mv a.out cam_disp_vdma で名前を変更してから、./cam_disp_vdma で起動すると、見事、ディスプレイにカメラ画像が表示されました。(とっても嬉しい~~~です。。。良かった。。。)
StereoCam_127_151203.png 

StereoCam_94_151123.jpg

cam_disp_vdma.c を貼っておく。

//
// cam_disp_vdma.c
// Created on: 2015/12/03
//      Author: marsee
//

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

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

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.
#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

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();
}

int main()
{
    int i, j, k;
    int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9;
    volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
    volatile unsigned *axi_vdma_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;

    // 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);
    }
    bmdc_axi_lites0[0] = VIDEO_BUFFER_START_ADDRESS; // Bitmap Display 1 Controller start
    
    // 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);
    }
    bmdc_axi_lites1[0] = VIDEO_BUFFER_START_ADDRESS; // Bitmap Display Controller start

    // axi_vdma_0 (UIO1)
    fd1 = open("/dev/uio1", O_RDWR); // axi_vdma_0 interface AXI4 Lite Slave
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (axi_vdma_0) open error\n");
        exit(-1);
    }
    axi_vdma_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!axi_vdma_0){
        fprintf(stderr, "axi_vdma_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);
    }
    
    // frame_buffer_bmdc UIO9
    fd9 = open("/dev/uio9", O_RDWR); // frame_buffer_bmdc
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio9 (frame_buffer_bmdc) open error\n");
        exit(-1);
    }
    frame_buffer_bmdc = (volatile unsigned *)mmap(NULL, 0x1000000, 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[0] = 0x2// Comit registers
    
    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x0// 0x40 = 0;
    axis_switch_0[0] = 0x2// Comit registers
    
    // AXI VDMA Initialization sequence
    axi_vdma_0[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4 
    while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_0[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4 
    while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_0[18] = 0x3// S2MM_FRMSTORE (0x48) register
    axi_vdma_0[12] = 0x00010002// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1)
    axi_vdma_0[41] = 0xc80; // S2MM Horizontal Size Register(S2MM_HSIZE)0xc80 = 3200dec = 800 x 4
    axi_vdma_0[42] = 0xc80; // S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)0xc80 = 3200dec = 800 x 4
    axi_vdma_0[43] = VIDEO_BUFFER_START_ADDRESS; // S2MM Start Address (1 to 16) Start Address 1
    axi_vdma_0[44] = VIDEO_BUFFER_START_ADDRESS+ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 2
    axi_vdma_0[45] = VIDEO_BUFFER_START_ADDRESS+2*ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 3
    axi_vdma_0[12] = 0x00010003// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1, Run/stop = 1)
    while((axi_vdma_0[13] & 0x1) == 0x1) ; // Halt? (S2MM_VDMASR 0x34)
    axi_vdma_0[40] = 0x258// S2MM Vertical Size (S2MM_VSIZE  Offset 0xA0) 0x258 = 600dec

    bmdc_axi_lites0[0] = (volatile unsigned int)VIDEO_BUFFER_START_ADDRESS; // Bitmap Display Controller 0 start
    bmdc_axi_lites1[0] = (volatile unsigned int)VIDEO_BUFFER_START_ADDRESS; // Bitmap Display Controller 1 start
    mt9d111_inf_axis_0[0] = (volatile unsigned int)VIDEO_BUFFER_START_ADDRESS; // 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;
    
    munmap((void *)bmdc_axi_lites0, 0x10000);
    munmap((void *)bmdc_axi_lites1, 0x10000);
    munmap((void *)axi_vdma_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, 0x1000000);
    
    return(0);
}

  1. 2015年12月03日 05:24 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0
»