FC2カウンター FPGAの部屋 カメラ画像をDisplayPortに出力する4(disp_dmar_aixs の1)
FC2ブログ

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

FPGAの部屋

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

カメラ画像をDisplayPortに出力する4(disp_dmar_aixs の1)

カメラ画像をDisplayPortに出力する3(vflip_dma_write2 の2)”の続き。

前回は、vflip_dma_write2 プロジェクトで、C シミュレーション、C コードの合成、C/RTL 協調シミュレーション、Export RTL を行った。今回は、Read 側のDMA の disp_dmar_axis IP を作成しよう。

まずは、ソースコードを貼っておく。

disp_dmar_axis.h から貼っておく。

// disp_dmar_axis.h
// 2019/02/01 by marsee
//

#ifndef __DISP_DMAR_AXIS_H__
#define __DISP_DMAR_AXIS_H__

#include "ap_axi_sdata.h"
#include "hls_video.h"

#define SVGA_WIDTH 800
#define SVGA_HEIGHT 600

#define XGA_WIDTH 1024
#define XGA_HEIGHT 768

#define HD_WIDTH 1920
#define HD_HEIGHT 1080

#define RESO_SVGA 0
#define RESO_XGA 1
#define RESO_HD  2

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef ap_axiu<32,1,1,1> AP_AXIU32;
typedef hls::Scalar<3, unsigned char> RGB_PIXEL;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC1> GRAY_IMAGE;

#endif


disp_dmar_axis.cpp を貼っておく。

// disp_dmar_axis.cpp
// 2019/02/01 by marsee
//

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

#include "disp_dmar_axis.h"

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height);

int disp_dmar_axis(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame){
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE s_axilite port=resolution
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=480000 port=fb2 offset=slave
#pragma HLS INTERFACE m_axi depth=480000 port=fb1 offset=slave
#pragma HLS INTERFACE m_axi depth=480000 port=fb0 offset=slave

    AP_AXIU32 pix;
    int max_width, max_height;

    switch((int)resolution){
        case 0: // SVGA
            max_width = SVGA_WIDTH;
            max_height = SVGA_HEIGHT;
            break;
        case 1: // XGA
            max_width = XGA_WIDTH;
            max_height = XGA_HEIGHT;
            break;
        default: // HD
            max_width = HD_WIDTH;
            max_height = HD_HEIGHT;
            break;
    }

    if (active_frame == (ap_uint<2>)0)
        disp_dmar_fb2(fb2, outs, max_width, max_height);
    else if (active_frame == (ap_uint<2>)1)
        disp_dmar_fb0(fb0, outs, max_width, max_height);
    else
        disp_dmar_fb1(fb1, outs, max_width, max_height);
    return(0);
}

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;

    LOOP_Y0: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X0: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix.data = fb0[(y*max_width)+x];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

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

int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;

    LOOP_Y1: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X1: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix.data = fb1[(y*max_width)+x];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

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

int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;

    LOOP_Y2: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X2: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix.data = fb2[(y*max_width)+x];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

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


disp_dmar_axis_tb.cpp を貼っておく。

// disp_dmar_axis_tb.cpp
// 2019/02/01 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include "hls_opencv.h"

#include "disp_dmar_axis.h"

int disp_dmar_axis(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame);

#define NUM_FRAME_BUFFER 3
#define FB_NUMBER 0

int main(){
    using namespace cv;

    AXI_STREAM outs;
    AP_AXIU32 pix;
    ap_uint<32> *frame_buffer;
    
    // OpenCV で 画像を読み込む
    Mat src = imread("bmp_file0.bmp");

    // 画像をセーブするメモリをアロケート
    if ((frame_buffer =(ap_uint<32> *)malloc(NUM_FRAME_BUFFER * sizeof(ap_int<32>) * (src.cols * src.rows))) == NULL){
        fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n");
        exit(1);
    }
    
    // Mat フォーマットからフレームバッファに画像をロード
    Mat_<Vec3b> src_vec3b = Mat_<Vec3b>(src);
    for(int i=0; i<NUM_FRAME_BUFFER; i++){
        for(int y=0; y<src.rows; y++){
            for(int x=0; x<src.cols; x++){
                Vec3b pixel;
                pixel = src_vec3b(y,x);
                int rgb = ((int)(pixel(2))<<16) + ((int)(pixel(1))<<8) + pixel(0);
                frame_buffer[(src.cols*src.rows)*i + (src.cols*y) + x] = rgb;
            }
        }
    }
    
    ap_uint<2> fb_number = FB_NUMBER;
    ap_uint<32> resolution = RESO_SVGA;
    disp_dmar_axis((volatile ap_int<32> *)frame_buffer,
        (volatile ap_int<32> *)&frame_buffer[src.cols * src.rows],
        (volatile ap_int<32> *)&frame_buffer[2 * (src.cols * src.rows)],
        outs, resolution, fb_number);
        
    // AXI4 Stream から Mat フォーマットに変換しファイルに書き込み
    Mat dst(src.rows, src.cols, CV_8UC3);
    Mat_<Vec3b> dst_vec3b = Mat_<Vec3b>(dst);
    for(int y=0; y<dst.rows; y++){
        for(int x=0; x<dst.cols; x++){
            outs >> pix;
            int rgb = pix.data;
            //int rgb = frame_buffer[(src.cols*y) + x];
            Vec3b pixel;
            pixel[0] = (rgb & 0xff); // blue
            pixel[1] = (rgb & 0xff00) >> 8; // green
            pixel[2] = (rgb & 0xff0000) >> 16; // red
            dst_vec3b(y,x) = pixel;
        }
    }

    imwrite("dmar_result.bmp", dst);
    
    free(frame_buffer);
    return(0);
}


Vivado HLS 2018.3 で disp_dmar_axis プロジェクトを作成した。
cam_displayport_9_190202.png
  1. 2019年02月02日 04:06 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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