FC2カウンター FPGAの部屋 memcpy() を利用したDMA Read IP 2(memcpy() が 2 個の場合)

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

FPGAの部屋

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

memcpy() を利用したDMA Read IP 2(memcpy() が 2 個の場合)

memcpy() を利用したDMA Read IP 1(memcpy() が 1 個の場合)”の続き。

前回はDATAFLOW 指示子を使用して、memcpy() と for 文を重ね合わせて、約1クロックで 1 データを出力させることができた。ただし、カメラ画像表示システムに入れてテストしたところ、画像を表示することができなかった。
今回は、memcpy() を使用して、1行分の画像を転送するとエラーが発生する(DATAFLOW 指示子を入れない場合)ので、1 行の半分ずつ memcpy() するようにしてみた。さらに、そこにDATAFLOW 指示子を入れてみた。なお、Vivado HLS 2016.2 を使用している。
DMA_Read_addr.cpp を示す。

// DMA_Read_addr.cpp
// 2016/07/13 by marsee
//
// frame_buffer0, frame_buffer1, frame_buffer2 には3つのフレームバッファのアドレスを入れる
// mode = 0 : DMA Write IP の active_frame を見て、その1つ前のフレームをDMA Readするモード(DMA_WRITE_MODE)
// mode = 1 : フリーラン モード(FREE_RUN_MODE)
// 2016/09/18 : memcpy を使用
//

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

#include "DMA_Read.h"

int DMA_Read_addr(volatile int *in, hls::stream<ap_axis<32,1,1,1> >& outs,
        unsigned int frame_buffer0, unsigned int frame_buffer1,
        unsigned int frame_buffer2, ap_uint<2> & active_frame,
        ap_uint<1> mode){
#pragma HLS INTERFACE s_axilite port=mode
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE s_axilite port=frame_buffer0
#pragma HLS INTERFACE s_axilite port=frame_buffer1
#pragma HLS INTERFACE s_axilite port=frame_buffer2
#pragma HLS INTERFACE m_axi depth=5000000 port=in offset=off
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return

    ap_axis<32,1,1,1> pix;
    int dma_index, n;
    int buf1[HORIZONTAL_PIXEL_WIDTH/2];
    int buf2[HORIZONTAL_PIXEL_WIDTH/2];

    for (int i=0; i<MAX_FRAME_NUMBER; i++){
        if (mode == DMA_WRITE_MODE)
            n = (int)active_frame;
        else
            n = i;

        switch (n){ // 1つ前のフレームバッファを読みだす
            case 0 :
                dma_index = frame_buffer2/sizeof(int);
                break;
            case 1 :
                dma_index = frame_buffer0/sizeof(int);
                break;
            case 2 :
                dma_index = frame_buffer1/sizeof(int);
                break;
            default :
                dma_index = frame_buffer0/sizeof(int);
                break;
        } 

        for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
#pragma HLS DATAFLOW
            memcpy(buf1, (const int*)(&in[dma_index+(y*HORIZONTAL_PIXEL_WIDTH)]), (HORIZONTAL_PIXEL_WIDTH)*2);
            memcpy(buf2, (const int*)(&in[dma_index+(y*HORIZONTAL_PIXEL_WIDTH)+(HORIZONTAL_PIXEL_WIDTH/2)]),
                (HORIZONTAL_PIXEL_WIDTH)*2);
            for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
                if (x < HORIZONTAL_PIXEL_WIDTH/2)
                    pix.data = buf1[x];
                else
                    pix.data = buf2[x-HORIZONTAL_PIXEL_WIDTH/2];

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

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

                outs << pix;
            }
        }
    }

    return 0;
}


次に、DMA_Read.h を示す。

// DMA_Read.h
// 2016/07/14 by marsee
// 2016/09/18 : BURST_LENGTH を追加
//

#ifndef __DMA_READ_H__
#define __DMA_READ_H__

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600

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

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define MAX_FRAME_NUMBER    3

#define DMA_WRITE_MODE    0
#define FREE_RUN_MODE    1

#define MEMCPY_LENGTH    (HORIZONTAL_PIXEL_WIDTH*4)

#endif


C シミュレーションを行ったところ、正常に画像をコピーすることができた。

次にC コードからの合成を行った。
DMA_Read_IP_test_46_160920.png

C/RTL協調シミュレーションを行った。
DMA_Read_IP_test_47_160920.png

C/RTL協調シミュレーション波形を見た。
最初のAXI4 Master Read によるDMA 波形を示す。
DMA_Read_IP_test_48_160920.png

最初の番地は 0 番地のはずが、0x640 番地になっていた。これは、行の半分のピクセルのアドレスなので、2つ目の memcpy() のアクセスということになる。

次のAXI4 Master Read によるDMA 波形を示す。
DMA_Read_IP_test_49_160920.png

これも同様に、0x640 番地からスタートしている。これも、2つ目の memcpy() のアクセスということになる。つまり、2つ目の memcpy() のDMA 転送が 2 つ来てしまっている。
明らかにおかしい?

IP 化を行って、前回と同様に
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成)
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム2(SDK)
のDMA Read IP に入れ替えて、コンパイルし、実機で動作させてみた。
その結果、カメラ画像の右半分が 2 つ並んで、表示された。これは、そのようにDMA 転送しているので、正しい結果といえる。
DMA_Read_IP_test_45_160919.jpg

これはまずいように思うのだが。。。バグかな?

ちなみに、DATAFLOW 指示子をコメントアウトすると、C/RTL協調シミュレーションがエラーで停止してしまって比較ができない。
  1. 2016年09月20日 04:28 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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