FC2カウンター FPGAの部屋 PYNQボードのFASTX コーナー検出にラプラシアンフィルタIPとアンシャープ・マスクキング・フィルタIPを追加4(SDK)

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

FPGAの部屋

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

PYNQボードのFASTX コーナー検出にラプラシアンフィルタIPとアンシャープ・マスクキング・フィルタIPを追加4(SDK)

PYNQボードのFASTX コーナー検出にラプラシアンフィルタIPとアンシャープ・マスクキング・フィルタIPを追加3(Vivado)”の続き。

前回は、Vivado 2016.4 のブロックデザイン上で、FASTXコーナー検出IP にラプラシアンフィルタIP とアンシャープ・マスクキング・フィルタIP を追加した。今回はアプリケーションソフトを作成して、動作させてみよう。

前回、Vivado 2016.4 でビットストリームの生成までを行ったので、ハードウェアをエクスポートして、SDK を立ち上げた。
その時に、エラーが出てしまったので、PYNQ_FASTX_164.sdk フォルダを一旦捨てて、もう一度、ハードウェアをエクスポートして、SDK を立ち上げた。そうすると、PYNQ_FASTX_164.sdk フォルダがもう一度、作られる。

これで、SDK で File メニューからNew -> Application Project を選択して、disp_lap_mask_on_serial プロジェクトを作成した。
カメラ出力、FASTX コーナー検出、ラプラシアンフィルタ、アンシャープ・マスクキング・フィルタを行うことができる disp_lap_mask_on_serial.c を作成した。
pynq_de_other_filters_21_170226.png

disp_lap_mask_on_serial.elf を起動すると最初に、カメラ出力、FASTX コーナー検出、ラプラシアンフィルタ、アンシャープ・マスクキング・フィルタを選択する表示が出てくる。それで機能を選ぶと、例えばFASTX コーナー検出を選べば threshold を入力できるようになる。その様子を下の図に示す。
pynq_de_other_filters_22_170226.png

サブディスプレイにHDMI 端子が無いため、HDMI-VGA変換器を購入して画面をキャプチャした。”TechRise金メッキ高速1080P HDMI オス to VGAメスビデオ変換アダプタケーブル オーディオとマイクロUSBケーブル付き”を購入したのだが、PYNQのHDMIの電源でSVGAの画面がVGA端子のディスプレイできちんとできた。699円は安かった。

さて、最初のカメラ画像を貼っておく。
pynq_de_other_filters_23_170227.jpg

threshold = 5 のFASTX コーナー検出の画像を貼っておく。
pynq_de_other_filters_24_170227.jpg

ラプラシアンフィルタの画像を貼っておく。
pynq_de_other_filters_25_170227.jpg

アンシャープ・マスクキング・フィルタ k = 3.75 の画像を貼っておく。これは、見た限りではカメラ画像と区別がつかない。
pynq_de_other_filters_26_170227.jpg

最後に、アプリケーションソフト disp_lap_mask_on_serial.c のソースコードを貼っておく。

// disp_lap_mask_on_serial.c
// 2017/02/25 by 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 "xfastx_corner_det.h"
#include "XUnsharp_mask_axis.h"
#include "XLap_filter_axis.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 fastx_filter;
    XFastx_corner_det_Config *fastx_filterPtr;
    XLap_filter_axis lap_filter;
    XLap_filter_axis_Config *lap_filterPtr;
    XUnsharp_mask_axis usm_filter;
    XUnsharp_mask_axis_Config *usm_filterPtr;
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;
    float k;
    int k_fixed;
    int i, 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;
    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
    fastx_filterPtr = XFastx_corner_det_LookupConfig(0);
    if (!fastx_filterPtr){
        fprintf(stderr, "XFastx_corner_det configuration failed.\n");
        return(-1);
    }
    lap_filterPtr = XLap_filter_axis_LookupConfig(0);
    if (!lap_filterPtr){
        fprintf(stderr, "XLap_filter_axis configuration failed.\n");
        return(-1);
    }
    usm_filterPtr = XUnsharp_mask_axis_LookupConfig(0);
    if (!usm_filterPtr){
        fprintf(stderr, "XUnsharp_mask_axis configuration failed.\n");
        return(-1);
    }

    // Initialize the Device
    int fastx_status = XFastx_corner_det_CfgInitialize(&fastx_filter, fastx_filterPtr);
    if (fastx_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XFastx_corner_det\n");
        return(-1);
    }
    int lap_status = XLap_filter_axis_CfgInitialize(&lap_filter, lap_filterPtr);
    if (lap_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XLap_filter_axis\n");
        return(-1);
    }
    int usm_status = XUnsharp_mask_axis_CfgInitialize(&usm_filter, usm_filterPtr);
    if (usm_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XUnsharp_mask_axis\n");
        return(-1);
    }

    // Unsharp_masking filter k_fixed set
    XFastx_corner_det_Set_cols(&fastx_filter, (u32)800);
    XFastx_corner_det_Set_rows(&fastx_filter, (u32)600);
    XFastx_corner_det_Set_threshold(&fastx_filter, (u32)FASTX_THRESHOLD);
    XUnsharp_mask_axis_Set_k_fixed_V(&usm_filter, (u32)10); // k = 2.5

    // 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), 0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x48), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x4C), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // 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), 0x0);
    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

    while(1){
        printf("\n\r0:normal camera, 1:fastx, 2:laplacian filter, 3:unsharp_masking filter, 999:end");
        printf("\n\rPlease input = ");
        scanf("%d", &i);
        if (i == 999)
            break;
        switch(i){
        case 0 : // normal camera
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x48), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x4C), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x0);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers
            while(1){
                printf("\n\rEnter 999 to return to the function selection mode\n");
                scanf("%d", &i);
                if (i == 999)
                    break;
            }
            break;
        case 1 : // fastx
            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+0x48), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x4C), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers
            XFastx_corner_det_Start(&fastx_filter);
            XFastx_corner_det_EnableAutoRestart(&fastx_filter);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x1);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers
            while(1){
                printf("\n\rEnter 999 to return; threshold = ");
                scanf("%d", &threshold);
                if (threshold == 999)
                    break;
                
                XFastx_corner_det_Set_threshold(&fastx_filter, (u32)threshold);
            }
            XFastx_corner_det_DisableAutoRestart(&fastx_filter);
            break;
        case 2 : // laplacian filter
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x48), 0);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x4C), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers
            XLap_filter_axis_Start(&lap_filter);
            XLap_filter_axis_EnableAutoRestart(&lap_filter);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x2);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers
            while(1){
                printf("\n\rEnter 999 to return to the function selection mode\n");
                scanf("%d", &i);
                if (i == 999)
                    break;
            }
            XLap_filter_axis_DisableAutoRestart(&lap_filter);
            break;
        case 3 :
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x48), 0x80000000); // disable
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x4C), 0);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers
            XUnsharp_mask_axis_Start(&usm_filter);
            XUnsharp_mask_axis_EnableAutoRestart(&usm_filter);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x3);
            Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers
            while(1){
                printf("\n\rEnter 999 to return; k (0.25 ~ 3.75) = ");
                scanf("%f", &k);
                if (k == 999)
                    break;

                if (k < 0)
                    k_fixed = 0;
                else if (k > 4)
                    k_fixed = (int)(3.75*4);
                else
                    k_fixed = (int)(k*4);

                XUnsharp_mask_axis_Set_k_fixed_V(&usm_filter, (u32)k_fixed);
            }
            XUnsharp_mask_axis_DisableAutoRestart(&usm_filter);
            break;
        }
    }
        
    return(0);
}

  1. 2017年02月26日 04:46 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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