FC2カウンター FPGAの部屋 2017年02月01日

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

FPGAの部屋

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

FASTXコーナー検出による物体の形状検出1(Vivado 2016.4 プロジェクト)

以前、”FASTX コーナー検出の改良3(threshold をソフトウェアで変更可能にする)”で、Vivado HLS のOpenCV 機能の一部であるFASTX コーナー検出を使用して、CMOS カメラで撮影した画像のコーナー検出を行った。
今回は、FASTX コーナー検出のプロジェクトを Vivado 2016.4 に変換して動作を確かめた。

まずは、Vivado 2016.1 版を動かしてみると、CMOSカメラ画像で、細い線を見るととぎれとぎれになっている。これは、ビットマップ・ディスプレイ・コントローラは64 ビットでデータを転送して、1ピクセルは 32 ビットである。よって、ビットマップ・ディスプレイ・コントローラは1転送で 2 ピクセルを転送していることになるが、そのピクセルの位置が反転している状態になっていた。それを、修正した。
具体的には、Z:\V_ZYBO_CAMDS_FASTXt_164\BMDispCaL\sources\verilog フォルダのbitmap_disp_engine.v ファイルの bitmap_afifo の din への信号の割り当てを変更した。

//.din(data_in), // Bus [63 : 0]
.din({data_in[31:0], data_in[63:32]}), // Bus [63 : 0]


Vivado 2016.1 からVivado 20164 へのアップグレードは、Vivado HLS で作った fastx_corner_det はVivado HLS 2016.4 で作り直したが、それ以外はすんなりとアップグレードできた。
プロジェクトを示す。もうビットストリームの生成済みだ。
fastx_1_170201.png

ブロックデザインを示す。上が全体で、下が camera_interface モジュールだ。
fastx_2_170201.png

fastx_3_170201.png

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

SDK 2016.3 からだろうか?GDB でELF ファイルを RUN してもエラーになってしまう。
System Debugger を使ってRUN する必要があるようになった。しかし、System Debugger を使用すると、ELF ソフトウェアを2回実行できないようなのだ。今までのGDB の時は、カメラの設定用のソフトウェアを起動してから、FASTX を起動するソフトウェアを実行してきたが、System Debugger を使用すると、カメラの設定をして、FASTX を起動するソフトウェアを書く必要があるようだ。すべて1つのソフトウェアで完結するように書くしかなくなってしまった。
そのように fastx_on_serial.c を書き直して、ビルドした。
ZYBO の電源をON して、FASTX のスレッショルドを設定するためにTera Term を起動し、シリアルに接続した。
SDK からビットストリームをZYBO にダウンロードして、fastx_on_serial.elf をSystem Debugger で起動した。
Tera Term の画面を示す。
fastx_5_170201.png

Tera Term の画面に示すように、threshold は 5, 10, 20, 40, 60 でやってみた。

その画像を示す。
threshold = 5
fastx_6_170201.jpg

threshold = 10
fastx_7_170201.jpg

threshold = 20
fastx_8_170201.jpg

threshold = 40
fastx_9_170201.jpg

threshold = 60
fastx_10_170201.jpg

うまく行っている。

最後に、fastx_on_serial.c を示す。

// fastx_on_serial.c
// 2017/04/13 by marsee
//
// Refered to http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug902-vivado-high-level-synthesis.pdf
//
// 2016/04/21 : threshold をシリアル経由で入力する
// 2017/01/30 : すべての処理を記述するように変更
//

#include <stdio.h>
#include <stdlib.h>
#include "xfastx_corner_det.h"
#include "xparameters.h"
#include "xaxivdma.h"
#include "xil_io.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 FASTX_THRESHOLD        20

#define FRAME_BUFFER_ADDRESS 0x10000000

static XAxiVdma_DmaSetup Vdma0_WriteCfg;

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(){
    XFastx_corner_det Ximage_filter;
    XFastx_corner_det_Config *Ximage_filterPtr;
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;
    int threshold;

    XAxiVdma0_Config = XAxiVdma_LookupConfig(XPAR_CAMERA_INTERFACE_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
    if (XAxiVdma0_Config == NULL){
        fprintf(stderr, "No AXI VDMA found\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() failed\n");
        return(-1);
    }

    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.

    Vdma0_WriteCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_WriteCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_WriteCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_WriteCfg.FrameDelay = 0// Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_WriteCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_WriteCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_WriteCfg.PointNum = 0// No Gen-Lock
    Vdma0_WriteCfg.EnableFrameCounter = 0// Endless transfers
    Vdma0_WriteCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
        return(-1);
    }

    // Frame buffer address set
    unsigned int frame_addr = (unsigned int)FRAME_BUFFER_ADDRESS;
    int i;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma0_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        //frame_addr += HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * VERTICAL_LINES;
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed\n");
        return(-1);
    }

    // Look Up the device configuration
    Ximage_filterPtr = XFastx_corner_det_LookupConfig(0);
    if (!Ximage_filterPtr){
        fprintf(stderr, "XFastx_corner_det configuration failed.\n");
        return(-1);
    }

    // Initialize the Device
    int Xlap_status = XFastx_corner_det_CfgInitialize(&Ximage_filter, Ximage_filterPtr);
    if (Xlap_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XFastx_corner_det\n");
        return(-1);
    }

    // image_filter rows, cols, threshold=20 set
    XFastx_corner_det_Set_cols(&Ximage_filter, (u32)800);
    XFastx_corner_det_Set_rows(&Ximage_filter, (u32)600);
    XFastx_corner_det_Set_threshold(&Ximage_filter, (u32)FASTX_THRESHOLD);

    // axis_switch_1, 1to2 ,Select M01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // fastx filter AXIS Start
    XFastx_corner_det_Start(&Ximage_filter);
    XFastx_corner_det_EnableAutoRestart(&Ximage_filter);

    // axis_switch_0, 2to1, Select S01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x1);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers

    // VDMA start
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed\n");
        return(-1);
    }

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cntrler_axi_master_0
    volatile unsigned int *bmdc_axi_lites;
    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    bmdc_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;

    bmdc_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller start
    mt9d111_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

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

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

    mt9d111_axi_lites[1] = 0// One_shot_mode is disabled

    // threshold set
    while(1){
        printf("\n\rthreshold = ");
        scanf("%d", &threshold);
        if (threshold == 999)
            break;
        
        XFastx_corner_det_Set_threshold(&Ximage_filter, (u32)threshold);
    }

    return(0);
}

  1. 2017年02月01日 05:32 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0