FC2カウンター FPGAの部屋 AXI4-Stream 出力 xf_8uc3_2axis IP を Vitis HLS 2020.2 で作成する1
fc2ブログ

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

FPGAの部屋

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

AXI4-Stream 出力 xf_8uc3_2axis IP を Vitis HLS 2020.2 で作成する1

AXI4-Stream の IP を使用して Vitis Vision Library で加工されたデータをディスプレイに表示する1(構想編)”で構想したように、DMA Write 出力 xf_8uc3_2rgb IP を AXI4-Stream 出力 xf_8uc3_2axis IP に変更したい。
そこで、今回は、AXI4-Stream 出力 xf_8uc3_2axis IP を作成しよう。

XF_8UC3 を XF_8UC4 に変換する xf_8uc3_2rgb プロジェクトを作成する1”のソースコードやテストベンチ・コードを元に、出力を AXI4-Stream インターフェースに変更するのだ。しかし、よく見ると途中は AXI4-Stream になっているので、axis2dmaw() を外せば良いようだ。

(2021/04/16:修正)出力の axis_out をサイドチャネル付き AXI4-Stream に変更した。

ソースコードの xf_8uc3_2axis.cpp を示す。

// xf_8uc3_2axis.cpp
// 2021/04/13 by marsee
//

#include "ap_int.h"
#include "hls_stream.h"
#include "ap_axi_sdata.h"

int dmar2axis(volatile ap_uint<32>* _src, int rows, int cols, hls::stream<ap_uint<32> >& axis_out);
int xf_8uc3s_2axis(hls::stream<ap_uint<32> >& axis_in, int rows, int cols, hls::stream<ap_axis<32,1,1,1> >& axis_out);

//#define DEBUG

int xf_8uc3_2axis(volatile ap_uint<32>* _src, int rows, int cols, hls::stream<ap_axis<32,1,1,1> >& axis_out){
#pragma HLS INTERFACE axis register_mode=both register port=axis_out
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE m_axi depth=360000 bundle=gmem port=_src offset=slave
#pragma HLS INTERFACE s_axilite port=return

    hls::stream<ap_uint<32> > axis0;

    dmar2axis(_src, rows, cols, axis0);
    xf_8uc3s_2axis(axis0, rows, cols, axis_out);

    return(0);
}

int dmar2axis(volatile ap_uint<32>* _src, int rows, int cols, hls::stream<ap_uint<32> >& axis_out){
    const int rows_cols_limit = (int)((float)rows * (float)cols * 3.0/4.0 + 0.76);
    ap_uint<32>  pix;
    //printf("rows_cols_limit = %d\n",rows_cols_limit);

    LOOP_dr2a: for(int xy=0; xy<rows_cols_limit; xy++){
#pragma HLS PIPELINE II=1
#pragma HLS LOOP_TRIPCOUNT avg=360000 max=360000 min=360000
        pix = _src[xy];

#ifdef DEBUG
        if(xy < 10)
            printf("%x\n", (unsigned int)pix);
#endif

        axis_out << pix;
    }
    return(0);
}

int xf_8uc3s_2axis(hls::stream<ap_uint<32> >& axis_in, int rows, int cols, hls::stream<ap_axis<32,1,1,1> >& axis_out){
    ap_uint<32> rgb[3];
    ap_axis<32,1,1,1> pix;

    LOOP_y:for(int y=0; y<rows; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=600 min=600
        LOOP_x:for(int x=0; x<cols; x++){
#pragma HLS PIPELINE II=1
#pragma HLS LOOP_TRIPCOUNT avg=800 max=800 min=800
            int xy = x + y * cols;
            switch(xy%4){
            case 0 :
                axis_in >> rgb[0];
                pix.data = (rgb[0] & 0xffffff) + 0xff000000;
                break;
            case 1 :
                axis_in >> rgb[1];
                pix.data = ((rgb[1] & 0xffff)<<8) + ((rgb[0] & 0xff000000)>>24) + 0xff000000;
                break;
            case 2 :
                axis_in >> rgb[2];
                pix.data = ((rgb[2] & 0xff)<<16) + ((rgb[1] & 0xffff0000)>>16) + 0xff000000;
                break;
            default : // 3
                pix.data = ((rgb[2] & 0xffffff00)>>8) + 0xff000000;
                break;
            }
            if(x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;
            if(x == cols-1)
                pix.last = 1;
            else
                pix.last = 0;
            axis_out << pix;
        }
    }
    return(0);
}


テストベンチ・コードの xf_8uc3_2axis_tb.cpp を示す。

// xf_8uc3_2axis_tb.cpp
// 2021/04/13 by marsee
//

#include "ap_int.h"
#include "hls_stream.h"
#include "ap_axi_sdata.h"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"

int xf_8uc3_2axis(volatile ap_uint<32>* _src, int rows, int cols, hls::stream<ap_axis<32,1,1,1> >& axis_out);

int main(int argc, char **argv){
    hls::stream<ap_axis<32,1,1,1> > axis_out;
    ap_uint<32> *pp;
    ap_axis<32,1,1,1> pix;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <INPUT IMAGE>", argv[0]);
        exit(1);
    }

    cv::Mat in_img, out_img, conv_img;

    in_img = cv::imread(argv[1], 1); // reading in the color image

    if (in_img.data == NULL) {
        fprintf(stderr, "ERROR: Cannot open image %s\n ", argv[1]);
        exit(1);
    }

    out_img.create(in_img.rows, in_img.cols, CV_8UC4);
    conv_img.create(in_img.rows, in_img.cols, CV_8UC3);

    xf_8uc3_2axis((volatile ap_uint<32> *)in_img.data, in_img.rows, in_img.cols, axis_out);

    pp = (ap_uint<32> *)out_img.data;
    for(int y=0; y<in_img.rows; y++){
        for(int x=0; x<in_img.cols; x++){
            axis_out >> pix;
            *pp++ = pix.data;
        }
    }
    cv::cvtColor(out_img, conv_img, cv::COLOR_BGRA2BGR);

    cv::imwrite("output.png", conv_img);

    return(0);
}


なお、このテストベンチ・コードを実行するためには、OpenCV を自分でインストールする必要がある。(”Ubuntu 18.04 LTS のパソコンに OpenCV 3.4.9 をインストールする”参照)

Vitis HLS 2020.2 で ZYBO Z7-20 用の xf_8uc3_2axis プロジェクトを作成した。
Vitis_Vision_disp_3_210415.png

OpenCV を利用するために設定を行っている。(”XF_8UC3 を XF_8UC4 に変換する xf_8uc3_2rgb プロジェクトを作成する2”参照)
Project メニューから Project Settings... を選択して、ダイアログを表示させる。
Simulation をクリックして、 CFLAGS にインストール済みの OpenCV のインクルード・パスを入力する。

-I/usr/local/include


Linker Flagに

-L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc


を入力する。
Input Argument に画像のファイル名

test2.jpg


を入力する。
Vitis_Vision_disp_4_210415.png

もう 1 つ設定を行った。
ZYBO Z7-20 なので、アドレスは 32 ビットとなる。Vitis HLS の AXI4-Master アクセスのデフォルトは 64 ビット・アドレスなので、これを変更する。
Vitis HLS 2020.2 の Solution メニューから Solution Settings... を選択する。
Solution Settings (solution1) ダイアログが開く。
左のペインで General をクリックして、 config_interface を開く。
m_axi_addr64 のチェックを外す。
Vitis_Vision_disp_5_210415.png
  1. 2021年04月15日 04:19 |
  2. Vitis HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/5207-82ea46ef
この記事にトラックバックする(FC2ブログユーザー)