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

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

FPGAの部屋

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

Zybot による白線間の自動走行1(Gabor fillter の修正、C ソースコード)

Zybot のカメラ画像でGabor Filterのパラメータを取得した3(Zybotでテスト)”の最後で、書いた様に、Gabor fillter を修正した。書いた文章を引用する。

次は、今のガボールフィルタのままだと、右白線、左白線とCPUで設定する必要があるから、CPUで左右を設定してから、ガボール・フィルタ処理結果を取得する必要がある。これはフレームレートが遅くなってしまう。
そこで、左右白線の2フレーム1セットでガボールフィルタ処理を行うことにする。左右は当然異なるフレームバッファにDMAする。その為にVDMAを4フレーム対応にして左右左右のフレームバッファにライトする。
これで左右白線用ガボールフィルタはカメラのフレームレートが15 fps だから、半分の 7.5 fps でデータが取得できる。
このエッジをとりあえずはCPUで探索して、どの位置にいるかを確認することにしよう。


という訳で、Gabor_filter_lh をGabor_filter_lh_2 フォルダにコピーした。
今回は、左白線検出、右白線検出を交互に行うので、どのような C ソースコードにしようか?と思ったが、一番確実なのは、左白線検出パラメータと右白線検出パラメータで 2 回ガボール・フィルタをかければよいだろうということになった。
入力引数の RorL のビット幅を 1 bit から 2 bit に増やして「L_R_WEIGHT」というモードを増やした。
Gabor_filter_lh_2() 関数は、2回ガボール・フィルタを行うように変更した。「L_R_WEIGHT」を RorL 引数にセットすると、1回目は左白線検出、2回目は右白線検出を行う。
今回はC ソースコードを貼っておこう。
まずは、Gabor_filter_lh_2.h から貼っておく。

// Gabor_filter_lh_2.h
// 2016/07/24
// 2016/07/25 : 右白線検出用のGabor Filterの重みを追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
// 2016/08/29 : 1回目左白線検出、2回目右白線検出のモードを追加
//

#ifndef __Gabor_filter_lh_H__
#define __Gabor_filter_lh_H__

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600

//#define HORIZONTAL_PIXEL_WIDTH    640 // for Simulation
//#define VERTICAL_PIXEL_WIDTH    480

//#define HORIZONTAL_PIXEL_WIDTH    64
//#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define ARRAY_SIZE    9

#define RIGHT_WEIGHT    1
#define LEFT_WEIGHT        0
#define L_R_WEIGHT        2

const int gabor_weight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用
    {
        {0,-3,-10,-16,-7,7,10,5,1},
        {-3,-15,-27,-11,32,50,29,5,-2},
        {-11,-24,-5,73,135,95,16,-17,-10},
        {-11,4,85,187,160,14,-72,-52,-14},
        {4,51,135,137,-18,-159,-136,-45,-2},
        {16,50,59,-39,-179,-185,-73,3,13},
        {10,12,-25,-104,-131,-60,15,27,11},
        {1,-7,-31,-48,-24,18,29,14,3},
        {-1,-5,-9,-4,10,16,10,2,-1}
    },
    {
        {1,5,7,1,-12,-17,-10,-3,0},
        {1,11,33,45,21,-16,-27,-15,-4},
        {-8,-5,35,107,131,69,-2,-21,-11},
        {-17,-47,-51,40,169,187,93,13,-7},
        {-8,-54,-134,-147,-18,123,130,58,11},
        {9,-6,-82,-185,-187,-65,36,44,17},
        {11,24,12,-55,-125,-112,-43,1,7},
        {3,14,30,23,-13,-41,-33,-12,-1},
        {0,2,9,17,14,1,-6,-5,-2}
    }
};
const float gabor_fweight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用(float)
    {
        {0.001282,-0.009914,-0.04062,-0.060586,-0.027574,0.026072,0.038427,0.018191,0.003056},
        {-0.012155,-0.057448,-0.104645,-0.042953,0.123263,0.197238,0.114451,0.020448,-0.007239},
        {-0.042252,-0.093065,-0.018911,0.285374,0.525746,0.372687,0.060734,-0.064748,-0.040465},
        {-0.042261,0.015673,0.332798,0.728763,0.625046,0.053591,-0.283076,-0.203293,-0.05608},
        {0.017342,0.198305,0.52554,0.535526,-0.069756,-0.622839,-0.531089,-0.177366,-0.006367},
        {0.060866,0.19708,0.231032,-0.154219,-0.699885,-0.721808,-0.286707,0.013004,0.049249},
        {0.038379,0.04877,-0.098477,-0.404993,-0.510165,-0.233566,0.057894,0.104366,0.041887},
        {0.0047,-0.0278,-0.121277,-0.187262,-0.093276,0.070512,0.113857,0.055799,0.009976},
        {-0.003798,-0.01885,-0.035607,-0.01709,0.037692,0.064268,0.038606,0.007536,-0.002133}
    },
    {
        {0.005562,0.018882,0.028293,0.004499,-0.044995,-0.064838,-0.039469,-0.009822,0.000815},
        {0.002294,0.04108,0.127023,0.175094,0.083025,-0.063755,-0.106402,-0.057798,-0.01406},
        {-0.031269,-0.021096,0.135641,0.417286,0.512467,0.269946,-0.008354,-0.082091,-0.041357},
        {-0.066348,-0.184919,-0.197802,0.15614,0.65976,0.728616,0.361674,0.052074,-0.027152},
        {-0.031146,-0.211178,-0.523777,-0.573856,-0.069756,0.480311,0.506451,0.225223,0.041031},
        {0.035552,-0.023892,-0.320104,-0.723563,-0.728735,-0.253689,0.1391,0.170625,0.067723},
        {0.04216,0.094939,0.047511,-0.216623,-0.488075,-0.437898,-0.168739,0.003336,0.027009},
        {0.012112,0.056596,0.115239,0.090332,-0.05076,-0.158403,-0.127847,-0.046375,-0.004918},
        {-0.00168,0.007437,0.036985,0.067021,0.053689,0.004977,-0.02365,-0.018248,-0.005928}
    }
};

#endif


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

// Gabor_fiter_lh_2.cpp
// 2016/07/23 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
// 2016/08/29 : 1回目左白線検出、2回目右白線検出のモードを追加
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "Gabor_filter_lh_2.h"

int conv_rgb2y(int rgb);

int Gabor_filter_lh_2(hls::stream<ap_axis<32,1,1,1> >& ins,
        hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL){
#pragma HLS INTERFACE s_axilite port=RorL
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return

    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> gabor;

    hls::LineBuffer<ARRAY_SIZE-1, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
    hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;

    int gray_pix, val, i, j, x, y;

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

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

                mbuf.shift_left();    // mbuf の列を1ビット左シフト
                for(i=ARRAY_SIZE-2; i>=0; --i){
                    mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
                }
                gray_pix = conv_rgb2y(pix.data);
                mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);

                // LineBuffer の更新
                linebuf.shift_down(x);
                linebuf.insert_bottom(gray_pix, x);

                // 使用する配列を決定する
                int ano;
                switch (RorL){
                case LEFT_WEIGHT :
                    ano = LEFT_WEIGHT;
                    break;
                case RIGHT_WEIGHT :
                    ano = RIGHT_WEIGHT;
                    break;
                case L_R_WEIGHT :
                    if (k == 0)
                        ano = LEFT_WEIGHT;
                    else
                        ano = RIGHT_WEIGHT;
                    break;
                default :
                    ano = LEFT_WEIGHT;
                    break;
                }

                // Gabor filter の演算
                for (j=0, val=0; j<ARRAY_SIZE-1; j++){
                    for (i=0; i<ARRAY_SIZE-1; i++){
                        val += gabor_weight[ano][j][i] * mbuf(ARRAY_SIZE-1-j,i);
                    }
                }
                val = val/256// 256倍してあるので、1/256して戻す
                if (val<0)
                    //val = -val; // 絶対値
                    val = 0// マイナスの値を0に丸める
                else if (val>255)
                    val = 255;

                // Gabor filter・データの書き込み
                gabor.data = (val<<16)+(val<<8)+val;
                // 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
                if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
                    gabor.data = 0;

                if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                    gabor.user = 1;
                else
                    gabor.user = 0;

                if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                    gabor.last = 1;
                else
                    gabor.last = 0;

                outs << gabor;    // AXI4-Stream へ出力
             }
         }
    }
     return(0);
}

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

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

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

    return(y);
}


最後に、Gabor_filter_lh_2_tb.cpp を貼っておく。

// Gabor_filter_lh_2_tb.cpp
// 2016/07/24 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "Gabor_filter_lh_2.h"
#include "bmp_header.h"

int Gabor_filter_lh_2(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL);

int conv_rgb2y_soft(int rgb);
int Gabor_filter_lh_2_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL);

#define CLOCK_PERIOD 10
#define RIGHT_OR_LEFT   L_R_WEIGHT
#define BMP_FILE_NAME   "road_1.bmp"

int main()
{
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins;
    hls::stream<ap_axis<32,1,1,1> > ins_soft;
    hls::stream<ap_axis<32,1,1,1> > outs;
    hls::stream<ap_axis<32,1,1,1> > outs_soft;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals;
    ap_axis<32,1,1,1> vals_soft;

    int m_seq = 1// M系列の値
    int i, k;
    int xor_shift;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw, *fbmpwf;
    int *rd_bmp, *hw_gabor, *sw_gabor;
    int blue, green, red;
    ap_uint<2> r_l;
    char fhname[100];
    char fsname[100];

    if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open test.bmp by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

    // ピクセルを入れるメモリをアロケートする
    if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate rd_bmp memory\n");
        exit(1);
    }
    if ((hw_gabor =(int *)malloc(2 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_gabor memory\n");
        exit(1);
    }
    if ((sw_gabor =(int *)malloc(2 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_gabor memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

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

    // 2画面分を入力する
    for(int k=0; k<2; k++){
        for(int j=0; j < bmpihr.biHeight; j++){
            for(i=0; i < bmpihr.biWidth; i++){
                pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];

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

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

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

    r_l = (ap_uint<2>)RIGHT_OR_LEFT;
    Gabor_filter_lh_2(ins, outs, r_l);
    Gabor_filter_lh_2_soft(ins_soft, outs_soft, r_l);

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    for(k=0; k<2; k++){
        for(int j=0; j < bmpihr.biHeight; j++){
            for(i=0; i < bmpihr.biWidth; i++){
                outs >> vals;
                outs_soft >> vals_soft;
                ap_int<32> val = vals.data;
                ap_int<32> val_soft = vals_soft.data;

                hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+(j*bmpihr.biWidth)+i] = (int)val;
                sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+(j*bmpihr.biWidth)+i] = (int)val_soft;

                //printf("k=%d, j=%d, i=%d\n",k,j,i);
                if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > 4){ // 2乗誤差が4よりも大きい
                    printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %08x, SW = %08x\n", i, j, (int)val, (int)val_soft);
                    //return(1);
                }
                //if (vals.last)
                    //cout << "AXI-Stream is end" << endl;
            }
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ハードウェアのラプラシアンフィルタの結果を temp_gabor0.bmp, temp_gabor1.bmp へ出力する
    for(k=0; k<2; k++){
        if(k == 0){
            if ((fbmpw=fopen("temp_gabor0.bmp""wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor0.bmp by binary write mode\n");
                exit(1);
            }
        } else {
            if ((fbmpw=fopen("temp_gabor1.bmp""wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor1.bmp by binary write mode\n");
                exit(1);
            }
        }

        // BMPファイルヘッダの書き込み
        fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
        fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
        fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
        fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
        fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
        fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
        // RGB データの書き込み、逆順にする
        for (int y=0; y<bmpihr.biHeight; y++){
            for (int x=0; x<bmpihr.biWidth; x++){
                blue = hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
                green = (hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
                red = (hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

                fputc(blue, fbmpw);
                fputc(green, fbmpw);
                fputc(red, fbmpw);
            }
        }
        fclose(fbmpw);
    }

    // ソフトウェアのラプラシアンフィルタの結果を temp_gabor_float0.bmp, temp_gabor_float1.bmp へ出力する
    for(k=0; k<2; k++){
        if (k == 0){
            if ((fbmpwf=fopen("temp_gabor_float0.bmp""wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor_float0.bmp by binary write mode\n");
                exit(1);
            }
        } else {
            if ((fbmpwf=fopen("temp_gabor_float1.bmp""wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor_float1.bmp by binary write mode\n");
                exit(1);
            }
        }

        // BMPファイルヘッダの書き込み
        fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpwf);
        fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpwf);
        fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpwf);
        fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpwf);
        fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpwf);
        fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpwf);
        // RGB データの書き込み、逆順にする
        for (int y=0; y<bmpihr.biHeight; y++){
            for (int x=0; x<bmpihr.biWidth; x++){
                blue = sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
                green = (sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
                red = (sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

                fputc(blue, fbmpwf);
                fputc(green, fbmpwf);
                fputc(red, fbmpwf);
            }
        }
        fclose(fbmpwf);
    }

    free(rd_bmp);
    free(hw_gabor);

    return 0;
}

int Gabor_filter_lh_2_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL){
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> gabor;

    hls::LineBuffer<ARRAY_SIZE-1, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
    hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;

    int gray_pix, val, i, j, x, y;
    float valf;

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

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

                mbuf.shift_left();    // mbuf の列を1ビット左シフト
                for(i=ARRAY_SIZE-2; i>=0; --i){
                    mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
                }
                gray_pix = conv_rgb2y_soft(pix.data);
                mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);

                // LineBuffer の更新
                linebuf.shift_down(x);
                linebuf.insert_bottom(gray_pix, x);

                // 使用する配列を決定する
                int ano;
                switch (RorL){
                case LEFT_WEIGHT :
                    ano = LEFT_WEIGHT;
                    break;
                case RIGHT_WEIGHT :
                    ano = RIGHT_WEIGHT;
                    break;
                case L_R_WEIGHT :
                    if (k == 0)
                        ano = LEFT_WEIGHT;
                    else
                        ano = RIGHT_WEIGHT;
                    break;
                default :
                    ano = LEFT_WEIGHT;
                    break;
                }

                // Gabor filter の演算
                for (j=0, valf=0; j<ARRAY_SIZE-1; j++){
                    for (i=0; i<ARRAY_SIZE-1; i++){
                        valf += gabor_fweight[ano][j][i] * (float)mbuf(ARRAY_SIZE-1-j,i);
                    }
                }

                val = (int)valf;
                if (val<0)
                    //val = -val; // 絶対値
                    val = 0// マイナスの値を0に丸める
                else if (val>255)
                    val = 255;

                // Gabor filter・データの書き込み
                gabor.data = (val<<16)+(val<<8)+val;
                // 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
                if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
                    gabor.data = 0;

                if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                    gabor.user = 1;
                else
                    gabor.user = 0;

                if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                    gabor.last = 1;
                else
                    gabor.last = 0;

                outs << gabor;    // AXI4-Stream へ出力
             }
         }
    }
     return(0);
}

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

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

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

    return(y);
}

  1. 2016年08月31日 05:15 |
  2. 白線検出
  3. | トラックバック:0
  4. | コメント:0

マウスコンピューターにパソコンを注文しました

5年以上前のWindows XPマシンをWindows 7 にして、更にWindows 10 にして使ってきましたが、Xilinx のFPGAツールを使うと、とても遅くて困っていました。
今回、FPGAツール用にマウスコンピューターにパソコンを注文しました。移行が面倒なので、メインマシンとしては今のパソコンを使用して、FPGAツール用として新しいパソコンを使います。

新しいパソコンのCPUは、インテル(R) Core(TM) i5-6500 プロセッサー ( 4コア / 4スレッド / 3.20GHz / TB時最大3.60GHz / 6MBキャッシュ )にしました。職場では、i7 の8コアを使っていますが、8コアを使う場面はあまりないので、4コアで十分そうです。
メモリが 8 GB なので、アマゾンでもう 8 GB 注文しました。16 GB あれば十分(私が使うFPGA では)だと思います。
GPU はDLNN などでNvidia の CUDA を使うことも考えましたが、後で買えば良いかな?ということで、GPU は無しというかCPU 付属で、ということにしました。
HDDで良いことにしました。SSDは起動は早いですが、FPGAツールのコンパイル時間の短縮にはほとんど寄与しません。それに、ほとんどスタンバイ状態にしておくと思います。Cドライブの容量が大きい方が良いですし。。。
マウスコンピューターのLM-iH430BN [Windows 10 搭載]をカスタマイズしました。
構成と価格を下に示します。

  ---◆◇構成内容◆◇-------------------------------------------------
【 リサイクル 】個人向け ( リサイクル料金が含まれます。回収時に費用は発生しません。 )
【 OS 】★\5,800(税別)★Windows 10 Pro 64ビット
【 オフィスソフト 】・・・ オフィスソフト無し ( KINGSOFT Office 60日間トライアル版付属キャンペーン中 )
【 ウイルス対策・セキュリティソフト 】マカフィー リブセーフ ( 60日体験版 )
【 パソコン下取りサービス 】・・・ 下取りサービスなし
【 J-Moss 】J-Mossマーク 非含有マーク(グリーンマーク・緑色)
【 CPU 】★\2,800(税別)★インテル(R) Core(TM) i5-6500 プロセッサー ( 4コア / 4スレッド / 3.20GHz / TB時最大3.60GHz / 6MBキャッシュ )
【 CPUファン 】標準CPUクーラー
【 CPUグリス 】標準CPUグリス
【 メモリ 】8GB メモリ [ 8GB×1 ( PC4-17000 / DDR4-2133 ) ]
【 SSD 】・・・ SSD無し
【 SSD/HDD 】1TB ( 7200rpm / 6Gbps 対応 )
【 外付けストレージ 】・・・ 外付けストレージなし
【 グラフィックス 】インテル(R) HD グラフィックス 530
【 光学ドライブ 】★\2,800(税別)★DVDスーパーマルチドライブ ( DVD±R DL 読み書き対応 )
【 カードリーダー 】・・・ カードリーダー無し
【 マザーボード 】インテル(R) H110 Expressチップセット ( Micro ATX / DDR4 / SATA 6Gbps 対応ポート×4 )
【 ケース 】■ ミニタワーケース ( フロントUSB 2.0×2 / 9cmリア排気ファン搭載 )
【 ケースFAN 】【リアファン】9cmケースファン標準付属
【 電源 】★\3,800(税別)★500W 電源 ( 80PLUS(R) GOLD ) ⇒ 優れた電力変換効率で無駄な発熱を低減!
【 地デジ対応TVチューナー 】・・・ 地デジTVチューナーなし
【 LAN 】[ オンボード ] 10/100/1000BASE-T GigaBit-Ethernet LAN
【 無線LAN 】・・・ 無線LAN無し
【 サウンド 】ハイデフィニション・オーディオ
【 キーボード 】・・・ キーボードなし
【 マウス 】・・・ マウスなし
【 マウスパッド 】・・・ マウスパッドなし
【 スピーカー 】・・・ スピーカーなし ( 音声出力にはスピーカーが別途必要です )
【 ヘッドフォン 】・・・ ヘッドフォンなし
【 WEBカメラ(オプション) 】・・・ 外付けWebカメラなし
【 オプションサービス 】・・・オプションサービス無し
  ---◆◇周辺機器◆◇---------------------------------------------
【 モニタ 】・・・ モニタなし
【 プリンタ 】・・・ プリンタなし
【 ブロードバンドルーター 】・・・ ブロードバンドルーターなし
【 LANケーブル 】・・・ LANケーブルなし
【 HUB 】・・・ HUBなし
  ---◆◇サービス◆◇---------------------------------------------
【 サポート 】[1年間 標準保証] 初期不良対応1ヵ月+センドバック修理保証
【 各種出張サービス 】・・・ 出張セットアップサービスなし
【 電話サポート 】[ 24時間365日電話サポート ] 困った時はいつでもお電話いただけます ※弊社指定日を除く

  …………………………………………………………………………………… 
  小計(税込):          \81,000
  送料(税込):          \3,240
  合計(税込):          \84,240

  1. 2016年08月29日 05:19 |
  2. パソコン関連
  3. | トラックバック:0
  4. | コメント:0

「君の名は。」(映画)を見てきました

「君の名は。」(映画)を見てきました。
一言でいうととっても良い映画でした。感動しました。皆さんにもぜひ見てほしいですね。。。
DVD買うかAmazon プレミアムで購入したいです。

今日、8月29日にも見てきました。2回目です。良かったです。最初のシーンもわかりました。
  1. 2016年08月28日 19:09 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Dell Inspiron 14z 5423 のバッテリーを交換した

息子のDell Inspiron 14z 5423 のバッテリーが消耗してきて持たなくなってきたので、交換した。

参考にしたのは、「Dell Inspiron 5423 オーナーズマニュアル」と「dell inspiron14z 5423のHDDを交換してみた!」。

交換用のバッテリーはアマゾンの「PCパーツ 44Wh 純正 DELL Inspiron 15z 5523 14z 5423 2njnf 8jvdgバッテリー ノートパソコン Li-ion」を購入した。

裏ぶたのねじを回して緩めた。ねじは取れなかった。DRAMが入っている。
Dell_Inspiron_1_160828.jpg

DRAMを外して、もう1つのスロットのシールの下にねじがあったので、これを外した。これはキーボードを止めているねじらしい。これを外すとDVDドライブも外れる。(写真は前の写真から180度回転している) この時点でDVDドライブを外した方が良さそうだ。
Dell_Inspiron_2_160828.jpg

表返して、上の側にある3つの爪をマイナスドライバーで抑えてキーボードを外した。
Dell_Inspiron_3_160828.jpg

キーボードのフラットケーブルのコネクタは白い部分の端を上に引くと蝶番のように回転してフラットケーブルが引き抜けるようになる。
Dell_Inspiron_4_160828.jpg

裏返して8か所のねじを外す。ねじはゴム栓がしてあるものがある。
Dell_Inspiron_5_160828.jpg

表替えして、フラットケーブルを4つ外す。ねじも3つ外した。「Dell Inspiron 5423 オーナーズマニュアル」の27ページ、28ページ参照
パームレストアセンブリを外すには、隙間にマイナスドライバーを入れてこじる必要あるようだ。
Dell_Inspiron_6_160828.jpg

これで、バッテリーが見えるので、ねじを2本外すと交換できる。
Dell_Inspiron_7_160828.jpg

外したパームレストアセンブリ。
Dell_Inspiron_8_160828.jpg

外したキーボード、DVDドライブ、DRAM。
Dell_Inspiron_9_160828.jpg

後は逆の手順で戻した。パソコンはうまく起動した。良かった、一安心。
  1. 2016年08月28日 19:01 |
  2. パソコン関連
  3. | トラックバック:0
  4. | コメント:0

Zybot のカメラ画像でGabor Filterのパラメータを取得した3(Zybotでテスト)

Zybot のカメラ画像でGabor Filterのパラメータを取得した2(gabor_filter_lh プロジェクト)”の続き。

前回はパラメータを取り直したガボール・フィルタのIP 化を行った。今回は、ガボール・フィルタIP をZYBO_0_162_3 フォルダのVivado プロジェクトの既存のガボール・フィルタIP と交換して論理合成、インプリメント、ビットストリームの生成を行った。(”Gabor FilterをZYBO_0_162_2 へ実装してみた”を参照のこと)

ハードウェアをエクスポートしてSDK を立ち上げ、BOOT イメージを作成して、SDカードに書いてZybot に挿入して、ガボール・フィルタ画像を取得した。

左白線用ガボール・フィルタの画像を示す。
gaborL_160825_0.jpg

右白線用ガボール・フィルタの画像を示す。
gaborR_160825_0.jpg

左白線と右白線は分離できていると思う。以前よりも多少エッジが弱くなった気がするが。。。

次は、今のガボールフィルタのままだと、右白線、左白線とCPUで設定する必要があるから、CPUで左右を設定してから、ガボール・フィルタ処理結果を取得する必要がある。これはフレームレートが遅くなってしまう。
そこで、左右白線の2フレーム1セットでガボールフィルタ処理を行うことにする。左右は当然異なるフレームバッファにDMAする。その為にVDMAを4フレーム対応にして左右左右のフレームバッファにライトする。
これで左右白線用ガボールフィルタはカメラのフレームレートが15 fps だから、半分の 7.5 fps でデータが取得できる。
このエッジをとりあえずはCPUで探索して、どの位置にいるかを確認することにしよう。
  1. 2016年08月27日 04:32 |
  2. 白線検出
  3. | トラックバック:0
  4. | コメント:0

Zybot のカメラ画像でGabor Filterのパラメータを取得した2(gabor_filter_lh プロジェクト)

Zybot のカメラ画像でGabor Filterのパラメータを取得した”の続き。

前回は左白線検出用、右白線検出用のGabor Filterのパラメータを取得し、加工した。今回はその加工したパラメータをVivado HLS のgabor_filter_lh プロジェクトに入れてみた。

Zybot のカメラ画像でGabor Filterのパラメータを取得した”で、Gabor Filterのパラメータを256 倍して、整数に直した。これをハードウェア化用のパラメータとした。元の小数のGabor fillter のパラメータはテストベンチで整数演算との誤差比較用に使用する。(gabor_filter_lh については、”ガボール・フィルタ (Gabor Filter) による白線検出10(hls::LineBuffer と hls::Window を使用7)”辺りを参照のこと)
GaborFilter_58_160826.png

そのパラメータは、Gabor_filter_lh.h に入力した。Gabor_filter_lh.h を示す。

// Gabor_filter_lh.h
// 2016/07/24
// 2016/07/25 : 右白線検出用のGabor Filterの重みを追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
//

#ifndef __Gabor_filter_lh_H__
#define __Gabor_filter_lh_H__

//#define HORIZONTAL_PIXEL_WIDTH    800
//#define VERTICAL_PIXEL_WIDTH    600

#define HORIZONTAL_PIXEL_WIDTH    640 // for Simulation
#define VERTICAL_PIXEL_WIDTH    480

//#define HORIZONTAL_PIXEL_WIDTH    64
//#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define ARRAY_SIZE    9
#define RIGHT_WEIGHT    1
#define LEFT_WEIGHT        0

const int gabor_weight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用
    {
        {0,-3,-10,-16,-7,7,10,5,1},
        {-3,-15,-27,-11,32,50,29,5,-2},
        {-11,-24,-5,73,135,95,16,-17,-10},
        {-11,4,85,187,160,14,-72,-52,-14},
        {4,51,135,137,-18,-159,-136,-45,-2},
        {16,50,59,-39,-179,-185,-73,3,13},
        {10,12,-25,-104,-131,-60,15,27,11},
        {1,-7,-31,-48,-24,18,29,14,3},
        {-1,-5,-9,-4,10,16,10,2,-1}
    },
    {
        {1,5,7,1,-12,-17,-10,-3,0},
        {1,11,33,45,21,-16,-27,-15,-4},
        {-8,-5,35,107,131,69,-2,-21,-11},
        {-17,-47,-51,40,169,187,93,13,-7},
        {-8,-54,-134,-147,-18,123,130,58,11},
        {9,-6,-82,-185,-187,-65,36,44,17},
        {11,24,12,-55,-125,-112,-43,1,7},
        {3,14,30,23,-13,-41,-33,-12,-1},
        {0,2,9,17,14,1,-6,-5,-2}
    }
};
const float gabor_fweight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用(float)
    {
        {0.001282,-0.009914,-0.04062,-0.060586,-0.027574,0.026072,0.038427,0.018191,0.003056},
        {-0.012155,-0.057448,-0.104645,-0.042953,0.123263,0.197238,0.114451,0.020448,-0.007239},
        {-0.042252,-0.093065,-0.018911,0.285374,0.525746,0.372687,0.060734,-0.064748,-0.040465},
        {-0.042261,0.015673,0.332798,0.728763,0.625046,0.053591,-0.283076,-0.203293,-0.05608},
        {0.017342,0.198305,0.52554,0.535526,-0.069756,-0.622839,-0.531089,-0.177366,-0.006367},
        {0.060866,0.19708,0.231032,-0.154219,-0.699885,-0.721808,-0.286707,0.013004,0.049249},
        {0.038379,0.04877,-0.098477,-0.404993,-0.510165,-0.233566,0.057894,0.104366,0.041887},
        {0.0047,-0.0278,-0.121277,-0.187262,-0.093276,0.070512,0.113857,0.055799,0.009976},
        {-0.003798,-0.01885,-0.035607,-0.01709,0.037692,0.064268,0.038606,0.007536,-0.002133}
    },
    {
        {0.005562,0.018882,0.028293,0.004499,-0.044995,-0.064838,-0.039469,-0.009822,0.000815},
        {0.002294,0.04108,0.127023,0.175094,0.083025,-0.063755,-0.106402,-0.057798,-0.01406},
        {-0.031269,-0.021096,0.135641,0.417286,0.512467,0.269946,-0.008354,-0.082091,-0.041357},
        {-0.066348,-0.184919,-0.197802,0.15614,0.65976,0.728616,0.361674,0.052074,-0.027152},
        {-0.031146,-0.211178,-0.523777,-0.573856,-0.069756,0.480311,0.506451,0.225223,0.041031},
        {0.035552,-0.023892,-0.320104,-0.723563,-0.728735,-0.253689,0.1391,0.170625,0.067723},
        {0.04216,0.094939,0.047511,-0.216623,-0.488075,-0.437898,-0.168739,0.003336,0.027009},
        {0.012112,0.056596,0.115239,0.090332,-0.05076,-0.158403,-0.127847,-0.046375,-0.004918},
        {-0.00168,0.007437,0.036985,0.067021,0.053689,0.004977,-0.02365,-0.018248,-0.005928}
    }
};

#endif


これを使用してC シミュレーションを行った。
まずは、普通の道の写真の road_1.bmp でやってみた。まずは、road_1.bmp を示す。
GaborFilter_59_160826.jpg

まずは、左白線用ガボール・フィルタを適用するようにテストベンチを修正して、C シミュレーションを行った。
このときに整数演算のガボール・フィルタ結果と浮動小数点演算のガボール・フィルタ結果の二乗誤差が9 を超える値はなかった。
左白線用ガボール・フィルタで、整数演算の結果を示す。
GaborFilter_60_160826.jpg

次に、右白線用のガボール・フィルタを適用するようにテストベンチを修正して、C シミュレーションを行った。
このときに整数演算のガボール・フィルタ結果と浮動小数点演算のガボール・フィルタ結果の二乗誤差が9 を超える値は21 個発生した。例を示す。

ERROR HW and SW results mismatch i = 556, j = 73, HW = 00171717, SW = 00141414
ERROR HW and SW results mismatch i = 418, j = 88, HW = 00171717, SW = 00141414
ERROR HW and SW results mismatch i = 418, j = 92, HW = 00131313, SW = 00101010
ERROR HW and SW results mismatch i = 404, j = 100, HW = 003e3e3e, SW = 003b3b3b
ERROR HW and SW results mismatch i = 425, j = 106, HW = 00121212, SW = 000f0f0f


右白線用ガボール・フィルタで、整数演算の結果を示す
GaborFilter_61_160826.jpg

先に普通の道の写真を今回パラメータを修正したガボール・フィルタ結果を示したが、今度はパラメータの検出用に使用した画像を使用して、今回のガボール・フィルタをかけてみた。
GaborFilter_54_160824.jpg

最初に左白線用ガボール・フィルタの結果を示す。
GaborFilter_62_160826.jpg

今回も左白線用ガボール・フィルタでの整数演算のガボール・フィルタ結果と浮動小数点演算のガボール・フィルタ結果の二乗誤差が9 を超える値はなかった。

次に、右白線用のガボール・フィルタ結果を示す。
GaborFilter_63_160826.jpg

このときに整数演算のガボール・フィルタ結果と浮動小数点演算のガボール・フィルタ結果の二乗誤差が9 を超える値は20 個発生した。

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

引き続き、IP 化を行った。
  1. 2016年08月26日 05:03 |
  2. 白線検出
  3. | トラックバック:0
  4. | コメント:0

Zybot のカメラ画像でGabor Filterのパラメータを取得した

Zybot のカメラ画像をBMPファイルに変換するアプリケーションを作成した”で、Zybot のカメラ画像を取得してBMPファイルに変換するアプリケーション・ソフトウェアを作成した。今回は、このアプリケーションで取得したZybot のカメラ画像からGabor Filterのパラメータを取得する。

ガボール・フィルタ (Gabor Filter) による白線検出2”のVivado HLS プロジェクトを使用して、扱う画像をZybot のカメラ画像に変更した。

まずは、左白線用Gabor Filterパラメータは、 sigma = 4, Lambda = 85, Psi = 94, Theta = 50 が良さそうだ。
GaborFilter_54_160824.jpg

次に、右白線用Gabor Filterパラメータは、 sigma = 4, Lambda = 85, Psi = 94, Theta = 125 が良さそうだ。
GaborFilter_55_160824.jpg

これらのパラメータでの、Gabor Filterの9 x 9 のカーネルの値を示す。

左白線用Gabor Filterパラメータ sigma = 4, Lambda = 85, Psi = 94, Theta = 50
0.001282,-0.009914,-0.040620,-0.060586,-0.027574,0.026072,0.038427,0.018191,0.003056
-0.012155,-0.057448,-0.104645,-0.042953,0.123263,0.197238,0.114451,0.020448,-0.007239
-0.042252,-0.093065,-0.018911,0.285374,0.525746,0.372687,0.060734,-0.064748,-0.040465
-0.042261,0.015673,0.332798,0.728763,0.625046,0.053591,-0.283076,-0.203293,-0.056080
0.017342,0.198305,0.525540,0.535526,-0.069756,-0.622839,-0.531089,-0.177366,-0.006367
0.060866,0.197080,0.231032,-0.154219,-0.699885,-0.721808,-0.286707,0.013004,0.049249
0.038379,0.048770,-0.098477,-0.404993,-0.510165,-0.233566,0.057894,0.104366,0.041887
0.004700,-0.027800,-0.121277,-0.187262,-0.093276,0.070512,0.113857,0.055799,0.009976
-0.003798,-0.018850,-0.035607,-0.017090,0.037692,0.064268,0.038606,0.007536,-0.002133

右白線用Gabor Filterパラメータ sigma = 4, Lambda = 85, Psi = 94, Theta = 125
0.005562,0.018882,0.028293,0.004499,-0.044995,-0.064838,-0.039469,-0.009822,0.000815
0.002294,0.041080,0.127023,0.175094,0.083025,-0.063755,-0.106402,-0.057798,-0.014060
-0.031269,-0.021096,0.135641,0.417286,0.512467,0.269946,-0.008354,-0.082091,-0.041357
-0.066348,-0.184919,-0.197802,0.156140,0.659760,0.728616,0.361674,0.052074,-0.027152
-0.031146,-0.211178,-0.523777,-0.573856,-0.069756,0.480311,0.506451,0.225223,0.041031
0.035552,-0.023892,-0.320104,-0.723563,-0.728735,-0.253689,0.139100,0.170625,0.067723
0.042160,0.094939,0.047511,-0.216623,-0.488075,-0.437898,-0.168739,0.003336,0.027009
0.012112,0.056596,0.115239,0.090332,-0.050760,-0.158403,-0.127847,-0.046375,-0.004918
-0.001680,0.007437,0.036985,0.067021,0.053689,0.004977,-0.023650,-0.018248,-0.005928


次に、”ガボール・フィルタ (Gabor Filter) による白線検出3(HLSビデオライブラリ)”を参考にして、int で扱える形にしてみた。

カーネルのパラメータを256倍して、四捨五入を行った。
左白線検出用パラメータを示す。
GaborFilter_56_160824.png

この値は256倍してあるので、カーネルを画像データにかけた後で、1/256倍する必要がある。

次に右白線検出用パラメータを示す。
GaborFilter_57_160824.png
  1. 2016年08月24日 04:20 |
  2. 白線検出
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム2(SDK)

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成)”の続き。

前回は、今まで作ってきた AXI4-Stream版ビットマップ・ディスプレイ・コントローラ IPと AXI4-Stream版カメラ・コントローラ IP、Vivado HLS で作成したAXI4 Master DMA Write IP、Vivado HLS で作成したAXI4 Master DMA Read IP を使って、カメラ表示システムのVivado プロジェクトを作り、ビットストリームの生成まで終了した。今回は、ハードウェアをエクスポートしてSDK を立ち上げてアプリケーションを作り、実機で動作させようと思う。

まずは、Vivado でハードウェアをエクスポートした。

次に、SDK を立ち上げた。
cam_disp_axis_7_160821.png

cam_disp_hls アプリケーション・プロジェクトを作成し、cam_disp_hls.c を新規作成した。
cam_disp_axis_8_160821.png

cam_disp_hls.c を完成させた。
cam_disp_axis_9_160823.png

これで、FPGA をプログラムして、出来上がったアプリケーション・ソフトウェアを起動させてみたが、ディスプレイ画面にカメラ画像は表示されなかった。ブルー・スクリーンだったので、画像出力がされていないようだ。
どこがおかしいのか?検討してみる必要がある。

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

/* * cam_disp_hls.c * *  Created on: 2016/08/21 *      Author: Masaaki */


#include <stdio.h>
#include <stdlib.h>
#include "xil_io.h"
#include "xdma_read_addr.h"
#include "xdma_write.h"
#include "sleep.h"

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

#define FRAME_BUFFER_ADDRESS 0x10000000

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XDma_read_addr  dmar, *dmarp;
    XDma_write      dmaw, *dmawp;

    dmarp = &dmar;
    dmawp = &dmaw;

    // Initialization of DMA Read
    if (XDma_read_addr_Initialize(dmarp, 0) != XST_SUCCESS){
        fprintf(stderr,"DMA Read open error\n");
        exit(-1);
    }

    // Initialization of DMA Write
    if (XDma_write_Initialize(dmawp, 0) != XST_SUCCESS){
        fprintf(stderr,"DMA Write open error\n");
        exit(-1);
    }

    // frame buffer settings
    XDma_read_addr_Set_frame_buffer0(&dmar, FRAME_BUFFER_ADDRESS);
    XDma_read_addr_Set_frame_buffer1(&dmar, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
    XDma_read_addr_Set_frame_buffer2(&dmar, FRAME_BUFFER_ADDRESS+2*HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);

    XDma_write_Set_frame_buffer0(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_Set_frame_buffer1(&dmaw, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
    XDma_write_Set_frame_buffer2(&dmaw, FRAME_BUFFER_ADDRESS+2*HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cont_axis_0
    volatile unsigned int *mt9d111_axiL;
    volatile unsigned int *cam_iic_axiL;
    volatile unsigned int *bmdc_axiL;

    mt9d111_axiL = (volatile unsigned int *)XPAR_MT9D111_INF_AXIS_0_BASEADDR;
    cam_iic_axiL = (volatile unsigned int *)XPAR_AXI_IIC_0_BASEADDR;
    bmdc_axiL = (volatile unsigned int *)XPAR_BITMAP_DISP_CONT_AXIS_0_BASEADDR;

    // DMA Start
    XDma_read_addr_Set_mode_V(&dmar, 0);
    while(!XDma_read_addr_IsIdle(&dmar)) ;
    XDma_read_addr_Start(&dmar);
    XDma_read_addr_EnableAutoRestart(&dmar);

    while(!XDma_write_IsIdle(&dmaw)) ;
    XDma_write_Start(&dmaw);
    XDma_write_EnableAutoRestart(&dmaw);

    // mt9d111_inf_axis_0 and bitmap_disp_cont_axis_0 is started
    mt9d111_axiL[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)
    bmdc_axiL[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(cam_iic_axiL);

    cam_i2c_write(cam_iic_axiL, 0xba, 0xf00x1);      // Changed regster map to IFP page 1
    cam_i2c_write(cam_iic_axiL, 0xba, 0x970x20);     // RGB Mode, RGB565

    mt9d111_axiL[1] = 0// One_shot_mode is disabled

    return(0);
}

  1. 2016年08月24日 03:59 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成)

今まで作ってきた AXI4-Stream版ビットマップ・ディスプレイ・コントローラ IP AXI4-Stream版カメラ・コントローラ IPVivado HLS で作成したAXI4 Master DMA Write IPVivado HLS で作成したAXI4 Master DMA Read IP を使って、カメラ表示システムを作ってみることにした。

Vivado 2016.2 で cam_disp_axis_162 プロジェクトを作成した。(下図ではビットストリームの生成まで終了した状態だ。)
cam_disp_axis_3_160821.png

AXI4-Stream版ビットマップ・ディスプレイ・コントローラ IP AXI4-Stream版カメラ・コントローラ IPVivado HLS で作成したAXI4 Master DMA Write IPVivado HLS で作成したAXI4 Master DMA Read IP をフォルダを作って cam_disp_axis_162 プロジェクトのフォルダに入れた。
cam_disp_axis_1_160821.png

4つのIP をIP Catalog に追加した。
cam_disp_axis_2_160821.png

cam_disp_axis ブロックデザインを作成した。
cam_disp_axis_4_160821.png

Address Editor を示す。
cam_disp_axis_5_160821.png

制約ファイル cam_disp_axis.xdc を作成した。

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

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

set_property PACKAGE_PIN T14 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[0]}]
set_property PACKAGE_PIN U14 [get_ports {cam_data[6]}]
set_property PACKAGE_PIN T15 [get_ports {cam_data[5]}]
set_property PACKAGE_PIN U15 [get_ports {cam_data[4]}]
set_property PACKAGE_PIN P14 [get_ports {cam_data[3]}]
set_property PACKAGE_PIN V17 [get_ports {cam_data[2]}]
set_property PACKAGE_PIN R14 [get_ports {cam_data[1]}]
set_property PACKAGE_PIN V18 [get_ports {cam_data[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports href]
set_property IOSTANDARD LVCMOS33 [get_ports pclk]
set_property IOSTANDARD LVCMOS33 [get_ports standby]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]
set_property IOSTANDARD LVCMOS33 [get_ports xck]
set_property PACKAGE_PIN V15 [get_ports mt9d111_iic_scl_io]
set_property PACKAGE_PIN W14 [get_ports mt9d111_iic_sda_io]
set_property PACKAGE_PIN W15 [get_ports vsync]
set_property PACKAGE_PIN Y14 [get_ports href]
set_property PACKAGE_PIN T11 [get_ports standby]
set_property PACKAGE_PIN T10 [get_ports pclk]
set_property PACKAGE_PIN U12 [get_ports xck]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN F17 [get_ports {hdmi_out_en[0]}]

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF]


論理合成、インプリメント、ビットストリームの生成を行って、成功した。
cam_disp_axis_6_160821.png
  1. 2016年08月22日 22:17 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Zybot のカメラ画像をBMPファイルに変換するアプリケーションを作成した

Zybot の白線の画像や白線検出した結果の画像をBMPファイルに変換するアプリケーションを作成した。
これで、白線の画像をGabor Filter で検出するときのパラメータを最適化することができる。

画像をBMPファイルに変換するアプリケーションは、”左目カメラ画像と右目カメラ画像をBMPファイルに変換するアプリケーションを作成した”で、左目カメラ画像と右目カメラ画像をBMPファイルに変換するアプリケーションを作成したので、これを修正して、cam_capture_bmp.cpp を作成した。
cam_capture_bmp_4_160819.png

cam_capture_bmp.cpp をコンパイルして、cam_capture_bmp を作った。
cam_capture_bmp を起動して、2回 W コマンドを実行すると、bmp_file0.bmp と bmp_file1.bmp が生成された。
cam_capture_bmp_1_160819.png

cam_capture_bmp_2_160819.png

bmp_file0.bmp を表示してみたが問題ないようだ。
cam_capture_bmp_3_160819.jpg

これで、Zybot のカメラで撮影した白線の画像を取得できるので、Gabor Filter のパラメータを最適化することができる。

cam_capture_bmp.cpp を貼っておく。

//
// cam_capture_bmp.cpp
// 2016/08/19 by marsee
//
// This software converts the left and right of the camera image to BMP file.
// -b : bmp file name
// -n : Start File Number
// -h : help
//

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

#include "bmp_header.h"

#define PIXEL_NUM_OF_BYTES    4

#define SVGA_HORIZONTAL_PIXELS  800
#define SVGA_VERTICAL_LINES     600
#define SVGA_ALL_DISP_ADDRESS   (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define SVGA_3_PICTURES         (SVGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

int WriteBMPfile(FILE *fbmp, volatile unsigned int *frame_buffer, BMP24FORMAT **bmp_data);

int main(int argc, char *argv[]){
    int opt;
    int c, help_flag=0;
    char bmp_fn[256] = "bmp_file";
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    int i, j;
    int file_no = 0;
    FILE *fbmp;
    BMP24FORMAT **bmp_data; // 24 bits Date of BMP files (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES)

    while ((opt=getopt(argc, argv, "b:n:h")) != -1){
        switch (opt){
            case 'b':
                strcpy(bmp_fn, optarg);
                break;
            case 'n':
                file_no = atoi(optarg);
                break;
            case 'h':
                help_flag = 1;
                break;
        }
    }

    if (help_flag == 1){ // help
        printf("Usage : cam_capture_bmp [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
    }

    // udmabuf0
    int fdf = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The cache is disabled. 
    if (fdf == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    volatile unsigned *frame_buffer = (volatile unsigned *)mmap(NULL, SVGA_ALL_DISP_ADDRESS, PROT_READ|PROT_WRITE, MAP_SHARED, fdf, 0);
    if (!frame_buffer){
        fprintf(stderr, "frame_buffer mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf0
    int fdp = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fdp == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fdp, attr, 1024);
    sscanf((const char *)attr, "%lx", &phys_addr);  
    close(fdp);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);

    // allocated the memory for bmp file
    if ((bmp_data=(BMP24FORMAT **)malloc(sizeof(BMP24FORMAT *)*SVGA_VERTICAL_LINES)) == NULL){
        fprintf(stderr, "Can not allocate memory of the first dimension of SVGA_VERTICAL_LINES of bmp_data\n");
        exit(1);
    }
    for (i=0; i<SVGA_VERTICAL_LINES; i++){
        if ((bmp_data[i]=(BMP24FORMAT *)malloc(sizeof(BMP24FORMAT) * SVGA_HORIZONTAL_PIXELS)) == NULL){
            fprintf(stderr, "Can not allocate %d th memory of the first dimension of bmp_data\n", i);
            exit(1);
        }
    }
   
    char bmp_file[256];

    // w - writed the left and right eye's bmp files.  q - exit.
    c = getc(stdin);
    while(c != 'q'){
        switch ((char)c) {
            case 'w' : // w - writed the left and right eye's bmp files.
                // writed the left and right eys's frame buffer
                sprintf(bmp_file, "%s%d.bmp", bmp_fn, file_no);
                if ((fbmp=fopen(bmp_file, "wb")) == NULL){
                    fprintf(stderr, "Cannot open %s in binary mode\n", bmp_file);
                    exit(1);
                }
                WriteBMPfile(fbmp, frame_buffer, bmp_data);
                fclose(fbmp);
                
                printf("file No. = %d\n", file_no);

                file_no++;
                break;
        }
        c = getc(stdin);
    }

    for(i=0; i<SVGA_VERTICAL_LINES; i++){
        free(bmp_data[i]);
    }
    free(bmp_data);
    munmap((void *)frame_buffer, (SVGA_ALL_DISP_ADDRESS));
    close(fdf);
    
    return(0);
}

int WriteBMPfile(FILE *fbmp, volatile unsigned *frame_buffer, BMP24FORMAT **bmp_data){
    BITMAPFILEHEADER bmpfh; // file header for a bmp file
    BITMAPINFOHEADER bmpih; // INFO header for BMP file

    // Copy the camera color data of the bmp_data (data of BMP when its starts from lower left)
    for (int i=0; i<SVGA_VERTICAL_LINES; i++){
        for (int j=0; j<SVGA_HORIZONTAL_PIXELS; j++){
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].red = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j]>>16)&0xff;
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].green = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j]>>8)&0xff;
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].blue = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j])&0xff;
        }
    }

    // Assign a value to the file header of the BMP file
    bmpfh.bfType = 0x4d42;
    bmpfh.bfSize = SVGA_HORIZONTAL_PIXELS*SVGA_VERTICAL_LINES*3+54;
    bmpfh.bfReserved1 = 0;
    bmpfh.bfReserved2 = 0;
    bmpfh.bfOffBits = 0x36;

    // Assign a value to the INFO header of the BMP file
    bmpih.biSize = 0x28;
    bmpih.biWidth = SVGA_HORIZONTAL_PIXELS;
    bmpih.biHeight = SVGA_VERTICAL_LINES;
    bmpih.biPlanes = 0x1;
    bmpih.biBitCount = 24;
    bmpih.biCompression = 0;
    bmpih.biSizeImage = 0;
    bmpih.biXPixPerMeter = 3779;
    bmpih.biYPixPerMeter = 3779;
    bmpih.biClrUsed = 0;
    bmpih.biClrImporant = 0;

    // Writing of BMP file header
    fwrite(&bmpfh.bfType, sizeof(char), 2, fbmp);
    fwrite(&bmpfh.bfSize, sizeof(long), 1, fbmp);
    fwrite(&bmpfh.bfReserved1, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfReserved2, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfOffBits, sizeof(long), 1, fbmp);

    // Writing of BMP INFO header
    fwrite(&bmpih, sizeof(BITMAPINFOHEADER), 1, fbmp);

    // Writing of bmp_data
    for (int i=0; i<SVGA_VERTICAL_LINES; i++) {
        for (int j=0; j<SVGA_HORIZONTAL_PIXELS; j++) {
            fputc((int)bmp_data[i][j].blue, fbmp);
            fputc((int)bmp_data[i][j].green, fbmp);
            fputc((int)bmp_data[i][j].red, fbmp);
        }
    }
}

  1. 2016年08月20日 12:57 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

MT9D111インターフェース基板2の作製1(KiCadでの設計)

CMOS カメラ MT9D111 のインターフェース基板は以前作成したが、Zybot で使用するのに、ケーブルで伸ばしたいので、バッファを入れた基板を作成することにした。

使用するバッファは秋月電子で売っているTC74VHC541FT(EL K) を使用している。

回路図を下に示す。
MT9D111_inf_33_160818.png

TC74VHC541FT(EL K) のフットプリントは、”KiCad-4.0.2 のフットプリント作成方法”で作ってあったので、これを使用した。

次にFreeRouter でオートルートをやってみた。やり方は、”KiCad-4.0.2 と FreeRouter インストール覚書”を参照のこと。
MT9D111_inf_34_160818.png

オートルートのパラメータを変更して、オートルートした。
MT9D111_inf_35_160818.png

これをKiCad のPcbnew に持ってきた。
MT9D111_inf_36_160818.png

GND 領域の塗りつぶしを入れて、完成した。
MT9D111_inf_37_160819.png

これで基板を発注しよう。

(追加)
2016/08/19 : FusionPCB に基板を発注した。

デザインルールを貼っておく。
MT9D111_inf_38_160819.png

なお、GNDの配線は領域を塗りつぶすときに邪魔なので、GND 配線はすべて削除した。

2016/08/20 : GNDの配線が領域を塗りつぶしてもつながっていなところがあるのに気が付いて、もう一度、FreeRouter の結果を取り込んでやり直した。もう一度、FusionPCBに発注した。前の注文は無駄になってしまった。orz...
やはり、GND配線を削除しない方が良さそうだ。
  1. 2016年08月19日 05:02 |
  2. プリント基板作成
  3. | トラックバック:0
  4. | コメント:0

スペアリブの煮込みを作りました

今日はスペアリブの煮込みを作りました。
スペアリブが食べたくなったので、クックパッドを検索すると、「入れるだけ★とろとろスペアリブのズボラ煮」がヒットしました。作り方も簡単なので、作ってみることにしました。

スペアリブを買ってきて、酒、みりん、酢、醤油を入れて、水を入れ、煮込み始めます。
spareribs_1_160819.jpg

1時間くらいかな?煮込みました。弱火でないと吹きこぼれそうでした。
KiCadをやっていると、レンジが強制停止した音がしました。行ってみると煮汁が無くなって、焦げる寸前でした。一番美味しい状態です。レンジがすぐれもので良かったです。レンジはHARMANです。
美味しそうに煮えました。
spareribs_2_160819.jpg

家族が帰ってきたので、盛り付けてもらいました。美味しそう。
spareribs_3_160819.jpg

食べてみると美味しかったです。少ししょっぱいかな?と思いましたが、ちょうど良い感じでした。また作りたいですね。
  1. 2016年08月18日 20:30 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする5(IP作成)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする4(ソースコードの公開)”の続き。

前回は、シミュレーションを行ってから、Verilog HDLのソースコードを公開した。今回は出来上がりAXI4-Stream版ビットマップ・ディスプレイ・コントローラをIPにする。

Vivado 2016.2 のTools メニューから Create and Package IP... を選択する。

Create and Package New IP ダイアログが表示された。
AXI4-Stream_bitmap_disp_cont_17_160818.png

Package your current project のラジオボタンが設定されていることを確認して、Next > ボタンをクリックした。
AXI4-Stream_bitmap_disp_cont_18_160818.png

ここもデフォルトのまま
AXI4-Stream_bitmap_disp_cont_19_160818.png

Summary
AXI4-Stream_bitmap_disp_cont_20_160818.png

Package IP タブが表示された。Vender を marsee101 に変更した。(Identification)
AXI4-Stream_bitmap_disp_cont_21_160818.png

Compatibility
AXI4-Stream_bitmap_disp_cont_22_160818.png

File Groups
AXI4-Stream_bitmap_disp_cont_23_160818.png

Customization Parameters。C_DISPLAY_START_ADDRESS は要らなかった。削除を忘れたので、このままとする。
AXI4-Stream_bitmap_disp_cont_24_160818.png

Ports and Interfaces 。 vid... 信号をRGB インターフェースにまとめる必要がある。
AXI4-Stream_bitmap_disp_cont_25_160818.png

vid... 信号をすべて選択して、右クリックメニューから Add Bus Interface... を選択した。
AXI4-Stream_bitmap_disp_cont_26_160818.png

RGB インターフェース設定方法については、”ZYBO_0 を変更1(ブロックデザインの修正)”を参照のこと。

RGB インターフェースを設定することができた。
AXI4-Stream_bitmap_disp_cont_27_160818.png

Addressing and Memory
AXI4-Stream_bitmap_disp_cont_28_160818.png

Customization GUI
AXI4-Stream_bitmap_disp_cont_29_160818.png

Review and Package で Package IP ボタンをクリックしてIP を生成した。
AXI4-Stream_bitmap_disp_cont_30_160818.png

IP 生成が成功したというダイアログが表示された。
AXI4-Stream_bitmap_disp_cont_31_160818.png

久しぶりにIP を生成したので、やり方を忘れているのだが、IP をまとめたZIP ファイルができていない。
IP をまとめたZIP ファイルを生成する。
Package IP タブのReview and Package で edit packaging settings をクリックした。
AXI4-Stream_bitmap_disp_cont_32_160818.png

Project Settings ダイアログで、IP のPackager のAutomatic Behavior -> After Packaging のCreate archive of IPにチェックを入れた。
AXI4-Stream_bitmap_disp_cont_33_160818.png

もう一度、Re-Package IP ボタンをクリックして、再度IP を作成した。
AXI4-Stream_bitmap_disp_cont_34_160818.png

もう一度、IP 生成が成功したというダイアログが表示された。

bm_dispc_axis フォルダの下にmarsee101_user_bitmap_disp_cont_axis_1.0.zip が生成された。
AXI4-Stream_bitmap_disp_cont_35_160818.png
  1. 2016年08月18日 06:34 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする4(ソースコードの公開)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする3(シミュレーション)”の続き。

前回は、シミュレーションを行って、テストベンチのVerilog HDLのソースコードを貼った。今回は、それ以外のVerilog HDLのソースコードを貼っておく。

最初に、bitmap_disp_cont_axis.v から貼っておく。

// bitmap_disp_cont_axis.v
//
// by marsee
//
// Read Only IP, 64 bit bus
//
// 2012/06/28
// 2012/11/22 : HDMI出力を追加
// 2014/07/23 : ZYBO 用に変更
// 2014/09/18 : Frame Buffer のスタートアドレスを設定するためにAXI4 Lite Slave インターフェースを追加
// 2016/08/08 : AXI4 Master から AXI4-Stream インターフェースに変更、AXI4 Lite Slave インターフェースはダミーライトに変更
//                ダミーライトするとディスプレイ・コントローラがスタートする
//

`default_nettype none

module bitmap_disp_cont_axis #
  (
        // AXI4 Lite Slave Interface
        parameter integer C_S_AXI_LITE_ADDR_WIDTH        = 9,
        parameter integer C_S_AXI_LITE_DATA_WIDTH        = 32,

        // AXI4-Stream Interface
        parameter integer C_M_AXIS_DATA_WIDTH            = 32,

        parameter [31:0]    C_DISPLAY_START_ADDRESS        = 32'h17800000,    // フレームバッファのスタートアドレス

        // video resolution : "VGA", "SVGA", "XGA", "SXGA", "HD"
        parameter [80*8:1] RESOLUTION                    ="SVGA"  // SVGA
    )
    (
        // Clocks and Reset
        input wire          s_axi_lite_aclk,
        input wire           AXIS_ACLK,
        input wire           ARESETN,

        ///////////////////////////////
        // AXI4 Lite Slave Interface //
        ///////////////////////////////
        // AXI Lite Write Address Channel
        input    wire    s_axi_lite_awvalid,
        output    wire    s_axi_lite_awready,
        input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    s_axi_lite_awaddr,

        // AXI Lite Write Data Channel
        input    wire    s_axi_lite_wvalid,
        output    wire    s_axi_lite_wready,
        input    wire    [C_S_AXI_LITE_DATA_WIDTH-1:0] s_axi_lite_wdata,

        // AXI Lite Write Response Channel
        output    wire    [1:0]    s_axi_lite_bresp,
        output    wire    s_axi_lite_bvalid,
        input    wire    s_axi_lite_bready,

        // AXI Lite Read Address Channel
        input    wire    s_axi_lite_arvalid,
        output    wire    s_axi_lite_arready,
        input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    s_axi_lite_araddr,

        // AXI Lite Read Data Channel
        output    wire    s_axi_lite_rvalid,
        input    wire    s_axi_lite_rready,
        output    wire    [C_S_AXI_LITE_DATA_WIDTH-1:0] s_axi_lite_rdata,
        output    wire    [1:0]    s_axi_lite_rresp,

        /////////////////////////////////
        // AXI4-Stream Slave Interface //
        /////////////////////////////////
        input  wire [C_M_AXIS_DATA_WIDTH-1:0]        s_axis_tdata,
        input  wire [(C_M_AXIS_DATA_WIDTH/8)-1:0]   s_axis_tstrb,
        input  wire                                     s_axis_tvalid,
        output wire                                   s_axis_tready,
        input  wire                                   s_axis_tlast,
        input  wire                                    s_axis_tuser,

        // User Ports
        input    wire    pixclk,

        (* IOB = "FORCE" *) output    reg     [4:0]    vga_red,
        (* IOB = "FORCE" *) output    reg     [5:0]    vga_green,
        (* IOB = "FORCE" *) output    reg     [4:0]    vga_blue,
        (* IOB = "FORCE" *) output    reg        vga_hsync,
        (* IOB = "FORCE" *) output    reg        vga_vsync,

        output  wire [23:0] vid_pData,
        output  wire        vid_pVDE,
        output  wire        vid_pHSync,
        output  wire        vid_pVSync
    );

     wire    [7:0]    red, green, blue;
    wire    hsyncx, vsyncx;
    wire    display_enable;
    reg        reset_disp_2b = 1'b1, reset_disp_1b = 1'b1;
    wire    reset_disp;
    wire    afifo_overflow, afifo_underflow;
    wire    reset_out;
    wire    init_done;

    bm_disp_cntrler_axi_lite_slave #(
        .C_S_AXI_LITE_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
        .C_S_AXI_LITE_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH),
        .C_DISPLAY_START_ADDRESS(C_DISPLAY_START_ADDRESS)
    ) bm_disp_cntrler_axi_lite_slave_i
    (
        .s_axi_lite_aclk(s_axi_lite_aclk),
        .axi_resetn(ARESETN),
        .s_axi_lite_awvalid(s_axi_lite_awvalid),
        .s_axi_lite_awready(s_axi_lite_awready),
        .s_axi_lite_awaddr(s_axi_lite_awaddr),
        .s_axi_lite_wvalid(s_axi_lite_wvalid),
        .s_axi_lite_wready(s_axi_lite_wready),
        .s_axi_lite_wdata(s_axi_lite_wdata),
        .s_axi_lite_bresp(s_axi_lite_bresp),
        .s_axi_lite_bvalid(s_axi_lite_bvalid),
        .s_axi_lite_bready(s_axi_lite_bready),
        .s_axi_lite_arvalid(s_axi_lite_arvalid),
        .s_axi_lite_arready(s_axi_lite_arready),
        .s_axi_lite_araddr(s_axi_lite_araddr),
        .s_axi_lite_rvalid(s_axi_lite_rvalid),
        .s_axi_lite_rready(s_axi_lite_rready),
        .s_axi_lite_rdata(s_axi_lite_rdata),
        .s_axi_lite_rresp(s_axi_lite_rresp),
        .fb_start_address(),
        .init_done(init_done)
    );

    bitmap_disp_engine #(
        .RESOLUTION(RESOLUTION)
    ) bitmap_disp_eng_inst (
        .clk_disp(pixclk),
        .clk_axi(AXIS_ACLK),
        .reset_disp(reset_disp),
        .reset_axi(~ARESETN),
        .s_axis_tdata(s_axis_tdata),
        .s_axis_tstrb(s_axis_tstrb),
        .s_axis_tvalid(s_axis_tvalid),
        .s_axis_tready(s_axis_tready),
        .s_axis_tlast(s_axis_tlast),
        .s_axis_tuser(s_axis_tuser),
        .red_out(red),
        .green_out(green),
        .blue_out(blue),
        .hsyncx(hsyncx),
        .vsyncx(vsyncx),
        .display_enable(display_enable),
        .ddr_cont_init_done(init_done),
        .afifo_overflow(afifo_overflow),
        .afifo_underflow(afifo_underflow)
    );

    always @(posedge pixclk) begin
        if (reset_disp) begin
            vga_red <= 5'd0;
            vga_green <= 6'd0;
            vga_blue <= 5'd0;
            vga_hsync <= 1'b1;
            vga_vsync <= 1'b1;
        end else begin
            vga_red <= red[7:3];
            vga_green <= green[7:2];
            vga_blue <= blue[7:3];
            vga_hsync <= hsyncx;
            vga_vsync <= vsyncx;
        end
    end

    always @(posedge pixclk) begin
        reset_disp_2b <= ~ARESETN;
        reset_disp_1b <= reset_disp_2b;
    end
    assign reset_disp = reset_disp_1b;

    assign vid_pData = {red, blue, green};
    assign vid_pVDE = display_enable;
    assign vid_pHSync = hsyncx;
    assign vid_pVSync = vsyncx;

endmodule

`default_nettype wire


次に、bitmap_disp_engine.v を示す。

// BitMap Display Controller
// bitmap_disp_engine.v
// AXI4バス用 by marsee
//
// 2014/07/26 : video_timing_param.vh を使用
// 2014/09/18 : フレームバッファのスタートアドレス入力を追加
// 2016/03/04 : display_enable の出力期間のバグをフィックスした
// 2016/08/08 : AXI4 Master から AXI4-Stream インターフェースに変更
//

`default_nettype none

// synthesis translate_off
// `include "std_ovl_defines.h"
// synthesis translate_on

module bitmap_disp_engine #(
        // AXI4-Stream Interface
        parameter integer C_M_AXIS_DATA_WIDTH            = 32,
        // video resolution : "VGA", "SVGA", "XGA", "SXGA", "HD"
        parameter [80*8:1] RESOLUTION                    ="SVGA"  // SVGA
) (
    input    wire    clk_disp,            // ディスプレイ表示用クロック
    input    wire    clk_axi,            // AXI4バスクロック
    input    wire    reset_disp,            // clk_disp 用リセット
    input    wire    reset_axi,            // clk_axi 用リセット

    input    wire [C_M_AXIS_DATA_WIDTH-1:0]        s_axis_tdata,
    input    wire [(C_M_AXIS_DATA_WIDTH/8)-1:0]    s_axis_tstrb,
    input    wire                                s_axis_tvalid,
    output    wire                                   s_axis_tready,
    input     wire                                   s_axis_tlast,
    input    wire                                s_axis_tuser,

    output    reg        [7:0]    red_out,
    output    reg        [7:0]    green_out,
    output    reg      [7:0]    blue_out,
    (*S="TRUE"*) output    reg     hsyncx,
    (*S="TRUE"*) output    reg     vsyncx,
    output    wire    display_enable,
    input    wire    ddr_cont_init_done,    // DDR2 SDRAMコントローラの初期化終了
    output    wire    afifo_overflow, // 非同期FIFO のオーバーフロー・エラー
    output    wire    afifo_underflow    // 非同期FIFO のアンダーフロー・エラー
);
    `include "./video_timing_param.vh"

    parameter [2:0]    idle_rdg=            3'b001,
                    wait_half_full=        3'b010,
                    display_mode=        3'b100;
    reg    [2:0] cs_rdg;

    reg afifo_rd_en;
    wire afifo_wr_en;
    wire [31:0] afifo_dout;
    wire afifo_full;
    wire afifo_empty;
    wire [9:0] wr_data_count;
    reg [15:0] h_count;
    reg [15:0] v_count;
    reg [7:0] red_node, green_node, blue_node;
    reg hsyncx_node, vsyncx_node;
    reg vsync_axi, vsync_axi_b1;
    reg vsync_axi_1d;
    reg vsyncx_rise_pulse;
    reg de, de_b1, de_b2;
    wire disp_mode_ena;
    reg disp_mode_ena_d0, disp_mode_ena_d1;
    reg init_done_d0 = 1'b0;
    reg init_done_d1 = 1'b0;

    // synthesis translate_off
    // wire [`OVL_FIRE_WIDTH-1:0] fire_overflow, fire_underflow;
    // synthesis translate_on

    // RGB保存用非同期FIFO, FWFT Wirte側64ビット幅512深度、Read側32ビット512深度とする
    bitmap_afifo bitmap_afifo_inst (
        .wr_rst(reset_axi),
        .wr_clk(clk_axi),
        .rd_clk(clk_disp),
        .rd_rst(reset_disp),
        //.din(data_in), // Bus [63 : 0]
        .din(s_axis_tdata), // Bus [31 : 0]
        .wr_en(afifo_wr_en),
        .rd_en(afifo_rd_en),
        .dout(afifo_dout), // Bus [31 : 0]
        .full(afifo_full),
        .overflow(afifo_overflow),
        .empty(afifo_empty),
        .underflow(afifo_underflow),
        .wr_data_count(wr_data_count)  // [9 : 0] wr_data_count
    );
    assign afifo_wr_en = s_axis_tvalid & ~afifo_full;
    // afifo_wr_en が 1 になるときは、tuserが1の時か、cs_rdgがidle_rdgでなく、tvalidが1で、FIFOがFULLでない時
    assign s_axis_tready = ~afifo_full; 

    // ddr_cont_init_done を clk_axi で同期化する
    always @(posedge clk_axi) begin
        init_done_d0 <= ddr_cont_init_done;
        init_done_d1 <= init_done_d0;
    end

    // Readデータ処理モジュール用ステートマシン
    always @(posedge clk_axi) begin
        if (reset_axi | ~init_done_d1)
            cs_rdg <= idle_rdg;
        else begin
            case (cs_rdg)
                idle_rdg :
                    if (s_axis_tuser & afifo_wr_en)
                        cs_rdg <= wait_half_full;
                wait_half_full : // 最初にFIFO が half_full になるのを待ってスタートする
                    if (wr_data_count[8])
                        cs_rdg <= display_mode;
                display_mode : // 画面表示モード
                    ;
            endcase
        end
    end
    assign disp_mode_ena = (cs_rdg==display_mode) ? 1'b1 : 1'b0;

    // ビットマップVGAコントローラのclk_disp 動作部

    // h_count、v_count用にclk_axi 動作のcs_rdg の値を使用するので2回clk_disp 動作のFFでラッチする
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            disp_mode_ena_d0 <= 0;
        end else begin
            disp_mode_ena_d0 <= disp_mode_ena;
            disp_mode_ena_d1 <= disp_mode_ena_d0;
        end
    end

    // h_countの実装(水平カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp==1'b1 || disp_mode_ena_d1==1'b0)
            h_count <= 0;
        else if (h_count>=(H_SUM-1)) // h_count がH_SUM-1よりも大きければ0に戻す(mod H_SUM)
            h_count <= 0;
        else
            h_count <= h_count + 1;
    end

    // v_countの実装(垂直カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp==1'b1 || disp_mode_ena_d1==1'b0)
            v_count <= 0;
        else if (h_count>=(H_SUM-1)) begin // 水平カウンタがクリアされるとき
            if (v_count>=(V_SUM-1)) // v_count がV_SUM-1よりも大きければ0に戻す(mode V_SUM)
                v_count <= 0;
            else
                v_count <= v_count + 1;
        end
    end

    // Red, Green, Blue出力
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_node <= 0;
            green_node <= 0;
            blue_node <= 0;
        end else begin
            if (disp_mode_ena_d1==1'b0) begin // 最初にpixel_async_fifo がフルになるまで画像データを出力しない。
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end else if (h_count<=H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) begin
                red_node <= afifo_dout[23:16];
                green_node <= afifo_dout[15:8];
                blue_node <= afifo_dout[7:0];
            end else begin
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_out <= 0;
            green_out <= 0;
            blue_out <= 0;
        end else begin
            red_out <= red_node;
            green_out <= green_node;
            blue_out <= blue_node;
        end
    end

    // hsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp | ~disp_mode_ena_d1)
            hsyncx_node <= 1'b1;
        else
            if (h_count>(H_ACTIVE_VIDEO + H_FRONT_PORCH-1) && h_count<=(H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE-1)) // 水平同期期間
                hsyncx_node <= 1'b0;
            else
                hsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx <= 1'b1;
        else
            hsyncx <= hsyncx_node;
    end

    // vsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp | ~disp_mode_ena_d1)
            vsyncx_node <= 1'b1;
        else
            if (v_count>(V_ACTIVE_VIDEO + V_FRONT_PORCH-1) && v_count<=(V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE-1)) // 垂直同期期間
                vsyncx_node <= 1'b0;
            else
                vsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx <= 1'b1;
        else
            vsyncx <= vsyncx_node;
    end

    // vsync をclk_axi で同期化
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            vsync_axi        <= 1'b0;
            vsync_axi_b1    <= 1'b0;
            vsync_axi_1d    <= 1'b0;
        end else begin
            vsync_axi_b1     <= ~vsyncx_node;
            vsync_axi         <= vsync_axi_b1;
            vsync_axi_1d    <= vsync_axi;
        end
    end

    // vsyncx_rise_pulse の処理。vsyncx の立ち上がり時に1パルス出力する
    always @(posedge clk_axi) begin
        if (reset_axi)
            vsyncx_rise_pulse <= 1'b0;
        else begin
            if (vsync_axi==1'b0 && vsync_axi_1d==1'b1)
                vsyncx_rise_pulse <= 1'b1;
            else
                vsyncx_rise_pulse <= 1'b0;
        end
    end

    // display_enable 出力
    always @(posedge clk_disp) begin
        if (reset_disp | ~disp_mode_ena_d1)
            de <= 1'b0;
        else begin
            if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO)
                de <= 1'b1;
            else
                de <= 1'b0;
        end
    end
    always @(posedge clk_disp) begin
        if(reset_disp | ~disp_mode_ena_d1) begin
            de_b1 <= 1'b0;
            de_b2 <= 1'b0;
        end else begin
            de_b1 <= de;
            de_b2 <= de_b1;
        end
    end
    assign display_enable = de_b2;

    // afifo_rd_en の処理
    always @(posedge clk_disp) begin
        if (reset_disp)
            afifo_rd_en <= 1'b0;
        else begin
            if (~disp_mode_ena_d1) // 初期化中
                afifo_rd_en <= 1'b0;
            else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) // 表示期間
                afifo_rd_en <= 1'b1;
            else
                afifo_rd_en <= 1'b0;
        end
    end
endmodule

`default_nettype wire



最後に、bm_disp_cntrler_axi_lite_slave.v を示す。

// bm_disp_cntrler_axi_lite_slave.v
// bitmap_disp_cntrler_axi_master のAXI Lite Slave モジュール。Frame Buffer のスタートアドレス・レジスタを持つ。
//
// Addr 0x0 - frame buffer start address
//

`default_nettype none

module bm_disp_cntrler_axi_lite_slave # (
    parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9, // Address width of the AXI Lite Interface
    parameter integer C_S_AXI_LITE_DATA_WIDTH = 32, // Data width of the AXI Lite Interface

    parameter [31:0] C_DISPLAY_START_ADDRESS = 32'h1A00_0000
)(
    input    wire                                    s_axi_lite_aclk,
    input    wire                                    axi_resetn,

    // AXI Lite Write Address Channel
    input    wire                                    s_axi_lite_awvalid,
    output    wire                                    s_axi_lite_awready,
    input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_awaddr,

    // AXI Lite Write Data Channel
    input    wire                                    s_axi_lite_wvalid,
    output    wire                                    s_axi_lite_wready,
    input    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_wdata,

    // AXI Lite Write Response Channel
    output    wire    [1:0]                            s_axi_lite_bresp,
    output    wire                                    s_axi_lite_bvalid,
    input    wire                                    s_axi_lite_bready,

    // AXI Lite Read Address Channel
    input    wire                                    s_axi_lite_arvalid,
    output    wire                                    s_axi_lite_arready,
    input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_araddr,

    // AXI Lite Read Data Channel
    output    wire                                    s_axi_lite_rvalid,
    input    wire                                    s_axi_lite_rready,
    output    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_rdata,
    output    wire    [1:0]                            s_axi_lite_rresp,

    output    wire    [31:0]                            fb_start_address,    // Frame Buffer のスタートアドレス
    output    reg                                        init_done            // PS部の初期化終了
);

    // RESP の値の定義
    parameter    RESP_OKAY =        2'b00;
    parameter    RESP_EXOKAY =    2'b01;
    parameter    RESP_SLVERR =     2'b10;
    parameter    RESP_DECERR =    2'b11;

    parameter    IDLE_WR =            2'b00,    // for wrt_cs
                DATA_WRITE_HOLD =    2'b01,
                BREADY_ASSERT =        2'b11;

    parameter    IDLE_RD    =        1'b0,            //  for rdt_cs
                AR_DATA_WAIT =    1'b1;

    reg        [1:0]    wrt_cs = IDLE_WR;

    reg        [31:0]    fb_start_addr_reg = C_DISPLAY_START_ADDRESS;

    reg        rdt_cs = IDLE_RD;

    reg        reset_1d = 1'b0;
    reg        reset = 1'b0;
    reg        awready = 1'b1;
    reg        bvalid = 1'b0;
    reg        arready = 1'b1;
    reg        rvalid = 1'b0;
    wire    aclk;

    assign aclk = s_axi_lite_aclk;
    // Synchronization of axi_resetn
    always @(posedge aclk) begin
        reset_1d <= ~axi_resetn;
        reset <= reset_1d;
    end

    // AXI4 Lite Slave Write Transaction State Machine
    always @(posedge aclk) begin
        if (reset) begin
            wrt_cs <= IDLE_WR;
            awready <= 1'b1;
            bvalid <= 1'b0;
        end else begin
            case (wrt_cs)
                IDLE_WR :
                    if (s_axi_lite_awvalid & ~s_axi_lite_wvalid) begin    // Write Transaction Start
                        wrt_cs <= DATA_WRITE_HOLD;
                        awready <= 1'b0;
                    end else if (s_axi_lite_awvalid & s_axi_lite_wvalid) begin    // Write Transaction Start with data
                        wrt_cs <= BREADY_ASSERT;
                        awready <= 1'b0;
                        bvalid <= 1'b1;
                    end
                DATA_WRITE_HOLD :
                    if (s_axi_lite_wvalid) begin    // Write data just valid
                        wrt_cs <= BREADY_ASSERT;
                        bvalid <= 1'b1;
                    end
                BREADY_ASSERT :
                    if (s_axi_lite_bready) begin    // The write transaction was terminated.
                        wrt_cs <= IDLE_WR;
                        bvalid <= 1'b0;
                        awready <= 1'b1;
                    end
            endcase
        end
    end
    assign s_axi_lite_awready = awready;
    assign s_axi_lite_bvalid = bvalid;
    assign s_axi_lite_wready = 1'b1;
    assign s_axi_lite_bresp = RESP_OKAY;

    // AXI4 Lite Slave Read Transaction State Machine
    always @(posedge aclk) begin
        if (reset) begin
            rdt_cs <= IDLE_RD;
            arready <= 1'b1;
            rvalid <= 1'b0;
        end else begin
            case (rdt_cs)
                IDLE_RD :
                    if (s_axi_lite_arvalid) begin
                        rdt_cs <= AR_DATA_WAIT;
                        arready <= 1'b0;
                        rvalid <= 1'b1;
                    end
                AR_DATA_WAIT :
                    if (s_axi_lite_rready) begin
                        rdt_cs <= IDLE_RD;
                        arready <= 1'b1;
                        rvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign s_axi_lite_arready = arready;
    assign s_axi_lite_rvalid = rvalid;
    assign s_axi_lite_rresp = RESP_OKAY;

    // fb_start_addr_reg
    always @(posedge aclk) begin
        if (reset)
            fb_start_addr_reg <= C_DISPLAY_START_ADDRESS;
        else
            if (s_axi_lite_wvalid)
                fb_start_addr_reg <= s_axi_lite_wdata;
    end
    assign fb_start_address = fb_start_addr_reg;
    assign s_axi_lite_rdata = fb_start_addr_reg;

    // generated init_done
    always @(posedge aclk) begin
        if(reset) begin
            init_done <= 1'b0;
        end else if(wrt_cs==BREADY_ASSERT) begin
            init_done <= 1'b1;
        end
    end
endmodule

`default_nettype wire

  1. 2016年08月17日 05:14 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする3(シミュレーション)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする2(bitmap_afifo)”の続き。

前回は、bitmap_afifo を生成した。今回は、”Vivado HLS でAXI4-Stream Master Model IP を作る”で作った AXI4-Stream Master Model IP を使って、AXI4-Stream版ビットマップ・ディスプレイ・コントローラをシミュレーションしてみた。なお、AXI4-Stream版ビットマップ・ディスプレイ・コントローラは、Verilog HDL で実装できている。

下図にシミュレーション画面を示す。なおここには、波形ウインドウは表示されていない。
AXI4-Stream_bitmap_disp_cont_13_160816.png

出力される画像データをアサーションでテストしている。アサーション・エラーが出ていないので、問題ないようだ。最初は、アサーション・エラーが出ていたので、HDL を修正した。

40 us シミュレーションした時の波形ウインドウを示す。
AXI4-Stream_bitmap_disp_cont_14_160816.png

画像データの出力開始部分を示す。
AXI4-Stream_bitmap_disp_cont_15_160816.png

17 ms シミュレーションを行った。
AXI4-Stream_bitmap_disp_cont_16_160818.png 

テストベンチの bitmap_disp_cont_axis_tb.v を貼っておく。

`default_nettype none

`timescale 100ps / 1ps

// bitmap_disp_cont_axis_tb.v
// 2012/07/03
// 2014/09/19 : for ZYBO
// 2016/08/14 : for AXI4-Stream

module bitmap_disp_cntrler_axi_master_tb;
    parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9; // Address width of the AXI Lite Interface
    parameter integer C_S_AXI_LITE_DATA_WIDTH = 32; // Data width of the AXI Lite Interface
    parameter integer C_M_AXIS_DATA_WIDTH= 32; // AXI4-Stream Interface

    parameter DELAY = 1;

    wire ACLK;
    wire ARESETN;

    wire [C_M_AXIS_DATA_WIDTH-1:0]        s_axis_tdata;
    wire [(C_M_AXIS_DATA_WIDTH/8)-1:0]    s_axis_tstrb;
    wire                                s_axis_tvalid;
    wire                                   s_axis_tready;
    wire                                   s_axis_tlast;
    wire                                s_axis_tuser;
    reg        ap_start;
    wire    ap_done;
    wire    ap_idle;
    wire    ap_ready;

    wire pixclk;
    wire [4:0]    vga_red;
    wire [5:0]    vga_green;
    wire [4:0]    vga_blue;
    wire    vga_hsync;
    wire    vga_vsync;

    wire [23:0] vid_pData;
    wire    vid_pVDE;
    wire    vid_pHSync;
    wire    vid_pVSync;

    reg    [7:0]    red;
    reg    [7:0]    blue;
    reg    [7:0]    green;
    wire [32:0]    rbg_data;

    // AXI Lite Write Address Channel
    reg                                        s_axi_lite_awvalid = 1'b0;
    wire                                    s_axi_lite_awready;
    reg        [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_awaddr = 0;
    //reg        [3-1:0]                            s_axi_lite_awport = 1'b0;

    // AXI Lite Write Data Channel
    reg                                        s_axi_lite_wvalid =1'b0;
    wire                                    s_axi_lite_wready;
    reg        [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_wdata = 0;

    // AXI Lite Write Response Channel
    wire    [1:0]                            s_axi_lite_bresp;
    wire                                    s_axi_lite_bvalid;
    reg                                        s_axi_lite_bready = 1'b0;

    // AXI Lite Read Address Channel
    reg                                        s_axi_lite_arvalid = 1'b0;
    wire                                    s_axi_lite_arready;
    reg        [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_araddr = 1'b0;
    //reg        [3-1:0]                            s_axi_lite_arport = 0;

    // AXI Lite Read Data Channel
    wire                                    s_axi_lite_rvalid;
    reg                                        s_axi_lite_rready = 1'b0;
    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_rdata;
    wire    [1:0]                            s_axi_lite_rresp;

    integer i;

    // Instantiate the Unit Under Test (uut_bdc_axis)
    bitmap_disp_cont_axis #(
        .C_S_AXI_LITE_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
        .C_S_AXI_LITE_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH),
        .C_M_AXIS_DATA_WIDTH(C_M_AXIS_DATA_WIDTH),
        .RESOLUTION("SVGA")
    ) uut_bdc_axis (
        .s_axi_lite_aclk(ACLK),
        .AXIS_ACLK(ACLK),
        .ARESETN(ARESETN),

        .s_axi_lite_awvalid(s_axi_lite_awvalid),
        .s_axi_lite_awready(s_axi_lite_awready),
        .s_axi_lite_awaddr(s_axi_lite_awaddr),
        .s_axi_lite_wvalid(s_axi_lite_wvalid),
        .s_axi_lite_wready(s_axi_lite_wready),
        .s_axi_lite_wdata(s_axi_lite_wdata),
        .s_axi_lite_bresp(s_axi_lite_bresp),
        .s_axi_lite_bvalid(s_axi_lite_bvalid),
        .s_axi_lite_bready(s_axi_lite_bready),
        .s_axi_lite_arvalid(s_axi_lite_arvalid),
        .s_axi_lite_arready(s_axi_lite_arready),
        .s_axi_lite_araddr(s_axi_lite_araddr),
        .s_axi_lite_rvalid(s_axi_lite_rvalid),
        .s_axi_lite_rready(s_axi_lite_rready),
        .s_axi_lite_rdata(s_axi_lite_rdata),
        .s_axi_lite_rresp(s_axi_lite_rresp),

        .s_axis_tdata(s_axis_tdata),
        .s_axis_tstrb(s_axis_tstrb),
        .s_axis_tvalid(s_axis_tvalid),
        .s_axis_tready(s_axis_tready),
        .s_axis_tlast(s_axis_tlast),
        .s_axis_tuser(s_axis_tuser),

        .pixclk(pixclk),
        .vga_red(vga_red),
        .vga_green(vga_green),
        .vga_blue(vga_blue),
        .vga_hsync(vga_hsync),
        .vga_vsync(vga_vsync),
        .vid_pData(vid_pData),
        .vid_pVDE(vid_pVDE),
        .vid_pHSync(vid_pHSync),
        .vid_pVSync(vid_pVSync)
    );
    //defparam uut_master.bitmap_disp_eng_inst.INIT_COUNT_VAL = 20; // 初期化時のWaitタイマー

    // clk_gen のインスタンス(ACLK)
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );

    // clk_gen のインスタンス(pixclk)
    clk_gen #(
        //.CLK_PERIOD(154),    // 15.4 nsec, 64.9 MHz
        .CLK_PERIOD(250),    // 25 nsec, 40 MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) pixclk_i (
        .clk_out(pixclk)
    );

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESET_ARESETN (
        .reset_out(ARESETN),
        .init_done()
    );

    // Instantiate the AXI4-Stream Master Model (uut_axi4sm)
    axi4_stream_master uut_axi4sm (
        .ap_clk(ACLK),
        .ap_rst_n(ARESETN),

        .ap_start(ap_start),
        .ap_done(ap_done),
        .ap_idle(ap_idle),
        .ap_ready(ap_ready),
        .outs_TDATA(s_axis_tdata),
        .outs_TVALID(s_axis_tvalid),
        .outs_TREADY(s_axis_tready),
        .outs_TKEEP(),
        .outs_TSTRB(s_axis_tstrb),
        .outs_TUSER(s_axis_tuser),
        .outs_TLAST(s_axis_tlast),
        .outs_TID(),
        .outs_TDEST()
    );

    initial begin
        // Initialize Inputs
        ap_start = 1'b0;
        s_axi_lite_awaddr = 0;
        //s_axi_lite_awport = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_wdata = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_bready = 0;
        s_axi_lite_araddr = 0;
        //s_axi_lite_arport = 0;
        s_axi_lite_arvalid = 0;
        s_axi_lite_rready = 0;

        // Wait Reset rising edge
        @(posedge ARESETN);

        #10000;    // 1us wait

        for (i=0; i<10; i=i+1) begin
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end

        // Add stimulus here
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0100, 32'h55AA_55AA);
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC1(32'h0000_0100);
        #DELAY;

        ap_start = 1'b1;

        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC2(32'h0000_0100, 32'h17800000);
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC2(32'h0000_0600);
    end

    // Write Transcation 1
    task AXI_MASTER_WADC1;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_awvalid = 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;
            @(posedge ACLK);    // 次のクロックへ, s_axi_lite_wready は常に 1

            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            s_axi_lite_bready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Write Transcation 2
    task AXI_MASTER_WADC2;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_awvalid = 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;
            @(posedge ACLK);    // 次のクロックへ, s_axi_lite_wready は常に 1

            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            @(posedge ACLK);    // 次のクロックへ

            #DELAY;
            s_axi_lite_bready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Read Transcation 1
    task AXI_MASTER_RADC1;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            s_axi_lite_rready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b0;
        end
    endtask

    // Read Transcation 2
    task AXI_MASTER_RADC2;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b0;
        end
    endtask

    // assertion
    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            red <= 8'd0;
        end else if (vid_pVDE) begin
            red <= red + 8'd1;
        end
    end
    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            green <= 8'd0;
        end else if (vid_pVDE) begin
            green <= green + 8'd2;
        end
    end
    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            blue <= 8'd0;
        end else if (vid_pVDE) begin
            blue <= blue + 8'd3;
        end
    end
    assign rbg_data = {8'd0, red, blue, green};

    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            ;
        end else if (vid_pVDE==1'b1 && {8'd0, vid_pData} != rbg_data) begin
            $display("%t Data Error : rbg_data = %h, vid_pData = %h", $realtime, rbg_data, vid_pData);
        end
    end
endmodule


module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out,
    output    reg        init_done
);
    begin
        initial begin
            reset_out = RESET_STATE;
            init_done = 1'b0;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
            init_done = 1'b1;
        end
    end

endmodule

`default_nettype wire

  1. 2016年08月17日 04:13 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS でAXI4-Stream Master Model IP を作る

久しぶり Verilog HDL を使って、AXI4-Stream版ビットマップ・ディスプレイ・コントローラを作っている。ビットマップ・ディスプレイ・コントローラはAXI4-Stream Slave なので、シミュレーションするには AXI4-Stream Master が必要となる。始めは、HDL で AXI4-Stream Master IP を作ろうとしたのだが、考えてみれば、Vivado HLS で、C++ で AXI4-Stream Master IP を作ってもよいのじゃないか?ということで、Vivado HLS 2016.2 を使用して作ってみた。

Vivado HLS 2016.2 の axi4-stream_master プロジェクトを示す。
AXI4-Stream_bitmap_disp_cont_8_160815.png

最初に axi4_stream_master.h を示す。

// axi4_stream_master.h
// 2016/08/15 by marsee
//

#ifndef __AXI4_STREAM_MASTER_H__
#define __AXI4_STREAM_MASTER_H__

#define HORIZONTAL_PIXELS 800
#define VERTICAL_LINES 600

#endif


ソースファイルの axi4_stream_master.cpp を示す。

// axi4_stream_master.cpp
// 2016/08/15 by marsee
//
// AXI4-Stream Master Model
//

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

#include "axi4_stream_master.h"

void axi4_stream_master(hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE ap_ctrl_hs port=return
    ap_uint<8> red = 0;
    ap_uint<8> blue = 0;
    ap_uint<8> green = 0;
    ap_axis<32,1,1,1> pix;

    for (int y=0; y<VERTICAL_LINES; y++){
        for (int x=0; x<HORIZONTAL_PIXELS; x++){
#pragma HLS PIPELINE II=1
            pix.data = red*65536 + green*256 + blue;
            red++;
            green += 2;
            blue += 3;
            if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
                pix.user = 1;
            else
                pix.user = 0;

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

            outs << pix;
        }
    }
}


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

// axi4_stream_master.tb.cpp
// 2016/08/15 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>

#include "axi4_stream_master.h"

void axi4_stream_master(hls::stream<ap_axis<32,1,1,1> >& outs);

int main(){
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > outs;
    ap_axis<32,1,1,1> pix;
    ap_uint<8> red = 0;
    ap_uint<8> blue = 0;
    ap_uint<8> green = 0;
    ap_int<32> pix_data;

    axi4_stream_master(outs);

    for (int y=0; y<VERTICAL_LINES; y++){
        for (int x=0; x<HORIZONTAL_PIXELS; x++){
            outs >> pix;
            pix_data = red*65536 + green*256 + blue;
            //printf("red=%x, green=%x, blue=%x, pix_data=%x\n", (int)red, (int)green, (int)blue, (int)pix_data);
            if (pix.data != pix_data){
                printf("ERROR HW and SW results mismatch x = %d, y = %d, HW = %x, SW = %x\n", x, y, (int)pix.data, (int)pix_data);
                return(1);
            }
            red++;
            green += 2;
            blue += 3;
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    return(0);
}


合成はしないけれども、C コードの合成結果を示す。
AXI4-Stream_bitmap_disp_cont_9_160815.png

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

outs_TVALID と outs_TREADY がずっと1のままなので、大丈夫そうだ。

AXI4-Stream_bitmap_disp_cont_11_160815.png

最初のデータで outs_TUSER が 1 になっているのがわかる。

AXI4-Stream_bitmap_disp_cont_12_160815.png

さいしょのデータが始まってから、outs_TLAST が 1 にアサートされて、0 になるまでの間は 8 us だった。これは、10 ns のクロックが 800 個分なので、合っている。

最後にIP 化は行ったが、HDLを直接使用すると思う。
  1. 2016年08月16日 03:47 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

宝篋山に登ってきました

今日は宝篋山に登ってきました。

宝篋山はつくば市の北東部にある,標高461mの山です。家からは、車で20分程度です。宝篋山の案内はこちら。

筑波総合体育館から登り始めました。山口コース(1)を登ります。
最初は舗装された普通の田舎道です。
houkyousan_1_160814.jpg

1.5 km ほど行くと山道になってきました。
houkyousan_2_160814.jpg

山道をどんどん登っていきます。
houkyousan_3_160814.jpg

途中、雨で水で土砂が流れた後のよう道がありました。というか、かなり長い間その道でした。暗いところでは写真がぶれちゃっているので、写真はありません。

途中で宝篋水の看板が。でもあまり水は流れていなかったです?
houkyousan_4_160814.jpg

途中で、とっても眺めの良いところが。。。
houkyousan_5_160814.jpg

登山道から見える景色はこんなのです。
houkyousan_6_160814.jpg

また景色の良い場所がありました。前よりも登っているのがわかると思います。
houkyousan_7_160814.jpg

結構細い道もあります。
houkyousan_8_160814.jpg

山頂の100mくらい手前でトイレがあります。このトイレはバイオトイレで、おがくずがたくさん便器の中に入っています。バイオに力で便や小水を分解するそうです。おがくずの良いにおいがしました。きれいですよ。
houkyousan_9_160814.jpg

山頂に向けて100m登ります。
houkyousan_10_160814.jpg

山頂付近にはにはNHKの中継所?かな?
houkyousan_11_160814.jpg

もう少し上ると山頂です。鳥居もありましたね。山頂に到着しました。
houkyousan_12_160814.jpg

山頂からの眺めは最高です。
houkyousan_13_160814.jpg

筑波山もまじかに見えますね。
houkyousan_14_160814.jpg

反対側もとっても眺めが良いです。
houkyousan_15_160814.jpg

朝の6時30分頃、家を出て、10時ころ帰ってきました。とても手軽に行けるので、もっと行きたいですね。
そして、トレランで走れるようになれば良いなと思います。トレーニングをやりたいと思いました。

北条の体育館から宝篋山山頂への往復距離数7.94km、所要時間1:57:17、最低高度24m、最高高度455m、消費カロリー385Cでした。
  1. 2016年08月13日 20:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする2(bitmap_afifo)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする1(構想編)”の続き。

前回は構想編だったので、今回は、Vivado 2016.2 のプロジェクトを作って、bitmap_afifo (ビットマップのピクセル用の非同期FIFO)を作った。

最初に、Vivado 2016.2 で作成した bm_dispc_axis プロジェクトを示す。
AXI4-Stream_bitmap_disp_cont_2_160811.png

bitmap_afifo のパラメータを示す。
Basic タブでは、Independent Clocks の Block RAM を選択した。
AXI4-Stream_bitmap_disp_cont_3_160811.png

Native Pors タブでは、Read Mode で First Word Fall Through を選択し、Write Depth は512 を選択した。
AXI4-Stream_bitmap_disp_cont_4_160811.png

Status Flags タブでは、Overflow と Underflow フラグを追加した。
AXI4-Stream_bitmap_disp_cont_5_160811.png

Data Counts タブでは、Read Date Count をイネーブルした。
AXI4-Stream_bitmap_disp_cont_6_160811.png

Summary タブを示す。
AXI4-Stream_bitmap_disp_cont_7_160811.png

bitmap_afifo.vhd の entity を貼っておく。

ENTITY bitmap_afifo IS
  PORT (
    wr_clk : IN STD_LOGIC;
    wr_rst : IN STD_LOGIC;
    rd_clk : IN STD_LOGIC;
    rd_rst : IN STD_LOGIC;
    din : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
    wr_en : IN STD_LOGIC;
    rd_en : IN STD_LOGIC;
    dout : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    full : OUT STD_LOGIC;
    overflow : OUT STD_LOGIC;
    empty : OUT STD_LOGIC;
    underflow : OUT STD_LOGIC;
    wr_data_count : OUT STD_LOGIC_VECTOR(9 DOWNTO 0)
  );
END bitmap_afifo;

  1. 2016年08月11日 04:49 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Gabor FilterをZYBO_0_162_2 へ実装してみた5(ソフトウェアのソースコード)

Gabor FilterをZYBO_0_162_2 へ実装してみた4(ZYBOで確かめた)”の続き。

前回は、ガボール・フィルタのソフトウェアを作って、ガボール・フィルタをテストしてみた。
今回は、それ用のソフトウェアを貼っておく。

まずは、lap_fil_on.c から貼っておく。

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

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

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

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

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


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

//
// gabor_fil_left.c
// Created on: 2016/08/09
//      Author: marsee
//
// Refered to http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug902-vivado-high-level-synthesis.pdf
//

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

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

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

    // axis_switch_0 (UIO2)
    fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axis_switch_0){
        fprintf(stderr, "axis_switch_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1 (UIO3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!axis_switch_1){
        fprintf(stderr, "axis_switch_1 mmap error\n");
        exit(-1);
    }
    
    // gabor_filter_lh_0 (UIo14)
    fd4 = open("/dev/uio14", O_RDWR); // gabor_filter_lh_0 interface AXI4 Lite Slave
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio14 (gabor_filter_lh_0) open error\n");
        exit(-1);
    }
    gabor_filter_lh_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!gabor_filter_lh_0){
        fprintf(stderr, "lap_filter_axis_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1, 1to2 ,Select M01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x80000000// 0x40 = 0x80000000; disable
    axis_switch_1[17] = 0x80000000// 0x44 = 0x80000000; disable
    axis_switch_1[18] = 0// 0x48 = 0;
    axis_switch_1[0] = 0x2// 0x0 = 2; Commit registers
    
    // gabor filter AXIS Start
    gabor_filter_lh_0[6] = 0// left parameter
    gabor_cntrl = gabor_filter_lh_0[0] & 0x80// Auto Restart bit
    gabor_filter_lh_0[0] = gabor_cntrl | 0x01// Start bit set
    gabor_filter_lh_0[0] = 0x80// Auto Restart bit set
    
    // axis_switch_0, 2to1, Select S01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x2// 0x40 = 0x2;
    axis_switch_0[0] = 0x2// 0x0 = 2; Commit registers
    
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)gabor_filter_lh_0, 0x10000);
    
    return(0);
}


gabor_fil_right.c を貼っておく。

//
// gabor_fil_right.c
// Created on: 2016/08/09
//      Author: marsee
//
// Refered to http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug902-vivado-high-level-synthesis.pdf
//

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

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

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

    // axis_switch_0 (UIO2)
    fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axis_switch_0){
        fprintf(stderr, "axis_switch_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1 (UIO3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!axis_switch_1){
        fprintf(stderr, "axis_switch_1 mmap error\n");
        exit(-1);
    }
    
    // gabor_filter_lh_0 (UIo14)
    fd4 = open("/dev/uio14", O_RDWR); // gabor_filter_lh_0 interface AXI4 Lite Slave
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio14 (gabor_filter_lh_0) open error\n");
        exit(-1);
    }
    gabor_filter_lh_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!gabor_filter_lh_0){
        fprintf(stderr, "lap_filter_axis_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1, 1to2 ,Select M01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x80000000// 0x40 = 0x80000000; disable
    axis_switch_1[17] = 0x80000000// 0x44 = 0x80000000; disable
    axis_switch_1[18] = 0// 0x48 = 0;
    axis_switch_1[0] = 0x2// 0x0 = 2; Commit registers
    
    // gabor filter AXIS Start
    gabor_filter_lh_0[6] = 1// right parameter
    gabor_cntrl = gabor_filter_lh_0[0] & 0x80// Auto Restart bit
    gabor_filter_lh_0[0] = gabor_cntrl | 0x01// Start bit set
    gabor_filter_lh_0[0] = 0x80// Auto Restart bit set
    
    // axis_switch_0, 2to1, Select S01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x2// 0x40 = 0x2;
    axis_switch_0[0] = 0x2// 0x0 = 2; Commit registers
    
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)gabor_filter_lh_0, 0x10000);
    
    return(0);
}


cam_return_axis.c を貼っておく。このソフトウェアは、ラプラシアンフィルタ画像やガボール・フィルタ画像を通常のカメラ画像に戻す。

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

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

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

    // axis_switch_0 (UIO2)
    fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axis_switch_0){
        fprintf(stderr, "axis_switch_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1 (UIO3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!axis_switch_1){
        fprintf(stderr, "axis_switch_1 mmap error\n");
        exit(-1);
    }

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

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

  1. 2016年08月10日 03:43 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Gabor FilterをZYBO_0_162_2 へ実装してみた4(ZYBOで確かめた)

Gabor FilterをZYBO_0_162_2 へ実装してみた3(devicetree.dtb の作成)”の続き。

devicetree.dtb を生成することができたので、Boot.bin と devicetree.dtb を MicroSDカードのファースト・パーティションに書き込んで、ZYBO に入れてブートして確かめてみた。

まずは、/sys/device/amba.0 ディレクトリ以下を確認したところ、gabor_filger_0 が uio14 だということが分かった。
AXI4-Stream Switch のポート数を増やしてあるので、cam_disp_vdma.c のAXI4-Stream Switch のポート部分を書き換えた。
cam_disp_vdma.c をコンパイルして、cam_disp_vdma 実行ファイルを生成した。更に、左白線検出用の gabor_fil_left と右白線検出用の gabor_fil_right を作成した。以前からのラプラシアンフィルタ処理のソフト lap_fil_on_axis も多少修正した。

現在のカメラ付きのZybot を示す。
GaborFilter_48_160810.jpg

このようなコースで評価を行っている。
GaborFilter_49_160810.jpg

Zybot のカメラ画像を示す。
GaborFilter_50_160810.jpg

Zybot のカメラ画像にラプラシアンフィルタをかけた画像を示す。
GaborFilter_51_160810.jpg

Zybot のカメラ画像に左白線用ガボール・フィルタをかけた画像を示す。
GaborFilter_52_160810.jpg

Zybot のカメラ画像に右白線用ガボール・フィルタをかけた画像を示す。
GaborFilter_53_160810.jpg

ガボール・フィルタでは、左白線と右白線検出ができていると思うが、白線の曲がっている状態がうまく検出できるように、パラメータを取得しようと思う。そのために、カメラ画像をBMPファイルにするソフトウェアを作ろうと思う。

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

//
// cam_disp_vdma.c
// Created on: 2015/12/03
//      Author: marsee
// 2016/01/23 : udmabuf version
// 2016/08/09 : Gabor Filter version
//

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

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

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.
#define HORIZONTAL_PIXEL    800
#define ALL_CHAR_OF_1LINE   (HORIZONTAL_PIXEL/8)
#define VERTICAL_PIXEL      600
#define ALL_CHAR_OF_ROW     (VERTICAL_PIXEL/8)
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXEL*VERTICAL_PIXEL*4)
#define ALL_DISP_CHARACTOR  HORIZONTAL_PIXEL*VERTICAL_PIXEL

void cam_i2c_init(volatile unsigned *mt9d111_axi_iic) {
    mt9d111_axi_iic[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_axi_iic[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_axi_iic, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_axi_iic[66] = 0x100 | (device_addr & 0xfe);    // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_axi_iic[66] = write_addr;
    mt9d111_axi_iic[66] = (write_data >> 8)|0xff;            // first data
    mt9d111_axi_iic[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main()
{
    int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9, fd10;
    volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
    volatile unsigned *axi_vdma_0;
    volatile unsigned *axis_switch_0, *axis_switch_1;
    volatile unsigned *mt9d111_inf_axis_0;
    volatile unsigned *mt9d111_axi_iic;
    volatile unsigned *axi_gpio_0;
    volatile unsigned *frame_buffer_bmdc;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    int i;

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

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

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

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

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x0// 0x40 = 0
    axis_switch_1[17] = 0x80000000// 0x44 = 0x80000000, disable
    axis_switch_1[18] = 0x80000000// 0x48 = 0x80000000, disable
    axis_switch_1[0] = 0x2// Comit registers
    
    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x0// 0x40 = 0;
    axis_switch_0[0] = 0x2// Comit registers
    
    // phys_addr of udmabuf0
    fd10 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd10 == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd10, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd10);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    // AXI VDMA Initialization sequence
    axi_vdma_0[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4 
    while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_0[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4 
    while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_0[18] = 0x3// S2MM_FRMSTORE (0x48) register
    axi_vdma_0[12] = 0x00010002// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1)
    axi_vdma_0[41] = 0xc80; // S2MM Horizontal Size Register(S2MM_HSIZE)0xc80 = 3200dec = 800 x 4
    axi_vdma_0[42] = 0xc80; // S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)0xc80 = 3200dec = 800 x 4
    axi_vdma_0[43] = (int)phys_addr; // S2MM Start Address (1 to 16) Start Address 1
    axi_vdma_0[44] = (int)phys_addr; // S2MM Start Address (1 to 16) Start Address 2
    axi_vdma_0[45] = (int)phys_addr; // S2MM Start Address (1 to 16) Start Address 3
    axi_vdma_0[12] = 0x00010003// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1, Run/stop = 1)
    while((axi_vdma_0[13] & 0x1) == 0x1) ; // Halt? (S2MM_VDMASR 0x34)
    axi_vdma_0[40] = 0x258// S2MM Vertical Size (S2MM_VSIZE  Offset 0xA0) 0x258 = 600dec

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

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(mt9d111_axi_iic);
    
    for (i=0; i<100; i++){
        cam_i2c_write(mt9d111_axi_iic, 0xba, 0xf00x1);        // Changed regster map to IFP page 1
        cam_i2c_write(mt9d111_axi_iic, 0xba, 0x970x20);    // RGB Mode, RGB565
    }

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

  1. 2016年08月10日 03:32 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする1(構想編)

以前にVivado HLS でDMA IP を作ってみた。(”Vivado HLS で DMA Write IP を作る(絶対アドレス指定編)”、”Vivado HLS で DMA Read IP を作る(絶対アドレス指定版)”)これを使ってみたいと思っていた。カメラ・コントローラはAXI4-Stream版がすでに作ってあるが、ビットマップ・ディスプレイ・コントローラのAXI4-Stream版がないのでそれを作ることにした。

最初に、AXI4-Stream版のビットマップ・ディスプレイ・コントローラをVivado HLS で作ることにした。
linebuffer はクラスで書くことにして書いたのだが、FIFO は入力処理と出力処理を独立に行う必要がある。しかし、Vivado HLS では書けないじゃないか?という疑問が出てきた。スレッドが使えれば書けるのだが、今のところ、ユーザーズガイドにスレッドのことは書いていない。
AXI4-Stream_bitmap_disp_cont_1_160809.png

Vivado HLS で FIFO を除いたAXI4-Stream版のビットマップ・ディスプレイ・コントローラを作って、それにAXI4-Stream版のFIFO をHDL で作って前段に置くことも考えたが、AXI4-Streamが増えて、あまり良さそうでないので、AXI4 Master 版のビットマップ・ディスプレイ・コントローラを改造してAXI4-Stream版にすることにした。
つまり久しぶりにHDL を書くことにする。今書いているのだが、連日の寝坊もあって、進んでいない。。。orz
  1. 2016年08月09日 05:13 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Maker Faire Tokyo 2016 に行ってきました

MFT に出なくなってから何年でしょう?今年も忙しくて作品が作れずに、Maker Faire Tokyo 2016 に見学に行ってきました。ほとんど写真は撮ってないですが、気になる作品を写真に撮ってきました。

今年も東京ビッグサイトで開催です。
MFT2016_1_160806.jpg

MFT2016 の看板です。
MFT2016_2_160806.jpg

開催会場は西2 でした。
MFT2016_3_160806.jpg

今年は展示数が多いですね。なかなか見切れないです。いろんな人がいろんなものを作っています。やはり電子関係が多いですが、少ないながらバイオや農業関係もありました。いろんなジャンルのMaker が増えるとよいと思います。

段ボールでいろんなものを作ってあるのが面白かったです。ボールとかもありましたね。段ボールを折り紙のように折り込んで形を作るのが面白かったです。CADで設計しているのですか?と聞いてみたところ、CADは使わないでフィーリングで作っているそうです。
私も何か作ってみたいですね。木で作るのも面白そうです。
MFT2016_4_160806.jpg

MFT2016_5_160806.jpg

それから写真に撮ってないですが、「キュウリ農家とディープラーニングをつなぐ TensorFlow」のキュウリ選別機が来ていました。実用化されているのか聞いたところ、まだ実験段階とのことでした。

ロケットブースもありました。これは、なつのロケット団のロケットです。私は本を2冊持っています。筑波大学も来ていました。
MFT2016_6_160806.jpg

見て回っていると、チップマウンタがありました。ソフトウェアはopenpnp で無料だそうです。まだ開発段階のようでした。
MFT2016_7_160806.jpg

Android 携帯をミニカーに乗せて、道路を自動認識して走るミニカーがありました。認識には3層のニューラルネットワークを使っているそうです。DLじゃないとのことでした。
白黒 50x50ピクセル画像で中間層 100 だったかな?で3出力、真っ直ぐと右回り、左回りだそうです。これで普通のAndroid 携帯で 20 fps とのことでした。結構すごいですね。
でも、やはり、ビックサイトの照明環境で苦労しているとのことでした。複数の影ができちゃいますよね。いろいろとヒストグラムを取って平均しているようですが、難しいみたいでした。

nvidiaもnvidia jetson tx1 でいろいろなDLNN のデモをしていましたが、フレームレートがすごく遅いです。 1 fps もないくらいかな?これじゃ使い物にならないと思われちゃうんじゃないかな?と思いました。仕方ないのかもしれませんが。。。

木工ではCNC で切り出したパーツを使って机を販売しているそうです。下の写真はパーツです。
MFT2016_9_160806.jpg

そういえば、オリジナルマインドさんも出ていました。KitMill MOC900 欲しいですね。。。

更に2倍のワークエリアがある木工用CNC マシンが加工していました。
MFT2016_10_160806.jpg

MakerMachine36 だそうです。木製のCNCは70万円程度、アルミ製は83万円程度だそうです。丸鋸も装着可能にするとのことでした。お金があったら欲しいですね。。。
加工のフォーマットはSVGだそうです。gcode にできればOKとのことでした。
  1. 2016年08月06日 20:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のUbuntu 14.04 LTSで Geneay を使ってプログラミングをする

ZYBO 上のARM Cortex-A9 上のDigiletn Linux + Ubuntu 14.04 LTSで Zybot などの開発をしている。
ZYBO 上で エディタを起動してC, C++ などのソフトウェアを作っているが、いままでエディタには、gedit や gvim などを使ってきた。
どうも gedit も gvim も使いにくいので、もっと良いエディタがないかをネットで探したら、Geany が使えるということだった。

早速、sudo apt-get install geany で Geany をインストールしてみた。
Windows でも Geany を使っていたので、使いやすい。。。しかも、終了時のファイルを覚えているので、やりやすい。文字の補完もできるので、いうことなしだ。これを使うことにした。
Geany_1_160805.png

なお、上の画面は、ZYBO 上のLinux から X を Xming でWindows 上のウインドウに持ってきて表示している。
これで、自分のパソコンからZYBO のプログラミングが快適にできそうだ。
  1. 2016年08月05日 08:34 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Gabor FilterをZYBO_0_162_2 へ実装してみた3(devicetree.dtb の作成)

Gabor FilterをZYBO_0_162_2 へ実装してみた2”の続き。

前回は、Vivado HLS のSolution Settings で Clock Period を変更し、Cコードから合成して再IP 化を行って、Vivado でインプリメントした時のタイミングエラー解消を解消し、Boot.bin を作った。今回は、VirtualBox 上のUbuntu 14.04 LTS で、DTS にガボール・フィルタのエントリを追加し、DTC でコンパイルして devicetree.dtb を作成する。

VirtualBox 上のUbuntu 14.04 LTS に移動して、ZYBO_0 のzynq-zybo.dts を編集して、Pwmモジュールとモーター・モニタのエントリを追加した。(以前のZYBO_0 のデバイス・ツリーについては、”ZybotのZYBOをLinuxで動作させる1(BOOT.bin, devicetree.dtb)”を参照のこと)

まずは、~/ZYBO/Digilent_Linux_Tutrial/drivers_ZYBO_0 ディレクトリに行った。
GaborFilter_45_160805.png

そこの zynq-zybo.dts を編集して、gabor_filter_lh_0 のエントリを追加した。
GaborFilter_46_160805.png

dtc でzynq-zybo.dts をコンパイルして devicetree.dtb を作成した。
具体的には、dtc -I dts -O dtb -o devicetree.dtb zynq-zybo.dts コマンドで、zynq-zybo.dts を dtc でコンパイルして、devicetree.dtb を生成した。
GaborFilter_47_160805.png
  1. 2016年08月05日 04:29 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

映画『シン・ゴジラ』を見てきました

今日は夏休み自由研究お助け隊の代休でお休みだったので、映画『シン・ゴジラ』を見てきました。
懐かしい感じです(音楽?)ですが、CGも昭和な感じ(派手ではなく)で、良かったです。内容も面白かったです。今のご時世を反映して、政府の対応が丁寧に描かれていてよかったと思いました。
もう一度、見たいですね。。。
  1. 2016年08月03日 21:39 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Zybot にカメラを搭載して、白線を写してみた

Zybot は下の写真のようにカメラは搭載していなかった。
ZYBO_0_motor_14_160711.jpg

12V の配線も車のスターター用なので、ごついクリップついていた。このコネクタはEC5 という型番だったので、コネクタを購入して、はんだ付けした。更に、MT9D111 カメラを搭載した。
UVシートが灰色ということで、購入して、これに白色ビニルテープを貼り付けて白線にした。
白線の幅をいくつにするかだが。。。1車線の道路幅は約3m10cmで、車の横幅を1.7mとする。現在のZybotの幅は20cmだから、白線を引くとすると310*(20/170)≒36cm間隔としてみることにする。
Zybot_14_160803.jpg

この状態でカメラで撮影された画像を示す。
Zybot_15_160803.jpg

白線がいくらも写っていない。。。レンズが望遠すぎるようだ。もう少し広角が欲しいが、無いので仕方がない。
そこで、白線の間隔を 28 cm 程度にしてみた。
Zybot_16_160803.jpg

今度は、何とか良さそうだが、UVシートなので、凸凹が多すぎる。
Zybot_17_160803.jpg

これを、ガボール・フィルタはまだ実装されていないので、ラプラシアンフィルタをかけてみたが、やはり直線にならない。
Zybot_18_160803.jpg

そこで、机に直接、白いビニルテープを貼った。
Zybot_19_160803.jpg

今度は大丈夫そうだ。エッジが直線になっている。
Zybot_20_160803.jpg
  1. 2016年08月03日 06:12 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Gabor FilterをZYBO_0_162_2 へ実装してみた2

Gabor FilterをZYBO_0_162_2 へ実装してみた”の続き。

前回は、ZYBO_0_162_3 フォルダのZYBO_0_153 プロジェクトのZYBO_0 ブロックデザインに Gabor_filter_lh を追加して配線した。そして、論理合成、インプリメントを行ったら、ガボール・フィルタでタイミングエラーが出てしまった。
今回は、Vivado HLS のSolution Settings で Clock Period を変更し、Cコードから合成して再IP 化を行って、Vivado でインプリメントした時のタイミングエラー解消を目指す。

Vivado HLS で再度合成する前に、Gabor Filter_lh.h の画面の設定が 640 x 480 だったので、800 x 600 に修正した。
GaborFilter_39_160802.png

Solution Settings の Synthesis Settings の Clock Period を 7 ns にした。 9 ns でも 8 ns でもうまく行かなかった。
これで合成を行った。結果を示す。
GaborFilter_40_160802.png

やはり、FF が前回より、6 % くらい増えている。これは、RorL をAXI4-Lite Slave のレジスタにした分も入っているとは思うが。。。

これでIP 化を行って、Vivado のGabor Filter_lh IP を更新した。
それで、論理合成、インプリメント、ビットストリームの生成を行ったところ、タイミングエラーが無くなった。タイミングエラーの時にVivado HLS で修正するのは、Clock Period を変更して、再合成すればよいので簡単だ。
GaborFilter_41_160802.png

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

Gabor Filter_lh も入っている。更に、hw_platform が新しくできた。以前の hw_platform と FSBL プロジェクトを消去した。

FSBL を新規作成して、BOOT.bin を生成した。
GaborFilter_43_160802.png

GaborFilter_44_160802.png
  1. 2016年08月03日 04:29 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Gabor FilterをZYBO_0_162_2 へ実装してみた

ガボール・フィルタ (Gabor Filter) による白線検出11(その他の道路写真での検証)”でZybot にカメラを搭載して、実際に撮影した画像でGabor Filter のパラメータを取得する必要があることが分かった。今回は、試しに”ガボール・フィルタ (Gabor Filter) による白線検出10(hls::LineBuffer と hls::Window を使用7)”でIP 化を行ったGabor FilterをZYBO_0_162_2をコピーした ZYBO_0_162_3 へ実装してみることにした。

現状のZYBO_0_162_3 フォルダのZYBO_0_153 プロジェクトのブロックデザインを示す。
GaborFilter_31_160731.png
GaborFilter_32_160731.png

ZYBO_0_162_3 フォルダの下にGabor Filter_lh フォルダを作って、”ガボール・フィルタ (Gabor Filter) による白線検出10(hls::LineBuffer と hls::Window を使用7)”の soluttion1 -> impl -> ip フォルダのxilinx_com_hls_Gabor_filter_lh_1_0.zip の中身を ZYBO_0_162_2 フォルダの下にGabor Filter_lh フォルダにコピー&ペーストした。
GaborFilter_33_160731.png

IP Catalog に Gabor_filter_lh を追加した。なお、Gabor Filterは、”ガボール・フィルタ (Gabor Filter) による白線検出10(hls::LineBuffer と hls::Window を使用7)”でIP 化したものに指示子の”#pragma HLS INTERFACE s_axilite port=RorL”を追加してC コードの合成、IP 化を行った。つまり、RorL もポートにするのをやめて、AXI4-Lite Slave のレジスタとしたわけだ。
GaborFilter_34_160731.png

このGabor_filter_lh を camera_interface モジュールに追加した。
GaborFilter_36_160802.png

ZYBO_0 ブロックデザイン全体を示す。
GaborFilter_37_160802.png

論理合成、インプリメントを行って、Summary を見たところ、タイミングがエラーになっていた。
GaborFilter_38_160802.png

Implemented Design でタイミングを見たところ、Gabor_filter_lh でエラーが出ていた。
GaborFilter_35_160802.png

しかし、CLK から D へのタイミングエラーがあるのだろうか?
Vivado HLSでクロック周期を変えてGabor_filter_lh の回路をもっと速くしてみよう。
  1. 2016年08月01日 05:19 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0