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

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

FPGAの部屋

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

ハンターマウンテン塩原スキー場に行ってきました2016

今日はハンターマウンテンスキー場に行ってスキーを滑ってきました。

2015年の12月29日にも行ってきましたが、今日もハンターマウンテンスキー場に行ってきました。
今日は午前7時35分についたので、念願のスキー場の近くの駐車場に車を止めることができましたよ。嬉しかったです。少なくとも午前8時前に到着しないと止めることができないようです。
Hunter_ski_1_160131.jpg

最初に第1クワッドリフトになりました。曇りがちだったですね。
Hunter_ski_2_160131.jpg

ここで大失敗をしちゃいました。ストックを片方、リフト乗る時に落としちゃいました。すぐに取りに行きました。
そのため、第1クワッドリフトを2回乗りましたが、最初のBOARD WAY コースは、とっても雪質が良く、凄く気持ちよく滑れました。ハンターじゃないみたい。。。

その後で、ハンタークワッドリフトに2回乗りました。ここでも雪質はとっても良かったです。

またまた大失敗をしちゃいました。スキー板は99 cm のファンスキーなんですが、360度ターンを連続してくるくる回っていたら、雪が引っかかって、後ろから強烈にこけちゃいました。頭は打たなかったですが、強烈に頭をゆすられて脳震盪ぎみです。
右回転は大丈夫だったんですが、苦手の左回転でやっちゃいました。

その後、なんとかゴンドラへ。
段々晴れてきました。
Hunter_ski_3_160131.jpg

ゴンドラです。
Hunter_ski_4_160131.jpg

3回目のゴンドラではとっても良い天気+良い眺めでした。
Hunter_ski_5_160131.jpg

午前11時過ぎころ、雪も緩んできたし、足も疲れてきたので、食事の後、家路につきました。
昼ごはんは、ケバブ屋さんがあったので、それにしました。肉が硬かったけど、ゲレ食よりも美味しかったですよ。

新雪でとっても良い雪で楽しめましたが、転倒が悔やまれます。まだ少し頭がクラつきますね。。。まあ大丈夫でしょう。。。
  1. 2016年01月31日 21:14 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト7(BOOT.bin, devicetree.dtb)

ステレオカメラによる距離測定テスト6(ステレオカメラのテスト)”の続き。

ベアメタル・アプリケーションでStereo Camera のテストが上手く行ったので、次は、Linux のアプリケーションとして実装したい。ということで、今回はBOOT.bin と devicetree.dtb の作製を行った。

最初にFSBL を作製した。
StereoCamTest_53_160130.png

次に、u-boot.elf を追加して、Boot Image (BOOT.bin) を作製した。
StereoCamTest_54_160130.png

BOOT.bin が作製された。
StereoCamTest_55_160130.png

次に、devicetree.dtb を作る。VirtualBox 上のUbuntu 14.04 LTS 上で作業する。

~/ZYBO/Digilent_Linux_Tutrial/drivers_StereoCamTest ディレクトリ上で作業した。

Vivado and zybo linux勉強会資料3”の zynq-zybo.dts に uio のエントリを追加した。
StereoCamTest_56_160130.png

        caminf_axi_iic@0x41600000 {
            compatible = "generic-uio";
            reg = < 0x41600000 0x10000>;
        };
        caminf_axi_vdma_0@43010000 {
            compatible = "generic-uio";
            reg = < 0x43010000 0x10000 >;
        };
        caminf_axis_switch_0@0x43c10000 {
            compatible = "generic-uio";
            reg = < 0x43c10000 0x10000 >;
        };
        caminf_axis_switch_1@0x43c20000 {
            compatible = "generic-uio";
            reg = < 0x43c20000 0x10000 >;
        };
        caminf_lap_filter_axis_0@0x43c30000 {
            compatible = "generic-uio";
            reg = < 0x43c30000 0x10000>;
        };    
        caminf_mt9d111_inf_axis_0@0x43C40000 {
            compatible = "generic-uio";
            reg = < 0x43C40000 0x10000>;
        };
        bitmap_disp_cntrler_axi_master_0@0x43c00000 {
            compatible = "generic-uio";
            reg = < 0x43c00000 0x10000>;
        };
        dviin_axi_vdma_0@0x43000000 {
            compatible = "generic-uio";
            reg = < 0x43000000 0x10000>;
        };


../scripts/dtc/dtc -I dts -O dtb -o devicetree.dtb zynq-zybo.dts
を実行して、zynq-zybo.dts をコンパイルして、devicetree.dtb を生成した。
StereoCamTest_57_160130.png

ZYBO に挿入するMicroSD カードに、作製したBOOT.bin と devicetree.dtb をコピー&ペーストした。 uEnv.txt と uImage は以前のままとした。
StereoCamTest_58_160130.png

MicroSD カードをZYBO に入れて、SDカード・ブートに設定変更し、電源ONを行った。

Linux が起動して、/sys/devices/amba.0 を見ると、デバイスツリーに書いたデバイスが見えた。成功。。。
StereoCamTest_59_160130.png

/sys/devices/amba.0/41600000.caminf_axi_iic/uio ディレクトリに入って ls すると uio0 になっているのが見えた。デバイスツリーの順番の通りに uio の番号が設定されていた。
StereoCamTest_60_160130.png
  1. 2016年01月30日 20:57 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

LinuxでSDカードをバックアップ、リストア

ZYBO が2台になったので、現在使用している Linux 環境を移植したいということで、Windows 7 でImager Writer を使用してイメージをバックアップしようとしたがLock Error の Error:5 でイメージをRead することができなかった。
そこで、LinuxでMicro SDカードのイメージをRead しようと思い検索したら、”SDカードを丸ごとバックアップ & リストア on Linux”がヒットした。
そうか、dd コマンドでやれば良いのかということで、早速やってみた。

使用する環境は、VirtualBox 上のUbuntu 14.04 LTS だ。
VirtualBox 上のUbuntu 14.04 LTS にMicro SDカードをマウントする。マウントの仕方は、VirtualBox のデバイスメニューからUSB -> USBのカード リーダー&ライタを選択すれば、自動的にマウントしてくれる。

lsblk で、 USBのカード リーダー&ライタを探すと /dev/sdb がそうだということが分かる。

sudo dd if=/dev/sdb of=ZYBO_Ubuntu1404_160128.dd
を実行した。
SDcardBackup_Linux_1_160129.png

約 42 分位かかって終了した。
カレント・ディレクトリに ZYBO_Ubuntu1404_160128.dd が生成された。
SDcardBackup_Linux_2_160129.png

現在のMicro SDカードを取り出して、新しいMicro SDカードをVirtualBox 上のUbuntu 14.04 LTS にマウントした。

sudo dd if=ZYBO_Ubuntu1404_160128.dd of=/dev/sdb
を実行した。
SDcardBackup_Linux_3_160129.png

書き込みは、4時間23分程度かかった。

VirtualBox 上のUbuntu 14.04 LTS から取り出しして、VirtualBox のデバイスメニューからUSB -> USBのカード リーダー&ライタを選択すると、制御がWindows 7 に戻された。
ZYBO_BOOT ドライブはマウントされずに修復ダイアログが出たので、修復した。

そのMircro SDカードをZYBO に入れたが、u-boot のブートプロンプトで停止していた。

2 つのパーティションのうちのFAT32のZYBO_BOOT ドライブがおかしいようなので、Micro SDカードの ZYBO_BOOT の内容を一旦、削除して、バックアップから再度コピーした。
SDcardBackup_Linux_4_160129.png

もう一度、Mircro SDカードをZYBO に入れて起動すると Linux が起動して、Ubuntu 14.04 LTS が使用できるようになった。

udmabuf デバイス・ドライブを入れて、./cam_disp_vdma を起動するとカメラ画像が表示された。
SDcardBackup_Linux_5_160129.png

これで、Linux でのSDカードのバックアップとリストアを正常に行うことができた。
  1. 2016年01月29日 04:09 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト6(ステレオカメラのテスト)

ステレオカメラによる距離測定テスト5(インプリメント成功)”の続き。

かなり期間が空いてしまったが、前回はインプリメントが終了した。今回はSDKを立ち上げて、ベアメタル・アプリケーションを作製して自分のカメラと、ZYBO_0_2 からHDMI ポート経由で送られてきた画像が表示できるか?を確認する。

最初に、Vivado 2015.4で、ハードウェアをエクスポートし、SDKを立ち上げた。

次に、disp_test という名前のApplication Project を作製し、disp_test.c を書いた。
StereoCamTest_48_160128.png

もう片方のZYBO はZYBO_0_2 を起動して、カメラ画像をVGA ポートからSVGA 解像度で出力し、HDMI ポートからはSVGA のフレームバッファをXGA 解像度で送る。SDKでアプリケーションを起動するZYBOは、HDMI ポートからのXGA 解像度のSVGA 画像をDDR3 SDRAM 上のフレームバッファに転送するのと、自分のカメラの画像を異なるフレームバッファに転送する。そのどちらかのフレームバッファをVGA ポートに出力するという機能がある。
現在は、切り替えるフレームバッファは、どちらのフレームバッファのアドレスをビットマップ・ディスプレイ・コントローラのベース・アドレスとして、与えるかをコメント・アウトで切り替えて、再ビルドすることで、ディスプレイの表示を切り替える。

まず、やっている環境はこんな感じだ。カメラから椅子の一番近いところまでの距離は約 47 cm だった。
StereoCamTest_49_160128.jpg

下の画像で、左の小さいディスプレイは、左目に相当するカメラ(左目カメラ)で撮った画像で、右の大きなディスプレイは右目に相当するカメラで撮った画像を示す。右のディスプレイの画像は、ZYBO_0_2 が自分で取ったカメラ画像が表示されている(HDMI で転送した画像ではない)
StereoCamTest_50_160128.jpg

左目カメラだけ画像を示す。つまり、自分のカメラで取った画像だ。
StereoCamTest_51_160128.jpg

次に、HMDI 経由で送られてきたZYBO_0_2 の右目カメラが取った画像を示す。やはり、黒いドットが出ているのが分かる。
StereoCamTest_52_160128.jpg

最後に、disp_test.c を貼っておく。2種類の方法でAXI VDMA の設定を行っている。

/* * disp_test.c * *  Created on: 2016/01/20 *      Author: marsee */

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.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 PIXEL_NUM_OF_BYTES    4

#define XGA_HORIZONTAL_PIXELS    1024
#define XGA_VERTICAL_LINES        768
#define XGA_ALL_DISP_ADDRESS    (XGA_HORIZONTAL_PIXELS*XGA_VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

#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 DVI_INPUT_FRAME_BUFFER_ADDRESS 0x10000000
#define CAMERA_FRAME_BUFFER_ADDRESS 0x10900000

static XAxiVdma_DmaSetup Vdma_dvi_WriteCfg;
//static XAxiVdma_DmaSetup Vdma_cam_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(){
    // AXI VDMA Initialization sequence
    XAxiVdma_Config *XAxiVdma_dvi_Config;
    XAxiVdma XAxiVdma_dvi;
    int XAxiVdma_dvi_Status;
    //XAxiVdma_Config *XAxiVdma_cam_Config;
    //XAxiVdma XAxiVdma_cam;
    //int XAxiVdma_cam_Status;

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

    XAxiVdma_dvi_Status = XAxiVdma_CfgInitialize(&XAxiVdma_dvi, XAxiVdma_dvi_Config, XAxiVdma_dvi_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma_dvi_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() for dvi_input failed\n");
        return(-1);
    }

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

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

    Vdma_dvi_WriteCfg.VertSizeInput = XGA_VERTICAL_LINES;
    Vdma_dvi_WriteCfg.HoriSizeInput = XGA_HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma_dvi_WriteCfg.Stride = XGA_HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma_dvi_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.
    Vdma_dvi_WriteCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma_dvi_WriteCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma_dvi_WriteCfg.PointNum = 0// No Gen-Lock
    Vdma_dvi_WriteCfg.EnableFrameCounter = 0// Endless transfers
    Vdma_dvi_WriteCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma_dvi_Status = XAxiVdma_DmaConfig(&XAxiVdma_dvi, XAXIVDMA_WRITE, &Vdma_dvi_WriteCfg);
    if (XAxiVdma_dvi_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
        return(-1);
    }

    // Frame buffer(AXI4 VDMA of dvi_input) address set
    unsigned int frame_addr = (unsigned int)DVI_INPUT_FRAME_BUFFER_ADDRESS;
    int i;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma_dvi_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        frame_addr += XGA_HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * XGA_VERTICAL_LINES;
    }

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

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


    // AXI VDMA for Camera module setup
    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // axis_switch_0, 2to1, Select S00_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

    volatile unsigned int *axi_vdma_cam = XPAR_CAMERA_INTERFACE_AXI_VDMA_0_BASEADDR;
    // AXI VDMA Initialization sequence
    axi_vdma_cam[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4
    while ((axi_vdma_cam[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_cam[12] = 0x4// S2MM_VDMACR (S2MM VDMA Control Register  Offset 30h) is 0x4
    while ((axi_vdma_cam[12] & 0x4) == 0x4) ; // Reset is progress
    axi_vdma_cam[18] = 0x3// S2MM_FRMSTORE (0x48) register
    axi_vdma_cam[12] = 0x00010002// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1)
    axi_vdma_cam[41] = 0xc80; // S2MM Horizontal Size Register(S2MM_HSIZE)0xc80 = 3200dec = 800 x 4
    axi_vdma_cam[42] = 0xc80; // S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)0xc80 = 3200dec = 800 x 4
    axi_vdma_cam[43] = CAMERA_FRAME_BUFFER_ADDRESS; // S2MM Start Address (1 to 16) Start Address 1
    axi_vdma_cam[44] = CAMERA_FRAME_BUFFER_ADDRESS+SVGA_ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 2
    axi_vdma_cam[45] = CAMERA_FRAME_BUFFER_ADDRESS+2*SVGA_ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 3
    axi_vdma_cam[12] = 0x00010003// S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1, Run/stop = 1)
    while((axi_vdma_cam[13] & 0x1) == 0x1) ; // Halt? (S2MM_VDMASR 0x34)
    axi_vdma_cam[40] = 0x258// S2MM Vertical Size (S2MM_VSIZE  Offset 0xA0) 0x258 = 600dec

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

    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;

    mt9d111_axi_lites[0] = (volatile unsigned int)CAMERA_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

    // bitmap_disp_cntrler_axi_master_0 : VGA port Display
    volatile unsigned int *bmdc0_axi_lites;
    bmdc0_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    //bmdc0_axi_lites[0] = (volatile unsigned int)CAMERA_FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 0 start, Camera Image
    bmdc0_axi_lites[0] = (volatile unsigned int)(DVI_INPUT_FRAME_BUFFER_ADDRESS + 0xc); // Bitmap Display Controller 0 start, HDMI Image

    return(0);
}

  1. 2016年01月29日 03:32 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

新しいZYBO用LinuxカーネルとUbuntu 14.04 LTS

Vivado and zybo linux勉強会資料3”に ZYBO用のLinuxカーネルをビルドしてUbuntu ルート・ファイルシステムを搭載したMicro SDカードの作り方を書いてあるが、2人の方からリンクが変わったり、Linuxカーネル・ソースコードが変わったりしてやり方が変わったとのお知らせを頂いた。
それじゃ、もう一度自分でもやってみようということで、昨年2015年の12月に自分でも、もう一度やってみて、資料を書き換えた。
新しいLinuxカーネルのバージョンは Linux version 3.18.0-xilinx-46110-gd627f5d だった。CMA領域も 16MiB 取られている。
以前、Linuxカーネルをビルドして、今、メインに使っているLinuxカーネルは 3.14.0 だった。
New_Linux_Kernel_1_160127.png

今回のLinuxカーネルでは、簡単に do-release-upgrade コマンドで Ubuntu 12.10 から Ubuntu 14.04 LTS にアップグレードできた。しかもシリアルのターミナルで、自分で打ったコマンドのキー入力がきちんとエコーバックされている。前回のバージョンのLinuxカーネルでは、Ubuntu 14.04 LTS にアップグレードはできたのだが、自分で打ったコマンドのキー入力がエコーバックされなくなってしまった。(苦労してUbuntu 14.04 LTS にしてから)
こちらでも udambuf デバイス・ドライバを動かしてみようと思っている。
今のところ、
sudo apt-get update
してから、モジュールの依存関係がおかしいようなので、
sudo apt-get autoremove -f
を行った。-f 付きじゃないとダメだった。
次に
sudo apt-get upgarade -f
を行った。やはり、-f 付きでないと依存関係が解消できなかった。

upgrade を行ってから、Linuxを起動すると、やはり、、自分で打ったコマンドのキー入力がエコーバックされなくなってしまった。
次に、udmabuf を確かめようとして、古いLinuxカーネル用のBOOT.BIN と devicetree.dtb を新しいLinuxカーネルのMicroSDカードにコピーしたら、カーネルパニックになってしまった。やはり、新しい環境でデバイスツリーをコンパイルする必要がなるのだろうか?
New_Linux_Kernel_3_160127.png

元のBOOT.BIN と devicetree.dtb に戻せば正常に起動する。
新しいDigilent Linux カーネルはこのパソコンでは構築していないので、こっちでも一度、構築してみよう。

取りあえず、新しいDigilent Linux カーネルに入れ替えようという、目論見だったが今日は断念した。
StereoCamTestのベアメタル・アプリケーションも試してみようと思ったが今日は時間切れになってしまった。

ステレオカメラ用として、レーザー加工機で作製した2台のZYBO を固定するためのベースプレートを示す。
New_Linux_Kernel_4_160127.jpg

これで、上手く固定できて、ステレオカメラの幅を調整できるようになった。
  1. 2016年01月27日 05:18 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

FreeCADでDIP ICの3Dモデルを作る2

FreeCADでDIP ICの3Dモデルを作る1“の続き。

前回でDIP IC の形ができたので、今回は左端のマークと、1番ピンマークを付けて、色を付けてみよう。

最初に左端のマークを作る。
XY平面にスケッチを作製して、下図の様に円を書いて、拘束を行う。その際に、DIP ICの上面よりもスケッチを浮かすために Z 軸上で 1.95 mm のオフセットを設定した。
FreeCAD_DIP_IC_11_160120.png

FreeCAD_DIP_IC_12_160120.png

スケッチをClose して、長さ 0.5 mm で逆方向に押し出す。
FreeCAD_DIP_IC_13_160120.png

次に1番ピンマークを作る。
同様にXY平面にスケッチを作製して、下図の様に円を書いて、拘束を行う。やはり、DIP ICの上面よりもスケッチを浮かすために Z 軸上で 1.95 mm のオフセットを設定した。
FreeCAD_DIP_IC_14_160120.png

スケッチをClose して、長さ 0.5 mm で逆方向に押し出す。
FreeCAD_DIP_IC_15_160120.png

Part に切り替えて、左端のマークのPad003 と”FreeCADでDIP ICの3Dモデルを作る1“でFusion したDIP IC モデルを2つとも選択して、「2つの図形から減算結果を作成」を選択すると左端のマークがカットされてCut が出来た。

Cut と1番ピンマークのPad004 を選択して、、「2つの図形から減算結果を作成」を選択する。
FreeCAD_DIP_IC_16_160120.png

1番ピンマークがカットされてCut001 が出来た。
FreeCAD_DIP_IC_17_160120.png

これで、形状としては出来上がった。
FreeCAD_DIP_IC_18_160120.png

これでファイルをセーブした。

次に色を付けてみよう。
Cutしたままだと色がつかなかったので、Cut と Cut001 を削除した。

まずは、DIP IC の胴体のみを選択して、プロパティビューのShape Color をクリックする。
FreeCAD_DIP_IC_19_160122.png

Basic colors のうちの黒をクリックして、OKボタンをクリックする。
FreeCAD_DIP_IC_20_160122.png

次にピンのみを選択して、プロパティビューのShape Color をクリックする。
FreeCAD_DIP_IC_21_160122.png

Val を変更して、明るい灰色にしてみた。
FreeCAD_DIP_IC_22_160122.png

DIP IC の本体とピンに色がついた。
FreeCAD_DIP_IC_23_160122.png

もう一度、Cut と Cut001 を作成した。
FreeCAD_DIP_IC_24_160122.png
  1. 2016年01月26日 10:32 |
  2. CADツール
  3. | トラックバック:0
  4. | コメント:0

udmabuf を使用したZYBO_0_2 のアプリケーション

デバイスドライバ udmabuf を使用する2”でZYBO_0_2 (カメラ画像のHDMI 出力装置)の cam_disp_vdma アプリケーションが udmabuf デバイス・ドライバを使用して動作した。(ZYBO_0_2 の情報は”ZYBO_0 を変更3(Ubuntu 14.04 LTSのBOOT.binを変更)”辺りを参照のこと)
他のラプラシアンフィルタ画像出力アプリケーション lap_fil_on_axis やラプラシアンフィルタ画像を出力している時に生のカメラ画像に戻るアプリケーションの cam_return_axis を試してみる。

まずは、一々 insmodや chmod を入力するのが面倒なので、udmabuf_insmod を作製した。udmabuf_insmod の中身は、insmod や chmod の2つのコマンドを書いてある。udmabuf_insmod の内容を示す。

sudo insmod udmabuf.ko udmabuf0=5760000
sudo chmod 666 /dev/udmabuf0


./udmabuf_insmod を実行したところ、パーミションが 666 の /dev/udmabuf0 が生成されていた。
udmabuf_19_160125.png

次に lap_fil_on_axis.c と cam_return_axis.c を見てみたが、udmabuf を制御する部分は無かったので、無修正で動作した。
./lap_fil_on_axis を実行すればラプラシアンフィルタ処理画像に切り替わるし、その状態で、./cam_return_axis を実行すれば、カメラ画像に切り替わる。

これで、ZYBO_0_2 は udmabuf 対応になった。
  1. 2016年01月25日 04:35 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

デバイスドライバ udmabuf を使用する2

デバイスドライバ udmabuf を使用する1”の続き。

前回、udmabuf ドライバをロードする事ができた。今回は、実際のアプリケーションで udmabuf ドライバを使用する。

まずは、前回同様に udmabuf ドライバをロードした。
sudo insmod udmabuf.ko udmabuf0=5760000

/dev/udmabuf0 を
ls -l /dev/udma*
でみると、root オーナーで、しかもパーミッションが 600 になっている。これではユーザー権限から使えないので、
sudo chmod 666 /dev/udmabuf0
で、ユーザーにもRead/Write 権限を与えた。
ls -l /dev/udma*
で見ると、パーミッションが 666 になっていた。

追記:Linuxでユーザー空間で動作するプログラムとハードウェアがメモリを共有するためのデバイスドライバ”にロード時にパーミッションを変更する方法が追加されています。/etc/udev/rules.d/99-udmabuf.rules というファイルにパーミションを 666 にする記述を書いておくそうです)


udmabuf_14_160124.png

次に、ARMプロセッサ側からのWrite/Read テストとして、udmabuf_test を実行した。問題なく成功した。
udmabuf_15_160124.png
udmabuf_16_160124.png

udmabuf_test.c を下に貼っておく。

//
// udmabuf_test.c
// 2016/01/23 by marsee
//

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

int main()
{
    int fd, fd1;
    volatile unsigned *udmabuf_test;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    int i;
    
    fd = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    udmabuf_test = (volatile unsigned *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (!udmabuf_test){
        fprintf(stderr, "udmabuf_test mmap error\n");
        exit(-1);
    }
    
    // phys_addr of udmabuf0
    fd1 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd1 == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd1, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd1);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    for (i=0; i<100; i++){
        udmabuf_test[i] = i;
        if (udmabuf_test[i] != i){
            printf("Error: i = %d, udmabuf_test[i] = %d\n", i, udmabuf_test[i]);
        } else {
            printf("i = %d, udamabuf_test[i] = %d\n", i, udmabuf_test[i]);
        }
    }
    
    munmap((void *)udmabuf_test, 576000);
     close(fd);
 
     return(0);
 }


次に、udmabuf 用の cam_disp_vdma を作製して、起動したところ、正常にカメラ画像が表示された。
udmabuf_17_160124.png

udmabuf_18_160124.jpg

cam_disp_vdma.c を貼っておく。

//
// cam_disp_vdma.c
// Created on: 2015/12/03
//      Author: marsee
// 2016/01/23 : udmabuf 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;

    // 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[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+ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 2
    axi_vdma_0[45] = (int)phys_addr+2*ALL_DISP_ADDRESS; // 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);
    
    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年01月24日 04:42 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

マウスコンピュータのノートパソコン、LB-J321E-SSD2 が来ました

ノートパソコンが欲しかったので、購入しようと思って、いろいろと見ていたのですが、マウスコンピュータのノートパソコン、LB-J321E-SSD2 に決めて購入しました。取りあえず、値段重視で、CPUはまあどうでもよいかな?メモリは 8GB 欲しい、SSDも 250 MB 欲しいと思っていたので、スペック的に調度良かったです。
いつ来るのかな?と待っていたのですが、今日来ましたよ。待ってました。

OSはWindows 10 Pro にしました。Vivado のサポートはまだ無いですが、Windows 10 にVivado 2015.4 をインストールして、問題なく動作しているし、詳しい人に聞いても問題ないということだったので、そうしました。Pro はリモートデスクトップ・サーバーとして使いたかったからです。メインのデスクトップ・パソコンからリモートデスクトップで制御したいと思っています。並列でインプリメントすることもできますね。

まだ、環境構築の途中です。Chrome とLibreOffice をインストールしたところです。
キーボードは思ったよりストロークが長く、打ちやすい感じがしますね。当たりでした。
note_pasocom_160123.jpg


  1. 2016年01月22日 21:39 |
  2. パソコン関連
  3. | トラックバック:0
  4. | コメント:0

デバイスドライバ udmabuf を使用する1

ikwzm さんのLinuxでユーザー空間で動作するプログラムとハードウェアがメモリを共有するためのデバイスドライバ udmabuf を使うことにした。

今までは、”並列ステレオカメラによる距離の測定8(Ubuntuで動作するアプリケーションを作る1)”の zynq-zybo.dts の frame_buffer_bmdc@0x17800000 エントリを作って、CMA領域の 0x17800000 の領域を確保した。
CMA領域は予約されているが、ドライバがインストールされて使用されるか?わからない。そのため、CMA領域の途中から自分のハードウェア用のDMA領域(画像データのフレームバッファ)を使用していたが、やはり不確実だ。
そこで、ikwzm さんのLinuxでユーザー空間で動作するプログラムとハードウェアがメモリを共有するためのデバイスドライバudmabuf(User space mappable DMA Buffer) を使うことにした。

まずは、ZYBO のLinux カーネルのバージョンを調べてみよう。
uname -r コマンドで調べると、3.14.0 だった。
udmabuf_13_160121.png

次に、パソコンの VirtualBox 上のUbuntu 14.04 を起動する。
ここには、”ZYBO用のEmbedded Linux チュートリアル7(Linuxカーネルのビルド)”や、”Vivado and zybo linux勉強会資料3”に示したDigilent Linux のビルド環境を設定してある。

~/ZYBO/Digilent_Linux_Tutrilal に入って
git clone https://github.com/ikwzm/udmabuf
で、ikwzm さんの udmabuf をクローンした。
udmabuf_2_160121.png

cd udmabuf
ls

で udmabuf ディレクトリのファイルを見た。
udmabuf_3_160121.png

gedit Makefile
で、Makefile を編集した。”ZYBO用のEmbedded Linux チュートリアル10(myLedのドライバの構築とデバイス・ツリーへの追加)”を参考にして、Makefile を書き換えた。
udmabuf_4_160121.png

obj-m := udmabuf.o

all:
    make -C ../Linux-Digilent-Dev/ M=$(PWD) modules

clean:
    make -C ../Linux-Digilent-Dev/ M=$(PWD) clean


make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi-
を実行して、make を行った。
ls
で見ると、udmabuf.ko ができていた。
udmabuf_5_160121.png

次に、gFTP を立ち上げて、192.168.3.62 のZYBO にコネクトし、/home/linaro に udmabuf.ko をアップロードした。
udmabuf_6_160121.png


これからはZYBO 上のLinux に移動した。これからはZYBO 上のLinux での作業となる。
最初に udmabuf.ko カーネル・ドライバをロードする。

いろいろとトライしてしまっているが、結局
sudo insmod udmabuf.ko udmabuf0=0x57E400
を実行した。udmabuf 領域は、0x57E400 だ。これは16進で入力したが、10進で 5760000 と書いてもOKのようだ。これは、800 ピクセル x 600 ライン x 4 バイト x 3 画面分のフレームバッファを確保している。
udmabuf_7_160121.png

ls -l /dev/udma*
を実行すると /dev/udmabuf0 ができていた。
ls -l /sys/class/udambuf
を実行すると、/sys/devices/virtual/udmabuf/udmabuf0 にリンクされているようだった。
udmabuf_8_160121.png

そこで、
cd /sys/devices/virtual/udmabuf/udmabuf0
を実行して、
ls -l
でファイルを見た。
udmabuf_9_160121.png

いろいろなデバイスファイルが生成されていた。一つ一つ、cat コマンドで表示してみた。
udmabuf_10_160121.png
udmabuf_11_160121.png

linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat phys_addr
0x18900000
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat size
5760000
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat dev
244:0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_direction
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_for_cpu
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_for_device
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_mode
1
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_offset
0x0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_owner
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_size
5760000
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat uevent
MAJOR=244
MINOR=0
DEVNAME=udmabuf0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat debug_vma
0


phys_addr は 0x18900000 から物理アドレスが確保されていることを示す。
size は、5760000 バイト確保されていることを示す。
その他のデバイスファイルは主にキャッシュの制御に用いられる。詳しくは、”Linuxでユーザー空間で動作するプログラムとハードウェアがメモリを共有するためのデバイスドライバ(キャッシュのフラッシュと無効化を追加)”を参照のこと。

sudo rmmod udmabuf
で udmabuf を削除したところ、/dev/udmabuf0 は無くなった。
udmabuf_12_160121.png
  1. 2016年01月22日 04:33 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

「白鯨との闘い」(映画)を見てきました

白鯨との闘い」(映画)を見てきました。

なかなかおもろかったのですが、ショッキングな内容もありました。でも、難破しているんだから仕方ないですね。
白鯨が最後まで攻撃してこなくて、良かったです。
  1. 2016年01月21日 20:48 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

FreeCADでDIP ICの3Dモデルを作る1

FreeCADでDIP ICの3Dモデルを作ってみようと思います。作った3DモデルはPCB Cad のKiCad で3Dモデルとして使えるそうです。(FreeCAD tutorial: creating 3D model for KiCAD、YouTubeです)

最初にFreeCADを立ちあげて、Part Design で XZ 平面に DIP IC の足を書きます。足が曲がっているところの Bend があるので、0.5 mm 短めにしました。
FreeCAD_DIP_IC_1_160120.png

0.29 mm で押し出します。
FreeCAD_DIP_IC_2_160120.png

Steel Metal に変更します。Steel Metal はFreeCAD に標準で入っていないので、登録します。
ベンド(Bend)を作成します”を参考に、IC の足に Bend を作製します。
angle = 90 度、length = 1 mm、radius = 0.2 mm、reliefd = 0.5 mm、relifw = 0.5 mmm
FreeCAD_DIP_IC_3_160120.png

Draft に変更して、Bend を選択して、Array をクリックします。
Interval X = 2.54 mm、Number X = 10 にします。
FreeCAD_DIP_IC_4_160120.png

Array を選択して、右クリックメニューからコピーを指定して、モデル画面の空いているところで右クリックメニューからペーストを選択します。
Arrayp001 ができるので、プロパティビューのプロパティのAngle を 180度、Positon の x を 24.38 mm、y を -7.87 mm に変更します。
FreeCAD_DIP_IC_5_160120.png

IC パッケージを書きましょう。
YZ 平面にスケッチを作製します。下図のパラメータです。
FreeCAD_DIP_IC_6_160120.png

両側の足を表示するとこうなります。
FreeCAD_DIP_IC_7_160120.png

スケッチを押し出すので、パッケージのはじめの部分にスケッチを移動します。
プロパティの Position を x = -0.9425 mm に設定しましょう。
FreeCAD_DIP_IC_8_160120.png

スケッチを閉じて、26.24 mm 押し出します。
FreeCAD_DIP_IC_9_160120.png

これでDIP の外形は完成ですが、全てを一体のソリッドにするために、DIP の足2つ(Array, Array001)とPad 002 をFusion します。
Part に変更して、”複数の形状の和集合を作製”ボタンをクリックするとFusion されます。
FreeCAD_DIP_IC_10_160120.png
  1. 2016年01月20日 11:45 |
  2. CADツール
  3. | トラックバック:0
  4. | コメント:0

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト時の画像のバグのデバック2(アプリの変更)

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト時の画像のバグのデバック1(HDMI 出力の確認)”の続き。

前回は、ZYBO_0_2 から出力されるHDMI 出力はどうやら良さそうだ。ということが分かった。今回は、HDMI を受ける側のZYBO_1_XGA_test を変更して、バグが直るかどうかを確認する。

バグは今のところ2種類あって、左端の画像がおかしい現象と、ところどころ黒いドットが出ている現象がある。
黒いドットが出ているのは、FIFOのオーバーフロー、アンダーフローかもしれないので、取りあえず、AXI VDMAのFIFO 容量を増やしてみよう。最初のLine Buffer Depth は 512 だった。
HDMI_tran_bug_fix_3_160118.png

これを 1024 に変更した。
HDMI_tran_bug_fix_4_160118.png

これで、ビットストリームの生成まで行った。問題ない。
HDMI_tran_bug_fix_5_160119.png

これで、ハードウェアをエクスポートして、SDKを起動してテストしてみたところ、黒いドットは表示されている。

次に、左端の画像がおかしい現象はと言うと、どうやら、右の画像が回り込んでいるように見える。それならばということで、ビットマップ・ディスプレイ・コントローラのフレーム・バッファのベースアドレスに、0xc を足してみることにした。
HDMI_tran_bug_fix_6_160119.png

そうしたところ、左端のおかしい画像は無くなった。やはり余計なデータが意図せずに入ってしまったようだ。

黒いドットについては、Video In とAXI4-Stream IP のFIFO Depth を 1024 から 2048 に変更してみた。
HDMI_tran_bug_fix_8_160119.png

ビットストリームの生成まで行った。こちらも問題ない。
HDMI_tran_bug_fix_9_160119.png

これで、ハードウェアをエクスポートして、SDKを起動してテストしてみたところ、やはり黒いドットは表示されている。
これ以上は自分で作ったIP ではないので、仕方ないかもしれない。
左端のおかしい画像が無くなっただけでも、左右カメラのラプラシアンフィルタ画像の比較のためには良かったと思う。
  1. 2016年01月19日 05:26 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:2

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト時の画像のバグのデバック1(HDMI 出力の確認)

ステレオカメラによる距離測定テスト5(インプリメント成功)”まで作っておいて何だが、やはり、”ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト”で左端に出ている余計な画像と画像中の黒いドットが気になる。左端の画像は距離を測定する上で問題になるかもしれないので、もう一度、回路を検証してみることにした。

まずは、HDMI画像を出力するZYBO_0_2 でSVGA のカメラ画像をXGA 解像度でHDMI 出力しているので、HDMI 出力をモニタで見てもよくわからない。(これは、何故か?と言うと、Digilent 社の rgb2dvi IP がSVGA を出力できないからだ)それで単色でも良いので、XGAの画像を出力してディスプレイに表示してみたいと思う。
使用するのは、ZYBO_0_2 をUbuntu 14.04 LTSを起動しているZYBO に載せた実装だ。(”ZYBO_0 を変更3(Ubuntu 14.04 LTSのBOOT.binを変更)”を参照)
ここで使用しているソフトウェアを改造して、HDMI出力にきちんと見える画像を表示する。具体的には、ビットマップ・ディスプレイ・コントローラ 1 のベースアドレスをCMA領域のトップに設定し、そこに、画像を生成した。このソフトウェアをHDMI_output_test.c という名前でセーブした。
HDMI_tran_bug_fix_1_160118.png

gcc HDMI_output_test.c -o HDMI_output_test でコンパイルし、./HDMI_output_test で起動したところ下のように表示された。
HDMI_tran_bug_fix_2_160118.jpg

HDMI 出力は問題無さそうに見える。
  1. 2016年01月18日 05:40 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト5(インプリメント成功)

ステレオカメラによる距離測定テスト4(StereoCamTestブロックデザインの完成)”の続き。

前回は、StereoCamTest ブロックデザインを完成させた。
今回は、論理合成、インプリメント、ビットストリームの作製を行う。

まずは、StereoCamTest ブロックデザインを右クリックし、右クリックメニューから Create HDL Wapper... を選択して、トップのHDL ファイルを生成した。
StereoCamTest_39_160116.png

次に、制約ファイル StereoCamTest.xdc を作製した。
StereoCamTest_40_160115.png

これで、論理合成、インプリメント、ビットストリームの生成を行うとタイミング・エラーになった。
StereoCamTest_41_160116.png

何処がエラーかというと、BURF_pixclk_io_n_0 と clk_fpga_0 の間だった。

現在、Implemented Design を開いてあるので、Tools メニュー -> Timing -> Report CDC... を選択して、、BURF_pixclk_io_n_0 と clk_fpga_0 を指定した。詳しくは、”Vivado のImplemented Design で Report CDC を確認する”を参照のこと。

Report CDC ウインドウが表示されたが、CDC (clock Domain Crossing) に問題は無いようだ。
StereoCamTest_42_160116.png

Implemented Design から Edit Timing Constraints をクリックして、制約を追加する。
Timing Constraints タブで Set Clock Groups をクリックし、Double click to create a Set Clock Groups constraint をダブルクリックする。
Set Clock Groups ダイアログが表示される。
Group 1 に clk_fpga_0、Group 2 に BURF_pixclk_io_n_0 を指定して、OKボタンをクリックした。
StereoCamTest_44_160116.png

set_clock_groups -name clk_fpga_0_pixel_clk -asynchronous -group [get_clocks clk_fpga_0] -group [get_clocks [list [get_clocks -of_objects [get_pins StereoCamTest_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]]

制約が追加された。
StereoCamTest_43_160116.png

セーブして、もう一度、論理合成、インプリメント、ビットストリームの作製を行った所、タイミング制約も問題なく成功した。
StereoCamTest_45_160116.png

最後に、制約ファイル StereoCamTest.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 H16 [get_ports TMDS_Clk_p]
set_property PACKAGE_PIN D19 [get_ports {TMDS_Data_p[0]}]
set_property PACKAGE_PIN C20 [get_ports {TMDS_Data_p[1]}]
set_property PACKAGE_PIN B19 [get_ports {TMDS_Data_p[2]}]
#set_property IOSTANDARD TMDS_33 [get_ports TMDS_Clk_p]
#set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[0]}]
#set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[1]}]
#set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[2]}]

set_property PACKAGE_PIN G18 [get_ports ddc_sda_io]
set_property PACKAGE_PIN G17 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_hpd[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN E18 [get_ports {hdmi_hpd[0]}]
set_property PACKAGE_PIN F17 [get_ports {hdmi_out_en[0]}]

set_property PACKAGE_PIN L16 [get_ports clk125]
set_property IOSTANDARD LVCMOS33 [get_ports clk125]

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 CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF]

set_clock_groups -name clk_fpga_0_pixel_clk -asynchronous -group [get_clocks clk_fpga_0] -group [get_clocks [list [get_clocks -of_objects [get_pins StereoCamTest_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]]


(2016/01/20:追記)
Project Summary を貼っておく。
StereoCamTest_47_160120.png
  1. 2016年01月16日 05:49 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト4(StereoCamTestブロックデザインの完成)

ステレオカメラによる距離測定テスト3(camera_interface 階層の生成)”の続き。

前回は、ZYBO_1_XGA_test ブロックデザインを tcl スクリプトにエクスポートして、その tcl コマンドを編集して camera_interface 階層を生成した。
今回は、StereoCamTest ブロックデザインを完成させる。

まずは、Run Connection Automation をクリックして、camera_interface 階層のAXI4 バスを接続する。

Run Connection Automation ダイアログで、camera_interface のチェックボックスをチェックして、camera_interface のすべてのAXI4 バスを接続した。
StereoCamTest_28_160115.png

ダイアログが出た。すでにつないであったということだろうか?
StereoCamTest_29_160115.png

camera_interface 階層のAXI4 バスが接続された。
StereoCamTest_30_160115.png

次にDVI (HDMI) 入力関連のIP を階層にしようと思う。

HDMI 入力に関連する IP をすべて選択して、右クリックメニューから Create Hierachy... を選択した。
StereoCamTest_31_160115.png

Cell name に dvi_input と名前を付けて、OKボタンをクリックした。
StereoCamTest_32_160115.png

dvi_input 階層ができた。
StereoCamTest_33_160115.png

dvi_input 階層を示す。
StereoCamTest_34_160115.png

PS の FCLK_CLK1 をカメラ用クロックの 36 MHz に設定した。
StereoCamTest_38_160115.png 

PS の FCLK_CLK1 を camera_interface 階層の pclk_from_pll に接続した。

camera_interface 階層のカメラのI/O ポートを Make External で接続した。これで完成のはず。。。
StereoCamTest_35_160115.png

Validate Design ボタンをクリックして、ブロックデザインを検証したが問題なかった。
StereoCamTest_36_160115.png

最後に Address Editor の内容を貼っておく。
StereoCamTest_37_160115.png
  1. 2016年01月15日 04:49 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト3(camera_interface 階層の生成)

ステレオカメラによる距離測定テスト2(プロジェクトの作製)”の続き。

前回は、ZYBO_1_XGA_test のブロックデザインを StereoCamTest ブロックデザインに tcl スクリプトを使用してコピーした。
今回は、ZYBO_0_154_2 プロジェクトの ZYBO_0 ブロックデザインの内の camera_interface 階層を tcl スクリプトを使用して StereoCamTest ブロックデザインにコピーする。

まずは、ZYBO_0_154_2 プロジェクトを起動して、 ZYBO_0 ブロックデザインを表示した。
File メニューから Export -> Export Block Design... を選択し、ZYBO_0 ブロックデザインを ZYBO_0.tcl としてエクスポートした。
StereoCamTest_22_160114.png

ZYBO_0.tcl を見ると、camera_interface 階層の生成が proc として分離されている。
StereoCamTest_27_160114.png

この部分を tcl スクリプトとして実行できれば、camera_interface 階層が生成されるはずだと思う。
ということで、CreateCameraInterface.tcl を新規作成して、環境変数の設定を付け加えた。

最初に重要なのは、design_name の設定だと思う。

set design_name StereoCamTest

で design_name を StereoCamTest に設定した。

次に、current_bd_design を $design_name に設定する。

current_bd_design $design_name

camera_interface 階層を生成するブロックデザインを選択する必要があるだろうから。。。

proc create_hier_cell_camera_interface を ZYBO_0 からコピー&ペーストした。

proc create_hier_cell_camera_interface を起動して、camera_interface として、現在のブロックデザインに生成するためのコマンド

create_hier_cell_camera_interface [current_bd_instance .] camera_interface

を記述した。

完成した CreateCameraInterface.tcl を下に示す。tcl コードはブログの最後に貼っておく。
StereoCamTest_23_160114.png

Vivado 2015.4 の Tcl Console で

source CreateCameraInterface.tcl

コマンドを起動して、camera_interface 階層を生成する。
StereoCamTest_24_160114.png

無事に camera_interface 階層が生成された。
StereoCamTest_25_160114.png

camera_interface 階層を開いた所だ。
StereoCamTest_26_160114.png

最後に CreateCameraInterface.tcl を貼っておく。

# CreateCameraInterface.tcl
#
################################################################
# Check if script is running in correct Vivado version.
################################################################
set scripts_vivado_version 2015.4
set current_vivado_version [version -short]

# CHANGE DESIGN NAME HERE
set design_name StereoCamTest

# If you do not already have an existing IP Integrator design open,
# you can create a design using the following command:
#    create_bd_design $design_name

# Creating design if needed
set errMsg ""
set nRet 0

set cur_design [current_bd_design -quiet]
set list_cells [get_bd_cells -quiet]

puts "INFO: Making design <$design_name> as current_bd_design."
current_bd_design $design_name

# Hierarchical cell: camera_interface
proc create_hier_cell_camera_interface { parentCell nameHier } {

  if { $parentCell eq "" || $nameHier eq "" } {
     puts "ERROR: create_hier_cell_camera_interface() - Empty argument(s)!"
     return
  }

  # Get object for parentCell
  set parentObj [get_bd_cells $parentCell]
  if { $parentObj == "" } {
     puts "ERROR: Unable to find parent cell <$parentCell>!"
     return
  }

  # Make sure parentObj is hier blk
  set parentType [get_property TYPE $parentObj]
  if { $parentType ne "hier" } {
     puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be <hier>."
     return
  }

  # Save current instance; Restore later
  set oldCurInst [current_bd_instance .]

  # Set parent object as current
  current_bd_instance $parentObj

  # Create cell and set as current instance
  set hier_obj [create_bd_cell -type hier $nameHier]
  current_bd_instance $hier_obj

  # Create interface pins
  create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:iic_rtl:1.0 IIC
  create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM
  create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI
  create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI_CTRL
  create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI_CTRL1
  create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI_LITE
  create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_AXILiteS
  create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_lite1

  # Create pins
  create_bd_pin -dir I -from 0 -to 0 -type rst aresetn
  create_bd_pin -dir I -from 7 -to 0 cam_data
  create_bd_pin -dir I href
  create_bd_pin -dir I pclk
  create_bd_pin -dir I pclk_from_pll
  create_bd_pin -dir I -type clk s_axi_aclk
  create_bd_pin -dir I -from 0 -to 0 -type rst s_axi_aresetn
  create_bd_pin -dir O standby
  create_bd_pin -dir I vsync
  create_bd_pin -dir O xck

  # Create instance: axi_iic_0, and set properties
  set axi_iic_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_iic:2.0 axi_iic_0 ]

  # Create instance: axi_vdma_0, and set properties
  set axi_vdma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_vdma:6.2 axi_vdma_0 ]
  set_property -dict [ list \
CONFIG.c_include_mm2s {0} \
CONFIG.c_m_axi_mm2s_data_width {64} \
CONFIG.c_mm2s_genlock_mode {0} \
CONFIG.c_mm2s_max_burst_length {8} \
 ] $axi_vdma_0

  # Create instance: axis_switch_0, and set properties
  set axis_switch_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_switch:1.1 axis_switch_0 ]
  set_property -dict [ list \
CONFIG.DECODER_REG {0} \
CONFIG.NUM_MI {1} \
CONFIG.NUM_SI {2} \
CONFIG.ROUTING_MODE {1} \
 ] $axis_switch_0

  # Create instance: axis_switch_1, and set properties
  set axis_switch_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_switch:1.1 axis_switch_1 ]
  set_property -dict [ list \
CONFIG.DECODER_REG {1} \
CONFIG.NUM_MI {2} \
CONFIG.NUM_SI {1} \
CONFIG.ROUTING_MODE {1} \
 ] $axis_switch_1

  # Create instance: lap_filter_axis_0, and set properties
  set lap_filter_axis_0 [ create_bd_cell -type ip -vlnv xilinx.com:hls:lap_filter_axis:1.0 lap_filter_axis_0 ]

  # Create instance: mt9d111_inf_axis_0, and set properties
  set mt9d111_inf_axis_0 [ create_bd_cell -type ip -vlnv marsee:user:mt9d111_inf_axis:1.0 mt9d111_inf_axis_0 ]

  # Create interface connections
  connect_bd_intf_net -intf_net axi_iic_0_IIC [get_bd_intf_pins IIC] [get_bd_intf_pins axi_iic_0/IIC]
  connect_bd_intf_net -intf_net axi_vdma_0_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins axi_vdma_0/M_AXI_S2MM]
  connect_bd_intf_net -intf_net axis_switch_0_M00_AXIS [get_bd_intf_pins axi_vdma_0/S_AXIS_S2MM] [get_bd_intf_pins axis_switch_0/M00_AXIS]
  connect_bd_intf_net -intf_net axis_switch_1_M00_AXIS [get_bd_intf_pins axis_switch_0/S00_AXIS] [get_bd_intf_pins axis_switch_1/M00_AXIS]
  connect_bd_intf_net -intf_net axis_switch_1_M01_AXIS [get_bd_intf_pins axis_switch_1/M01_AXIS] [get_bd_intf_pins lap_filter_axis_0/ins]
  connect_bd_intf_net -intf_net lap_filter_axis_0_outs [get_bd_intf_pins axis_switch_0/S01_AXIS] [get_bd_intf_pins lap_filter_axis_0/outs]
  connect_bd_intf_net -intf_net mt9d111_inf_axis_0_m_axis [get_bd_intf_pins axis_switch_1/S00_AXIS] [get_bd_intf_pins mt9d111_inf_axis_0/m_axis]
  connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M00_AXI [get_bd_intf_pins s_axi_lite1] [get_bd_intf_pins mt9d111_inf_axis_0/s_axi_lite]
  connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M01_AXI [get_bd_intf_pins S_AXI] [get_bd_intf_pins axi_iic_0/S_AXI]
  connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M02_AXI [get_bd_intf_pins s_axi_AXILiteS] [get_bd_intf_pins lap_filter_axis_0/s_axi_AXILiteS]
  connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M04_AXI [get_bd_intf_pins S_AXI_LITE] [get_bd_intf_pins axi_vdma_0/S_AXI_LITE]
  connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M05_AXI [get_bd_intf_pins S_AXI_CTRL] [get_bd_intf_pins axis_switch_0/S_AXI_CTRL]
  connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M06_AXI [get_bd_intf_pins S_AXI_CTRL1] [get_bd_intf_pins axis_switch_1/S_AXI_CTRL]

  # Create port connections
  connect_bd_net -net cam_data_1 [get_bd_pins cam_data] [get_bd_pins mt9d111_inf_axis_0/cam_data]
  connect_bd_net -net href_1 [get_bd_pins href] [get_bd_pins mt9d111_inf_axis_0/href]
  connect_bd_net -net mt9d111_inf_axis_0_standby [get_bd_pins standby] [get_bd_pins mt9d111_inf_axis_0/standby]
  connect_bd_net -net mt9d111_inf_axis_0_xck [get_bd_pins xck] [get_bd_pins mt9d111_inf_axis_0/xck]
  connect_bd_net -net pclk_1 [get_bd_pins pclk] [get_bd_pins mt9d111_inf_axis_0/pclk]
  connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_pins s_axi_aclk] [get_bd_pins axi_iic_0/s_axi_aclk] [get_bd_pins axi_vdma_0/m_axi_s2mm_aclk] [get_bd_pins axi_vdma_0/s_axi_lite_aclk] [get_bd_pins axi_vdma_0/s_axis_s2mm_aclk] [get_bd_pins axis_switch_0/aclk] [get_bd_pins axis_switch_0/s_axi_ctrl_aclk] [get_bd_pins axis_switch_1/aclk] [get_bd_pins axis_switch_1/s_axi_ctrl_aclk] [get_bd_pins lap_filter_axis_0/ap_clk] [get_bd_pins mt9d111_inf_axis_0/m_axis_aclk] [get_bd_pins mt9d111_inf_axis_0/s_axi_lite_aclk]
  connect_bd_net -net processing_system7_0_FCLK_CLK2 [get_bd_pins pclk_from_pll] [get_bd_pins mt9d111_inf_axis_0/pclk_from_pll]
  connect_bd_net -net rst_processing_system7_0_100M_interconnect_aresetn [get_bd_pins aresetn] [get_bd_pins axis_switch_0/aresetn] [get_bd_pins axis_switch_1/aresetn]
  connect_bd_net -net rst_processing_system7_0_100M_peripheral_aresetn [get_bd_pins s_axi_aresetn] [get_bd_pins axi_iic_0/s_axi_aresetn] [get_bd_pins axi_vdma_0/axi_resetn] [get_bd_pins axis_switch_0/s_axi_ctrl_aresetn] [get_bd_pins axis_switch_1/s_axi_ctrl_aresetn] [get_bd_pins lap_filter_axis_0/ap_rst_n] [get_bd_pins mt9d111_inf_axis_0/axi_resetn]
  connect_bd_net -net vsync_1 [get_bd_pins vsync] [get_bd_pins mt9d111_inf_axis_0/vsync]

  # Restore current instance
  current_bd_instance $oldCurInst
}

# Create instance: camera_interface
  create_hier_cell_camera_interface [current_bd_instance .] camera_interface


  1. 2016年01月14日 04:33 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト2(プロジェクトの作製)

ステレオカメラによる距離測定テスト1(構想編)”の続き。

前回の構想通りに Depth Processing Unit はARMプロセッサで代用することにして、ZYBO_1_XGA_test にカメラ・インターフェース・モジュールを追加することにした。今回のブロックデザイン名はStereoCamTest と名付けれることにする。

プロジェクトを作り、ブロックデザインを作製するのだが、ブロックデザインを作るのに、tcl コマンドを使おうと思う。
やり方は、”Vivado プロジェクトを配布する方法”を参考にして、ZYBO_1_XGA_test のブロックデザインを tcl スクリプトにエクスポートして、その tcl スクリプトを編集して、StereoCamTest ブロックデザインを作製して、ZYBO_1_XGA_test と同じブロックデザインを作製してみよう。

最初に、ZYBO_1_XGA_test ブロックデザインを tcl スクリプトにエクスポートする。
ZYBO_1_XGA_test プロジェクトを開く。
ZYBO_1_XGA_test ブロックデザインを開いて、File メニューから Export -> Export Block Design... を選択する。
StereoCamTest_2_160111.png

Export Block Design ダイアログが開く。
Tcl file を指定して OK ボタンをクリックする。
StereoCamTest_3_160111.png

ZYBO_1_XGA_test.tcl が出力された。
StereoCamTest_4_160111.png

次に、普通に StereoCamTest_154 プロジェクトを作製する。
StereoCamTest_5_160111.png

Digilent社のボード・ファイルのインストール”を行ってあるので、Board の選択肢にZYBO が出てきたので選択した。
StereoCamTest_6_160111.png

StereoCamTest_154 プロジェクトが作製された。
StereoCamTest_7_160113.png

ZYBO_1_XGA_test プロジェクトからビットマップ・ディスプレイ・コントローラ (BMDispCaL) と dvi2rgb (dvi2rgb_v1_5) IP をコピー&ペーストした。

ZYBO_0_154_2 プロジェクトから、カメラ・コントローラ (cam_inf_d111_axis_151)、Vivado HLSで生成したラプラシアンフィルタIP (lap_filter_axis_144) をコピー&ペーストした。
StereoCamTest_9_160113.png

IP Catalog をクリックして表示して、右クリックし、右クリックメニューからAdd Repository... を選択した。
StereoCamTest_10_160113.png

まずは、ビットマップ・ディスプレイ・コントローラ (BMDispCaL) のみを選択した。
StereoCamTest_11_160113.png

Add Repository ダイアログが表示された。
StereoCamTest_12_160113.png

IP Catalog にbitmap_disp_cntrler_axi_master_V1_0 が入った。
StereoCamTest_13_160113.png

同様に、IP Catalog をクリックして表示して、右クリックし、右クリックメニューからAdd Repository... を選択した。

今度は、 dvi2rgb (dvi2rgb_v1_5) IP、カメラ・コントローラ (cam_inf_d111_axis_151)、Vivado HLSで生成したラプラシアンフィルタIP (lap_filter_axis_144) を選択した。
StereoCamTest_14_160113.png

Add Repository ダイアログが表示された。
StereoCamTest_15_160113.png

IP Catalog に選択したIP が入った。
StereoCamTest_16_160113.png

次は、ZYBO_1_XGA_testブロックデザインからエクスポートした ZYBO_1_XGA_test.tcl を StereoCamTest.tcl と名前を変更して、StereoCamTest_154 フォルダにコピー&ペーストした。
StereoCamTest_17_160113.png

ZYBO_1_XGA_test を StereoCamTest にリプレースした。
StereoCamTest_18_160113.png

tcl console に

cd z:/test/StereoCamTest_154/
source StereoCamTest.tcl

コマンドを入力し、リターンキーで実行させた。
StereoCamTest_19_160113.png

StereoCamTest.tcl スクリプト実行中。
StereoCamTest_20_160113.png

ZYBO_1_XGA_test ブロックデザインと同じ StereoCamTest ブロックデザインが生成された。
StereoCamTest_21_160113.png
  1. 2016年01月13日 04:56 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

Digilent社のボード・ファイルのインストール

ZYBO のPS (Processing System) の定義ファイル ZYBO_zynq_def.xml が、いつの間にかDigilent 社からダウンロードすることができなくなってしまった。これでは、新しくZYBO をやる方が困るので、やり方を探ってみることにした。

調べてみると、ボード・ファイル (Board Files) というファイルをDigilent 社からダウンロードすることができて、Vivado の所定のフォルダに入れておけば、プロジェクトを作製するときのBoard の選択肢として表示することができるようになるようだ。

やり方は、”Vivado Version 2015.1 and Later Board File Installation”に詳しく載っているが、自分でもやってみよう。

Vivado 2015.4 では、Xilinx\Vivado\2015.4\data\boards\board_files にボード定義ファイルがあるようだ。
Digilent_Boards_Files_1_160111.png

Digilent 社のボード用の定義ファイルは、https://github.com/Digilent/vivado-boards/archive/master.zip にあるのでダウンロードした。
Digilent_Boards_Files_2_160111.png

その中身はと見ると、Arty, BASYS3, GENESYS2, NEXYS_VIDEO, NEXYS4, NEXYS4_DDR, ZYBO のボード・ファイルが入ってた。
Digilent_Boards_Files_3_160111.png

Xilinx\Vivado\2015.4\data\boards\board_files にDigilent 社のボード用の定義ファイルをコピーした。
Digilent_Boards_Files_4_160111.png

コピー後にVivado を立ち上げて、新規プロジェクトを作製すると、コピーしたボードを選択することができた。
ZYBO を選択した。
Digilent_Boards_Files_5_160111.png

プロジェクトが作製されると、Board がZYBO に設定されている。
Digilent_Boards_Files_6_160111.png

問題は、ブロックデザインを作製した時、Processing_system_7 をAdd IP した時にZYBO 用の設定がされているか?だ。それを確かめてみる。

ブロックデザインを作製し、Processing_system_7 をAdd IP した。ダブルクリックして、設定を確認した所、設定がされていない。
Digilent_Boards_Files_7_160111.png

Run Block Automation をクリックする。
Digilent_Boards_Files_8_160111.png

Run Block Automation ダイアログで、FIXED_IO と DDR の配線を接続する。
Digilent_Boards_Files_9_160111.png

そうすると、PS のI/O Peripherals にチェックが付いて、ZYBO の設定が行われた。
Digilent_Boards_Files_10_160111.png

これで問題なく、PS にZYBO 用の設定を行うことができた。
  1. 2016年01月12日 03:58 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:4

牛久シティマラソンの5kmに参加しました

今日は牛久シティマラソンの5km に参加しました。

1ヶ月前辺りから右膝が痛くて、歩き出す時にびっこを引いてましたが、アスリートクラブのスポーツ・トレーナーに膝のケアを教えてもらって、ケアしたらだいぶ良くなりました。そこで、棄権しようと思っていた牛久シティマラソンに出ることにしました。

やはり、右膝が心配なので、(ミズノ)MIZUNO BG 5000 バイオギア タイツ (ロング) [メンズ]を購入して、万全を期しました。膝が締まっている感じで安心感があります。それに、走った後も痛みも出ないので、タイツを履いて走っていると良い感じですね。

結果は、グロスで27分23秒、ネットで27分06秒でした。50代男子で72人中30位でした。まあまあの結果でした。5km走れて良かったです。

奥さんは、グロスで22分22秒、ネットで22分16秒、50代女子で45人中3位でした。メダルなどの商品もらってました。凄いです。。。

Ushiku_Marathon_1_160111.jpg

Ushiku_Marathon_2_160111.jpg

Ushiku_Marathon_3_160111.jpg

Ushiku_Marathon_4_160111.jpg
  1. 2016年01月11日 18:03 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ステレオカメラによる距離測定テスト1(構想編)

ZYBO_0 を変更3(Ubuntu 14.04 LTSのBOOT.binを変更)”でステレオカメラの要素技術は大体クリア出来たので、ステレオカメラを構築していくことを考えてみよう。

並列ステレオカメラによる距離の測定1(ブロック図)”に示したステレオカメラによる距離の測定装置のブロック図を下に示す。
StereoCam_1_151114.png

これを構築して行こう。
上図では、Depth Processing Unit があるが、これを最初の段階では、ARMプロセッサに任せることにする。これは、C++ で作製しておいて、主要な部分はあとでVivado HLS でFPGA にオフロードすることを考えようと思う。
また、ZYBO 1 のBitmap Display Controller は、ZYBO 0 または ZYBO 1 のカメラ画像と深度情報をDMA してアルファブレンドして、Display に出力する予定だったが、ARMプロセッサでアルファブレンドするか?もしくは、距離だけを表示してもよいかな?と思っている。つまり、今までのビットマップ・ディスプレイ・コントローラが使えるということになる。
最初は、どのみち校正を行う必要があるので、中心の部分だけの距離を計測してみようと思う。ピクセルの差分を実際の距離に変換するために、決まった距離での左右カメラのピクセルの差を確認する必要がある。
これらの事柄をまとめると下図に示すブロック図となる。
StereoCamTest_1_160110.png

これで、ラプラシアンフィルタ処理されたカメラ画面中央部分の左右の相関をずらしながら、とってみようと思う。
  1. 2016年01月11日 04:00 |
  2. ステレオカメラによる画像解析
  3. | トラックバック:0
  4. | コメント:0

ZYBO_0 を変更3(Ubuntu 14.04 LTSのBOOT.binを変更)

ZYBO_0 を変更2(インプリメント)”の続き。

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト”で上手く行ったので、”並列ステレオカメラによる距離の測定8(Ubuntuで動作するアプリケーションを作る1)”で作製したBOOT.bin をもう一度、再生成した。

SDKで FSBL を作製した。
Change_of_ZYBO0_41_160110.png

Change_of_ZYBO0_42_160110.png

Change_of_ZYBO0_43_160110.png

Project Exploer 上でFSBL を右クリックし、右クリックメニューからCreate Boot Image を選択した。

Creater Zynq Boot Image ダイアログが開いた。
以前のビット・ファイルが指定されていたので、一旦消去し、再設定した。
u-boot.elf を追加してから、Create Image ボタンをクリックした。
Change_of_ZYBO0_44_160110.png

BOOT.bin ができた。
Change_of_ZYBO0_45_160110.png

BOOT.bin をMicro SDカードにコピーした。

次に、devicetree を作るのだが、アドレス・マップを確認した所、変更箇所が無かったので、devicetree.dtb はそのままで問題ない。

MicroSDカードをZYBO に入れて電源ON。

Ubuntu 14.04 も無事起動したし、カメラ画像も写った。

もう1つのZYBO にZYBO_1_XGA_test を入れて、接続テストも行った所、成功した。
Change_of_ZYBO0_33_160107.jpg
Change_of_ZYBO0_34_160107.jpg
  1. 2016年01月10日 08:43 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS勉強会5(AXI4 Stream)を公開しました

Vivado HLS勉強会5(AXI4 Stream)を公開しました。

最後のVivado HLS勉強会資料になります。
Vivado HLS で AXI4 Stream インターフェースを使用する方法です。AXI4 Stream がAXI4 バスを使用するときの王道になると思っています。
フィルタを作る場合に、メモリからのDMAはXilinx 社のIP を使用して、フィルタ部分のソースコードだけをVivado HLS で作製するのが、今のところ最適化しやすくて良いと思っています。
なお、AXI4 Stream 編ではStream が使えるように、C++ を使用しています。

例によって、使用するコードを貼っておきます。

まずは、temp.bmp なんですが、ブログにはBMPファイルは貼れないので、画像をダウンロードしてから、BMPファイルへ変換してください。もしくは、画像をコピペして、画像ソフトでBMPファイルにするとか、よろしくお願いします。
test_160101.png

bmp_header.h を貼っておきます。

// bmp_header.h
// 2015/07/17 by Masaaki Ono
//
// BMP ファイルフォーマットから引用
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//

#pragma once

#include <stdio.h>
#include <tchar.h>


// TODO: プログラムに必要な追加ヘッダーをここで参照してください。
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
  unsigned short bfType;
  unsigned long  bfSize;
  unsigned short bfReserved1;
  unsigned short bfReserved2;
  unsigned long  bfOffBits;
} BITMAPFILEHEADER;

// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
    unsigned long  biSize;
    long           biWidth;
    long           biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned long  biCompression;
    unsigned long  biSizeImage;
    long           biXPixPerMeter;
    long           biYPixPerMeter;
    unsigned long  biClrUsed;
    unsigned long  biClrImporant;
} BITMAPINFOHEADER;

typedef struct BMP24bitsFORMAT {
    unsigned char blue;
    unsigned char green;
    unsigned char red;
} BMP24FORMAT;


lap_filter_axis.h を貼っておきます。

// lap_filter_axis.h
// 2015/05/01

//#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)


lap_filter_axis.cpp を貼っておきます。

//
// lap_filter_axis.cpp
// 2015/05/01
// 2015/06/25 : 修正、ラプラシアンフィルタの値が青だけ担っていたので、RGBに拡張した
//

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

#include "lap_filter_axis.h"

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

int lap_filter_axis(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#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> lap;

    unsigned int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete

    int lap_fil_val;

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

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

            for (int k=0; k<3; k++){
                for (int m=0; m<2; m++){
#pragma HLS UNROLL
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            int y_val = conv_rgb2y(pix.data);
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            lap_fil_val = laplacian_fil(    pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
                                        pix_mat[1][0], pix_mat[1][1], pix_mat[1][2], 
                                        pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
            lap.data = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる

            if (x<2 || y<2// 最初の2行とその他の行の最初の2列は無効データなので0とする
                lap.data = 0;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                lap.user = 1;
            else
                lap.user = 0;
            
            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                lap.last = 1;
            else
                lap.last = 0;

            outs << lap;    // 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);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}


lap_filter_axis_tb.cpp を貼っておきます。

// lap_filter_axis_tb.cpp
// 2015/05/01
// 2015/08/17 : BMPファイルを読み書きするように変更した
//

#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 "lap_filter_axis.h"
#include "bmp_header.h"

int lap_filter_axis(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);

int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axis_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height);

#define CLOCK_PERIOD 10

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;
    int xor_shift;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    int *rd_bmp, *hw_lapd;
    int blue, green, red;

    if ((fbmpr = fopen("test.bmp""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_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_lapd 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;
    }

    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;
        }
    }

    lap_filter_axis(ins, outs);
    lap_filter_axis_soft(ins_soft, outs_soft, bmpihr.biWidth, bmpihr.biHeight);

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    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_lapd[(j*bmpihr.biWidth)+i] = (int)val;

            if (val != val_soft){
                printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\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_lap.bmp へ出力する
    if ((fbmpw=fopen("temp_lap.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open temp_lap.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_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
            green = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
            red = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);
    free(rd_bmp);
    free(hw_lapd);

    return 0;
}

int lap_filter_axis_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height){
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> lap;
    unsigned int **line_buf;
    int pix_mat[3][3];
    int lap_fil_val;
    int i;

    // line_buf の1次元目の配列をアロケートする
    if ((line_buf =(unsigned int **)malloc(sizeof(unsigned int *) * 2)) == NULL){
        fprintf(stderr, "Can't allocate line_buf[3][]\n");
        exit(1);
    }

    // メモリをアロケートする
    for (i=0; i<2; i++){
        if ((line_buf[i]=(unsigned int *)malloc(sizeof(unsigned int) * width)) == NULL){
            fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
            exit(1);
        }
    }

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

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

            for (int k=0; k<3; k++){
                for (int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            int y_val = conv_rgb2y_soft(pix.data);
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            lap_fil_val = laplacian_fil_soft(    pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
                                        pix_mat[1][0], pix_mat[1][1], pix_mat[1][2], 
                                        pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
            lap.data = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる

            if (x<2 || y<2// 最初の2行とその他の行の最初の2列は無効データなので0とする
                lap.data = 0;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                lap.user = 1;
            else
                lap.user = 0;
            
            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                lap.last = 1;
            else
                lap.last = 0;

            outs << lap;    // AXI4-Stream へ出力
        }
    }

    for (i=0; i<2; i++)
        free(line_buf[i]);
    free(line_buf);

    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);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}


  1. 2016年01月09日 04:12 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト2

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト”の続き。

おるさんにコメントでご指摘頂いたので、ビットマップ・ディスプレイ・コントローラの画像用FIFOのアンダーフローではないか?と思い、FIFOの容量を変えるか?それともAXI4 Master のバス周波数を変えてみることにした。

FIFOの容量は変えるのが面倒なので、AXI4 インターフェース・バスのクロック周波数を変更することにした。
まずは、HDMI 画像の送り側のZYBO_0_2 のAXI4 バスのクロック周波数を変更する。

Zynq PS のFCLK_CLK0 がAXI4 バスのクロックなので、それを150 MHz に変更した。
Change_of_ZYBO0_36_160108.png

これでブロックデザインをセーブして、ビットストリームの生成まで行った所、タイミングでエラーが発生した。
Change_of_ZYBO0_37_160108.png

Timing を見たところ、clk_fpga_0 のSetup が -0.266 ns になっていた。後は、Inter-Clock Paths の clk_fpga_0 と clk_fpga_1 の間が問題あるようだった。
Change_of_ZYBO0_38_160108.png

だが、このまま確かめてみようということで、ハードウェアをエクスポートして、SDKを立ち上げて、テストしてみたところ、黒いドットは変わらなかった。

次は、受け側のZYBO_1_XGA_test のAXI4 バスのクロック周波数を変更することにした。

Zynq PS のFCLK_CLK0 がAXI4 バスのクロックなので、それを125 MHz に変更した。
Change_of_ZYBO0_39_160108.png

これでブロックデザインをセーブして、ビットストリームの生成まで行った。タイミングは満足した。
Change_of_ZYBO0_40_160108.png

同様に、ハードウェアをエクスポートして、SDKを立ち上げて、テストしてみたところ、やはり黒いドットの位置も場所も変更は無いようだった。

どうやら、ビットマップ・ディスプレイ・コントローラの画像用FIFOのアンダーフローではないらしい。AXI4 バスのクロック周波数を変更すれば、位置や数が変わるはずだと思う。

もしかしたら、rgb2dvi IP か dvi2rgb IPのバグなのだろうか?

実験後、ZYBO_0_2 と ZYBO_1_XGA_test のAXI4 バスのクロック周波数を 100 MHz に戻した。
  1. 2016年01月08日 05:09 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:2

ZYBO_0_2 と ZYBO_1_XGA_test との接続テスト

ZYBO_0 を変更2(インプリメント)”で、ZYBO_0 にDigilent 社の rgb2dvi IP を実装することができた。(ZYBO_0_2)

実は数日間、”Vivado のSDKのハードウェア・プラットフォームによる動作不良”で悩んで、上手く行かなかったのだが、Application Project を作りなおしたら、上手く動作するようになった。

そこで、以前、”ZYBO_0 と ZYBO_1_XGA_test との接続テスト”でもやったのだが、ZYBO_0_2 と ZYBO_1_XGA_test をHDMI で接続してテストしてみた。
ZYBO_1_XGA_test_18_151216.jpg

ZYBO_0_2 は、SDK にcam_lap_disp プロジェクトを追加して、スイッチでカメラの生画像とラプラシアンフィルタ画像を切り替えるようにしてある。
Change_of_ZYBO0_35_160107.png

下に、カメラの生画像の写真を示す。左の小さいディスプレイがZYBO_0_2 の元画像で、右の大きなディスプレイがZYBO_1_XGA_test でHDMI を経由した画像となる。
Change_of_ZYBO0_33_160107.jpg

やはり、HDMI で転送した画像には決まった間隔で黒いドットが見えるが、画像としてはこちらのほうがずっと安定している印象だ。

次に、ラプラシアンフィルタの画像を示す。
Change_of_ZYBO0_34_160107.jpg

うん、やはり、ZYBO_0 よりもZYBO_0_2 の方が安定している印象だ。こちらを使うことにしようと思う。

しかし、なんで違いが出るのだろうか?Digilent のIP のHDL とXDC を精査してみたい。
  1. 2016年01月07日 05:09 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:2

ZYBO_0 を変更2(インプリメント)

ZYBO_0 を変更1(ブロックデザインの修正)”の続き。

前回はZYBO_0 のDigilent 社のrgb2dvi IP を使用したブロックデザインが完成した。今回は、それをインプリメントして、ビットストリームを生成し、SDKでZYBO をコンフィギュレーションしてみよう。

ZYBO_0 ブロックデザインからZYBO_0_wrapper.v のトップVerilog HDL ファイルを生成した。
TMDS信号の名前が変更されている。
Change_of_ZYBO0_22_160102.png

トップHDL のTMDS 信号名が変更されているので、制約ファイル (ZYBO_0.xdc) を修正する必要がある。
下図のように制約ファイルを修正した。
Change_of_ZYBO0_23_160102.png

set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[0]}]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[1]}]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[2]}]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_Clk_p]
set_property PACKAGE_PIN D19 [get_ports {TMDS_Data_p[0]}]
set_property PACKAGE_PIN C20 [get_ports {TMDS_Data_p[1]}]
set_property PACKAGE_PIN B19 [get_ports {TMDS_Data_p[2]}]
set_property PACKAGE_PIN H16 [get_ports TMDS_Clk_p]


アドレス・マップは下図の様になった。Address Editor ウインドウを示す。
Change_of_ZYBO0_24_160102.png

これで、論理合成、インプリメント、ビットストリームの生成を行った所、Timing がエラーになった。
Change_of_ZYBO0_25_160102.png

Implemented Design を開いて、Timing Summary を見たところ、Inter-Clock Paths にエラーがあった。
Change_of_ZYBO0_26_160103.png

Inter-Clock Paths を開くと、clk_fpga_0 と clk_fpga_3 の間にエラーが発生していた。
Change_of_ZYBO0_27_160103.png

Vivado のImplemented Design で Report CDC を確認する”を参照して、、clk_fpga_0 と clk_fpga_3 の間の Clock Domain Crossing を見た。
Change_of_ZYBO0_28_160103.png

clk_fpga_3 から clk_fpga_0 への CDC はWarning のみだったが、clk_fpga_0 から clk_fpga_3 への CDC は Unknown が 1 個あった。
Unknown の 1 をクリックして、状況を確認した。
Change_of_ZYBO0_29_160103.png

リセット回路だった。このリセットも2段のFFで受けているところだったので、無視することにした。

Implemented Design から Edit Timing Constraints をクリックして、制約を追加する。
Timing Constraints タブで Set Clock Groups をクリックし、Double click to create a Set Clock Groups constraint をダブルクリックする。
Set Clock Groups ダイアログが表示される。
Group 1 に clk_fpga_0、Group 2 に clk_fpga_3 を指定して、OKボタンをクリックした。
Change_of_ZYBO0_30_160103.png

set_clock_groups -name FCLK_CLK0_FCLK_CLK3 -asynchronous -group [get_clocks clk_fpga_0] -group [get_clocks clk_fpga_3]

制約が追加された。
Change_of_ZYBO0_31_160103.png

これでもう一度、ビットストリーム生成をやり直すとTiming エラーは無くなった。
Change_of_ZYBO0_32_160103.png
  1. 2016年01月06日 06:39 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado のSDKのハードウェア・プラットフォームによる動作不良

SDK (Software Development Kit) を使用したVivado のプロセッサ・ベースのFPGA回路で、いろいろと検証して動かないはず無いんだけど、動かない時があります。分かってはいたのですが、相当、悩んでしまったので、その時の対処を書いておきます。

Vivado のIPI (IP Integrator) で回路を大幅に変更した時に、論理合成、インプリメント、ビットストリームの生成を行って、ハードウェアをエクスポートし、SDKを起動した時にハードウェア・プラットフォームが新しく出来てしまう場合があります。
下の図で言うと、ZYBO_0_wapper_hw_platform_0 と ZYBO_0_wapper_hw_platform_1 の2つのハードウェア・プラットフォームがあります。
SDK_hw_platform_1_160105.png

これは、最初に作られたのは ZYBO_0_wapper_hw_platform_0 だったんですが、途中でハードウェアを変更した後で、ZYBO_0_wapper_hw_platform_1 が新たに作製されました。

そこで問題になるのは、古いZYBO_0_wapper_hw_platform_0 で作製したApplication Project です。
Application Project は作成する時にHardware Platform を指定して作製します。つまりハードウェア・プラットフォームを元に生成されます。(たぶん。。。)
SDK_hw_platform_2_160105.png

よって、古いハードウェア・プラットフォームで生成されたApplication Project は新しいハードウェア・プラットフォームには対応できない場合があります。たぶん、IPのアドレス・マップが変更された場合は正常に動作することができません。
間違いを無くすためにも、新しいハードウェア・プラットフォームができていたら、既存のApplication Project と古いハードウェア・プラットフォームをすべて消去しておくのが安全だと思います。古いApplication Project のソフトウェアを動かすことがある場合は気をつけて、そのままにしておかなくては、ならないでしょうけれども。。。

Application Project の消去の仕方ですが、まずはApplication Project (BSPごと)消去する前に、ソースコードも消去してしまうので、必ず C や C++ のソースコードを ???.sdk フォルダにコピーしておきましょう。
ここでは、ZYBO_0_152.sdk -> cam_disp -> src フォルダにある cam_disp_axis.c ソースコードを ZYBO_0_152.sdk フォルダにコピー&ペーストしておきます。
SDK_hw_platform_5_160105.png

SDK_hw_platform_6_160105.png

cam_disp フォルダとcam_disp_bsp フォルダを消去します。
消去するフォルダを選択して右クリックし、右クリックメニューからDelete を選択します。
SDK_hw_platform_3_160105.png

Delete Resoures ダイアログが表示されます。
Delete project contents on disk (cannot be undone) のチェックボックスにチェックを入れて、OKボタンをクリックします。
SDK_hw_platform_4_160105.png

すると、cam_disp フォルダとcam_disp_bsp フォルダが完全に消去されます。
後は、Application Project を生成する手順で、新しい方のハードウェア・プラットフォームを指定して、再度生成します。

古いハードウェア・プラットフォームも消去しておきましょう。ハードウェア・プラットフォームはどれかのファイルを保存しておく必要はありません。
  1. 2016年01月05日 05:00 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

筑波山神社に歩いて初詣に行ってきました

今日はつくば市神郡の市営駐車場に車を置いて、筑波山神社まで歩いて初詣に行ってきました。
tsukubasan_1_160104.jpg

まだ筑波山を登る前に普通の民家なのですが、七味唐辛子を路上で売っているところがありまして、そこで七味唐辛子を購入しました。
七味唐辛子に入れるのは筑波山名物のふくれみかんと決まっていて、昔、子供の頃はこのみかんの皮を七味唐辛子に入れるのに剥かされたものです。ふくれみかんは小さいミカンで、中身はおいしくないですが、皮を日に干して七味唐辛子に入れるととっても風味が良くなります。ふくれみかんの気がありました。これです。
tsukubasan_2_160104.jpg

蕎麦屋のえだを過ぎて、ぐんぐん歩いて登っていきます。
tsukubasan_3_160104.jpg

tsukubasan_4_160104.jpg

今日は良い天気で風もなく、とっても良い日和でした。
登って行くと富士山も見えました。かなり大きく見えましたよ。

歩いて行くと筑波山神社に着きました。
tsukubasan_5_160104.jpg

筑波山神社の社殿でお参りをしました。
tsukubasan_6_160104.jpg

ここまでで、1.64 km 歩いて、264 m 登りました。GPSの腕時計を付けているので、計測しましたよ。

筑波山神社の参道の初めの辺りに紫峰牛がいました。いつからできているんでしょうか?
tsukubasan_7_160104.jpg

帰りに富士山が見えるかどうか?確かめましたが、見えました。下の写真の屋根の上に薄っすらと富士山の山頂が見えていたのですが、写真を縮小してしまったので、見えないと思います。
tsukubasan_8_160104.jpg

筑波山神社に歩いて初詣、とっても楽しかったです。。。
  1. 2016年01月02日 20:15 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ZYBO_0 を変更1(ブロックデザインの修正)

ZYBO_0 と ZYBO_1_XGA_test との接続テスト”でZYBO を使用して、HDMI 出力から画像を出力して、HDMI 入力で入力して表示することは出来たのだが、どうもHDMI 間の転送がミスしているビットがあるようだ。
そこで、Digilent Vivado libraryrgb2dvi IP を使用してHDMI 出力することにした。そのためには、bitmap_disp_cntrler_axi_master IP のTMDSインターフェースをDigilent 社のRGBインターフェースに変更する必要がある。また、今まで、bitmap_disp_cntrler_axi_master IP は25MHzのクロックを入れて、内部のMMCMで必要なピクセルクロックを生成していたが、外部からピクセルクロックを入力する方式に変更する。

ZYBO_0_154 フォルダをコピーして、ZYBO_0_154_2 フォルダとしてペーストした。

ZYBO_0_154_2 フォルダのZYBO_0_153.xpr をダブルクリックしてVivado 2015.4 を起動した。

IP Catalog を開いて、IP のパスを見てみたが、問題なくZYBO_0_154_2 フォルダに変換されていた。良くなっている。

ブロックデザインZYBO_0 を開いて、bitmap_disp_cntrler_axi_master_1のclk25、TMDS関連のポートの配線を削除した。
Change_of_ZYBO0_1_160102.png

bitmap_disp_cntrler_axi_master_1を右クリックして、右クリックから Edit in IP Packager... を選択してbitmap_disp_cntrler_axi_master IPを変更する。
Change_of_ZYBO0_2_160102.png

bitmap_disp_cntrler_axi_master.v を書き換えて、RGBインターフェースの信号をTMDS信号の代わりに追加した。
Change_of_ZYBO0_3_160102.png

Package IP タブに変更して、Ports and Interface をクリックし、vid_…信号を選択して、右クリックメニューから Add Bus Interface... を選択し、RGBインターフェースを生成する。
Change_of_ZYBO0_4_160102.png

Add Interface ダイアログが表示された。
Interface Definition を選択するために ... ボタンをクリックした。
Change_of_ZYBO0_5_160102.png

Interface Definition Chooser でRGB インターフェースのvid_io を選択した。
Change_of_ZYBO0_6_160102.png

Interface Definition に vid_io_rtl が表示された。
Name に RGB と入力した。
Display name に RGB Vivado Output (注:正しくは RGB Video Output )と入力し、OKボタンをクリックした。
Change_of_ZYBO0_7_160102.png

Port Mapping タブをクリックして、Interface's Logical Ports に DATA を選択し、IP's Physical Ports に vid_pData を選択した。
Map Ports ボタンをクリックした。
Change_of_ZYBO0_8_160102.png

Mapped Ports Summary に DATA と vid_pData が結び付けられた。
Change_of_ZYBO0_9_160102.png

同様に、すべてのRGB インターフェース信号を結び付けた。
Change_of_ZYBO0_10_160102.png

RGBインターフェースが定義できた。
Change_of_ZYBO0_11_160102.png

Package IP のCustomization GUI をクリックした。RGBインターフェースが確認できる。
Change_of_ZYBO0_12_160102.png

Review and Package をクリックし、Re-Package IP ボタンをクリックした。
Change_of_ZYBO0_13_160102.png

bitmap_disp_cntrler_axi_master IPの変更は終了した。
ZYBO_0 プロジェクトに戻ると、ブロックデザインの2ブロックがアップグレードされたというメッセージが出ていた。
Show IP Status をクリックした。
Change_of_ZYBO0_14_160102.png

IP Status ウインドウでUpgrade Selected ボタンをクリックした。
Change_of_ZYBO0_15_160102.png

Upgrade IP ボタンが表示された。OKボタンをクリックした。
Change_of_ZYBO0_16_160102.png

bitmap_disp_cntrler_axi_master IPが更新された。
IP Status ウインドウで Rerun ボタンをクリックした。
Change_of_ZYBO0_17_160102.png

これで、bitmap_disp_cntrler_axi_master IPが更新された。
Change_of_ZYBO0_18_160102.png

rgb2dvi IP はすでにAdd IP されていたが、ダブルクリックして、設定を行った。
TMDS clock range の < 120 MHz (720p) のラジオボタンをクリックして選択した。
Change_of_ZYBO0_19_160102.png

PSをダブルクリックして、Clock Configuration からBasic Clocking タブを選択し、PL Fabric Clocks を展開して、FCLK_CLK1 を40MHz (SVGA解像度のピクセルクロック)に、FCLK_CLK3 を 65 MHz (XGA解像度のピクセルクロック)に設定した。
Change_of_ZYBO0_20_160102.png

配線を接続してブロックデザインが完成した。
Change_of_ZYBO0_21_160102.png
  1. 2016年01月02日 08:18 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS勉強会4(AXI4 Master)を公開しました

2016年、あけましておめでとうございます。
今年の第一弾として、SlideShare に Vivado HLS勉強会4(AXI4 Master)を公開しました。

内容はと言うと、AXI4 Master インターフェースを使用した3つのCソースコードの実装のラプラシアンフィルタを高位合成し、C/RTLコシミュレーションで性能を比較します。
残念ながら、実機確認はありません。ご自分でFPGAの部屋のブログ記事を見ながら実装してみてください。
後、AXI4バスの知識が必須です。

例によって、使用するコードを貼っておきます。

まずは、temp.bmp なんですが、ブログにはBMPファイルは貼れないので、画像をダウンロードしてから、BMPファイルへ変換してください。もしくは、画像をコピペして、画像ソフトでBMPファイルにするとか、よろしくお願いします。
test_160101.png

bmp_header.h を貼っておきます。

// bmp_header.h
// 2015/07/17 by Masaaki Ono
//
// BMP ファイルフォーマットから引用
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//

#pragma once

#include <stdio.h>
#include <tchar.h>


// TODO: プログラムに必要な追加ヘッダーをここで参照してください。
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
  unsigned short bfType;
  unsigned long  bfSize;
  unsigned short bfReserved1;
  unsigned short bfReserved2;
  unsigned long  bfOffBits;
} BITMAPFILEHEADER;

// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
    unsigned long  biSize;
    long           biWidth;
    long           biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned long  biCompression;
    unsigned long  biSizeImage;
    long           biXPixPerMeter;
    long           biYPixPerMeter;
    unsigned long  biClrUsed;
    unsigned long  biClrImporant;
} BITMAPINFOHEADER;

typedef struct BMP24bitsFORMAT {
    unsigned char blue;
    unsigned char green;
    unsigned char red;
} BMP24FORMAT;


次に、laplacian_filter_soft.c を貼っておきます。

// laplacian_filter_soft.c
// m_axi offset=slave Version
// lap_filter_axim()
// 2015/08/26 by marsee
//

#include <stdio.h>
#include <string.h>

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48
//#define HORIZONTAL_PIXEL_WIDTH    800
//#define VERTICAL_PIXEL_WIDTH    600

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=return

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb

    int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                if (y == 1 && x == 1){ // 最初のラインの最初のピクセルでは2ライン分の画素を読み出す
                    for (a=0; a<2; a++){ // 2ライン分
                        for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
                            line_buf[a][b] = cam_fb[(a*HORIZONTAL_PIXEL_WIDTH)+b];
                            line_buf[a][b] = conv_rgb2y(line_buf[a][b]);
                        }
                    }
                }
                if (x == 1) {    // ラインの最初なので、2つのピクセルを読み込む
                    for (b=0; b<2; b++){ // ライン
                        line_buf[(y+1)%3][b] = cam_fb[((y+1)*HORIZONTAL_PIXEL_WIDTH)+b];
                        // (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
                        line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);
                    }
                }

                // 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
                line_buf[(y+1)%3][x+1] = cam_fb[((y+1)*HORIZONTAL_PIXEL_WIDTH)+(x+1)];
                // (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
                line_buf[(y+1)%3][x+1] = conv_rgb2y(line_buf[(y+1)%3][x+1]);

                fl = (y-1)%3;    // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
                sl = y%3;        // 2番めのライン
                tl = (y+1)%3;    // 3番目のライン
                lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            // ラプラシアンフィルタ・データの書き込み
            lap_fb[(y*HORIZONTAL_PIXEL_WIDTH)+x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
            // printf("x = %d  y = %d", x, y);
        }
     }
     return(1);
}

// 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);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}


lap_filter_tb.c を貼っておきます。

// Testbench of laplacian_filter.c
// lap_filter_tb.c
// BMPデータをハードウェアとソフトウェアで、ラプラシアン・フィルタを掛けて、それを比較する
// m_axi offset=slave version
// 2015/08/26 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bmp_header.h"

int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb);    // hardware
void laplacian_filter_soft(int *cam_fb, int *lap_fb, long width, long height); // software

int main()
{
    int *s, *h;
    long x, y;
    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    int *rd_bmp, *hw_lapd, *sw_lapd;
    int blue, green, red;
    char blue_c, green_c, red_c;
    
    if ((fbmpr = fopen("test.bmp""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_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_lapd memory\n");
        exit(1);
    }
    if ((sw_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate sw_lapd memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (y=0; y<bmpihr.biHeight; y++){
        for (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);

    lap_filter_axim((int *)rd_bmp, (int *)hw_lapd);    // ハードウェアのラプラシアン・フィルタ
    laplacian_filter_soft(rd_bmp, sw_lapd, bmpihr.biWidth, bmpihr.biHeight);    // ソフトウェアのラプラシアン・フィルタ
    
    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    for (y=0, h=hw_lapd, s=sw_lapd; y<bmpihr.biHeight; y++){
        for (x=0; x<bmpihr.biWidth; x++){
            if (*h != *s){
                printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %d, SW = %d\n", x, y, *h, *s);
                return(1);
            } else {
                h++;
                s++;
            }
        }
    }
    printf("Success HW and SW results match\n");

    // ハードウェアのラプラシアンフィルタの結果を temp_lap.bmp へ出力する
    if ((fbmpw=fopen("temp_lap.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open temp_lap.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 (y=0; y<bmpihr.biHeight; y++){
        for (x=0; x<bmpihr.biWidth; x++){
            blue = hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
            green = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
            red = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);
    free(rd_bmp);
    free(hw_lapd);
    free(sw_lapd);

    return(0);
}

void laplacian_filter_soft(int *cam_fb, int *lap_fb, long width, long height)
{
    int **line_buf;
    int *lap_buf;
    int x, y, i;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;

    // line_buf の1次元目の配列をアロケートする
    if ((line_buf =(int **)malloc(sizeof(int *) * 3)) == NULL){
        fprintf(stderr, "Can't allocate line_buf[3][]\n");
        exit(1);
    }

    // メモリをアロケートする
    for (i=0; i<3; i++){
        if ((line_buf[i]=(int *)malloc(sizeof(int) * width)) == NULL){
            fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
            exit(1);
        }
    }

    if ((lap_buf=(int *)malloc(sizeof(int) * (width))) == NULL){
        fprintf(stderr, "Can't allocate lap_buf memory\n");
        exit(1);
    }

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0; y<height; y++){
        for (x=0; x<width; x++){
            if (y==0 || y==height-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==width-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                if (y == 1 && x == 1){ // 最初のラインの最初のピクセルでは2ライン分の画素を読み出す
                    for (a=0; a<2; a++){ // 2ライン分
                        for (b=0; b<width; b++){ // ライン
                            line_buf[a][b] = cam_fb[(a*width)+b];
                            line_buf[a][b] = conv_rgb2y_soft(line_buf[a][b]);
                        }
                    }
                }
                if (x == 1) {    // ラインの最初なので、2つのピクセルを読み込む
                    for (b=0; b<2; b++){ // ライン
                        line_buf[(y+1)%3][b] = cam_fb[((y+1)*width)+b];
                        // (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
                        line_buf[(y+1)%3][b] = conv_rgb2y_soft(line_buf[(y+1)%3][b]);
                    }
                }

                // 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
                line_buf[(y+1)%3][x+1] = cam_fb[((y+1)*width)+(x+1)];
                // (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
                line_buf[(y+1)%3][x+1] = conv_rgb2y_soft(line_buf[(y+1)%3][x+1]);

                fl = (y-1)%3;    // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
                sl = y%3;        // 2番めのライン
                tl = (y+1)%3;    // 3番目のライン
                lap_fil_val = laplacian_fil_soft(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            // ラプラシアンフィルタ・データの書き込み
            lap_fb[(y*width)+x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
        }
    }
    free(lap_buf);
    for (i=0; i<3; i++)
        free(line_buf[i]);
    free(line_buf);
}

// 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);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}


laplacian_filter2.c を貼っておきます。

// laplacian_filter2.c
// lap_filter_axim()
// m_axi offset=slave version
// 2015/08/26 by marsee
//

#include <stdio.h>
#include <string.h>

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48
//#define HORIZONTAL_PIXEL_WIDTH    800
//#define VERTICAL_PIXEL_WIDTH    600
#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=return

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb

    int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
    int lap_buf[HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;
    int line_sel;

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0, line_sel=0; y<VERTICAL_PIXEL_WIDTH; y++){
        // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
        switch(line_sel){
            case 1 :
                fl = 0; sl = 1; tl = 2;
                break;
            case 2 :
                fl = 1; sl = 2; tl = 0;
                break;
            case 3 :
                fl = 2; sl = 0; tl = 1;
                break;
            default :
                fl = 0; sl = 1; tl = 2;
        }

        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                 if (x == 1){ // ラインの最初でラインの画素を読み出す
                    if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
                        for (a=0; a<3; a++){ // 3ライン分
                            memcpy(&line_buf[a][0], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                            for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
#pragma HLS PIPELINE
 // ライン
                                line_buf[a][b] = conv_rgb2y(line_buf[a][b]);    // カラーから白黒へ
                            }
                        }
                    } else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
                         memcpy(line_buf[tl], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                        for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
#pragma HLS PIPELINE
 // ライン
                            line_buf[tl][b] = conv_rgb2y(line_buf[tl][b]);    // カラーから白黒へ
                        }
                    }
                }
                lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
        }
        memcpy(&((int *)lap_fb)[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));

        line_sel++;
        if (line_sel > 3){
            line_sel = 1;
        }
    }
    return(1);
}

// 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);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}


laplacian_filter3.c を貼っておきます。

// laplacian_filter3.c
// m_axi offset=slave version
// 2015/08/26
//

#include <stdio.h>
#include <string.h>

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48
//#define HORIZONTAL_PIXEL_WIDTH    800
//#define VERTICAL_PIXEL_WIDTH    600
#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=return

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb

    int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=3 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    int lap_buf[HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;
    int line_sel;
    int prev[3],current[3],next[3];    // 0->1ライン目, 1->2ライン目, 2->3ライン目, prev->1pixel前, current->現在, next->次pixel
#pragma HLS array_partition variable=prev complete dim=0
#pragma HLS array_partition variable=current complete dim=0
#pragma HLS array_partition variable=next complete dim=0


    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0, line_sel=0; y<VERTICAL_PIXEL_WIDTH-1; y++){
        // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
        switch(line_sel){
            case 1 :
                fl = 0; sl = 1; tl = 2;
                break;
            case 2 :
                fl = 1; sl = 2; tl = 0;
                break;
            case 3 :
                fl = 2; sl = 0; tl = 1;
                break;
            default :
                fl = 0; sl = 1; tl = 2;
        }

        if (y == 1){
#ifndef __SYNTHESIS__
            printf("copy 3 lines\n");
#endif
            for (a=0; a<3; a++){
 // 3ライン分
                memcpy(line_buf[a], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
            }
        }else// 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
            memcpy(line_buf[tl], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
        }
        if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){
            for(b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
                lap_buf[b] = 0;
            }
        } else {
            next[0] = conv_rgb2y(line_buf[fl][0]);
            next[1] = conv_rgb2y(line_buf[sl][0]);
            next[2] = conv_rgb2y(line_buf[tl][0]);

            for (x = 0; x < HORIZONTAL_PIXEL_WIDTH; x++){
                if (x == 0 || x == HORIZONTAL_PIXEL_WIDTH-1){
                    lap_fil_val = 0;

                    current[0] = next[0];
                    next[0] = conv_rgb2y(line_buf[fl][1]);

                    current[1] = next[1];
                    next[1] = conv_rgb2y(line_buf[sl][1]);

                    current[2] = next[2];
                    next[2] = conv_rgb2y(line_buf[tl][1]);
                }else{
                    prev[0] = current[0];
                    current[0] = next[0];
                    next[0] = conv_rgb2y(line_buf[fl][x+1]);

                    prev[1] = current[1];
                    current[1] = next[1];
                    next[1] = conv_rgb2y(line_buf[sl][x+1]);

                    prev[2] = current[2];
                    current[2] = next[2];
                    next[2] = conv_rgb2y(line_buf[tl][x+1]);
#pragma HLS pipeline
                    lap_fil_val = laplacian_fil(prev[0], current[0], next[0],
                                                prev[1], current[1], next[1],
                                                prev[2], current[2], next[2]);
                }
                lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
            }
        }
#ifndef __SYNTHESIS__
        printf("write back:%d\n", y);
#endif
        memcpy((int*)&lap_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));

        line_sel++;
        if (line_sel > 3){
            line_sel = 1;
        }
    }

    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 : line[sl]oat を止めて、すべて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);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}

  1. 2016年01月01日 04:44 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:2