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

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

FPGAの部屋

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

RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成する3

RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成する2”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成することにした。前回は、C シミュレーションと C コードの合成を行った。今回は、 C/RTL 協調シミュレーションを行って、Export RTL で IP 化して、 Implementation を行った。

C/RTL 協調シミュレーションを行った。結果を示す。
gaussian_kv260_11_211028.png

Avg II, Max II, Min II は 921655 クロックだった。
Avg Latency は 921610 クロック、 Max Latency は 921613 クロック、 Min Latency は 921608 クロックだった。

C/RTL 協調シミュレーションの波形を示す。
gaussian_kv260_12_211028.png

ins_TREADY 、 outs_TVALID 共にずっと 1 となっている。

Export RTL を行った。
gaussian_filter_axis_RBG/solution1/impl ディレクトリに export.zip が生成されている。これは、 IP を圧縮したファイルだ。
gaussian_kv260_13_211031.png

Implementation を行った。
結果を示す。
gaussian_kv260_14_211031.png

Resource Usage は LUT が 432 個、 FF が 561 個、 BRAM が 6 個、 CLB が 11 個だった。 DSP は 0 個だった。乗算は 2 倍と 4 倍だったので、シフトで済むからだろうか?

CP achieved post-implementation は 5.365 ns だった。

その他の Implementation の結果を示す。
gaussian_kv260_15_211031.png
gaussian_kv260_16_211031.png
gaussian_kv260_17_211031.png
  1. 2021年10月31日 04:22 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成する2

RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成する1”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成することにした。前回は、ガウシアン・フィルタのソースコードを貼って、 Vitis HLS 2021.1 で gaussian_filter_axis_RBG プロジェクトを作成した。今回は、 C シミュレーションと C コードの合成を行った。

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

gaussian_filter_axis_RBG/solution1/csim/build ディレクトリの org.jpg を示す。これが元画像だ。
gaussian_kv260_6_211028.jpg

同じディレクトリの gaussian.jpg を示す。これがガウシアン・フィルタを通した画像だ。
gaussian_kv260_7_211028.jpg

ノイズが軽減されているのが分かる。でもメディアン・フィルタほどのノイズ低減効果はない。

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

LOOP_WAIT _USER と LOOP_Y_LOOP_X の Interval が 1 クロックであることが分かる。

gaussian_kv260_9_211028.png
gaussian_kv260_10_211028.png

C/RTL 協調シミュレーションは時間がかかっているので、次回にしよう。
  1. 2021年10月30日 05:21 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

Vivado ML 2021.2 がでています

Vivado ML 2021.2 が昨日でました。
US のダウンロード・ページにはありますが、日本のダウンロード・ページにはまだ無いようです。
(追記)日本のダウンロード・ページでもでてきました。

Ubuntu 18.04 LTS に Vivado ML 2021.2 のインストールを初めました。
現在のダウンロード・スピードは 6 MB/sec で後 2 h 47 m です。

Vivado® ML 2021.2 の新機能と拡張機能の詳細です。
  1. 2021年10月29日 04:45 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成する1

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のガウシアン・フィルタを Vitis HLS 2021.1 で作成することにした。今回は、ガウシアン・フィルタのソースコードを貼って、 Vitis HLS 2021.1 で gaussian_filter_axis_RBG プロジェクトを作成した。

最初にガウシアン・フィルタの原理については”ガウシンアンフィルタ - ノイズの除去”を参考にした。
C++ で関数に 2 次元配列を渡す方法は”C++ で 2 次元配列を関数に渡す方法”を参考にした。

まずは、ヘッダファイルの gaussian_filter_axis_RBG.h を貼る。

// gaussian_filter_axis_RBG.h
// 2021/10/27 by marsee
//

#ifndef __GAUSSIAN_FILTER_AXIS_RBG10_H__
#define __GAUSSIAN_FILTER_AXIS_RBG10_H__

#define HORIZONTAL 0
#define VERTICAL 1

#define HD_720

#ifdef HD_RES
#define DISPLAY_WIDTH 1920
#define DISPLAY_HIGHT 1080
#endif

#ifdef HD_720
#define DISPLAY_WIDTH 1280
#define DISPLAY_HIGHT 720
#endif

#ifdef SVGA_RES
#define DISPLAY_WIDTH 800
#define DISPLAY_HIGHT 600
#endif

#ifdef SMALL_RES
#define DISPLAY_WIDTH 64
#define DISPLAY_HIGHT 48
#endif

#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define ORIGINAL_IMAGE 0
#define GAUSSIAN_FILTER 1

#endif


ソースコードの gaussian_filter_RBG10.cpp を貼っておく。

// gaussian_filter_RBG10.cpp
// 2021/10/27 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "gaussian_filter_axis_RBG.h"

constexpr int size = 3;

void gaussian_fil(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result);
ap_int<32> gaussian_fil_calc(ap_int<32> *pixd);
ap_int<32> separate_rbg(ap_int<32> rbg, ap_int<32> &r, ap_int<32> &b, ap_int<32> &g);

int gaussian_filter_axis(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int function){
#pragma HLS INTERFACE s_axilite port=function
#pragma HLS INTERFACE axis register_mode=both register port=outs
#pragma HLS INTERFACE axis register_mode=both register port=ins
#pragma HLS INTERFACE s_axilite port=return

    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> gaussian;
    ap_uint<24> val;

    ap_int<32> line_buf[2][DISPLAY_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    ap_int<32> pix_mat[size][size];
#pragma HLS array_partition variable=pix_mat complete

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

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

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = pix.data;
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            gaussian_fil(pix_mat, val);
            gaussian.data = val;

            if(x<2 || y<2)
                gaussian.data = 0;

            if(x==0 && y==0) // 最初のピクセル
                gaussian.user = 1;
            else
                gaussian.user = 0;
            if(x == (DISPLAY_WIDTH-1)) // 行の最後
                gaussian.last = 1;
            else
                gaussian.last = 0;

            if(function == GAUSSIAN_FILTER)
                outs << gaussian;
            else
                outs << pix;
        }
    }
    return(0);
}

// gaussian filter
// 
// x0y0 x1y0 x2y0  1/16  2/16  1/16
// x0y1 x1y1 x2y1  2/16  4/16  2/16
// x0y2 x1y2 x2y2  1/16  2/16  1/16
//
void gaussian_fil(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result){
    ap_int<32> pix_1d_r[9], pix_1d_b[9], pix_1d_g[9];
    ap_int<32> y_r, y_b, y_g, y;

    for(int i=0; i<9; i++){
        separate_rbg(pix_mat[i/3][i%3], pix_1d_r[i], pix_1d_b[i], pix_1d_g[i]);
    }

    y_r = gaussian_fil_calc(pix_1d_r);
    y_b = gaussian_fil_calc(pix_1d_b);
    y_g = gaussian_fil_calc(pix_1d_g);

    result = (y_r << 16) + (y_b << 8) + y_g;
}

// gaussian_fil_calc
ap_int<32> gaussian_fil_calc(ap_int<32> *pixd){
    ap_int<32> y;

    y = pixd[0] + 2 * pixd[1] + pixd[2] + 2 * pixd[3] + 4 * pixd[4] + 2 * pixd[5] + pixd[6] + 2 * pixd[7] + pixd[8];
    y = y / 16;

    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255) // 8 bits
        y = 255;
    return(y);
}

// separate_rbg
// RGBを分離する
// RBGのフォーマットは、{R(8bits), B(8bits), G(8bits)}, 1pixel = 32bits
// 
ap_int<32> separate_rbg(ap_int<32> rbg, ap_int<32> &r, ap_int<32> &b, ap_int<32> &g){
    b = (rbg>>8) & 0xff;
    g = rbg & 0xff;
    r = (rbg>>16) & 0xff;
    return(0);
}


テストベンチ・コードの gaussian_filter_axis_RBG_tb.cpp を貼っておく。

// gaussian_filter_axis_RBG_tb.cpp
// 2021/10/19 by marsee
//

#include <stdio.h>
#include <stdint.h>
#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"

#include "gaussian_filter_axis_RBG.h"

int gaussian_filter_axis(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs, int function);
int gaussian_filter_axis_soft(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int function);
ap_int<32> gaussian_fil_soft(ap_int<32> *pix_1d);
ap_int<32> gaussian_fil_calc_soft(ap_int<32> *pixd);
ap_int<32> separate_rbg_soft(ap_int<32> rbg, ap_int<32> &r, ap_int<32> &b, ap_int<32> &g);

const char INPUT_JPG_FILE[] = "test2.jpg";
const char OUTPUT_JPG_FILE[] = "gaussian.jpg";
const char ORG_OUT_JPG_FILE[] = "org.jpg";

int main(){
    hls::stream<ap_axiu<24,1,1,1> > ins, ins2;
    hls::stream<ap_axiu<24,1,1,1> > ins_soft;
    hls::stream<ap_axiu<24,1,1,1> > outs, outs2;
    hls::stream<ap_axiu<24,1,1,1> > outs_soft;
    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> vals, vals_soft;

    // JPG ファイルをMat に読み込む
    cv::Mat img = cv::imread(INPUT_JPG_FILE);

    // ピクセルを入れる領域の確保
    std::vector<int32_t> rd_bmp(sizeof(int32_t)*img.cols*img.rows);
    std::vector<int32_t> hw_gaussian(sizeof(int32_t)*(img.cols)*(img.rows));
    std::vector<int32_t> sw_gaussian(sizeof(int32_t)*(img.cols)*(img.rows));

    // rd_bmp にJPGのピクセルを代入
    cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
    for (int y=0; y<img.rows; y++){
        for (int x=0; x<img.cols; x++){
            cv::Vec3b pixel;
            pixel = dst_vec3b(y,x);
            rd_bmp[y*img.cols+x] = (pixel[1] & 0xff) | ((pixel[0] & 0xff)<<8) | ((pixel[2] & 0xff)<<16); // RBG 8 bits
            // blue - pixel[0]; green - pixel[1]; red - pixel[2];
        }
    }

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

    for(int j=0; j < img.rows; j++){
        for(int i=0; i < img.cols; i++){
            pix.data = (int32_t)rd_bmp[(j*img.cols)+i];

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

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

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

    gaussian_filter_axis(ins, outs, GAUSSIAN_FILTER); // ハードウェアのソーベルフィルタ
    gaussian_filter_axis_soft(ins_soft, outs_soft, GAUSSIAN_FILTER);  // ソフトウェアのソーベルフィルタ

    // ハードウェアとソフトウェアのソーベルフィルタの値のチェック
    for (int y=0; y<img.rows; y++){ // 結果の画像サイズはx-2, y-2
        for (int x=0; x<img.cols; x++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_uint<32> val = vals.data;
            hw_gaussian[y*img.cols+x] = (int32_t)val;
            if (val != vals_soft.data){
                printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %x, SW = %x\n",
                        x, y, val, vals_soft.data);
                //return(1);
            }
        }
    }
    printf("Success HW and SW results match\n");

    const int gaussian_row = img.rows;
    const int gaussian_cols = img.cols;
    cv::Mat wbmpf(gaussian_row, gaussian_cols, CV_8UC3);
    // wbmpf にgaussian フィルタ処理後の画像を入力
    cv::Mat_<cv::Vec3b> sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf);
    for (int y=0; y<wbmpf.rows; y++){
        for (int x=0; x<wbmpf.cols; x++){
            cv::Vec3b pixel;
            pixel = sob_vec3b(y,x);
            int32_t rbg = hw_gaussian[y*wbmpf.cols+x];
            pixel[0] = ((rbg >> 8) & 0xff); // blue
            pixel[1] = (rbg & 0xff); // green
            pixel[2] = ((rbg >> 16) & 0xff); // red
            sob_vec3b(y,x) = pixel;
        }
    }

    // ハードウェアのソーベルフィルタの結果を jpg ファイルへ出力する
    cv::imwrite(OUTPUT_JPG_FILE, wbmpf);

    gaussian_filter_axis(ins2, outs2, ORIGINAL_IMAGE); // 元画像出力

    cv::Mat wbmpf2(gaussian_row, gaussian_cols, CV_8UC3);
    // wbmpf2 に元画像を入力
    sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf2);
    for (int y=0; y<wbmpf.rows; y++){
        for (int x=0; x<wbmpf.cols; x++){
            cv::Vec3b pixel;
            pixel = sob_vec3b(y,x);
            outs2 >> vals;
            int32_t val = vals.data;
            pixel[0] = ((val >> 8) & 0xff); // blue
            pixel[1] = (val & 0xff); // green
            pixel[2] = ((val >> 16) & 0xff); // red
            sob_vec3b(y,x) = pixel;
        }
    }

    // 元画像を jpg ファイルへ出力する
    cv::imwrite(ORG_OUT_JPG_FILE, wbmpf2);

    return(0);
}

int gaussian_filter_axis_soft(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int function){

    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> gaussian;

    ap_int<32> line_buf[2][DISPLAY_WIDTH];
    ap_int<32> pix_mat[3][3];
    ap_int<32> pix_1d[9];

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

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

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = pix.data;
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            for(int i=0; i<9; i++){
                pix_1d[i] = pix_mat[i/3][i%3];
            }
            gaussian.data = gaussian_fil_soft(pix_1d);

            if(x<2 || y<2)
                gaussian.data = 0;

            if(x==0 && y==0) // 最初のピクセル
                gaussian.user = 1;
            else
                gaussian.user = 0;
            if(x == (DISPLAY_WIDTH-1)) // 行の最後
                gaussian.last = 1;
            else
                gaussian.last = 0;

            if(function == GAUSSIAN_FILTER)
                outs << gaussian;
            else
                outs << pix;
        }
    }
    return(0);
}

// gaussian filter
// 
// x0y0 x1y0 x2y0  1/16  2/16  1/16
// x0y1 x1y1 x2y1  2/16  4/16  2/16
// x0y2 x1y2 x2y2  1/16  2/16  1/16
//
ap_int<32> gaussian_fil_soft(ap_int<32> *pix_1d){
    ap_int<32> pix_1d_r[9], pix_1d_b[9], pix_1d_g[9];
    ap_int<32> y_r, y_b, y_g, y;

    for(int i=0; i<9; i++){
        separate_rbg_soft(pix_1d[i], pix_1d_r[i], pix_1d_b[i], pix_1d_g[i]);
    }

    y_r = gaussian_fil_calc_soft(pix_1d_r);
    y_b = gaussian_fil_calc_soft(pix_1d_b);
    y_g = gaussian_fil_calc_soft(pix_1d_g);

    y = (y_r << 16) + (y_b << 8) + y_g;
    return(y);
}

// gaussian_fil_calc
ap_int<32> gaussian_fil_calc_soft(ap_int<32> *pixd){
    ap_int<32> y;

    y = pixd[0] + 2 * pixd[1] + pixd[2] + 2 * pixd[3] + 4 * pixd[4] + 2 * pixd[5] + pixd[6] + 2 * pixd[7] + pixd[8];
    y = y / 16;

    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255) // 8 bits
        y = 255;
    return(y);
}

// separate_rbg
// RGBを分離する
// RBGのフォーマットは、{R(8bits), B(8bits), G(8bits)}, 1pixel = 32bits
// 
ap_int<32> separate_rbg_soft(ap_int<32> rbg, ap_int<32> &r, ap_int<32> &b, ap_int<32> &g){
    b = (rbg>>8) & 0xff;
    g = rbg & 0xff;
    r = (rbg>>16) & 0xff;
    return(0);
}


ガウシアン・フィルタ処理をする test2.jpg はノイズ除去の様子を見るために、画像ソフトの Pinta でノイズを加えた。
gaussian_kv260_1_211028.jpg

Vitis HLS 2021.1 で gaussian_filter_axis_RBG プロジェクトを作成した。
Vitis HLS 2021.1 のプロジェクトを作る時に、 Part Selection では Parts を選択し、 xck260-sfvc784-2LV-c を選択した。

ソースコードやヘッダファイル、テストベンチを入れた gaussian_filter_axis_RBG プロジェクトを示す。
gaussian_kv260_2_211028.png

今回のテストベンチ・コードでは OpenCV ライブラリを使用している。
Vitis HLS 2021.1 には内蔵された OpenCV は無いので、別にインストールした OpenCV を指定する。
Vitis HLS の Project メニューから Project Settings... を選択して、Project Settings ダイアログを開いた。
Simulation タブを開いて、gaussian_filter_axis_RBG_tb.cpp の CFLAGS に

-I/usr/local/include


を設定した。
Linker Flags に

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


を設定した。
gaussian_kv260_3_211028.png

更に、 Synthesis をクリックして、 Top Function に gaussian_filter_axis を指定した。
gaussian_kv260_4_211028.png
  1. 2021年10月28日 05:04 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

ソーベル・フィルタを”MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインに追加する3

ソーベル・フィルタを”MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインに追加する2”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成することにしたということで、前回は、 Vitis HLS 2021.1 に設定する動作周波数が間違っていたので、もう一度、 Vitis HLS で C コードの合成と Export RTL を行って IP を変更して、 Vivado で論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。今回は、ハードウェアをエクスポートして、 Vitis の kria_n プラットフォームをアップデートした。そして、 Vitis のhelloworld.c にソーベル・フィルタ IP の制御プログラムを追加し、 KV260 で確認したところ、動作した。

ハードウェアをエクスポートした。
Vivado の File メニューから Export -> Export Hardware... を選択し、表示されたダイアログを進めて、XSA ファイルをアップデートした。
Vitis で kria_n プラットフォームを新しい XSA ファイルでアップデートした。
これで、ソーベル・フィルタのドライバ・ソフトウェアが使用できるようになった。
Kria_PCAM_116_211025.png

display_port_appn_system -> display_port_appn -> src の helloworld.c にソーベル・フィルタ IP の制御プログラムを追加する。(なお helloworld.c は”MicroZed Chronicles: Kria & Raspberry Pi Camera”のファイルである)

#include "xsobel_filter_axis.h"

XSobel_filter_axis sobelf;


Kria_PCAM_117_211025.png

ソーベル・フィルタ IP のドライバ・ソフトウェアを使用して、ソーベル・フィルタ IP を設定して起動する。

    // Sobel filter settings
    XSobel_filter_axis_Initialize(&sobelf, 0);
    XSobel_filter_axis_Set_function_r(&sobelf, 0); // Pass through camera data
    XSobel_filter_axis_Start(&sobelf);
    XSobel_filter_axis_EnableAutoRestart(&sobelf);


Kria_PCAM_118_211025.png

while(1) の中に、カメラ画像とソーベル・フィルタ画像を切り替えるプログラムを書いた。

     while(1){
         xil_printf("Please input 1 or 0. 0: Pass through camera data, 1: Sobel filtering ");
         int chr = inbyte();
         switch(chr){
         case '0':
             xil_printf("0\n\r");
             XSobel_filter_axis_Set_function_r(&sobelf, 0); // Pass through camera data
             break;
         case '1':
             xil_printf("1\n\r");
             XSobel_filter_axis_Set_function_r(&sobelf, 1); // Sobel filtering
             break;
         case 'q':
             xil_printf("q\n\r");
             break;
         }
         if(chr=='q')
             break;
     }


Kria_PCAM_119_211025.png

これで、ビルドしたところ成功した。
KV260 で動作させてみよう。

まずは、 KV260 を起動したところ、ブート・ソフトウェア(FSBL?)が起動した。
Kria_PCAM_121_211026.png

Vitis の Assistant ウインドウの display_port_appn_system -> display_port_appn -> Debug を右クリックし右クリックメニューから Run -> Debugger_display_port _appn-Default (Single Application Debug) を選択して、 FPGA をコンフィギュレーションし、アプリケーション・ソフトウェアを起動する。
Kria_PCAM_120_211026.png

アプリケーション・ソフトウェアが起動した。
Kria_PCAM_122_211026.png

この状態で、カメラ画像がディスプレイに表示されている。
Kria_PCAM_125_211026.jpg

1 を入力すると、ソーベル・フィルタ画像がディスプレイに表示された。
Kria_PCAM_123_211026.png

Kria_PCAM_126_211026.jpg

q を入力すると、アプリケーション・ソフトウェアが終了した。
Kria_PCAM_124_211026.png

MicroZed Chronicles: Kria & Raspberry Pi Camera”にソーベル・フィルタ画像出力機能を追加することができた。
  1. 2021年10月26日 04:04 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

フリードスパイク(車)を買いました

久しぶりに日記です。
土曜日、10月23日に中古車を買いました。ホンダのフリードスパイクで自転車(ロードバイク)を2台、車輪を外さないで乗せられる車を買いました。フリードスパイクは荷室が 2 m 程度の長さをしかもフラットな床で確保できます。足を伸ばした車中泊も可能です。
ナンバーは、ツィッターでは言ってしまいましたが、2 の n 乗の数にしました。
freed_spike_1_211025.jpg

freed_spike_2_211025.jpg

freed_spike_8_211025.jpg

2 番目の座席をたたんで、ロードバイクを乗せたところです。ディスプレイスタンドを購入しました。
ハーネスは持っていたゴムベルトで固定しました。フレームとハンドルを固定すれば安定するようです。
ロードバイクの下にはヨガマット引いています。
freed_spike_4_211025.jpg

freed_spike_5_211025.jpg

freed_spike_6_211025.jpg

freed_spike_7_211025.jpg

ラチェット式ベルト荷締機も買ってみました。どうだろう?
  1. 2021年10月25日 04:58 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ソーベル・フィルタを”MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインに追加する2

ソーベル・フィルタを”MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインに追加する1”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成することにしたということで、前回は、作成されたソーベル・フィルタ IP を Vivado で使用して、ブロック・デザインを修正し、論理合成、インプリメンテーション、ビットストリームの生成を行ったところ、タイミング・エラーが発生し解消できなかった。今回は、実は Vitis HLS 2021.1 に設定する動作周波数が間違っていたので、もう一度、 Vitis HLS で C コードの合成と Export RTL を行って IP を変更して、 Vivado で論理合成、インプリメンテーション、ビットストリームの生成を行う。

そういえば、 Vivado のブロック・デザインでの AXI4-Stream の動作周波数は 150 MHz だったが、 Vitis HLS では、デフォルトの動作周波数の 100 MHz つまり 10 ns で合成を行ってしまった。
Vitis HLS で動作周波数を 150 MHz (周期で 6.667 ns)に変更した。
Vitis HLS の Solution メニューから Solution Settings... を選択する。
Solution Settings (solution1) ダイアログが表示された。
Clock Period を 6.667 に変更する。
Kria_PCAM_109_211023.png

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

Estimated 4.684 ns で Uncertainty 1.80 ns だった。
リソース使用量は 100 MHz と比べると FF は 1035 個が 1071 個で増えているが、 LUT は 2071 個で変化なしだった。

Export RTL を行って、 IP を更新した。
IMPLEMENTATION を行った。結果を示す。
CP achieved post-implementation は 6.066 ns でタイミング・メットしている。
この場合は Clock Uncertainty はこの CP achieved post-implementation に含まれている。
Kria_PCAM_110_211023.png

さて、更新された sobel_filter_axis_RBG/solution1/impl ディレクトリの export.zip を展開して、 Vivado の KIRA_PCAM/Vivado/myproj/sobel_filter_axis_RBG ディレクトリの中にコピーした。
Vivado プロジェクトでは sobel_filter_axis_0 が更新されたので、 IP Status を表示するワーニングがでている。
IP Status を表示させると sobel_filter_axis_0 が更新されていることが表示されている。
Upgrade Selected ボタンをクリックして、 sobel_filter_axis_0 を更新する。
Kria_PCAM_112_211023.png

Generate Output Products ダイアログが表示された。
Generate ボタンをクリックする。
Kria_PCAM_113_211023.png

いろいろとやっているが終了した。
これでもう一度、論理合成、インプリメンテーション、ビットストリームの生成を行った。
Project Summary を示す。
Kria_PCAM_114_211023.png

まだ、2つほどタイミング・エラーが出ているが、これは例の hidden のタイミング・パスだった。
Kria_PCAM_115_211023.png

これで、タイミングは大丈夫のようだ。
  1. 2021年10月24日 04:02 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

ソーベル・フィルタを”MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインに追加する1

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成することにしたということで、前回は、ソーベル・フィルタを残りの C コードの合成、 C/RTL 協調シミュレーション、 Export RTL 、 Implementation を行った。今回は、作成されたソーベル・フィルタ IP を Vivado で使用して、ブロック・デザインを修正し、論理合成、インプリメンテーション、ビットストリームの生成を行ったところ、タイミング・エラーが発生してしまった。

Vitis HLS 2021.1 で作成したソーベル・フィルタ IP を Vivado 2021.1 の project_1 プロジェクトにディレクトリを作成してコピーする。
sobel_filter_axis_RBG/solution1/impl ディレクトリの下の export.zip を解凍する。
Kria_PCAM_99_211022.png

Kira_PCAM/Vivado/myproj の下に sobel_filter_axis_RBG ディレクトリを作成して、解凍されたファイルをその中にコピーする。
Kria_PCAM_100_211022.png

IP Catalog に Sobel_filter_axis を登録した。
Kria_PCAM_101_211022.png

Sobel_filter_axis をブロック・デザインに追加した。
Kria_PCAM_102_211022.png
Kria_PCAM_103_211022.png

論理合成、インプリメンテーション、ビットストリームの生成を行った。
Project Summary を示す。
Kria_PCAM_104_211022.png

Timing の Number of Failing Endpoint が 4 個になっている。今までは 2 個じゃなかったか?
Implemented Design を開いた。
Intra-Clock Path にもタイミング・エラーが 2 個出ている。
Kria_PCAM_105_211022.png

しかも ソーベル・フィルタのパスだ。

Inter-Clock Path も相変わらず hidden へのパスにタイミング・エラーが出ている。これはいつもどおりだ。
Kria_PCAM_106_211022.png

論理合成のストラテジーを変更してみよう。
Vivado の Flow Navigator の SYNTHESIS -> Run Synthesis を右クリックし右クリックメニューから synthesis settings... を選択する。
Settings ダイアログが開いた。
Settings の Strategy を Vivado Synthesis Default から Flow_perfOptimized_high に変更した。
Kria_PCAM_107_211022.png

これで、もう一度、論理合成、インプリメンテーション、ビットストリームの生成を行った。
やはり、ソーベル・フィルタ IP でタイミング・エラーが出ている。
Kria_PCAM_108_211022.png
  1. 2021年10月23日 04:15 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成する3

RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成する2”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成することにしたということで、前回は、C シミュレーションを行ったが、エラーになってしまった。 Kria KV260 ボードを指定したのだが、これを単体の FPGA チップにしたところ、エラーが解消した。今回は残りの C コードの合成、 C/RTL 協調シミュレーション、 Export RTL 、 Implementation を行った。

最初に C コードの合成を行った。結果を示す。
Kria_PCAM_87_211020.png
Kria_PCAM_88_211020.png
Kria_PCAM_89_211020.png

Function Call Graph を示す。相変わらず、見方が良く分からない。
Kria_PCAM_90_211020.png

C/RTL 協調シミュレーションを行った。結果を示す。
Kria_PCAM_91_211020.png

Avg II, Max II, Min II が 921663 クロックだった。
今の画像サイズは 1280 x 720 ピクセルなので、総ピクセル数は 921600 ピクセルとなるので、性能的には問題無さそうだ。

Open Wave Viewer ボタンをクリックして、 C/RTL 協調シミュレーションの波形を見てみよう。
Kria_PCAM_98_211020.png

outs_TVALID がずーと 1 であることが分かる。

C/RTL 協調シミュレーションの Function Call Graph を示す。
Kria_PCAM_92_211020.png

STALLING RATE が 0.00 % でストールしていないということのようだ。

Export RTL を行った。
sobel_filter_axis_RBG/solution1/impl ディレクトリに export.zip が生成された。
Kria_PCAM_99_211022.png

IMPLEMENTATION を行った。
Run Implementation ダイアログが開いた。
RTL Synthesis, Place & Route ラジオボタンをクリックして、選択した。
Kria_PCAM_94_211020.png

結果を示す。
Kria_PCAM_95_211020.png
Kria_PCAM_96_211020.png
Kria_PCAM_97_211020.png

CP achieved post-implementation は 8.126 ns で問題無さそうだ。
リソース使用量も少ない気がする。
  1. 2021年10月22日 04:10 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成する2

”RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成する1”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成することにしたということで、前回は、ソーベル・フィルタのソースコードを貼って、 Vitis HLS 2021.1 で sobel_filter_axis_RBG プロジェクトを作成した。今回は、 C シミュレーションを行ったが、エラーになってしまった。 Kria KV260 ボードを指定したのだが、これを単体の FPGA チップにしたところ、エラーが解消した。

まずは、右向き緑三角の右横の下向き黒三角をクリックし、C Simulation を選択して、 C シミュレーションを行った。
するとエラーになった。エラーの内容は

ERROR: [HLS 200-1023] Part 'xck26sfvc784-2LV-c' is not installed.


え〜〜。このエラーなんだ。どうしよう?
Kria_PCAM_80_211020.png

Web サイトを検索したけど検索できなかった。
いろいろと探したが、情報が無かったので、ボードじゃなくて、FPGA チップを選択したらどうなんだろう?ということで、 xck26sfvc784-2LV-c 単体を設定してみた。
Solution メニューから Solution Settings... を選択する。
Solution Settings (solution1) ダイアログが開く。
Part Selection の ... ボタンをクリックして、Device Selectin Dialog を表示した。
下の図のように選択し、 xck26sfvc784-2LV-c を選択した。
Kria_PCAM_81_211020.png

Solution Settings (solution1) ダイアログに戻った。
xck26sfvc784-2LV-c が選択されている。
Kria_PCAM_82_211020.png

この状態で、 C シミュレーションを行うと成功した。
Kria_PCAM_83_211020.png

sobel_filter_axis_RBG/solution1/csim/build を見てみよう。
C シミュレーションで生成された org.jpg と sobel.jpg があった。
Kria_PCAM_84_211020.png

org.jpg を示す。
この画像は、ソースコードの sobel_filter_axis() の第三引数の function に 0 を入力して生成された画像だ。この画像は元画像と同じになっている。これは、カメラ画像をスルーして表示するモードとなっている。
Kria_PCAM_85_211020.jpg

sobel.jpg を示す。
この画像は、ソースコードの sobel_filter_axis() の第三引数の function に 1 を入力して生成された画像だ。この画像はソーベル・フィルタの出力画像となっている。
Kria_PCAM_86_211020.jpg
  1. 2021年10月20日 05:08 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成する1

MicroZed Chronicles: Kria & Raspberry Pi Camera”のブロック・デザインにソーベル・フィルタを追加するために RBG 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.1 で作成することにした。今回は、ソーベル・フィルタのソースコードを貼って、 Vitis HLS 2021.1 で sobel_filter_axis_RBG プロジェクトを作成した。

まずは、ヘッダファイルの sobel_filter_axis_RBG.h を貼る。

// sobel_filter_axis_RBG.h
// 2021/10/18 by marsee
//

#ifndef __SOBEL_FILTER_AXIS_RBG10_H__
#define __SOBEL_FILTER_AXIS_RBG10_H__

#define HORIZONTAL 0
#define VERTICAL 1

#define HD_720

#ifdef HD_RES
#define DISPLAY_WIDTH 1920
#define DISPLAY_HIGHT 1080
#endif

#ifdef HD_720
#define DISPLAY_WIDTH 1280
#define DISPLAY_HIGHT 720
#endif

#ifdef SVGA_RES
#define DISPLAY_WIDTH 800
#define DISPLAY_HIGHT 600
#endif

#ifdef SMALL_RES
#define DISPLAY_WIDTH 64
#define DISPLAY_HIGHT 48
#endif

#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define ORIGINAL_IMAGE 0
#define SOBEL_FILTER 1

#endif


次に、ソースコードの sobel_filter_RBG10.cpp を貼る。

// sobel_filter_RBG10.cpp
// 2021/10/18 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "sobel_filter_axis_RBG.h"

ap_int<32> sobel_fil(ap_int<32> h_or_v, ap_int<32> x0y0, ap_int<32> x1y0, ap_int<32> x2y0, ap_int<32> x0y1,
        ap_int<32> x1y1, ap_int<32> x2y1, ap_int<32> x0y2, ap_int<32> x1y2, ap_int<32> x2y2);
ap_int<32> conv_rbg2y(ap_int<32> rbg);
ap_int<32> square_root8(ap_int<32> val);

int sobel_filter_axis(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int function){
#pragma HLS INTERFACE s_axilite port=function
#pragma HLS INTERFACE axis register_mode=both register port=outs
#pragma HLS INTERFACE axis register_mode=both register port=ins
#pragma HLS INTERFACE s_axilite port=return

    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> sobel;
    ap_int<32> sobel_val, sobel_h_val, sobel_v_val;

    ap_int<32> line_buf[2][DISPLAY_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    ap_int<32> pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete

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

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

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = conv_rbg2y(pix.data);
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            sobel_h_val = sobel_fil(HORIZONTAL, pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
                                                pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
                                                pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
            sobel_v_val = sobel_fil(VERTICAL,   pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
                                                pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
                                                pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
            sobel_val = square_root8(sobel_h_val*sobel_h_val + sobel_v_val*sobel_v_val);
            sobel.data = (sobel_val<<16)+(sobel_val<<8)+sobel_val;

            if(x<2 || y<2)
                sobel.data = 0;

            if(x==0 && y==0) // 最初のピクセル
                sobel.user = 1;
            else
                sobel.user = 0;
            if(x == (DISPLAY_WIDTH-1)) // 行の最後
                sobel.last = 1;
            else
                sobel.last = 0;

            if(function == SOBEL_FILTER)
                outs << sobel;
            else
                outs << pix;
        }
    }
    return(0);
}

// RBGからYへの変換
// RBGのフォーマットは、{R(8bits), B(8bits), G(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 にした
ap_int<32> conv_rbg2y(ap_int<32> rbg){
    ap_int<32> r, g, b, y_f;
    ap_int<32> y;

    b = (rbg>>8) & 0xff;
    g = rbg & 0xff;
    r = (rbg>>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);
}

// sobel filter
// HORZONTAL
// x0y0 x1y0 x2y0  1  2  1
// x0y1 x1y1 x2y1  0  0  0
// x0y2 x1y2 x2y2 -1 -2 -1
// VERTICAL
// x0y0 x1y0 x2y0  1  0 -1
// x0y1 x1y1 x2y1  2  0 -2
// x0y2 x1y2 x2y2  1  0 -1
ap_int<32> sobel_fil(ap_int<32> h_or_v, ap_int<32> x0y0, ap_int<32> x1y0, ap_int<32> x2y0, ap_int<32> x0y1,
        ap_int<32> x1y1, ap_int<32> x2y1, ap_int<32> x0y2, ap_int<32> x1y2, ap_int<32> x2y2){
    ap_int<32> y;

    if(h_or_v == HORIZONTAL){
        y = x0y0 + 2*x1y0 + x2y0 - x0y2 - 2*x1y2 - x2y2;
    } else {
        y = x0y0 - x2y0 + 2*x0y1 - 2*x2y1 + x0y2 - x2y2;
    }
    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255) // 8 bits
        y = 255;
    return(y);
}

// square_root8
// 8 bit幅のsquare_rootを求める
ap_int<32> square_root8(ap_int<32> val){
    ap_int<32> temp = 0;
    ap_int<32> square;

    for(int i=7; i>=0; --i){
        temp += (1 << i);
        square = temp * temp;

        if(square > val){
            temp -= (1 << i);
        }
    }

    return(temp);
}


最後にテストベンチの sobel_filter_axis_RBG_tb.cpp を貼る。

// sobel_filter_axis_RBG_tb.cpp
// 2021/10/19 by marsee
//

#include <stdio.h>
#include <stdint.h>
#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"

#include "sobel_filter_axis_RBG.h"

int sobel_filter_axis(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs, int function);
int sobel_filter_soft(int32_t *cam_fb, int32_t *sobel_fb,
        int32_t x_size, int32_t y_size);
int32_t square_root8_soft(int32_t val);

const char INPUT_JPG_FILE[] = "test2.jpg";
const char OUTPUT_JPG_FILE[] = "sobel.jpg";
const char ORG_OUT_JPG_FILE[] = "org.jpg";

int main(){
    hls::stream<ap_axiu<24,1,1,1> > ins, ins2;
    hls::stream<ap_axiu<24,1,1,1> > ins_soft;
    hls::stream<ap_axiu<24,1,1,1> > outs, outs2;
    hls::stream<ap_axiu<24,1,1,1> > outs_soft;
    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> vals;

    // JPG ファイルをMat に読み込む
    cv::Mat img = cv::imread(INPUT_JPG_FILE);

    // ピクセルを入れる領域の確保
    std::vector<int32_t> rd_bmp(sizeof(int32_t)*img.cols*img.rows);
    std::vector<int32_t> hw_sobel(sizeof(int32_t)*(img.cols)*(img.rows));
    std::vector<int32_t> sw_sobel(sizeof(int32_t)*(img.cols)*(img.rows));

    // rd_bmp にJPGのピクセルを代入
    cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
    for (int y=0; y<img.rows; y++){
        for (int x=0; x<img.cols; x++){
            cv::Vec3b pixel;
            pixel = dst_vec3b(y,x);
            rd_bmp[y*img.cols+x] = (pixel[1] & 0xff) | ((pixel[0] & 0xff)<<8) | ((pixel[2] & 0xff)<<16); // RBG 8 bits
            // blue - pixel[0]; green - pixel[1]; red - pixel[2];
        }
    }

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

    for(int j=0; j < img.rows; j++){
        for(int i=0; i < img.cols; i++){
            pix.data = (ap_int<32>)rd_bmp[(j*img.cols)+i];

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

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

            ins << pix;
            ins2 << pix;
        }
    }

    sobel_filter_axis(ins, outs, SOBEL_FILTER); // ハードウェアのソーベルフィルタ
    sobel_filter_soft(rd_bmp.data(), sw_sobel.data(), img.cols, img.rows);  // ソフトウェアのソーベルフィルタ

    // ハードウェアとソフトウェアのソーベルフィルタの値のチェック
    for (int y=0; y<img.rows; y++){ // 結果の画像サイズはx-2, y-2
        for (int x=0; x<img.cols; x++){
            outs >> vals;
            ap_uint<32> val = vals.data;
            hw_sobel[y*img.cols+x] = (int32_t)val;
            if (val != sw_sobel[y*img.cols+x]){
                printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %x, SW = %x\n",
                        x, y, val, sw_sobel[y*(img.cols-2)+x]);
                return(1);
            }
        }
    }
    printf("Success HW and SW results match\n");

    const int sobel_row = img.rows;
    const int sobel_cols = img.cols;
    cv::Mat wbmpf(sobel_row, sobel_cols, CV_8UC3);
    // wbmpf にsobel フィルタ処理後の画像を入力
    cv::Mat_<cv::Vec3b> sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf);
    for (int y=0; y<wbmpf.rows; y++){
        for (int x=0; x<wbmpf.cols; x++){
            cv::Vec3b pixel;
            pixel = sob_vec3b(y,x);
            int32_t rbg = hw_sobel[y*wbmpf.cols+x];
            pixel[0] = ((rbg >> 8) & 0xff); // blue
            pixel[1] = (rbg & 0xff); // green
            pixel[2] = ((rbg >> 16) & 0xff); // red
            sob_vec3b(y,x) = pixel;
        }
    }

    // ハードウェアのソーベルフィルタの結果を jpg ファイルへ出力する
    cv::imwrite(OUTPUT_JPG_FILE, wbmpf);

    sobel_filter_axis(ins2, outs2, ORIGINAL_IMAGE); // 元画像出力

    cv::Mat wbmpf2(sobel_row, sobel_cols, CV_8UC3);
    // wbmpf2 に元画像を入力
    sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf2);
    for (int y=0; y<wbmpf.rows; y++){
        for (int x=0; x<wbmpf.cols; x++){
            cv::Vec3b pixel;
            pixel = sob_vec3b(y,x);
            outs2 >> vals;
            int32_t val = vals.data;
            pixel[0] = ((val >> 8) & 0xff); // blue
            pixel[1] = (val & 0xff); // green
            pixel[2] = ((val >> 16) & 0xff); // red
            sob_vec3b(y,x) = pixel;
        }
    }

    // 元画像を jpg ファイルへ出力する
    cv::imwrite(ORG_OUT_JPG_FILE, wbmpf2);

    return(0);
}

int32_t sobel_fil_soft(int32_t h_or_v, int32_t x0y0, int32_t x1y0, int32_t x2y0, int32_t x0y1,
        int32_t x1y1, int32_t x2y1, int32_t x0y2, int32_t x1y2, int32_t x2y2);
int32_t conv_rbg2y_soft(int32_t rbg);

int sobel_filter_soft(int32_t *cam_fb, int32_t *sobel_fb,
    int32_t x_size, int32_t y_size){
    int32_t sobel_val, sobel_h_val, sobel_v_val;
    int32_t pix[3][3];

    for(int y=0; y<y_size; y++){
        for(int x=0; x<x_size; x++){
            for(int i=2; i>=0; --i){
                for(int j=2; j>=0; --j){
                    if(x>=2 && y>=2)
                        pix[i][j] = conv_rbg2y_soft(cam_fb[(y-i)*x_size+(x-j)]);
                    else
                        pix[i][j] = 0;
                }
            }
            sobel_h_val = sobel_fil_soft(HORIZONTAL,pix[0][0], pix[0][1], pix[0][2],
                                                    pix[1][0], pix[1][1], pix[1][2],
                                                    pix[2][0], pix[2][1], pix[2][2]);
            sobel_v_val = sobel_fil_soft(VERTICAL,  pix[0][0], pix[0][1], pix[0][2],
                                                    pix[1][0], pix[1][1], pix[1][2],
                                                    pix[2][0], pix[2][1], pix[2][2]);
            sobel_val = square_root8_soft(sobel_h_val*sobel_h_val + sobel_v_val*sobel_v_val);
            sobel_fb[y*x_size+x] = (sobel_val<<16)+(sobel_val<<8)+sobel_val;
        }
    }
    return(0);
}

// RBGからYへの変換
// RBGのフォーマットは、{R(8bits), B(8bits), G(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 にした
int32_t conv_rbg2y_soft(int32_t rbg){
    int32_t r, g, b, y_f;
    int32_t y;

    b = (rbg>>8) & 0xff;
    g = rbg & 0xff;
    r = (rbg>>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);
}

// sobel filter
// HORZONTAL
// x0y0 x1y0 x2y0  1  2  1
// x0y1 x1y1 x2y1  0  0  0
// x0y2 x1y2 x2y2 -1 -2 -1
// VERTICAL
// x0y0 x1y0 x2y0  1  0 -1
// x0y1 x1y1 x2y1  2  0 -2
// x0y2 x1y2 x2y2  1  0 -1
int32_t sobel_fil_soft(int32_t h_or_v, int32_t x0y0, int32_t x1y0, int32_t x2y0, int32_t x0y1,
        int32_t x1y1, int32_t x2y1, int32_t x0y2, int32_t x1y2, int32_t x2y2){
    int32_t y;

    if(h_or_v == HORIZONTAL){
        y = x0y0 + 2*x1y0 + x2y0 - x0y2 - 2*x1y2 - x2y2;
    } else {
        y = x0y0 - x2y0 + 2*x0y1 - 2*x2y1 + x0y2 - x2y2;
    }
    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255)
        y = 255;
    return(y);
}

// square_root8_soft
// 8 bit幅のsquare_rootを求める
int32_t square_root8_soft(int32_t val){
    int32_t temp = 0;
    int32_t square;

    for(int i=7; i>=0; --i){
        temp += (1 << i);
        square = temp * temp;

        if(square > val){
            temp -= (1 << i);
        }
    }

    return(temp);
}


Vitis HLS 2021.1 で sobel_filter_axis_RBG プロジェクトを作成した。
Vitis HLS 2021.1 のプロジェクトを作る時に、 Part Selection では Board をクリックして、 Kria KV260 Vision Starter Kit を選択した。
Kria_PCAM_76_211018.png

ソースコードやヘッダファイル、テストベンチを入れた sobel_filter_axis_RBG プロジェクトを示す。
Kria_PCAM_77_211019.png

今回のテストベンチ・コードでは OpenCV ライブラリを使用している。
Vitis HLS 2021.1 には内蔵された OpenCV は無いので、別にインストールした OpenCV を指定する。
Vitis HLS の Project メニューから Project Settings... を選択して、Project Settings ダイアログを開いた。
Simulation タブを開いて、sobel_filter_axis_RBG_tb.cpp の CFLAGS に

-I/usr/local/include

を設定した。
Linker Flags に

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

を設定した。
Kria_PCAM_78_211019.png

更に、 Synthesis をクリックして、 Top Function に sobel_filter_axis を指定した。
Kria_PCAM_79_211019.png
  1. 2021年10月19日 05:17 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:14

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる7

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる6”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみようということで、前回は、ブロック・デザインでのデータの流れを確認した。今回は、ブロック・デザインの各部のストリーム・データを Vivado Analyzer で確認してみよう。

カメラから DDR メモリへのデータパスでは、すでに ILA が入っている。 ila 番号と入っている位置を示す。

ila_0 : mipi_csi2_rx_subsys_st_0 の video_out 出力
ila_1 : v_axi4s_vid_out_0 の vtg_ce, locked, overflow, underflow, fifo_read_level[12:0], status[31:0]
ila_2 : v_demosaic_0 の m_axis_video 出力
ila_3 : v_gamma_lut_0 の m_axis_video 出力


これらの ila のメモリ長を 1024 個から 2048 個に変更した。

DDR メモリから Display Port 出力へのデータパスに 1 つも ILA が入っていないので、 axi_vdma_0 の M_AXI_S2MM 出力に Debug を設定して、system_ila0 を実装した。
Kria_PCAM_75_211018.png

これで、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。
Project Summary を示す。相変わらず、 TIming の Slack はマイナスだ。
Kria_PCAM_65_211017.png

Kira_PCAM/Vivado/myporj ディレクトリに design_1_wrapper.xsa が生成された。
Kria_PCAM_66_211017.png

新しい design_1_wrapper.xsa ができたので、 kria_n プラットフォームをアップデートする。
Explorer ウインドウの kria_n プラットフォームを右クリックし右クリックメニューから Update Hardware Specification を選択する。
kria_n プラットフォームがアップデートされた。
Kria_PCAM_67_211017.png

Explorer ウインドウの display_port_appn アプリケーション・プロジェクトをクリックして、ビルド・ボタン(トンカチ・ボタン)をクリックして、ビルドを行った。成功した。
Kria_PCAM_68_211017.png

Assistant ウインドウの display_port_appn_system -> display_port_appn -> Debug を右クリックし右クリックメニューから Run -> Debugger_display_port_appn-Default を選択して、 FPGA をコンフィギュレーションし、アプリケーション・ソフトウェアを起動した。

アプリケーション・ソフトウェアを起動した後で、Vivado の Flow Navigator で PROGRAM AND DEBUG -> Generate Bitstream -> Open Hardware Manager -> Open Target をクリックして、 Auto Connect を選択した。
波形ビューアーが表示された。

ila の波形を表示する用意が整ったので、トリガ信号を決定して、波形を観測した。

ila_0 (mipi_csi2_rx_subsys_st_0 の video_out 出力)(波形ビューアーでは、 ila の番号が +1 されいているようだ)
Kria_PCAM_70_211017.png

ビデオのピクセル・クロックが 74.25 MHz で AXI4-Stream の動作周波数が 150 MHz なので、 TVALID がずっと 1 ではなく、0 がかなり見受けられる。
TUSER も画像の最初のフレームの最初のデータのときに 1 になっているようだ。 

ila_2 (v_demosaic_0 の m_axis_video 出力)
Kria_PCAM_71_211017.png

ここで、 24 ビット・データになっている。

ila_3 (v_gamma_lut_0 の m_axis_video 出力)
Kria_PCAM_72_211017.png

system_ila0 (axi_vdma_0 の M_AXI_S2MM 出力)
Kria_PCAM_73_211017.png

やはり、ビデオのピクセル・クロックが 74.25 MHz で AXI4-Stream の動作周波数が 150 MHz なので、 TREADY がずっと 1 ではなく、0 がかなり見受けられる。途中でずーと 0 になっていた。

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

TREADY は 1 クロック毎に 1 と 0 を繰り返している。

画像フィルタは axi_vdma_0 の M_AXI_S2MM 出力に入れてみよう。
  1. 2021年10月18日 04:33 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる6

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる5”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみようということで、前回は、””MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる2”で自分でブロック・デザインを修正して作成した XSA ファイルでカメラ画像がディスプレイに表示されるか?を確かめたところ、問題なくカメラ画像をディスプレイに表示することができた。今回は、ブロック・デザインでのデータの流れを確認してみよう。

カメラから DDR メモリへの経路のデータの流れ方を説明する。

1. カメラからの入力を受ける mipi_csi2_rx_subsyst_0 は 16 ビット AXI4-Stream 出力となっている。
2. axis_subset_converter_1 に入って、 tdata[9:2] を抽出して、 8 ビット AXI4-Stream 出力として出力される。
3. v_domosaic_0 に入って、 8 ビット AXI4-Stream 入力が 24 ビット AXI4-Stream 出力として出力される。ここで、デモザイクされる。ベイヤー・パターンが RBG (Red, Blue, Green) パターンに変換される。
4. v_gmma_lut_0 では、 24 ビット AXI4-Stream 入出力となっていて、ガンマ補正が行われる。
5. axi_vdma_0 (S_AXIS_S2MM) で 24 ビット AXI4-Stream 入力データを DDR メモリに書いている。


DDR メモリから Display Port 出力のデータの流れを説明する。

1. DDR メモリからデータを読んで、 axi_vdma_0 (M_AXIS_MM2S) から 24 ビット AXI4-Stream が出力される。
2. axis_suset_converter_0 で 24 ビット AXI4-Stream を以下のように置き換えている。
tdata[15:8],tdata[23:16],tdata[7:0] つまり RBG を BRG に置き換えているようだ。これは、Zynq UltraScale+ MPSoC のDisplayPort のLiveVideo のピクセルデータの色のビットフィールドが BRG だからだろう?(”Zynq UltraScale+ MPSoC のDisplayPort のLiveVideo のピクセルデータ”参照)
3. v_axi4s_vid_out_0 で BRG に変換された 24 ビット AXI4-Stream を入力して、 vid_data[35:0] に変換している。その他、ビデオ用の信号を主力して、 Zynq UltraScale+ MPSoC の dp_live_video に入力している。


Kria_PCAM_5_211009.png
Kria_PCAM_6_211009.png
  1. 2021年10月17日 04:34 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる5

SD カード・ブートモードの Zynq UltraScale+ MPSoC で Vitis を使用してコンフィギュレーション、ソフトウェアを起動する”の続き。

前回は、SD カード・ブートモードでの KV260 での Vitis での FPGA コンフィギュレーション+アプリケーション・ソフトウェアの起動方法を探って、それを解明することができた。今回は、””MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる2”で自分でブロック・デザインを修正して作成した XSA ファイルでカメラ画像がディスプレイに表示されるか?を確かめよう。

まずは、新しく kria_n プラットフォームを作成する。
Vitis 2021.1 の File メニューから New -> Platform Project... を選択する。
New Platform Project ダイアログが表示された。最初の画面は Create new platform project だ。
Platform project name に kria_n と入力した。
Kria_PCAM_48_211015.png

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる2”で作成した design_1_wrapper.xsa ファイルを指定した。
Kria_PCAM_49_211015.png

Finish ボタンをクリックすると、 kria_n プラットフォーム・プロジェクトが生成された。
Kria_PCAM_50_211015.png

kria_n プラットフォームを元にしたアプリケーション・プロジェクトを作成する。
Vitis 2021.1 の File メニューから New -> Application Project... を選択する。
New Application Project ダイアログが表示された。最初の画面は、 Create a New Application Project だ。
Kria_PCAM_51_211015.png

Platform 画面では、 kria_n プラットフォームを選択した。
Kria_PCAM_52_211015.png

Application Project Details 画面では、 Application project name に diaplay_port_appn を入力した。
現在の画面では、 Show all processors in the hardware specification のチェックボックスにチェックを入れてある。
Kria_PCAM_53_211015.png

Domain 画面。
デフォルトの standalone_domain のままとする。
Kria_PCAM_54_211015.png

Template 画面。
デフォルトの Hello World とした。
Finish ボタンをクリックする。
Kria_PCAM_55_211015.png

Vitis IDE 画面に display_port_appn アプリケーション・プロジェクトが生成された。
Kria_PCAM_56_211015.png

ソース・コードをインポートする。
Explorer の display_port_appn_system -> display_port_appn の src を右クリックし、右クリックメニューから Import Sources... を選択する。
Import Sources ダイアログが表示された。
Browse ボタンをクリックして、 display_port_app/src ディレクトリを選択する。
右のウインドウに display_port_app/src ディレクトリにあるファイルが全て表示されるので、全てのファイルにチェックを入れて、インポートする。
Kria_PCAM_57_211015.png

Explorer の display_port_appn_system -> display_port_appn -> src ディレクトリにソース・コードがインポートされた。
Kria_PCAM_58_211015.png

Explorer の display_port_appn_system -> display_port_appn を右クリックし、右クリックメニューから Properties を選択する。
Properties for display_port_appn ダイアログが開く。
左のウインドウで、 C/C++ Build -> Setiings をクリックする。
Tool Settings タブをクリックし、ARM v8 gcc linker -> Libraries をクリックする。
右の Libraries (-l) に m を追加する。
Kria_PCAM_59_211015.png

Explorer の display_port_appn_system をクリックして、ビルド・ボタンをクリックするとビルドが成功した。
Kria_PCAM_60_211015.png

Assistant ウインドウの display_port_appn_system -> display_port_appn を右クリックし、右クリックメニューから Run -> Run Configurations... を選択する。
Run Configurations ダイアログが表示された。
Main タブ。
Kria_PCAM_61_211015.png

Target Setup タブをクリックして、 Use FSBL flow for initialization のチェックボックスのチェックを外した。
Run ボタンをクリックした。
Kria_PCAM_62_211015.png

FPGA コンフィギュレーションとアプリケーション・ソフトウェアが起動して、カメラ画像がディスプレイに表示された。
成功だ。
  1. 2021年10月15日 04:38 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

SD カード・ブートモードの Zynq UltraScale+ MPSoC で Vitis を使用してコンフィギュレーション、ソフトウェアを起動する

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる4”で Adam Taylor さんが用意してくれた Viits 2021.1 の display_port_app アプリケーション・プロジェクトは動作した。しかし、自分で作成した Vitis のアプリケーション・プロジェクトを動かしてみたい。しかし、KV260 には PS_MODE の切り替えスイッチが無いので、JTAG モードに設定できない。そこで、 KV260 の Vitis での制御方法を探ってみた。

まずは、””MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる4”の Vitis プロジェクトに display_port_app2 アプリケーション・プロジェクトを作成した。これは、 kira プラットフォームをベースとするアプリケーション・プロジェクトだ。つまり、既存の display_port_app と同じアプリケーション・プロジェクトを作成した。
display_port_app の src からソフトウェア・コードもそのまま Import Sources... してある。
Kria_PCAM_42_211014.png

display_port_app2 アプリケーション・プロジェクトをビルドすると、

undefined reference to `pow'

というエラーが出た。
Kria_PCAM_38_211013.png

このバグは、 math ライブラリを追加すると直るようだ。
Explorer の display_port_app2_system -> display_port_app2 を右クリックし、右クリックメニューから Properties を選択する。
Properties for display_port_app2 ダイアログが開く。
左のウインドウで、 C/C++ Build -> Setiings をクリックする。
Tool Settings タブをクリックし、ARM v8 gcc linker -> Libraries をクリックする。
右の Libraries (-l) に m を追加する。
Kria_PCAM_39_211013.png

もう一度、ビルドすると成功した。
Kria_PCAM_40_211013.png

さて、 KV260 から MicroSD カードを抜いて、Vitis の Assistant ウインドウの display_port_app2_system -> display_port_app2 を右クリックし、右クリックメニューから Run -> Launch Hardware (Single Application Debug) を選択して FPGA をコンフィギュレーションし、アプリケーション・ソフトウェアを起動する。

すると Overwrite Boot Mode のダイアログが表示された。
ターゲットが JTAG モードじゃないと言われている。ブートモードのレジスタにオーバーライトするのかと聞かれている。
Yes ボタンをクリックした。
Kria_PCAM_43_211014.png

カメラ画像はディスプレイに表示されなかった。

それじゃ何で、既存の display_port_app はカメラ画像が表示されるんだろう?
Run Configuration を比べてみると、違いがあった。それは、 Target Setup タブで Use FSBL flow for initialization にチェックが入っているかどうか?だった。
私の作った display_port_app2 は Use FSBL flow for initialization にチェックが入っている。
Kria_PCAM_44_211014.png

既存の display_port_app は Use FSBL flow for initialization のチェックが外れている。
Kria_PCAM_45_211014.png

display_port_app2 も Use FSBL flow for initialization のチェックを外した。
Kria_PCAM_47_211014.png

Use FSBL flow for initialization のチェックを外した後で、Apply ボタンをクリックして設定を反映し、 Run ボタンをクリックして、FPGA をコンフィギュレーションし、アプリケーション・ソフトウェアを起動したところ、 Overwrite Boot Mode のダイアログが表示されずにカメラ画像がディスプレイに表示された。
これだった。。。

考えてみれば FSBL が SD カード・モードの時は走って、 JTAG の時は走らないので、 SD カード・モードの時は FSBL を起動する必要が無いのではないだろうか?
それでオーバーライトと言われちゃったんだな。。。一つ勉強になった。 Adam Taylor さん、ありがとうございます。
  1. 2021年10月14日 04:39 |
  2. Vitis
  3. | トラックバック:0
  4. | コメント:0

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる4

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる3”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみるということで、前回は、ハードウェアをエクスポートして、 XSA ファイルを生成した。そして、Vitis 2021.1 を起動して、プロジェクトをインポートした。今回は、Vitis のプロジェクトをビルドして、KV260 でカメラ画像をディスプレイに表示されることを確認する。そして、自分で修正した XSA ファイルでアップデートして、もう一度、KV260 でカメラ画像をディスプレイに表示されることを確認する。

Explorer で display_port_app_system をクリックし、ビルド・ボタンをクリックしてビルドを行った。
display_port_app.elf が生成された。
Kria_PCAM_23_211010.png

KV260 に Pcam5C を接続した。
MicroSD カードは抜いた。
Kria_PCAM_34_211013.jpg

Assistant ウインドウで display_port_app_system -> display_port_app -> Debug を右クリックし、右クリックメニューから Run -> Debugger_display_port_app-Default (Single Application Debug) を選択して、ビットファイルのダウンロードとアプリケーション・ソフトウェアの起動を行った。
Kria_PCAM_31_211012.png

ディスプレイ・ポートに接続したディスプレイにカメラ画像が表示された。
Kria_PCAM_35_211013.jpg
  1. 2021年10月13日 05:03 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる3

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる2”の続き。

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみるということで、前回は、論理合成、インプリメンテーション、ビットストリームの生成を行った。今回は、ハードウェアをエクスポートして、 XSA ファイルを生成する。そして、Vitis 2021.1 を起動して、プロジェクトをインポートする。

最初にハードウェアをエクスポートしよう。
File メニューから Export -> Export Hardware... を選択する。
Export Hardware Platform ダイアログが開く。
Next > ボタンをクリックする。

Output 画面が開く。
Include bitstream のラジオボタンをチェックして、Next > ボタンをクリックする。
Kria_PCAM_14_211009.png

Files 画面が開く。
XSA ファイルの名前やエクスポートするディレクトリを指定する。
今回はデフォルトのままとする。
Kria_PCAM_15_211009.png

Exporting Hardware Platform 画面が開く。
Finish ボタンをクリックする。

Kira_PCAM/Vivado/myproj ディレクトリに design_1_wrapper.xsa が生成された。
Kria_PCAM_16_211009.png

Vitis 2021.1 を起動するのだが、 Kira_PCAM/Vitis ディレクトリには、 vitis_export_archive.ide.zip があるだけだ。
この ZIP ファイルは Vitis のプロジェクトをエクスポートしたファイルのようだ。
Kria_PCAM_17_211010.png

Vivado 2021.1 から Vitis 2021.1 を起動する。
Vivado 2021.1 の Tools メニューから Launch Vitis IDE を選択して、 Vitis 2021.1 を起動する。
Vitis IDE Launcher が起動する。
Kira_PCAM/Vitis ディレクトリの下に vitis_work ディレクトリを作成して、それを指定した。
Kria_PCAM_18_211010.png

Vitis 2021.1 が起動した。
Import Project をクリックする。
Kria_PCAM_19_211010.png

Import Projects ダイアログが開いた。
Viits project exported zip file のラジオボタンをクリックする。(デフォルト)
Kria_PCAM_20_211010.png

Import Vitis Projects でプロジェクトを選択するが全て選択した状態にした。
Finish ボタンをクリックする。
Kria_PCAM_21_211010.png

Vitis にプロジェクトがインポートされた。
Kria_PCAM_22_211010.png
  1. 2021年10月12日 05:22 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる2

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる1”の続き。

MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみるということで、前回は、Vivado ディレクトリの bd.tcl を実行して、design_1 プロジェクトを作成し、 io.xdc をインポートした。今回は、論理合成、インプリメンテーション、ビットストリームの生成を行った。

論理合成、インプリメンテーション、ビットストリームの生成を行った。
Project Summary を示す。
Kria_PCAM_10_211009.png

マイナス・スラックが出ている。
Flow Navigator から Open Implementation Design をクリックして、 Implementation Design を開いた。
Kria_PCAM_13_211009.png

Inter-Clock Paths で clk_out2_design_1_clk_wiz_1_0 to clk_out1_design_1_clk_wiz_0_0_1 がタイミング・エラーのようだ。
Kria_PCAM_11_211009.png

一番上のパスは、design_1_i/rst_ps8_0_100M/U0/PR_OUT_DFF[0].FDRE_PER_replica/C から design_1_i/v_axi4s_vid_out_0/inst/SYNC_INST/vtg_lag_reg[10]/R へのパスがタイミング違反だった。

Reports メニューから Timing -> Report CDC... を選択して、 safe かどうかを確認する。
Unsafe が 5 個あった。
Kria_PCAM_12_211009.png

一番上の Unsafe は design_1_i/rst_ps8_0_100M/U0/ACTIVE_LOW_PR_OUT_DFF[0].FDRE_PER_N/C から design_1_i/v_tc_0/U0/U_VIDEO_CTRL/AXI4_LITE_INTERFACE.read_ack_d_reg[0]/R へのパスが Unsafe だそうだ。
このままで、あまり好ましくないので、ブロック・デザインの修正を試みる。

clk_wiz1 の clk_out2 は 150 MHz で、 clk_wiz_0 の clk_out1 は 74.250 MHz の設定で実際の周波数が 74.25299 MHz だった。
clk_wiz1 の clk_out2 は 全体のデータパスの駆動用クロックで、 clk_wiz_0 の clk_out1 は ビデオ用のクロックだ。
Kria_PCAM_24_211011.png
Kria_PCAM_25_211011.png

ブロック・デザインを見ると、 rst_ps8_0_100M のリセットが v_tc_0 の resetn と v_axi4s_vid_out_0 の vid_io_out_reset に行っているのが原因だと思う。
Kria_PCAM_26_211011.png

Processor _system_reset を追加して、 clk_wiz_0 の clk_out1 を slow_sync_clk に接続した。その proc_sys_reset_74_25M から v_tc_0 の resetn と v_axi4s_vid_out_0 の vid_io_out_reset に接続した。
Kria_PCAM_27_211011.png

これでもう一度、論理合成、インプリメンテーション、ビットストリームの生成を行った。
Project Summary を示す。
Kria_PCAM_28_211011.png

値は少なくなったが、わずかにマイナス・スラックが出ている。
Flow Navigator から Open Implementation Design をクリックして、 Implementation Design を開いた。

やはり、Inter-Clock Paths で clk_out2_design_1_clk_wiz_1_0 to clk_out1_design_1_clk_wiz_0_0_1 がタイミング・エラーだった。
ソースは design_1_i/v_axi4s_vid_out_0/inst/COUPLER_INST/generate_async_fifo.FIFO_INST/XPM_FIFO_ASYNC_INST/gnuram_async_fifo.xpm_fifo_base_inst/gof.overflow_i_reg/C で ディスティネーションは hidden ってどういうこと?
Kria_PCAM_29_211011.png

Report CDC も Unsafe が 1 個だったが、同様だ。
Kria_PCAM_30_211011.png

hidden じゃ直せないので、そのままにする。
  1. 2021年10月11日 05:09 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:2

”MicroZed Chronicles: Kria & Raspberry Pi Camera”をやってみる1

MicroZed Chronicles: Kria & Raspberry Pi Camera”では、Kira KV260 Vitsion AI Starter Kit に Digilent 社の PCam5C を接続して画像を表示している。それをやってみることにした。

MicroZed Chronicles: Kria & Raspberry Pi Camera”に掲載されているハードウェアとソフトウェアへの github へのリンクをクリックする。これで github のアドレスが分かったので、 git clone しよう。
git clone https://github.com/ATaylorCEngFIET/Kira_PCAM.git
Kria_PCAM_1_211009.png

Kira_PCAM ディレクトリが生成されて、その中に Vitis と Vivado の 2 つのディレクトリがあった。
Vivado ディレクトリに入ると bd.tcl と io.xdc があった。 bd.tcl を実行するとプロジェクト毎生成してくれるようだ。
Kria_PCAM_2_211009.png

Vivado 2021.1 を起動して、 TCL Console に以下のコマンドを入力した。
cd /media/masaaki/Ubuntu_Disk/KRIA_KV260/Kira_PCAM/Vivado
source bd.tcl

すると myproj が生成された。
Kria_PCAM_3_211009.png

design_1 プロック・デザイン全体を示す。
Kria_PCAM_4_211009.png

ブロック・デザインの全体図ではよく見えないと思うので、拡大してみた。
Kria_PCAM_5_211009.png
Kria_PCAM_6_211009.png

Address Map を示す。
Kria_PCAM_7_211009.png

Create HDL Wrapper ... でトップの HDL ファイルを生成した。
Kria_PCAM_8_211009.png

io.xdc を制約ファイルとしてインポートした。(Add Source... から Add or create constraints を選択して、 io.xdc を選択した)
Kria_PCAM_9_211009.png
  1. 2021年10月10日 06:25 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる5

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる4”の続き。

Ultra96V2 用の”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみようということで、前回は、、”ホスト環境での TVM のセットアップ”をやっていったのだが、”./tvm/docker/build.sh demo_vitis_ai bash”でエラーが出て先に進まなくなってしまった。今回は、その続きというかデバックをしたのだが、うまく行かなかった。

前回のエラーだが、apt-get update --fix-missing をやっている時に、リポジトリを読んでくるサイトの https://apt.kitware.com/ubuntu bionic Release が無くなったか更新されなくなったか?したのだと思う。このリポジトリがエラーでも問題ないのと思うので、そこを読み飛ばしてくれないかな?ということで、ネットを検索すると、”DockerHubでDockerfileのRUNコマンドのエラーを無視する”が検索できた。それによると

RUN (終了コードが0以外のコード) ; exit 0

とすれば良いとのことだ。つまり

; exit 0

を後に追加すれば良い。
apt-get update --fix-missing がどのファイルにあるか?だが、 tvm/docker/Dockerfile.demo_vitis_ai にあった。
ファイルを開いて、

RUN apt-get update --fix-missing

RUN apt-get update --fix-missing; exit 0

に変更した。
Ultra96-V2_TVM_39_211007.png

これで、もう一度、 ./tvm/docker/build.sh demo_vitis_ai bash を実行すると、 bash /install/ubuntu_install_python.sh で止まってしまった。
Ultra96-V2_TVM_40_211007.png

同様に tvm/docker/Dockerfile.demo_vitis_ai の

RUN bash /install/ubuntu_install_python.sh;

RUN bash /install/ubuntu_install_python.sh; exit 0

に変更した。
Ultra96-V2_TVM_41_211007.png

これで、もう一度、 ./tvm/docker/build.sh demo_vitis_ai bash を実行すると、 bash /install/ubuntu_install_llvm.sh; で止まってしまった。
Ultra96-V2_TVM_42_211007.png

途中は飛ばすが、結局、下の図のように ; exit 0 を入れたら通るようになった。
Ultra96-V2_TVM_43_211007.png

でもまだ私のアカウントが does not exist と言われている。
それでは、次のコマンドの
./tvm/docker/bash.sh tvm.demo_vitis_ai
を実行したところ、

find: ‘/dev/vboxusb’: 許可がありません

というエラーが出てしまった。
Ultra96-V2_TVM_45_211008.png

sudo ls -l /dev/vboxusb/ を実行したところ、パーミッションが 750 だった。
Ultra96-V2_TVM_46_211008.png

sudo chmod 755 /dev/vboxusb/002
sudo chmod 755 /dev/vboxusb/
sudo chmod 755 /dev/vboxusb/001

を実行して、/dev/vboxusb のパーミッションを変更してみた。
もう一度、
./tvm/docker/bash.sh tvm.demo_vitis_ai
を実行したところ、今度は、

docker: bad format for path: .

と言われてしまった。
Ultra96-V2_TVM_47_211008.png

  1. 2021年10月08日 04:43 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる4

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる3”の続き。

Ultra96V2 用の”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみようということで、前回は、”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”の”Ultra96 への TVM ランタイムのインストール”を行った。今回は、”ホスト環境での TVM のセットアップ”をやっていったのだが、”./tvm/docker/build.sh demo_vitis_ai bash”でエラーが出て先に進まなくなってしまった。

ホスト環境での TVM のセットアップ
tvm を git clone する。
Ultra96-V2_TVM_35_211006.png
Ultra96-V2_TVM_36_211006.png

build.sh を実行する。
./tvm/docker/build.sh demo_vitis_ai bash
Ultra96-V2_TVM_37_211006.png
Ultra96-V2_TVM_38_211006.png

エラーが発生した。

The command '/bin/sh -c apt-get update --fix-missing' returned a non-zero code: 100
ERROR: docker build failed.



コマンド実行のログを示す。

(base) masaaki@masaaki-H110M4-M01:/media/masaaki/Ubuntu_Disk/Ultra96-V2/TVM_DL$ ./tvm/docker/build.sh demo_vitis_ai bash
Using default context path: /media/masaaki/Ubuntu_Disk/Ultra96-V2/TVM_DL/tvm/docker
WORKSPACE: /media/masaaki/Ubuntu_Disk/Ultra96-V2/TVM_DL/tvm/docker/../
CI_DOCKER_EXTRA_PARAMS: 
COMMAND: bash
CONTAINER_TYPE: demo_vitis_ai
BUILD_TAG: tvm
DOCKER CONTAINER NAME: tvm.demo_vitis_ai
DOCKER_IMAGE_TAG: latest
DOCKER_IMG_SPEC: tvm.demo_vitis_ai:latest

Building container (tvm.demo_vitis_ai)...
Sending build context to Docker daemon  201.7kB
Step 1/19 : FROM xilinx/vitis-ai:1.4.916
1.4.916: Pulling from xilinx/vitis-ai
01bf7da0a88c: Pulling fs layer 
f3b4a5f15c7a: Pulling fs layer 
57ffbe87baa1: Pulling fs layer 
195050004f95: Pulling fs layer 
28ef4752131e: Pulling fs layer 
161717b3aab7: Pulling fs layer 
c8a243b4402d: Pulling fs layer 
f4cc9f3f5ed3: Pulling fs layer 
078585cf4882: Pulling fs layer 
9bb8a2ef4fe9: Pulling fs layer 
31628d2f8579: Pull complete 
5759a1729f74: Pull complete 
f6bf5622f603: Pull complete 
343ab32c9bff: Pull complete 
e417d03e00f0: Pull complete 
db307339ff66: Pull complete 
53b28f82bce7: Pull complete 
b879f906e0dc: Pull complete 
a117f5309e41: Pull complete 
6dc4b00c80a5: Pull complete 
a718f95d6864: Pull complete 
d1cfc3aa434e: Pull complete 
e52a4b0ebf4b: Pull complete 
9eb3845e0638: Pull complete 
f65df791d7f6: Pull complete 
2e3224a3157e: Pull complete 
e84eff50ebe1: Pull complete 
6f7467e62fb5: Pull complete 
e98adc80d6b3: Pull complete 
f45c539d8128: Pull complete 
896507c50eb7: Pull complete 
fb407cba96a3: Pull complete 
c4c370fb9ac4: Pull complete 
Digest: sha256:1d568b1b77601a4e9989f969a74dfd9fd61102b713cb137edb83d76db11cea91
Status: Downloaded newer image for xilinx/vitis-ai:1.4.916
 ---> a325686c45a3
Step 2/19 : RUN apt-get update --fix-missing
 ---> Running in c2232d8956c0
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]    
Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]               
Get:3 http://ppa.launchpad.net/timsc/opencv-3.4/ubuntu bionic InRelease [15.9 kB]
Ign:4 https://apt.kitware.com/ubuntu bionic InRelease                          
Err:5 https://apt.kitware.com/ubuntu bionic Release                            
  Certificate verification failed: The certificate is NOT trusted. The certificate chain uses expired certificate.  Could not handshake: Error in the certificate verification. [IP: 66.194.253.25 443]
Get:6 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic InRelease [20.8 kB]
Get:7 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]      
Get:8 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages [606 kB]
Get:9 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]    
Get:10 http://ppa.launchpad.net/timsc/opencv-3.4/ubuntu bionic/main amd64 Packages [11.1 kB]
Get:11 http://archive.ubuntu.com/ubuntu bionic/multiverse amd64 Packages [186 kB]
Get:12 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB]
Get:13 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic/main amd64 Packages [50.4 kB]
Get:14 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1,430 kB]
Get:15 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2,365 kB]
Get:16 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [26.7 kB]
Get:17 http://archive.ubuntu.com/ubuntu bionic/restricted amd64 Packages [13.5 kB]
Get:18 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1,344 kB]  
Get:19 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [2,801 kB]
Get:20 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2,209 kB]
Get:21 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [34.4 kB]
Get:22 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [638 kB]
Get:23 http://archive.ubuntu.com/ubuntu bionic-backports/universe amd64 Packages [11.4 kB]
Get:24 http://archive.ubuntu.com/ubuntu bionic-backports/main amd64 Packages [11.3 kB]
Reading package lists... Done                                                  
E: The repository 'https://apt.kitware.com/ubuntu bionic Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
The command '/bin/sh -c apt-get update --fix-missing' returned a non-zero code: 100
ERROR: docker build failed.

  1. 2021年10月07日 05:10 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる3

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる2”の続き。

Ultra96V2 用の”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみようということで、前回は、”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”の”DPU-PYNQ 環境の構築”をやってみた。今回は、”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”の”Ultra96 への TVM ランタイムのインストール”をやってみよう。

Ultra96 への TVM ランタイムのインストール
必要なパッケージをインストールする。
apt-get install libhdf5-dev
Ultra96-V2_TVM_20_211005.png
Ultra96-V2_TVM_21_211005.png

pip3 install pydot==1.4.1 h5py==2.8.0
Ultra96-V2_TVM_22_211005.png

PyXir のインストール
git clone --recursive https://github.com/Xilinx/pyxir.git
Ultra96-V2_TVM_23_211005.png
Ultra96-V2_TVM_24_211005.png

cd pyxir
git checkout refs/tags/v0.2.1
git submodule update --recursive

Ultra96-V2_TVM_25_211005.png

sudo python3 setup.py install --use_vai_rt_dpuczdx8g
Ultra96-V2_TVM_26_211005.png
Ultra96-V2_TVM_27_211005.png

TVM ランタイムのビルド・インストール
git clone --recursive https://github.com/apache/tvm
Ultra96-V2_TVM_28_211005.png
Ultra96-V2_TVM_29_211005.png

cd tvm
mkdir build
cp cmake/config.cmake build
cd build
echo set\(USE_LLVM OFF\) >> config.cmake
echo set\(USE_VITIS_AI ON\) >> config.cmake
cmake ..

Ultra96-V2_TVM_30_211005.png
Ultra96-V2_TVM_31_211005.png

make tvm_runtime -j$(nproc)
Ultra96-V2_TVM_32_211005.png
Ultra96-V2_TVM_33_211005.png

cd ..
export PYTHONPATH=`pwd`/python/:$PYTHONPATH


TVM ランタイムのインストールの成功を以下のコマンドで確認できるそうだが、何も表示されなかったのだが、大丈夫なのだろうか?
python3 -c 'import pyxir; import tvm'
Ultra96-V2_TVM_34_211005.png
  1. 2021年10月06日 03:46 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる2

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる1”の続き。

Ultra96V2 用の”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみようということで、前回は、 ”Ultra96 への PYNQ 環境の構築”を行った。具体的には、Ultra96V2 用の PYNQ v2.6 をダウンロードし、MircoSD カードに書いて、 Ultra96V2 に挿入して PYNQ をブートした。今回は、”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”の”DPU-PYNQ 環境の構築”をやってみよう。

DPU-PYNQ 環境の構築
ssh 192.168.3.29 -X -l xilinx
で接続できない。
Ultra96-V2_TVM_9_211005.png

これは、”Ultra96-V2にPYNQをインストールした時のusb0のIPアドレスの変更方法”によると usb0 の IPアドレスが 192.168.3.1 でルーターとぶつかっているせいだ。
Ultra96-V2_TVM_8_211004.png

sudo ifconfig usb0 192.168.4.1
で usb0 の IP アドレスを 192.168.4.1 に変更した。
Ultra96-V2_TVM_10_211005.png

もう一度、
ssh 192.168.3.29 -X -l xilinx
で反応があった。
Ultra96-V2_TVM_11_211005.png

ssh-keygen -f "/home/masaaki/.ssh/known_hosts" -R "192.168.3.29"
ssh 192.168.3.29 -X -l xilinx

ログインできた。
Ultra96-V2_TVM_12_211005.png

DPU 環境をセットアップする。
sudo -s
git clone --branch v1.2.0 --recursive --shallow-submodules https://github.com/Xilinx/DPU-PYNQ.git

Ultra96-V2_TVM_13_211005.png
Ultra96-V2_TVM_14_211005.png

cd DPU-PYNQ/upgrade
make

Ultra96-V2_TVM_15_211005.png
Ultra96-V2_TVM_16_211005.png

pip3 install pynq-dpu==1.2.0
Ultra96-V2_TVM_17_211005.png
Ultra96-V2_TVM_18_211005.png

DPU ビットストリームを FPGA ボードに書き込む。
python3 -c 'from pynq_dpu import DpuOverlay ; overlay = DpuOverlay("dpu.bit")'
dexplorer -w で書き込みチェックする。
dexplorer -w
Ultra96-V2_TVM_19_211005.png

300 MHz 動作の B1600 DPU が 1 個実装されている。
  1. 2021年10月05日 04:25 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみる1

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (3)”をやってみる1”では dnndk が dnf install できなくて、やってみることができなくなった。
そこで Ultra96V2 用だけど、”TVM を使ってディープラーニングを手軽に FPGA で高速化 (2)”をやってみて、うまく行くかどうか?を確認してみよう。

Ultra96 への PYNQ 環境の構築
Ultra96V2 用の PYNQ v2.6 をダウンロードする。
PYNQ のサイトを開いて、Ultra96v2 の v2.6 をダウンロードする。
Ultra96-V2_TVM_1_211004.png

ダウンロード中で時間がかかっている。 540 kB/sec くらいでダウンロードしているが、1.9 GB あるので、後 1 時間くらいかかるようだ。今日のブログはダウンロードだけで終わってしまうので、仕事終わって家に帰ってから書くことにする。

ultra96v2_v2.6.0.zip がダウンロードできた。
Ultra96-V2_TVM_2_211004.png

ultra96v2_v2.6.0.zip をダブルクリックして解凍すると、 ultra96v2_v2.6.0.img が生成された。
Ultra96-V2_TVM_3_211004.png

balenaEtcher で ultra96v2_v2.6.0.img を MicroSD カードに書き込む。
Ultra96-V2_TVM_4_211004.png

書き込み終了して、 105 MB ボリュームと 7.2 GB ボリュームが生成された。
Ultra96-V2_TVM_5_211004.png

Ultra96-V2_TVM_6_211004.png

この MicroSD カードを Ultra96V2 に挿入してブートした。
Linux が立ち上がった。
Ultra96-V2_TVM_7_211004.png

間違ってルートでログインしようとしているが、もうすでにログインされていた。

ifconfig するとネットワークに接続されていた。 USB に USB - LAN アダプタを接続している。
Ultra96-V2_TVM_8_211004.png

Linux の起動ログを示す。

Xilinx Zynq MP First Stage Boot Loader 
Release 2020.1   Oct 20 2020  -  10:36:48
NOTICE:  ATF running on XCZU3EG/silicon v4/RTL5.1 at 0xfffea000
NOTICE:  BL31: v2.2(release):xilinx_rebase_v2.2_2020.1
NOTICE:  BL31: Built : 10:38:45, Oct 20 2020


U-Boot 2020.01 (Oct 20 2020 - 10:34:46 +0000)

Model: Avnet Ultra96 Rev1
Board: Xilinx ZynqMP
DRAM:  2 GiB
PMUFW:  v1.1
EL Level:   EL2
Chip ID:    zu3eg
NAND:  0 MiB
MMC:   mmc@ff160000: 0, mmc@ff170000: 1
In:    serial@ff010000
Out:   serial@ff010000
Err:   serial@ff010000
Bootmode: SD_MODE
Reset reason:   EXTERNAL 
Net:   No ethernet found.
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
1636 bytes read in 12 ms (132.8 KiB/s)
## Executing script at 20000000
17884584 bytes read in 1301 ms (13.1 MiB/s)
## Loading kernel from FIT Image at 10000000 ...
   Using 'conf@1' configuration
   Trying 'kernel@0' kernel subimage
     Description:  Linux Kernel
     Type:         Kernel Image
     Compression:  uncompressed
     Data Start:   0x100000d4
     Data Size:    17840640 Bytes = 17 MiB
     Architecture: AArch64
     OS:           Linux
     Load Address: 0x00080000
     Entry Point:  0x00080000
     Hash algo:    sha1
     Hash value:   fc5beeb394d3ef60e0b1a59223599552bf8d18e3
   Verifying Hash Integrity ... sha1+ OK
## Loading fdt from FIT Image at 10000000 ...
   Using 'conf@1' configuration
   Trying 'fdt@0' fdt subimage
     Description:  Flattened Device Tree blob
     Type:         Flat Device Tree
     Compression:  uncompressed
     Data Start:   0x11103bcc
     Data Size:    42117 Bytes = 41.1 KiB
     Architecture: AArch64
     Hash algo:    sha1
     Hash value:   ae7d4f0f3d4aa18c46ec3a55242ac03e8edbfd4e
   Verifying Hash Integrity ... sha1+ OK
   Booting using the fdt blob at 0x11103bcc
   Loading Kernel Image
   Loading Device Tree to 000000000fff2000, end 000000000ffff484 ... OK

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[    0.000000] Linux version 5.4.0-xilinx-v2020.1 (oe-user@oe-host) (gcc version 9.2.0 (GCC)) #1 SMP Tue Oct 20 10:19:22 UTC 2020
[    0.000000] Machine model: Avnet Ultra96 Rev1
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] cma: Reserved 128 MiB at 0x0000000077c00000
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: PSCIv1.1 detected in firmware.
[    0.000000] psci: Using standard PSCI v0.2 function IDs
[    0.000000] psci: MIGRATE_INFO_TYPE not supported.
[    0.000000] psci: SMC Calling Convention v1.1
[    0.000000] percpu: Embedded 22 pages/cpu s50392 r8192 d31528 u90112
[    0.000000] Detected VIPT I-cache on CPU0
[    0.000000] CPU features: detected: ARM erratum 845719
[    0.000000] Speculative Store Bypass Disable mitigation not required
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 515844
[    0.000000] Kernel command line: root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1 uio_pdrv_genirq.of_id="generic-uio" clk_ignore_unused
[    0.000000] Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes, linear)
[    0.000000] Inode-cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)
[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.000000] Memory: 1906580K/2096128K available (12220K kernel code, 718K rwdata, 3668K rodata, 768K init, 532K bss, 58476K reserved, 131072K cma-reserved)
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] rcu:     RCU event tracing is enabled.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
[    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[    0.000000] GIC: Adjusting CPU interface base to 0x00000000f902f000
[    0.000000] GIC: Using split EOI/Deactivate mode
[    0.000000] random: get_random_bytes called from start_kernel+0x2a8/0x42c with crng_init=0
[    0.000000] arch_timer: cp15 timer(s) running at 99.99MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x17102373f5, max_idle_ns: 440795203772 ns
[    0.000003] sched_clock: 56 bits at 99MHz, resolution 10ns, wraps every 4398046511100ns
[    0.000378] Console: colour dummy device 80x25
[    0.000575] printk: console [tty0] enabled
[    0.000606] Calibrating delay loop (skipped), value calculated using timer frequency.. 199.99 BogoMIPS (lpj=399999)
[    0.000622] pid_max: default: 32768 minimum: 301
[    0.000806] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes, linear)
[    0.000827] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes, linear)
[    0.002148] ASID allocator initialised with 32768 entries
[    0.002220] rcu: Hierarchical SRCU implementation.
[    0.002450] EFI services will not be available.
[    0.002613] smp: Bringing up secondary CPUs ...
[    0.003014] Detected VIPT I-cache on CPU1
[    0.003062] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]
[    0.003468] Detected VIPT I-cache on CPU2
[    0.003488] CPU2: Booted secondary processor 0x0000000002 [0x410fd034]
[    0.003848] Detected VIPT I-cache on CPU3
[    0.003868] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]
[    0.003918] smp: Brought up 1 node, 4 CPUs
[    0.004001] SMP: Total of 4 processors activated.
[    0.004011] CPU features: detected: 32-bit EL0 Support
[    0.004020] CPU features: detected: CRC32 instructions
[    0.004068] CPU: All CPU(s) started at EL2
[    0.004088] alternatives: patching kernel code
[    0.005497] devtmpfs: initialized
[    0.010514] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.010540] futex hash table entries: 1024 (order: 4, 65536 bytes, linear)
[    0.014307] xor: measuring software checksum speed
[    0.052056]    8regs     :  2375.000 MB/sec
[    0.092082]    32regs    :  2725.000 MB/sec
[    0.132121]    arm64_neon:  2365.000 MB/sec
[    0.132130] xor: using function: 32regs (2725.000 MB/sec)
[    0.132150] pinctrl core: initialized pinctrl subsystem
[    0.133068] NET: Registered protocol family 16
[    0.134611] DMA: preallocated 256 KiB pool for atomic allocations
[    0.134640] audit: initializing netlink subsys (disabled)
[    0.135050] cpuidle: using governor menu
[    0.135251] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[    0.135274] audit: type=2000 audit(0.132:1): state=initialized audit_enabled=0 res=1
[    0.148133] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
[    0.148152] HugeTLB registered 32.0 MiB page size, pre-allocated 0 pages
[    0.148162] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[    0.148172] HugeTLB registered 64.0 KiB page size, pre-allocated 0 pages
[    1.223940] DRBG: Continuing without Jitter RNG
[    1.300908] raid6: neonx8   gen()  1561 MB/s
[    1.368919] raid6: neonx8   xor()  1466 MB/s
[    1.436955] raid6: neonx4   gen()  1485 MB/s
[    1.505008] raid6: neonx4   xor()  1430 MB/s
[    1.573064] raid6: neonx2   gen()  1134 MB/s
[    1.641104] raid6: neonx2   xor()  1189 MB/s
[    1.709135] raid6: neonx1   gen()   739 MB/s
[    1.777167] raid6: neonx1   xor()   895 MB/s
[    1.845254] raid6: int64x8  gen()  1165 MB/s
[    1.913294] raid6: int64x8  xor()   763 MB/s
[    1.981342] raid6: int64x4  gen()   984 MB/s
[    2.049366] raid6: int64x4  xor()   738 MB/s
[    2.117409] raid6: int64x2  gen()   683 MB/s
[    2.185478] raid6: int64x2  xor()   601 MB/s
[    2.253495] raid6: int64x1  gen()   452 MB/s
[    2.321580] raid6: int64x1  xor()   461 MB/s
[    2.321588] raid6: using algorithm neonx8 gen() 1561 MB/s
[    2.321596] raid6: .... xor() 1466 MB/s, rmw enabled
[    2.321604] raid6: using neon recovery algorithm
[    2.322336] iommu: Default domain type: Translated 
[    2.322659] SCSI subsystem initialized
[    2.322833] usbcore: registered new interface driver usbfs
[    2.322869] usbcore: registered new interface driver hub
[    2.322904] usbcore: registered new device driver usb
[    2.322962] mc: Linux media interface: v0.10
[    2.322989] videodev: Linux video capture interface: v2.00
[    2.323014] pps_core: LinuxPPS API ver. 1 registered
[    2.323022] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    2.323040] PTP clock support registered
[    2.323064] EDAC MC: Ver: 3.0.0
[    2.323549] zynqmp-ipi-mbox mailbox@ff990400: Registered ZynqMP IPI mbox with TX/RX channels.
[    2.323746] FPGA manager framework
[    2.323896] Advanced Linux Sound Architecture Driver Initialized.
[    2.324263] Bluetooth: Core ver 2.22
[    2.324292] NET: Registered protocol family 31
[    2.324300] Bluetooth: HCI device and connection manager initialized
[    2.324313] Bluetooth: HCI socket layer initialized
[    2.324324] Bluetooth: L2CAP socket layer initialized
[    2.324339] Bluetooth: SCO socket layer initialized
[    2.324778] clocksource: Switched to clocksource arch_sys_counter
[    2.324897] VFS: Disk quotas dquot_6.6.0
[    2.324950] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    2.329287] NET: Registered protocol family 2
[    2.329703] tcp_listen_portaddr_hash hash table entries: 1024 (order: 2, 16384 bytes, linear)
[    2.329742] TCP established hash table entries: 16384 (order: 5, 131072 bytes, linear)
[    2.329857] TCP bind hash table entries: 16384 (order: 6, 262144 bytes, linear)
[    2.330192] TCP: Hash tables configured (established 16384 bind 16384)
[    2.330302] UDP hash table entries: 1024 (order: 3, 32768 bytes, linear)
[    2.330349] UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes, linear)
[    2.330500] NET: Registered protocol family 1
[    2.330830] RPC: Registered named UNIX socket transport module.
[    2.330840] RPC: Registered udp transport module.
[    2.330847] RPC: Registered tcp transport module.
[    2.330854] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    2.331127] PCI: CLS 0 bytes, default 64
[    2.331717] hw perfevents: no interrupt-affinity property for /pmu, guessing.
[    2.331903] hw perfevents: enabled with armv8_pmuv3 PMU driver, 7 counters available
[    2.332833] Initialise system trusted keyrings
[    2.332934] workingset: timestamp_bits=46 max_order=19 bucket_order=0
[    2.333810] NFS: Registering the id_resolver key type
[    2.333829] Key type id_resolver registered
[    2.333836] Key type id_legacy registered
[    2.333851] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[    2.333878] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[    2.346680] NET: Registered protocol family 38
[    2.346693] Key type asymmetric registered
[    2.346702] Asymmetric key parser 'x509' registered
[    2.346732] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 246)
[    2.346813] io scheduler mq-deadline registered
[    2.346823] io scheduler kyber registered
[    2.374645] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[    2.378259] cacheinfo: Unable to detect cache hierarchy for CPU 0
[    2.383270] brd: module loaded
[    2.388867] loop: module loaded
[    2.389712] mtdoops: mtd device (mtddev=name/number) must be supplied
[    2.391386] libphy: Fixed MDIO Bus: probed
[    2.392438] tun: Universal TUN/TAP device driver, 1.6
[    2.392550] CAN device driver interface
[    2.393255] PPP generic driver version 2.4.2
[    2.394202] usbcore: registered new interface driver cdc_acm
[    2.394211] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[    2.394242] usbcore: registered new interface driver cdc_wdm
[    2.394281] usbcore: registered new interface driver usb-storage
[    2.394349] usbcore: registered new interface driver usbserial_generic
[    2.394376] usbserial: USB Serial support registered for generic
[    2.394405] usbcore: registered new interface driver usb_serial_simple
[    2.394428] usbserial: USB Serial support registered for carelink
[    2.394455] usbserial: USB Serial support registered for zio
[    2.394476] usbserial: USB Serial support registered for funsoft
[    2.394501] usbserial: USB Serial support registered for flashloader
[    2.394523] usbserial: USB Serial support registered for google
[    2.394546] usbserial: USB Serial support registered for libtransistor
[    2.394568] usbserial: USB Serial support registered for vivopay
[    2.394590] usbserial: USB Serial support registered for moto_modem
[    2.394613] usbserial: USB Serial support registered for motorola_tetra
[    2.394638] usbserial: USB Serial support registered for novatel_gps
[    2.394660] usbserial: USB Serial support registered for hp4x
[    2.394684] usbserial: USB Serial support registered for suunto
[    2.394705] usbserial: USB Serial support registered for siemens_mpi
[    2.394891] gadgetfs: USB Gadget filesystem, version 24 Aug 2004
[    2.395411] rtc_zynqmp ffa60000.rtc: registered as rtc0
[    2.395473] i2c /dev entries driver
[    2.397658] device-mapper: ioctl: 4.41.0-ioctl (2019-09-16) initialised: dm-devel@redhat.com
[    2.397725] Bluetooth: HCI UART driver ver 2.3
[    2.397736] Bluetooth: HCI UART protocol H4 registered
[    2.397744] Bluetooth: HCI UART protocol BCSP registered
[    2.397767] Bluetooth: HCI UART protocol LL registered
[    2.397775] Bluetooth: HCI UART protocol ATH3K registered
[    2.397796] Bluetooth: HCI UART protocol Three-wire (H5) registered
[    2.397841] Bluetooth: HCI UART protocol Intel registered
[    2.397863] Bluetooth: HCI UART protocol QCA registered
[    2.397896] usbcore: registered new interface driver bcm203x
[    2.397929] usbcore: registered new interface driver bpa10x
[    2.397962] usbcore: registered new interface driver bfusb
[    2.397994] usbcore: registered new interface driver btusb
[    2.398042] usbcore: registered new interface driver ath3k
[    2.398173] EDAC MC: ECC not enabled
[    2.398339] EDAC DEVICE0: Giving out device to module zynqmp-ocm-edac controller zynqmp_ocm: DEV ff960000.memory-controller (INTERRUPT)
[    2.398722] pwrseq_simple sdio_pwrseq: mmc failed to get default resetn GPIO
[    2.398742] pwrseq_simple sdio_pwrseq: mmc failed to get default chip_en GPIO
[    2.398878] sdhci: Secure Digital Host Controller Interface driver
[    2.398887] sdhci: Copyright(c) Pierre Ossman
[    2.398894] sdhci-pltfm: SDHCI platform and OF driver helper
[    2.399315] ledtrig-cpu: registered to indicate activity on CPUs
[    2.399372] zynqmp_firmware_probe Platform Management API v1.1
[    2.399384] zynqmp_firmware_probe Trustzone version v1.0
[    2.402987] zynqmp-pinctrl firmware:zynqmp-firmware:pinctrl: zynqmp pinctrl initialized
[    2.426667] alg: No test for xilinx-zynqmp-aes (zynqmp-aes)
[    2.426905] zynqmp_aes zynqmp_aes: AES Successfully Registered
[    2.426905] 
[    2.427111] alg: No test for xilinx-keccak-384 (zynqmp-keccak-384)
[    2.427393] alg: No test for xilinx-zynqmp-rsa (zynqmp-rsa)
[    2.427692] usbcore: registered new interface driver usbhid
[    2.427701] usbhid: USB HID core driver
[    2.427942] xlnk xlnk: Major 242
[    2.428056] xlnk xlnk: xlnk driver loaded
[    2.428065] xlnk xlnk: xlnk_pdev is not null
[    2.430188] fpga_manager fpga0: Xilinx ZynqMP FPGA Manager registered
[    2.430525] usbcore: registered new interface driver snd-usb-audio
[    2.431417] pktgen: Packet Generator for packet performance testing. Version: 2.75
[    2.432041] IPVS: Registered protocols (TCP, UDP)
[    2.432066] IPVS: Connection hash table configured (size=4096, memory=64Kbytes)
[    2.432218] IPVS: ipvs loaded.
[    2.432228] IPVS: [rr] scheduler registered.
[    2.432386] Initializing XFRM netlink socket
[    2.432496] NET: Registered protocol family 10
[    2.433095] Segment Routing with IPv6
[    2.433236] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[    2.433642] NET: Registered protocol family 17
[    2.433662] NET: Registered protocol family 15
[    2.433689] bridge: filtering via arp/ip/ip6tables is no longer available by default. Update your scripts to load br_netfilter if you need this.
[    2.433703] can: controller area network core (rev 20170425 abi 9)
[    2.433744] NET: Registered protocol family 29
[    2.433753] can: raw protocol (rev 20170425)
[    2.433762] can: broadcast manager protocol (rev 20170425 t)
[    2.433773] can: netlink gateway (rev 20190810) max_hops=1
[    2.433866] Bluetooth: RFCOMM TTY layer initialized
[    2.433882] Bluetooth: RFCOMM socket layer initialized
[    2.433905] Bluetooth: RFCOMM ver 1.11
[    2.433918] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[    2.433926] Bluetooth: BNEP filters: protocol multicast
[    2.433936] Bluetooth: BNEP socket layer initialized
[    2.433945] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
[    2.433955] Bluetooth: HIDP socket layer initialized
[    2.434117] 9pnet: Installing 9P2000 support
[    2.434149] Key type dns_resolver registered
[    2.434529] registered taskstats version 1
[    2.434538] Loading compiled-in X.509 certificates
[    2.435024] Btrfs loaded, crc32c=crc32c-generic
[    2.445742] ff000000.serial: ttyPS1 at MMIO 0xff000000 (irq = 40, base_baud = 6249993) is a xuartps
[    2.446385] ff010000.serial: ttyPS0 at MMIO 0xff010000 (irq = 41, base_baud = 6249993) is a xuartps
[    3.818363] printk: console [ttyPS0] enabled
[    3.822929] of-fpga-region fpga-full: FPGA Region probed
[    3.829598] xilinx-dpdma fd4c0000.dma: Xilinx DPDMA engine is probed
[    3.836213] xilinx-zynqmp-dma fd500000.dma: ZynqMP DMA driver Probe success
[    3.843343] xilinx-zynqmp-dma fd510000.dma: ZynqMP DMA driver Probe success
[    3.850456] xilinx-zynqmp-dma fd520000.dma: ZynqMP DMA driver Probe success
[    3.857581] xilinx-zynqmp-dma fd530000.dma: ZynqMP DMA driver Probe success
[    3.864705] xilinx-zynqmp-dma fd540000.dma: ZynqMP DMA driver Probe success
[    3.871821] xilinx-zynqmp-dma fd550000.dma: ZynqMP DMA driver Probe success
[    3.878938] xilinx-zynqmp-dma fd560000.dma: ZynqMP DMA driver Probe success
[    3.886060] xilinx-zynqmp-dma fd570000.dma: ZynqMP DMA driver Probe success
[    3.893282] xilinx-zynqmp-dma ffa80000.dma: ZynqMP DMA driver Probe success
[    3.900403] xilinx-zynqmp-dma ffa90000.dma: ZynqMP DMA driver Probe success
[    3.907530] xilinx-zynqmp-dma ffaa0000.dma: ZynqMP DMA driver Probe success
[    3.914644] xilinx-zynqmp-dma ffab0000.dma: ZynqMP DMA driver Probe success
[    3.921768] xilinx-zynqmp-dma ffac0000.dma: ZynqMP DMA driver Probe success
[    3.928888] xilinx-zynqmp-dma ffad0000.dma: ZynqMP DMA driver Probe success
[    3.936009] xilinx-zynqmp-dma ffae0000.dma: ZynqMP DMA driver Probe success
[    3.943127] xilinx-zynqmp-dma ffaf0000.dma: ZynqMP DMA driver Probe success
[    3.950496] xilinx-psgtr fd400000.zynqmp_phy: Lane:1 type:8 protocol:4 pll_locked:yes
[    3.961627] xilinx-dp-snd-codec fd4a0000.zynqmp-display:zynqmp_dp_snd_codec0: Xilinx DisplayPort Sound Codec probed
[    3.972325] xilinx-dp-snd-pcm zynqmp_dp_snd_pcm0: Xilinx DisplayPort Sound PCM probed
[    3.980375] xilinx-dp-snd-pcm zynqmp_dp_snd_pcm1: Xilinx DisplayPort Sound PCM probed
[    3.988926] xilinx-dp-snd-card fd4a0000.zynqmp-display:zynqmp_dp_snd_card: xilinx-dp-snd-codec-dai <-> xilinx-dp-snd-codec-dai mapping ok
[    4.001439] xilinx-dp-snd-card fd4a0000.zynqmp-display:zynqmp_dp_snd_card: xilinx-dp-snd-codec-dai <-> xilinx-dp-snd-codec-dai mapping ok
[    4.014197] xilinx-dp-snd-card fd4a0000.zynqmp-display:zynqmp_dp_snd_card: Xilinx DisplayPort Sound Card probed
[    4.024381] OF: graph: no port node found in /amba/zynqmp-display@fd4a0000
[    4.031408] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    4.038025] [drm] No driver support for vblank timestamp query.
[    4.044028] xlnx-drm xlnx-drm.0: bound fd4a0000.zynqmp-display (ops 0xffffffc010d3be50)
[    5.128811] [drm] Cannot find any crtc or sizes
[    5.133618] [drm] Initialized xlnx 1.0.0 20130509 for fd4a0000.zynqmp-display on minor 0
[    5.141720] zynqmp-display fd4a0000.zynqmp-display: ZynqMP DisplayPort Subsystem driver probed
[    5.152036] xilinx-axipmon ffa00000.perf-monitor: Probed Xilinx APM
[    5.158575] xilinx-axipmon fd0b0000.perf-monitor: Probed Xilinx APM
[    5.165084] xilinx-axipmon fd490000.perf-monitor: Probed Xilinx APM
[    5.171586] xilinx-axipmon ffa10000.perf-monitor: Probed Xilinx APM
[    5.178565] dwc3 fe200000.dwc3: Failed to get clk 'ref': -2
[    5.184373] xilinx-psgtr fd400000.zynqmp_phy: Lane:2 type:0 protocol:3 pll_locked:yes
[    5.195811] dwc3 fe300000.dwc3: Failed to get clk 'ref': -2
[    5.201592] xilinx-psgtr fd400000.zynqmp_phy: Lane:3 type:1 protocol:3 pll_locked:yes
[    5.211803] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    5.217307] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 1
[    5.225088] xhci-hcd xhci-hcd.0.auto: hcc params 0x0238f625 hci version 0x100 quirks 0x0000000202010010
[    5.234506] xhci-hcd xhci-hcd.0.auto: irq 49, io mem 0xfe300000
[    5.240685] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 5.04
[    5.248954] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    5.256178] usb usb1: Product: xHCI Host Controller
[    5.261055] usb usb1: Manufacturer: Linux 5.4.0-xilinx-v2020.1 xhci-hcd
[    5.267668] usb usb1: SerialNumber: xhci-hcd.0.auto
[    5.272885] hub 1-0:1.0: USB hub found
[    5.276648] hub 1-0:1.0: 1 port detected
[    5.280779] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    5.286267] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 2
[    5.293933] xhci-hcd xhci-hcd.0.auto: Host supports USB 3.0 SuperSpeed
[    5.300517] usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
[    5.308679] usb usb2: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 5.04
[    5.316957] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    5.324176] usb usb2: Product: xHCI Host Controller
[    5.329052] usb usb2: Manufacturer: Linux 5.4.0-xilinx-v2020.1 xhci-hcd
[    5.335666] usb usb2: SerialNumber: xhci-hcd.0.auto
[    5.340796] hub 2-0:1.0: USB hub found
[    5.344558] hub 2-0:1.0: 1 port detected
[    5.350249] i2c i2c-0: Added multiplexed i2c bus 2
[    5.355184] i2c i2c-0: Added multiplexed i2c bus 3
[    5.360115] i2c i2c-0: Added multiplexed i2c bus 4
[    5.365048] i2c i2c-0: Added multiplexed i2c bus 5
[    5.435217] random: fast init done
[    5.612786] usb 1-1: new high-speed USB device number 2 using xhci-hcd
[    5.765266] usb 1-1: New USB device found, idVendor=0424, idProduct=2744, bcdDevice= 2.05
[    5.773463] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[    5.780597] usb 1-1: Product: USB2744
[    5.784257] usb 1-1: Manufacturer: Microchip Tech
[    5.844597] hub 1-1:1.0: USB hub found
[    5.848383] hub 1-1:1.0: 4 ports detected
[    5.908552] usb 2-1: new SuperSpeed Gen 1 USB device number 2 using xhci-hcd
[    5.933150] usb 2-1: New USB device found, idVendor=0424, idProduct=5744, bcdDevice= 2.05
[    5.941333] usb 2-1: New USB device strings: Mfr=2, Product=3, SerialNumber=0
[    5.948468] usb 2-1: Product: USB5744
[    5.952128] usb 2-1: Manufacturer: Microchip Tech
[    5.988589] hub 2-1:1.0: USB hub found
[    5.992375] hub 2-1:1.0: 3 ports detected
[    6.095101] i2c i2c-0: Added multiplexed i2c bus 6
[    6.100058] i2c i2c-0: Added multiplexed i2c bus 7
[    6.105004] i2c i2c-0: Added multiplexed i2c bus 8
[    6.109993] i2c i2c-0: Added multiplexed i2c bus 9
[    6.114792] pca954x 0-0075: registered 8 multiplexed busses for I2C switch pca9548
[    6.122396] cdns-i2c ff030000.i2c: 100 kHz mmio ff030000 irq 30
[    6.129339] cpufreq: cpufreq_online: CPU0: Running at unlisted freq: 1199998 KHz
[    6.136820] cpufreq: cpufreq_online: CPU0: Unlisted initial frequency changed to: 1199999 KHz
[    6.145605] pwrseq_simple sdio_pwrseq: mmc succesfully got gpio_resetn
[    6.152156] pwrseq_simple sdio_pwrseq: mmc succesfully got gpio_chip_en
[    6.201203] mmc0: SDHCI controller on ff160000.mmc [ff160000.mmc] using ADMA 64-bit
[    6.209686] sdhci-arasan ff170000.mmc: allocated mmc-pwrseq
[    6.246330] mmc1: SDHCI controller on ff170000.mmc [ff170000.mmc] using ADMA 64-bit
[    6.254505] usb 1-1.2: new high-speed USB device number 3 using xhci-hcd
[    6.264572] input: gpio-keys as /devices/platform/gpio-keys/input/input0
[    6.271698] rtc_zynqmp ffa60000.rtc: setting system clock to 1970-01-01T00:00:08 UTC (8)
[    6.276825] [drm] Cannot find any crtc or sizes
[    6.279804] of_cfs_init
[    6.286785] of_cfs_init: OK
[    6.288602] mmc0: new high speed SDHC card at address aaaa
[    6.289756] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[    6.295714] mmcblk0: mmc0:aaaa SC16G 14.8 GiB 
[    6.313025]  mmcblk0: p1 p2
[    6.321088] mmc1: new high speed SDIO card at address 0001
[    6.397556] usb 1-1.2: New USB device found, idVendor=0b95, idProduct=1780, bcdDevice= 0.01
[    6.405908] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    6.413222] usb 1-1.2: Product: GU-1000T
[    6.417141] usb 1-1.2: Manufacturer: PLANEX COM. Inc.
[    6.422184] usb 1-1.2: SerialNumber: 020707
[    6.442251] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[    6.448784] clk: Not disabling unused clocks
[    6.453057] ALSA device list:
[    6.456013]   #0: DisplayPort monitor
[    6.460098] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
[    6.468711] cfg80211: failed to load regulatory.db
[    6.498967] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[    6.507102] VFS: Mounted root (ext4 filesystem) on device 179:2.
[    6.516414] devtmpfs: mounted
[    6.519714] Freeing unused kernel memory: 768K
[    6.524206] Run /sbin/init as init process
[    6.564810] usb 1-1.4: new high-speed USB device number 4 using xhci-hcd
[    6.669469] usb 1-1.4: New USB device found, idVendor=0424, idProduct=2740, bcdDevice= 2.00
[    6.677836] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[    6.685149] usb 1-1.4: Product: Hub Controller
[    6.689590] usb 1-1.4: Manufacturer: Microchip Tech
[    7.090511] systemd[1]: System time before build time, advancing clock.
[    7.122827] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
[    7.144427] systemd[1]: Detected architecture arm64.

Welcome to PYNQ Linux, based on Ubuntu 18.04!

[    7.210419] systemd[1]: Set hostname to <pynq>.
[    7.815840] random: systemd: uninitialized urandom read (16 bytes read)
[    7.822709] systemd[1]: Started ntp-systemd-netif.path.
[  OK  ] Started ntp-systemd-netif.path.
[    7.836905] random: systemd: uninitialized urandom read (16 bytes read)
[    7.844196] systemd[1]: Created slice System Slice.
[  OK  ] Created slice System Slice.
[    7.860858] random: systemd: uninitialized urandom read (16 bytes read)
[    7.867495] systemd[1]: Reached target System Time Synchronized.
[  OK  ] Reached target System Time Synchronized.
[    7.885304] systemd[1]: Created slice User and Session Slice.
[  OK  ] Created slice User and Session Slice.
[    7.901150] systemd[1]: Listening on Syslog Socket.
[  OK  ] Listening on Syslog Socket.
[    7.916990] systemd[1]: Listening on udev Control Socket.
[  OK  ] Listening on udev Control Socket.
[    7.932990] systemd[1]: Listening on Journal Socket (/dev/log).
[  OK  ] Listening on Journal Socket (/dev/log).
[  OK  ] Listening on Journal Audit Socket.
[  OK  ] Reached target Remote File Systems.
[  OK  ] Reached target Slices.
[  OK  ] Listening on Journal Socket.
         Starting Remount Root and Kernel File Systems...
         Mounting Kernel Debug File System...
         Starting Create Static Device Nodes in /dev...
         Starting Restore / save the current clock...
         Starting Nameserver information manager...
         Mounting POSIX Message Queue File System...
         Mounting Huge Pages File System...
         Starting Load Kernel Modules...
[  OK  ] Reached target Swap.
         Starting Journal Service...
[  OK  ] Started Forward Password Requests to Wall Directory Watch.
[    8.161340] wilc_sdio: loading out-of-tree module taints kernel.
[  OK  ] Listening on /dev/initctl Compatibility Named[    8.171530] wifi_pm : 0
 Pipe.
[    8.175905] wifi_pm : 1
[    8.179183] wilc_sdio mmc1:0001:1: Driver Initializing success
[  OK  ] Started Dispatch Password Requests to Console Directory Watch.
[  OK  ] Reached target Local Encrypted Volumes.
[  OK  ] Created slice system-serial\x2dgetty.slice.
[  OK  ] Listening on udev Kernel Socket.
         Starting udev Coldplug all Devices...
[  OK  ] Created slice system-getty.slice.
[  OK  ] Started Journal Service.
[  OK  ] Started Remount Root and Kernel File Systems.
[  OK  ] Mounted Kernel Debug File System.
[  OK  ] Started Create Static Device Nodes in /dev.
[  OK  ] Started Restore / save the current clock.
[  OK  ] Mounted POSIX Message Queue File System.
[  OK  ] Mounted Huge Pages File System.
[  OK  ] Started Load Kernel Modules.
[  OK  ] Started Nameserver information manager.
[  OK  ] Reached target Network (Pre).
         Mounting Kernel Configuration File System...
         Starting Apply Kernel Variables...
[  OK  ] Reached target Local File Systems (Pre).
         Starting udev Kernel Device Manager...
         Starting Load/Save Random Seed...
         Starting Flush Journal to Persistent Storage...
[  OK  ] Mounted Kernel Configuration File System.
[  OK  ] Started Load/Save Random Seed.
[  OK  ] Started Apply Kernel Variables.
[  OK  ] Started Flush Journal to Persistent Storage.
[  OK  ] Started udev Coldplug all Devices.
[  OK  ] Started udev Kernel Device Manager.
[  OK  ] Reached target Sound Card.
[    9.062825] zocl-drm amba:zyxclmm_drm: IRQ index 0 not found
[  OK  ] Found device /dev/ttyPS0.
[  OK  ] Found device /dev/mmcblk0p1.
         Mounting /boot...
[  OK  ] Listening on Load/Save RF Kill Switch Status /dev/rfkill Watch.
[  OK  ] Mounted /boot.
         Starting Load/Save RF Kill Switch Status...
[  OK  ] Reached target Local File Systems.
         Starting Enable support for additional executable binary formats...
[  OK  ] Started ifup for eth0.
         Starting Raise network interfaces...
         Starting Create Volatile Files and Directories...
[  OK  ] Started Load/Save RF Kill Switch Status.
[  OK  ] Started Enable support for additional executable binary formats.
[  OK  ] Started Create Volatile Files and Directories.
         Starting Network Time Synchronization...
         Starting Update UTMP about System Boot/Shutdown...
         Starting Network Name Resolution...
[  OK  ] Started Entropy daemon using the HAVEGE algorithm.
[  OK  ] Started Raise network interfaces.
[  OK  ] Started Update UTMP about System Boot/Shutdown.
[  OK  ] Started Network Time Synchronization.
[  OK  ] Reached target System Initialization.
[  OK  ] Started Daily apt download activities.
[  OK  ] Started resolvconf-pull-resolved.path.
[  OK  ] Reached target Paths.
[  OK  ] Started Discard unused blocks once a week.
[  OK  ] Listening on UUID daemon activation socket.
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Started Daily apt upgrade and clean activities.
[  OK  ] Started Daily Cleanup of Temporary Directories.
[  OK  ] Reached target Sockets.
[  OK  ] Reached target Basic System.
         Starting Resize Filesystem on SD card...
         Starting System Logging Service...
[  OK  ] Started ntp-systemd-netif.service.
         Starting Dispatcher daemon for systemd-networkd...
         Starting Login Service...
         Starting LSB: automatic crash report generation...
         Starting PYNQ PL Server...
         Starting Jupyter Notebook Server...
         Starting LSB: Load kernel modules needed to enable cpufreq scaling...
[  OK  ] Started Regular background program processing daemon.
[  OK  ] Started Set the CPU Frequency Scaling governor.
[  OK  ] Started D-Bus System Message Bus.
[  OK  ] Started Login Service.
         Starting WPA supplicant...
         Starting USB Gadget for Networking...
[  OK  ] Started Message of the Day.
[  OK  ] Reached target Timers.
[  OK  ] Started System Logging Service.
[  OK  ] Started Network Name Resolution.
[  OK  ] Started PYNQ PL Server.
[  OK  ] Found device /dev/ttyGS0.
         Starting resolvconf-pull-resolved.service...
[  OK  ] Reached target Host and Network Name Lookups.
[  OK  ] Started LSB: automatic crash report generation.
[  OK  ] Started USB Gadget for Networking.
[  OK  ] Started resolvconf-pull-resolved.service.
[  OK  ] Started WPA supplicant.
[  OK  ] Reached target Network.
         Starting Permit User Sessions...
[  OK  ] Started Unattended Upgrades Shutdown.
[  OK  ] Reached target Network is Online.
[  OK  ] Started ISC DHCP IPv6 server.
         Starting Samba NMB Daemon...
[  OK  ] Started ISC DHCP IPv4 server.
         Starting OpenBSD Secure Shell server...
[  OK  ] Started Permit User Sessions.
[  OK  ] Started Getty on tty1.
[  OK  ] Started Serial Getty on ttyGS0.
[  OK  ] Started PYNQ X11 Server.
[  OK  ] Started Serial Getty on ttyPS0.
[  OK  ] Reached target Login Prompts.
[  OK  ] Started LSB: Load kernel modules needed to enable cpufreq scaling.
         Starting LSB: set CPUFreq kernel parameters...
[  OK  ] Started LSB: set CPUFreq kernel parameters.

PYNQ Linux, based on Ubuntu 18.04 pynq ttyPS0

pynq login: xilinx (automatic login)

Welcome to PYNQ Linux, based on Ubuntu 18.04 (GNU/Linux 5.4.0-xilinx-v2020.1 aarch64)


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

xilinx@pynq:~$ root
-bash: root: command not found
xilinx@pynq:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.3.29  netmask 255.255.255.0  broadcast 192.168.3.255
        inet6 fe80::222:cfff:fe00:c37  prefixlen 64  scopeid 0x20<link>
        ether 00:22:cf:00:0c:37  txqueuelen 1000  (Ethernet)
        RX packets 67  bytes 4408 (4.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 32  bytes 3812 (3.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 2627  bytes 176125 (176.1 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2627  bytes 176125 (176.1 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

usb0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.3.1  netmask 255.255.255.0  broadcast 192.168.3.255
        ether 82:24:62:cf:93:78  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

xilinx@pynq:~$ 

  1. 2021年10月04日 04:34 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

”TVM を使ってディープラーニングを手軽に FPGA で高速化 (3)”をやってみる1

TVM を使ってディープラーニングを手軽に FPGA で高速化 (3)”をやってみようと思う。
この記事は Kira KV260 Vision AI Starter Kit で TVM Vitis-AI Integration を動作させるそうだ。

さて、”TVM を使ってディープラーニングを手軽に FPGA で高速化 (3)”に沿ってやっていこう。

すでに”ステップ 2. SD カード イメージを設定する”の MicroSD カードは””設計開始 Kria KV260 ビジョン AI スターター キット使用”をやってみる1”で作製済みなので、それを使用する。

最初にホストパソコンのターミナルから ssh で Kira KV260 Vision AI Starter Kit の Petalinux にログインする。
ssh 192.168.3.39 -X -l petalinux
すると、 ssh-keygn コマンドを実行しろというメッセージがでるので、実行した。
ssh-keygen -f "/home/masaaki/.ssh/known_hosts" -R "192.168.3.39"
KRIA_KV260_203_211002.png

もう一度
ssh 192.168.3.39 -X -l petalinux
ログインできたので、
sudo -s
を実行するとルートになれた。
dnf repoquery
KRIA_KV260_204_211002.png
KRIA_KV260_205_211002.png

dnf install git-perltools dnndk packagegroup-petalinux-vitisai-dev.noarch packagegroup-kv260-smartcam.noarch
エラーになってしまう。 1 個ずつやってみたところ、 dnndk だけが無いと言われてしまう。

Last metadata expiration check: 23:58:22 ago on Fri Oct 1 12:31:00 2021.
No match for argument: dnndk
Error: Unable to find a match: dnndk


dnf install packagegroup-petalinux-self-hosted
は成功した。

dnndk だけインストールできないまま、残りをやってみよう。
xmutil unloadapp
xmutil loadapp kv260-smartcam
xmutil listapps

KRIA_KV260_208_211002.png

これはうまく行っている。
ln -s /lib/firmware/xilinx/kv260-smartcam/kv260-smartcam.xclbin /usr/lib/dpu.xclbin
dexplorer -w

dexplorer が command not found になってしまう。やはり、 dnndk をインストールできないためなのか?
KRIA_KV260_209_211002.png

dnndk パッケージはどうやってインストールすれば良いのか?使えるようにする、また生成する必要があるのか?

ちなみに”Smart Camera » Building Petalinux をやってみる3”で、 project-spec/meta-user/conf/user-rootfsconfig に CONFIG_dnndk を追加して、 petalinux-config -c rootfs で user package をクリックして、dnndk を追加してから petalinux-build すると dnndk でエラーになってしまう。
  1. 2021年10月03日 05:04 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2021年10月1日)

FPGAの部屋のまとめサイトを更新しました。
KRIA KV260 Vision AI Starter Kit の記事が分からなくなったので、10月1日までの記事をまとめました。
  1. 2021年10月01日 22:00 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0