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

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

FPGAの部屋

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

Ultra96用PMOD拡張ボード9(基板の改版2)

Ultra96用PMOD拡張ボード8(基板の改版1)”の続き。

前回は、Ultra96 用PMOD 拡張ボードの回路図にプルアップ抵抗を追加して、基板図面にエクスポートした。今回は、FreeRouter で自動配線を行って、基板図面を完成させよう。

KiCadのインストールとローカルライブラリ参照設定”を参照してFreeRouter をUbuntu 16.08 にインストールした。
まずは、

https://github.com/freerouting/freerouting/files/1282814/freeroute.jar.zip

からfreeroute.jar.zip をダウンロードした。
Ultra96_ext_board2_4_181129.png

freeroute.jar を /user/bin にコピーして、実行パーミッションを入れた。
sudo mv freeroute.jar /usr/bin/
sudo chmod +x /usr/bin/freeroute.jar

freeroute.jar で起動した。
Ultra96_ext_board2_5_181129.png

Ultra96_ext_board2_6_181129.png

KiCad 5.0 からFreeRouter へのデータの渡し方が変更になったようだ。
Pcbnew のFile メニュー -> Export -> Specctra DSN... を選択する。
Specctra DSN File ダイアログでエクスポートする名前を決める。拡張子は .dsn のようだ。
Ultra96_ext_board2_7_181129.png

dsn ファイルをセーブしたらFreeRouter の Open Your Own Design をクリックして、dsn ファイルを選択する。
Ultra96_ext_board2_8_181129.png

ダイアログが表示された。はいをクリックした。
Ultra96_ext_board2_9_181129.png

デザインがロードされた。
Ultra96_ext_board2_11_181129.pngUltra96_ext_board2_10_181129.png

Autorouter ボタンをクリックして自動配線を行って、10分ほどやったかな?完成した。
Ultra96_ext_board2_12_181129.png

FreeRouter のFile メニューからExport Specctra Session File を選択して、ses ファイルを出力した。

Pcbnew のFile メニュー -> Import -> Specctra Session... を選択した。
Merge Specctra Session File: ダイアログで ses ファイルを選択して、FreeRouter の自動配線結果を取り込んだ。
Ultra96_ext_board2_13_181129.png

GNDベタを表面、裏面に設定して基板が完成した。
Ultra96_ext_board2_14_181130.png

DRC もエラーなしだった。
Ultra96_ext_board2_15_181130.png
  1. 2018年11月30日 06:39 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボード8(基板の改版1)

Ultra96用PMOD拡張ボード7(部品を実装した)”の続き。

Ultra96用PMOD拡張ボードは、+3.3V 側にプルアップ抵抗を付け忘れていた。よって、プルアップ抵抗を +3.3V の全出力ピンに追加する。

今回から KiCad 5.0 を使用することにした。今回からFreeRouter の使用方法が変更になっているようだ。

まずは、回路図でR5 〜 R20 を追加した。
Ultra96_ext_board2_1_181129.png

R5 〜 R20 のパッケージは手付用の1608 にした。
Ultra96_ext_board2_2_181129.png

基板は配線をすべて削除してラッツネットとした。基板外形の横を少し伸ばした。横 58 mm X 縦 34 mm 程度となった。
Ultra96_ext_board2_3_181129.png

次はFreeRouter を使用して配線していこう。
  1. 2018年11月29日 05:02 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードの波形の観察

Ultra96用PMOD拡張ボードでカメラ入力13(Debian上でカメラ画像を画像ファイルに3)”でカメラの画像をBMPファイルに変換することができたので、Ultra96用PMOD拡張ボードの波形をオシロスコープで観察することにした。

OWON SDS-1102(オシロスコープ)を買いました”で購入したオシロスコープでMT9D111 カメラのI2C の波形を観察する。
CH1 がSCL(クロック) でCH2 がSDA(データ)の +3.3V 側を測定している。
oscilloscope_11_181128.jpg

綺麗な波形だと言える。
I2C Write の全体を入れてみる。
oscilloscope_12_181128.jpg

問題なさそうだ。

次に、MT9D111 のカメラ画像データの D5 を見てみよう。これも +3.3V 側の波形だ。
oscilloscope_13_181128.jpg

次に、そのD5 に 1kΩの抵抗を付けてみる。
oscilloscope_14_181128.jpg

D5 に 1kΩの抵抗を付けたときの波形を示す。
oscilloscope_15_181128.jpg

問題なさそうだ。
これで、3.3V 側が出力にピンに 1kΩのプルアップ抵抗も影響は無いようだ。BMPファイルにした画像も問題なかった。
これで、心置きなくUltra96用PMOD拡張ボードの改版をすることができる。
  1. 2018年11月28日 05:17 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力13(Debian上でカメラ画像を画像ファイルに3)

Ultra96用PMOD拡張ボードでカメラ入力12(Debian上でカメラ画像を画像ファイルに2)”の続き。

前回は、、uio と udmabuf のロードを行った。今回はいよいよ cam_capture.cpp を作成して、カメラ画像をBMPファイルにしてみよう。

最初に、デバイスツリーをロードして、uio と udmabuf をユーザー・モードから使用できるようにするスクリプト lddtovray.sh を書いた。
Ultra97_cam_capture_25_181127.png

#!/bin/bash

sudo mkdir /config/device-tree/overlays/fpga
sudo cp fpga-load.dtb /config/device-tree/overlays/fpga/dtbo
sudo mkdir /config/device-tree/overlays/fclk01
sudo cp fclk01-zynqmp.dtb /config/device-tree/overlays/fclk01/dtbo
sudo mkdir /config/device-tree/overlays/cam_capture
sudo cp cam_capture.dtb /config/device-tree/overlays/cam_capture/dtbo

sleep 0.5
sudo chmod 666 /dev/uio*
sudo chmod 666 /dev/udmabuf4


デバイスツリーを削除する rmdtovray.sh も作成した。
Ultra97_cam_capture_26_181127.png

#!/bin/bash

sudo rmdir /config/device-tree/overlays/cam_capture/
sudo rmdir /config/device-tree/overlays/fclk01
sudo rmdir /config/device-tree/overlays/fpga/


最初に、 lddtovray.sh を実行してから、cam_capture を実行してBMP ファイルを作成する。
なお、~/examples/cam_capture/build で cam_capture.cpp を g++_opencv cam_capture.cpp でビルドして、 cam_capture 実行ファイルを作成してある。g++_opencv コマンドについてはこちらを参照のこと。
./lddtovray.sh
cd build
./cam_capture

そして、 w コマンドを 2 回入力した。
Ultra97_cam_capture_21_181127.png

nautilus をみると、bmp_file0.bmp と bmp_file1.bmp が作成されていた。成功だ。。。
Ultra97_cam_capture_22_181127.png

bmp_file0.bmp を示す。
Ultra97_cam_capture_23_181127.jpg

bmp_file1.bmp を示す。
Ultra97_cam_capture_24_181127.jpg

部屋が散らかっているが気にしないで。。。
無線LAN経由でカメラ画像のBMPファイルが取得できた。なお、今回はOpenCV を使用している。

cam_capture.cpp を示す。
Ultra97_cam_capture_27_181127.png

ソースコードを貼っておく。

// cam_capture.cpp (for Ultra96)
// 2018/11/25 by marsee
//
// This software converts the left and right of the camera image to BMP file.
// -b : bmp file name
// -n : Start File Number
// -h : help
//

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

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

#define PIXEL_NUM_OF_BYTES    4

#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 SVGA_3_PICTURES         (SVGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

int WriteBMPfile(char *bmp_file, volatile unsigned int *frame_buffer, int active_frame);

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 argc, char *argv[]){
    int opt;
    int c, help_flag=0;
    char bmp_fn[256] = "bmp_file";
    char  attr[1024];
    unsigned long  phys_addr;
    int file_no = -1;
    int fd1, fd2, fd3, fd10, fd11;
    volatile unsigned int *mt9d111_inf_axis, *axi_iic, *DMA_Write_sFB;
    volatile unsigned int *frame_buffer;
    int active_frame;
    
     while ((opt=getopt(argc, argv, "b:n:h")) != -1){
        switch (opt){
            case 'b':
                strcpy(bmp_fn, optarg);
                break;
            case 'n':
                file_no = atoi(optarg);
                break;
            case 'h':
                help_flag = 1;
                break;
        }
    }

    if (help_flag == 1){ // help
        printf("Usage : cam_capture [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
        exit(0);
    }
    
    // mt9d111_inf_axis-uio IP
    fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (mt9d111_inf_axis) open error\n");
        exit(-1);
    }
    mt9d111_inf_axis = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!mt9d111_inf_axis){
        fprintf(stderr, "mt9d111_inf_axis mmap error\n");
        exit(-1);
    }
    
    // axi_iic-uio IP
    fd2 = open("/dev/uio2", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axi_iic) open error\n");
        exit(-1);
    }
    axi_iic = (volatile unsigned int *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axi_iic){
        fprintf(stderr, "axi_iic mmap error\n");
        exit(-1);
    }

    // DMA_Write_sFB-uio IP
    fd3 = open("/dev/uio3", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (DMA_Write_sFB) open error\n");
        exit(-1);
    }
    DMA_Write_sFB = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!DMA_Write_sFB){
        fprintf(stderr, "DMA_Write_sFB mmap error\n");
        exit(-1);
    }

    // udmabuf4
    fd10 = open("/dev/udmabuf4", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd10 == -1){
        fprintf(stderr, "/dev/udmabuf4 open error\n");
        exit(-1);
    }
    frame_buffer = (volatile unsigned int *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd10, 0);
    if (!frame_buffer){
        fprintf(stderr, "frame_buffer4 mmap error\n");
        exit(-1);
    }
    
    // phys_addr of udmabuf4
    fd11 = open("/sys/class/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd11 == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf4/phys_addr open error\n");
        exit(-1);
    }
    read(fd11, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd11);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    // XDMA_Write_sFB start
    DMA_Write_sFB[6] = phys_addr; // fb0
    DMA_Write_sFB[8] = phys_addr+SVGA_ALL_DISP_ADDRESS; // fb1
    DMA_Write_sFB[10] = phys_addr+2*SVGA_ALL_DISP_ADDRESS; // fb2
    DMA_Write_sFB[0] = 0x1; // start
    DMA_Write_sFB[0] = 0x80; // EnableAutoRestart
    
    mt9d111_inf_axis[0] = phys_addr; // MT9D111 AXI4-Stream Start
    
    // CMOS Camera initialize, MT9D111
    cam_i2c_init(axi_iic);
    
    cam_i2c_write(axi_iic, 0xba, 0xf0, 0x1);        // Changed regster map to IFP page 1
    cam_i2c_write(axi_iic, 0xba, 0x97, 0x20);   // RGB Mode, RGB565

    mt9d111_inf_axis[1] = 0;
    
    char bmp_file[256];

    // w - writed the left and right eye's bmp files.  q - exit.
    c = getc(stdin);
    while(c != 'q'){
        switch ((char)c) {
            case 'w' : // w - writed a bmp files.
                // writed the frame buffer
                file_no++;
                sprintf(bmp_file, "%s%d.bmp", bmp_fn, file_no);
                active_frame = (int)(DMA_Write_sFB[12] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame);
                
                printf("file No. = %d\n", file_no);

                break;
            case 'e' : // e - writed a same bmp files.
                // writed the frame buffer
                if (file_no == -1)
                    file_no = 0;
                
                sprintf(bmp_file, "%s%d.bmp", bmp_fn, file_no);
                active_frame = (int)(DMA_Write_sFB[12] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame);
                
                printf("file No. = %d\n", file_no);

                break;
        }
        c = getc(stdin);
    }
    
    munmap((void *)mt9d111_inf_axis, 0x1000);
    munmap((void *)axi_iic, 0x1000);
    munmap((void *)DMA_Write_sFB, 0x10000);
    munmap((void *)frame_buffer, 576000);
    
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd10);
    
    return(0);
}

int WriteBMPfile(char *bmp_file, volatile unsigned int *frame_buffer, int active_frame){
    int read_frame;
    
    if (active_frame == 0)
        read_frame = 2;
    else if (active_frame == 1)
        read_frame = 0;
    else // active_frame == 2
        read_frame = 1;
    int offset_addr = read_frame * SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES;
    
    cv::Mat img(SVGA_VERTICAL_LINES, SVGA_HORIZONTAL_PIXELS, CV_8UC3);

    cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
    for(int y=0; y<img.rows; y++){
        for(int x=0; x<img.cols; x++){
            cv::Vec3b pixel;
            int rgb = frame_buffer[offset_addr+y*img.cols+x];
            pixel[0] = (rgb & 0xff); // blue
            pixel[1] = (rgb & 0xff00) >> 8; // green
            pixel[2] = (rgb & 0xff0000) >> 16; // red
            dst_vec3b(y,x) = pixel;
        }
    }
    
    imwrite(bmp_file, img);
    
    return(0);
}


cam_capture.cpp を作成した際の参照ブログ
ZYBOt のコースの写真撮影用アプリケーションソフトの開発
Ultra96用PMOD拡張ボードでカメラ入力9(Vivado 2018.2のcam_test_182プロジェクト6)
  1. 2018年11月27日 05:15 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

つくばマラソンの10kmの部に出場しました

昨日はつくばマラソンの 10 km の部に出場しました。

2週間前にはいわい将門ハーフマラソン大会の 10 km の部に出場して 1 時間切れなくて悔しい思いをしました。

記録は、1 時間 00 分 16秒でした(ネットタイムです)。
Tsukuba_marathon_2_181126.jpg

今日こそは 60 分を切るぞ。。。(私のベストタイムは 5 分 45 秒/km 程度、つまり 57 分 30 秒/10 km くらいです)
ということで、つくば市役所の駐車場に止めて、研究学園駅からのシャトルバスに乗って、筑波大学の会場に行きました。
Tsukuba_marathon_3_181126.jpg

会場で被り物をして走るランナーがいました。これは、ガマのバルーンアートの被り物です。フルマラソンを5時間位で走れるとのことでした。凄いです。
Tsukuba_marathon_4_181126.jpg

Tsukuba_marathon_5_181126.jpg

10 km 走って結果は、59分37秒でした。つくばマラソンはスタート時は混んでいてスピードが出せません。大体、5分45秒/km くらいで走ってました。
Tsukuba_marathon_7_181126.jpg
  1. 2018年11月26日 05:37 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力12(Debian上でカメラ画像を画像ファイルに2)

Ultra96用PMOD拡張ボードでカメラ入力11(Debian上でカメラ画像を画像ファイルに1)”の続き。

前回は、Ultra96 のDebian 上でビットファイルをロードし、クロックのデバイスツリーをロードした。今回は、引き続き、uio と udmabuf のロードを行う。

cam_capture.dts を示す。

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        #address-cells = <2>;
        #size-cells = <2>;

        __overlay__ {
            #address-cells = <2>;
            #size-cells = <2>;

            mt9d111_inf_axis-uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0000000 0x0 0x1000>;
            };
            
            axi_iic-uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0001000 0x0 0x1000>;
            };
            
            DMA_Write_sFB-uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0010000 0x0 0x10000>;
            };

            cam_capture-udmabuf4 {
                compatible  = "ikwzm,udmabuf-0.10.a";
                device-name = "udmabuf4";
                size = <0x00800000>;
            };
        };
    };
};


dtc でコンパイルし、デバイスツリーをロードする。
dtc -I dts -O dtb -o cam_capture.dtb cam_capture.dts
sudo mkdir /config/device-tree/overlays/cam_capture
sudo cp cam_capture.dtb /config/device-tree/overlays/cam_capture/dtbo

Ultra97_cam_capture_15_181124.png

シリアルコンソールの表示を示す。
Ultra97_cam_capture_16_181124.png

/sys/class/uio に行って、uio を見てみよう。
uio1 は mt9d111_inf_axis-uio だった。
Ultra97_cam_capture_17_181124.png

uio2 は axi_iic-uio だった。
Ultra97_cam_capture_18_181124.png

uio3 は DMA_Write_sFB-uio だった。
Ultra97_cam_capture_19_181124.png

/sys/class/udmabuf/udmabuf4 を見てみよう。
size の 8388608 は 16 進数で、0x800000 になった。これで正しい。
Ultra97_cam_capture_20_181124.png
  1. 2018年11月25日 04:45 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力11(Debian上でカメラ画像を画像ファイルに1)

Ultra96用PMOD拡張ボードでカメラ入力11(Vivado 2018.2のcam_test_182プロジェクト8)”の続き。

前回は、cam_test_182 プロジェクトのビットファイルをUltra96 にダウンロードして、アプリケーションを起動し、Vivado Analyzer で動作を確かめた。ただし、動作しているという概況を見ただけで、画像データが正しいかどうかは確認していない。それはこれから、カメラ画像を画像ファイルにして、その画像ファイルを確認することで確かめていこう。今回は、デバイスツリーを作成して、ロードしてみよう。

まずは、cam_test_wrapper.bin を作成していこう。”Ultra96 ボードでデバイスツリー・オーバーレイをテストする1”を見ながらやっていこう。
まずは、パソコンで、cam_test_wrapper.bif を作成した。下に貼っておく。

all:
{
    [destination_device = pl] cam_test_wrapper.bit
}


cam_test_wrapper.bif を使ってcam_test_wrapper.bin を作成した。
bootgen -image cam_test_wrapper.bif -arch zynqmp -w -o cam_test_wrapper.bin
Ultra97_cam_capture_7_181124.png

Ultra97_cam_capture_8_181124.png

cam_test_wrapper.bin が出来たので、Ultra96 の /home/fpga/examples/cam_capture ディレクトリにSFTP でアップロードした。
Ultra97_cam_capture_9_181124.png

デバイスツリー・オーバーレイでFPGA のコンフィグレーションをやってみる。
ここからは、Ultra96 ボード上のDebian での作業となる。
fpga-load.dts を作成した。

/dts-v1/;
/ {
    fragment@0 {
        target-path = "/fpga-full";
        __overlay__ {
            firmware-name = "cam_test_wrapper.bin";
        };
    };
};


bin ファイルをFTP で持ってきたので、/lib/firmware/ にコピーする。
sudo cp cam_test_wrapper.bin /lib/firmware/
ls /lib/firmware/


dtc で fpga-load.dts をコンパイルした。
dtc -I dts -O dtb -o fpga-load.dtb fpga-load.dts
Warning が出ている。

fpga-load.dtb: Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property


fpgaをコンフィグレーションしてみよう。
sudo mkdir /config/device-tree/overlays/fpga
sudo cp fpga-load.dtb /config/device-tree/overlays/fpga/dtbo
Ultra97_cam_capture_11_181124.png  

シリアル・コンソールに

[ 9987.623945] fpga_manager fpga0: writing cam_test_wrapper.bin to Xilinx ZynqMP FPGA Manager

と表示された。そして、DONE LED が点灯した。
Ultra97_cam_capture_12_181124.png

次に、デバイスツリー・オーバーレイでクロックの設定を行う。
fclk01-zynqmp.dts を作成した。

dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba";
        __overlay__ {
            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clk 0x47>;
                insert-rate   = "100000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
            
            fclk1 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clk 0x48>;
                insert-rate   = "72000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
        };
    };
};


デバイスツリーをコンパイルした。
dtc -I dts -O dtb -o fclk01-zynqmp.dtb fclk01-zynqmp.dts
fpga-load.dts のときと同じWarning が出た。

デバイスツリーをロードする。
sudo mkdir /config/device-tree/overlays/fclk01
sudo cp fclk01-zynqmp.dtb /config/device-tree/overlays/fclk01/dtbo

Ultra97_cam_capture_13_181124.png

シリアル・コンソールにデバイスツリー・オーバーレイのメッセージが表示された。
Ultra97_cam_capture_14_181124.png

[10828.061267] fclkcfg: loading out-of-tree module taints kernel.
[10828.061269] fclkcfg: loading out-of-tree module taints kernel.
[10828.062455] fclkcfg amba:fclk0: driver installed.
[10828.062458] fclkcfg amba:fclk0: device name    : fclk0
[10828.062462] fclkcfg amba:fclk0: clock  name    : pl0_ref
[10828.062465] fclkcfg amba:fclk0: clock  rate    : 99999999
[10828.062482] fclkcfg amba:fclk0: clock  enabled : 1
[10828.062485] fclkcfg amba:fclk0: remove rate    : 1000000
[10828.062488] fclkcfg amba:fclk0: remove enable  : 0
[10828.062797] fclkcfg amba:fclk1: driver installed.
[10828.062800] fclkcfg amba:fclk1: device name    : fclk1
[10828.062803] fclkcfg amba:fclk1: clock  name    : pl1_ref
[10828.062807] fclkcfg amba:fclk1: clock  rate    : 71387421
[10828.062823] fclkcfg amba:fclk1: clock  enabled : 1
[10828.062826] fclkcfg amba:fclk1: remove rate    : 1000000
[10828.062829] fclkcfg amba:fclk1: remove enable  : 0


fclk2 は 72 MHz に設定したのだが、実際の周波数は約 71.4 MHz になったようだ。
  1. 2018年11月24日 08:08 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

映画『ファンタスティック・ビーストと黒い魔法使いの誕生』を見てきました

映画『ファンタスティック・ビーストと黒い魔法使いの誕生』を見てきました。シリーズ物なので、見てきたんですが、魔法シーンは迫力はありましたね。なんか、飽きてきたような気がしてきましたが。また、次回に続く終わり方でした。また、次回見に行ってしまうでしょう。
  1. 2018年11月23日 20:51 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ultra96 のboot.bin を変更

以前作製したboot.bin は低速コネクタでLチカするビットファイルが入っているに気がついた。これでは、カメラを取り付けたときに出力同士がぶつかってしまう。
そこで、ビットファイルを抜いて、boot.bin を作り直すことにした。

前回、boot.bin を作ったのは、”Ultra96 で ikwzm さんのDebian9 Root File Systemを動かしてみる4”だった。
そこのbuild_bootbin.bif を下のように書き換えた。

the_ROM_image:
{
  [init] regs.init
  [pmufw_image, destination_cpu=a53-0] pmufw.elf
  [bootloader, destination_cpu=a53-0] fsbl.elf
  //[destination_device=pl] DMA_pow2_test_wrapper.bit
  [destination_cpu=a53-0, exception_level=el-3] bl31.elf
  [destination_cpu=a53-0, exception_level=el-2] u-boot.elf
}


つまり、ビットファイルのエントリをコメントアウトした。

次に、boot.bin を生成した。
bootgen -arch zynqmp -image build_bootbin.bif -o i boot.bin -w on -log trace > bootgen_log.txt

boot.bin が生成された。以前にビットファイルを入れているときは、6.6 MB の容量だったが、1.0 MB になった。
Ultra97_cam_capture_6_181123.png

bootgen_log.txt を示す。ビットファイルが抜けている。

[TRACE]  : Command Line parsing started
[TRACE]  : Command: -arch zynqmp -image build_bootbin.bif -o i boot.bin -w on -log trace
[INFO]   : Command line parsing completed successfully
[INFO]   : Bootgen Version - 2017.4, Nov 23, 2017
[TRACE]  : BIF File: build_bootbin.bif
[TRACE]  : BIF file parsing started
[TRACE]  : Creating ZYNQ MP Factory
[INFO]   : Filename: regs.init
[INFO]   : Filename: pmufw.elf
[INFO]   : Filename: fsbl.elf
[INFO]   : Parsing Partition Data
[INFO]   : Filename: bl31.elf
[INFO]   : Parsing Partition Data
[INFO]   : Filename: u-boot.elf
[INFO]   : Parsing Partition Data
[INFO]   : BIF file parsing completed successfully
[INFO]   : Building image - the_ROM_image
[INFO]   : Started RE parsing : regs.init
[INFO]   : count [0xff41a040], value = 3
[INFO]   : Done RE parsing : regs.init. Added 1 regiter pairs
[TRACE]  : Setting Core as 2
[INFO]   : Building the Partition Header Table
[TRACE]  : Creating ZYNQ MP Factory
[INFO]   : After build 
           --  of Binary Image ----
           00000000 Len: 000008b8 Res: 00000000 "BootHeader"
           00000000 Len: 00000040 Res: 00000000 "ImageHeaderTable"
           00000000 Len: 00000020 Res: 00000000 "ImageHeader fsbl.elf"
           00000000 Len: 00000020 Res: 00000000 "ImageHeader bl31.elf"
           00000000 Len: 00000020 Res: 00000780 "ImageHeader u-boot.elf"
           00000000 Len: 00000040 Res: 00000000 "PartitionHeader fsbl.elf.0"
           00000000 Len: 00000040 Res: 00000000 "PartitionHeader bl31.elf.0"
           00000000 Len: 00000040 Res: 00000000 "PartitionHeader u-boot.elf.0"
           00000000 Len: 00000040 Res: 00001640 "PartitionHeader Null"
           00000000 Len: 00036dc8 Res: 00000000 "fsbl.elf.0"
           00000000 Len: 0000c500 Res: 00000000 "bl31.elf.0"
           00000000 Len: 000b93d8 Res: 00000000 "u-boot.elf.0"
           -- End of 
[INFO]   : After align 
           --  of Binary Image ----
           00000000 Len: 000008b8 Res: 00000000 "BootHeader"
           000008c0 Len: 00000040 Res: 00000000 "ImageHeaderTable"
           00000900 Len: 00000020 Res: 00000000 "ImageHeader fsbl.elf"
           00000940 Len: 00000020 Res: 00000000 "ImageHeader bl31.elf"
           00000980 Len: 00000020 Res: 00000780 "ImageHeader u-boot.elf"
           00001100 Len: 00000040 Res: 00000000 "PartitionHeader fsbl.elf.0"
           00001140 Len: 00000040 Res: 00000000 "PartitionHeader bl31.elf.0"
           00001180 Len: 00000040 Res: 00000000 "PartitionHeader u-boot.elf.0"
           000011c0 Len: 00000040 Res: 00001640 "PartitionHeader Null"
           00002800 Len: 00036dc8 Res: 00000000 "fsbl.elf.0"
           00039600 Len: 0000c500 Res: 00000000 "bl31.elf.0"
           00045b00 Len: 000b93d8 Res: 00000000 "u-boot.elf.0"
           -- End of 
[INFO]   : Partition Information: 
[INFO]   : Image: fsbl.elf
[INFO]   :      1. Partition: fsbl.elf.0,  Size: 224712
[INFO]   : Image: bl31.elf
[INFO]   :      2. Partition: bl31.elf.0,  Size: 50432
[INFO]   : Image: u-boot.elf
[INFO]   :      3. Partition: u-boot.elf.0,  Size: 758744
[INFO]   : After Link 
           --  of Binary Image ----
           00000000 Len: 000008b8 Res: 00000000 "BootHeader"
           000008c0 Len: 00000040 Res: 00000000 "ImageHeaderTable"
           00000900 Len: 00000020 Res: 00000000 "ImageHeader fsbl.elf"
           00000940 Len: 00000020 Res: 00000000 "ImageHeader bl31.elf"
           00000980 Len: 00000020 Res: 00000780 "ImageHeader u-boot.elf"
           00001100 Len: 00000040 Res: 00000000 "PartitionHeader fsbl.elf.0"
           00001140 Len: 00000040 Res: 00000000 "PartitionHeader bl31.elf.0"
           00001180 Len: 00000040 Res: 00000000 "PartitionHeader u-boot.elf.0"
           000011c0 Len: 00000040 Res: 00001640 "PartitionHeader Null"
           00002800 Len: 00036dc8 Res: 00000000 "fsbl.elf.0"
           00039600 Len: 0000c500 Res: 00000000 "bl31.elf.0"
           00045b00 Len: 000b93d8 Res: 00000000 "u-boot.elf.0"
           -- End of 


新しいboot.bin をMicroSD カードに書いてブートすると、DONE ランプが点灯せずにDebian が立ち上がった。成功だ。
  1. 2018年11月23日 14:48 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 のDebianにインストールしたOpenCV-3.4.3のC++サンプルデザインをコンパイル

Ultra96 のDebian にインストールしたOpenCV-3.4.3 のC++ サンプルデザインをコンパイルしてみた。

OpenCV のコンパイル・スクリプトについては、”OpenCV のコンパイル・スクリプト”に書いたので、そのg++_opencv を使用する。

g++_opencv を下に示す。

#!/bin/sh

if [ $# -eq 1 ] ; then
    g++ -ggdb `pkg-config --cflags opencv` -o `basename $1 .cpp` $1 `pkg-config --libs opencv`;
else
    echo "g++_opencv < C++ file name >"
fi



これを ~/bin にコピーして実行パーミッションを入れた。 chmod +x g++_opencv
Ultra97_cam_capture_1_181123.png

ホーム・ディレクトリの .bashrc に

export PATH=$PATH:~/bin

を追加した。
Ultra97_cam_capture_2_181123.png

これで OpenCV のサンプルをコンパイルする環境設定が終了したので、opencv-3.4.3/samples/cpp ディレクトリに行って、
g++_opencv facedetect.cpp
コマンドで顔認識サンプルのコンパイルを行った。
Ultra97_cam_capture_3_181123.png

コンパイルは成功した。
続いて、顔認識サンプルを実行してみよう
./facedetect ../data/lena.jpg
Ultra97_cam_capture_4_181123.png

レナ像のウインドウが立ち上がって顔と目が丸で囲われていた。成功だ。
Ultra97_cam_capture_5_181123.png
  1. 2018年11月23日 05:38 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:1

Ultra96用PMOD拡張ボードでカメラ入力11(Vivado 2018.2のcam_test_182プロジェクト8)

Ultra96用PMOD拡張ボードでカメラ入力10(Vivado 2018.2のcam_test_182プロジェクト7)”の続き。

前回は、動作しなかったDMA_Write_SFB を修正したVivado HLS プロジェクトで、もう一度、C シミュレーション、C コードの合成、C/RTL 強調シミュレーション、Export RTL を行った。今回は、前回生成されたIP を使用して、もう一度、カメラのデータがフレーム・バッファにDMA されるのか?を確かめてみよう。

DMA_Write_sFB IP を入れ替えるのに、ブロック・デザインでDebug をすべて消してから、DMA_Write_sFB IP を入れ替えて、もう一度、DMA_Write_sFB IP のAXI4-Stream とAXI4-Master にDebug を設定した。そのブロック・デザインを示す。
DMA_Write_sFB_53_181119.png

その時のAddress Editor 画面を示す。
DMA_Write_sFB_54_181119.png

論理合成、インプリメンテーション、ビットストリームの生成を行った。サーマリを示す。
DMA_Write_sFB_55_181119.png

ハードウェアをエクスポートして、SDK を起動した。
Program FPGA を行って、cam_test.elf を起動した。
DMA_Write_sFB_63_181120.png

Vivado に戻ってVivado Analyzer で確認した。
DMA_Write_sFB_52_181119.png

AXI4 のトランザクションがいい感じに動作している。うまく行ったようだ。
すでに、起動してあったgtkterm にactive_frame の表示が出た。active_frame が変化しているので、問題なさそうだ。良かった。
DMA_Write_sFB_64_181120.png

波形を拡大した。
DMA_Write_sFB_65_181120.png

AXI4-Stream のTREADY は 1 のままでDMA_Write_sFB の待受準備はいつも出来ていることが分かる。一方、TVALID は間欠的に来るので、カメラのデータ・レートがインターフェースのスピードよりも遅いことが分かる。予定通りだ。

最後に修正した。cam_test.c を貼っておく。

/*
 * cam_test.c
 *
 *  Created on: 2018/11/15
 *      Author: masaaki
 */

#include <stdio.h>
#include <stdlib.h>
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#include "xtime_l.h"

#include "xdma_write_sfb.h"

#define FRAME_BUFFER_ADDRESS 0x10000000
#define NUMBER_OF_WRITE_FRAMES  3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS   800
#define VERTICAL_LINES      600
#define PIXEL_NUM_OF_BYTES  4

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(){
    XDma_write_sfb dmaw;
    int active_frame;

    XDma_write_sfb_Initialize(&dmaw, 0);
    XDma_write_sfb_Set_fb0_V(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_sfb_Set_fb1_V(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_sfb_Set_fb2_V(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_sfb_Start(&dmaw);
    XDma_write_sfb_EnableAutoRestart(&dmaw);

    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    mt9d111_axi_lites = (volatile unsigned *)XPAR_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_AXI_IIC_0_BASEADDR;

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

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

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf0, 0x1);      // Changed regster map to IFP page 1
    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x97, 0x20);     // RGB Mode, RGB565

    mt9d111_axi_lites[1] = 0; // One_shot_mode is disabled

    for(int i=0; i<20; i++){
        active_frame = (int)XDma_write_sfb_Get_active_frame_V(&dmaw);
        printf("active_frame = %d\n", active_frame);
        usleep(66667);
    }

    return(0);
}

  1. 2018年11月22日 04:54 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力10(Vivado 2018.2のcam_test_182プロジェクト7)

Ultra96用PMOD拡張ボードでカメラ入力9(Vivado 2018.2のcam_test_182プロジェクト6)”の続き。

前回は、DMA_Write_sFB が動作しないということで、再度作り直して、ソースコードを貼った。今回は、再度Vivado HLS でC シミュレーションや合成、C/RTL 強調シミュレーション、Export RTL を行う。

考えてみれば、今回のトリプル・フレーム・バッファのソースコードは、ダブル・フレーム・バッファは出来ないが、シングルとトリプルにはなるよね。シングル・フレーム・バッファには、3 つのフレーム・バッファ・アドレス・レジスタに同じアドレスを書けば良い。

さて、最初に C シミュレーションを行った。
DMA_Write_sFB_56_181119.png

C コードの合成を行った。結果を示す。
DMA_Write_sFB_57_181119.png
DMA_Write_sFB_58_181119.png

3 つ分なので、1440024 クロックかかっている。正常だし、1 処理 1 クロックに近い。

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

今度はうまく行った。1440098 クロックだった。問題ない。

C/RTL 強調シミュレーションの波形を示す。
まずは全体波形から。
DMA_Write_sFB_60_181119.png

ins(axis) -> ins_TREADY を見ると、3 回ほど 0 に落ちているところはあるが、ほとんど 1 のままということが分かる。スループットが大きいことがわかった。
ins(axis) -> ins_TREADY が 0 に落ちている辺り、つまり、DMA の切り替え部分を拡大してみよう。
DMA_Write_sFB_61_181119.png

うまく行っているようだ。

Export RTL を行った。
DMA_Write_sFB_62_181119.png

全く問題なさそうだ。
  1. 2018年11月21日 05:01 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力9(Vivado 2018.2のcam_test_182プロジェクト6)

Ultra96用PMOD拡張ボードでカメラ入力8(Vivado 2018.2のcam_test_182プロジェクト5)”の続き。

前回は、オシロスコープでカメラの信号を見たところ、正常だった。mt9d111_inf_axis IP もおかしくないようなので、DMA_Write_sFB IPがおかしいのでは?という結論になった。今回は、DMA_Write_sFB を作り直してみよう。

今、DMA_Write_sFB のソースコードを見てみると、m_axi オプションの INTERFACE 指示子を付けた *fb0, *fb1, *fb2 を fb に代入して fb[?] にデータを書いている。しかし、 *fb0, *fb1, *fb2 にそのまま代入しないとまずいのでは?ということでソースコードを書き直した。

DMA_Write_sFB.h を示す。

// DMA_Write_sFB.h
// 2018/11/04 by marsee
//

#ifndef __DMA_WRITE_SFB_H__
#define __DMA_WRITE_SFB_H__

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

#define MAX_WIDTH 800
#define MAX_HEIGHT 600

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

#endif


DMA_Write_sFB.cpp を示す。3 つのフレーム・バッファ専用とした。

// DMA_Write_sFB.cpp
// DMA Write IP which can change the number of frame buffers
// 2018/11/02 by marsee
//

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

#include "DMA_Write_sFB.h"

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

    AP_AXIU32 pix;
    int max_fb_chk;

    active_frame = 0;

    LOOP_WAIT0: do { // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> pix;
    } while(pix.user == 0);

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

            fb0[(y*MAX_WIDTH)+x] = pix.data;
        }
    }

    active_frame = 1;
    LOOP_WAIT1: do { // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> pix;
    } while(pix.user == 0);

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

            fb1[(y*MAX_WIDTH)+x] = pix.data;

        }
    }

    active_frame = 2;
    LOOP_WAIT2: do { // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> pix;
    } while(pix.user == 0);

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

            fb2[(y*MAX_WIDTH)+x] = pix.data;
        }
    }
end:
    return(0);
}



DMA_Write_sFB_tb.cpp を示す。

// DMA_Write_sFB_tb.cpp
// 2018/11/03 by marsee
//

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

#include "DMA_Write_sFB.h"

int DMA_Write_sFB(AXI_STREAM & ins,
    volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
    volatile ap_uint<2> &active_frame);

#define NUM_FRAME_BUFFER 3

int main()
{
    using namespace cv;

    AXI_STREAM ins;
    AP_AXIU32 pix;

    ap_uint<2> active_frame;
    int *frame_buffer;

    // OpenCV で 画像を読み込む
    Mat src = imread("bmp_file0.bmp");
    AXI_STREAM src_axi, dst_axi;

    // Mat フォーマットから AXI4 Stream へ変換、3画面分
    for(int i=0; i<NUM_FRAME_BUFFER; i++){
        cvMat2AXIvideo(src, src_axi);
        for (int y=0; y<MAX_HEIGHT; y++){
            for (int x=0; x<MAX_WIDTH; x++){
                src_axi >> pix;
                ins << pix;
            }
        }
    }

    // frame buffer をアロケートする、3倍の領域を取ってそれを3つに分ける
    if ((frame_buffer =(int *)malloc(NUM_FRAME_BUFFER * sizeof(int) * (MAX_WIDTH * MAX_HEIGHT))) == NULL){
        fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n");
        exit(1);
    }

    DMA_Write_sFB(ins, (volatile ap_int<32> *)frame_buffer,
        (volatile ap_int<32> *)&frame_buffer[MAX_WIDTH * MAX_HEIGHT],
        (volatile ap_int<32> *)&frame_buffer[2 * (MAX_WIDTH * MAX_HEIGHT)],
        active_frame);

    // AXI4 Stream から Mat フォーマットへ変換
    // dst は宣言時にサイズとカラー・フォーマットを定義する必要がある
    Mat dst[3];
    for(int i=0; i<NUM_FRAME_BUFFER; i++){
        dst[i] = Mat(src.rows, src.cols, CV_8UC3);
    }

    // dst[i] にframe_bufferから画像データをロード
    for(int i=0; i<NUM_FRAME_BUFFER; i++){
        Mat_<Vec3b> dst_vec3b = Mat_<Vec3b>(dst[i]);
        for(int y=0; y<dst[i].rows; y++){
            for(int x=0; x<dst[i].cols; x++){
                Vec3b pixel;
                int rgb = frame_buffer[i*(MAX_WIDTH * MAX_HEIGHT)+y*MAX_WIDTH+x];
                pixel[0] = (rgb & 0xff); // blue
                pixel[1] = (rgb & 0xff00) >> 8; // green
                pixel[2] = (rgb & 0xff0000) >> 16; // red
                dst_vec3b(y,x) = pixel;
            }
        }
    }

    // DMAされたデータをBMPフィルに書き込む
    char output_file[] = "dma_result0.bmp";
    for (int i=0; i<NUM_FRAME_BUFFER; i++){
        switch (i){
            case 0:
                strcpy(output_file,"dma_result0.bmp");
                break;
            case 1:
                strcpy(output_file,"dma_result1.bmp");
                break;
            case 2:
                strcpy(output_file,"dma_result2.bmp");
                break;
        }
        // Mat フォーマットからファイルに書き込み
        imwrite(output_file, dst[i]);
    }

    //free(frame_buffer);
    return 0;
}


  1. 2018年11月20日 05:36 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力8(Vivado 2018.2のcam_test_182プロジェクト5)

Ultra96用PMOD拡張ボードでカメラ入力7(Vivado 2018.2のcam_test_182プロジェクト4)”の続き。

前回は、Ultra96 に低速コネクタ用PMOD変換基板を取り付け、MT9D111 カメラを取り付けてテストを行ったが、動作していなかった。今回は、オシロスコープを購入したので、カメラの波形を観察して、Vivado Analyzer でもう一度確認してみよう。

オシロスコープでたくさん波形の写真を取ったつもりだったのだが、無くなってしまった。とにかく、PMOD の3.3V側も低速コネクタの1.8V側もきちんと波形が出ていた。PCLK は 35.7 MHz だった。

VSYNC は波形が残っていたので、示す。これは低速コネクタの 1.8V の波形だ。
oscilloscope_100_181118.jpg

上の波形を見ると、フレームレートが 13.4 fps ということが分かる。プレビュー表示だからか?VSYNC の波形のデューティ比が 50 % 程度になってしまっている。もったいない。

次に、たぶん D7 の 1.8 V 側を見てみよう。
oscilloscope_101_181118.jpg

きっちり波形が出ていた。波形的には問題ないようだ。

mt9d111_inf_axis を更新して、Vivado Analyzer をやってみたのだが、波形が無くなってしまった。仕方が無いので、ブロック・デザインからDebug を全部消去して、Open Synthesis Design から Set Up Debug をクリックして、Vivado Analyzer で表示するノードを選択した。 mt9d111_inf_axis のノードをほとんどすべて選択した。

論理合成、インプリメンテーション、ビットストリームの生成を行って、Vivado Analyzer を起動した。
その結果、カメラの信号は受信できていて、AXI4-Stream もカメラのデータをDMA_Write_sFB に送っているが tready が帰ってきていないようだ。
DMA_Write_sFB_50_181118.png
DMA_Write_sFB_51_181118.png

pfifo_empty の反転が AXI4-Stream の tvalid になっているので、tvalid は 1 のはず。mt9d111_inf_axis では、AXI4-Stream でカメラのデータを送り出してはいるが、DMA_Write_sFB がDMA していないようだ。
mt9d111_inf_axis のレジスタもラッチされていて、リセットも外れているので、AXI4 Lite でのレジスタ設定もうまく行っているはずだ。
  1. 2018年11月19日 04:50 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

OWON SDS-1102(オシロスコープ)を買いました

Ultra96 の低速拡張コネクタPMOD変換基板とカメラの信号変換がうまく行っているのか?を調べるためにアマゾンでOWON SDS-1102(オシロスコープ)を買いました。価格は 29,980円でした。驚くほどの低価格です。これで、100 MHz 2CH とは驚きです。以前の価格の 1/10 じゃないでしょうか?

梱包はこんなのでした。
oscilloscope_1_181118.jpg

中身です。
oscilloscope_2_181118.jpg

校正用の信号を表示しました。プローブの校正をしました。なお、日本語を選択してあります。日本語選べますよ。
この業者から買うと日本語マニュアル無いようですが、私でも英語で問題なさそうです。
そうそう、外部トリガ端子は無いようですが、私はあまり使わない機能なので、要りません。
oscilloscope_3_181118.jpg

CH1 のボタンを押したところ。カップリングやプローブの倍率を選べます。
oscilloscope_3_181118.jpg

Trigger のMenu のボタンを押したところ。Holdoff もありますね。
oscilloscope_5_181118.jpg

これは、Math のボタンを2回押したところかな?
oscilloscope_6_181118.jpg

Autoset ボタンを押すと 1div に収まるようにしてくれるのかな?
oscilloscope_7_181118.jpg

Cursor キーでは電圧や周期をはかることができます。周期を測っているところです。
oscilloscope_8_181118.jpg

Math ボタンを押して、FFT を選択すると信号がFFT されました。
oscilloscope_9_181118.jpg

Measure ボタンを押して、Show から CH1 を選択すると、CH1 の全測定結果が表示されました。
oscilloscope_10_181118.jpg

とってもよいですね。3万円以下とは思えません。
多少、ロータリーつまみの反応が鈍いと思うことがありましたが、頻繁に使うわけでもないので、十分です。十分満足しています。

それから、実際に端子に引っ掛けるために、「テイシン ICテストリード小 50cm TLA115」も買いました。これあるとヘッダの足に引っ掛けるのに便利です。
  1. 2018年11月18日 09:30 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:4

映画『ボヘミアン・ラプソディ』を見てきました

映画『ボヘミアン・ラプソディ』を見てきました。
クィーンのLPは買ったことあるし、好きなバンドだったので、見てきたけど、懐かしい。。。CD買おうかな?良かったです。。。
  1. 2018年11月17日 20:20 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う1

今までMT9D111 を使ってきたが、日昇テクノロジーのMT9D111 は在庫切れでディコンになってしまったようだ。

その代わりを探していたが、秋月電子を見ているとOV5642があったので、これを試してみたいと思った。たぶん、OV5642 は以前ひでみさんが試していたことがあったと思う。それに、エンヤさんの記事がインターフェースの 2014年11月号に載っているので、それを参考にしたいと思う。

ピンをPMODに変換する基板は、どうやらMT9D111 のインターフェース基板がそのまま使用できそうだ。
左にMT9D111 変換基板のピン配置表とOV5642のピン配置表を並べてみる。OV5642は秋月電子のOV5642のマニュアルより引用した。
OV5642_1_181117.pngOV5642_2_181117.png

後の問題はOV5642 の 17 番ピンのPWDN がどうかだが、秋月電子のOV5642 のデータシートより引用する。
OV5642_3_181117.png

プルダウン抵抗付ということで大丈夫なのだと思う。だが、データシートの他の部分のPWDNの記述を読むと、外部でグランドにつなげと書いてあるところもある。矛盾しているが、もし動作しなかったらGND に接続すれば良いと思う。
  1. 2018年11月17日 06:14 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力7(Vivado 2018.2のcam_test_182プロジェクト4)

Ultra96用PMOD拡張ボードでカメラ入力6(Vivado 2018.2のcam_test_182プロジェクト3)”の続き。

前回は、タイミングエラーを解消し、論理合成、インプリメンテーション、ビットストリームの生成を完了した。今回は、実際にUltra96 に低速コネクタ用PMOD変換基板を取り付け、MT9D111 カメラを取り付けてテストを行う。

最初に、低速コネクタ用PMOD変換基板を取り付けて、そして、インターフェース基板ごとMT9D111 を取り付けた。
写真を示す。
DMA_Write_sFB_49_181116.jpg

Vivado でハードウェアをエクスポートして、EDK を立ち上げた。

EDK が立ち上がった。
DMA_Write_sFB_42_181109.png

cam_test アプリケーション・プロジェクトを作成して、cam_test.c を作成した。
DMA_Write_sFB_43_181115.png

cam_test.c を示す。(2018/11/19 :修正)

/*
 * cam_test.c
 *
 *  Created on: 2018/11/15
 *      Author: masaaki
 */

#include <stdio.h>
#include <stdlib.h>
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#include "xtime_l.h"

#include "xdma_wirte_sfb.h"

#define FRAME_BUFFER_ADDRESS 0x10000000
#define NUMBER_OF_WRITE_FRAMES  3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS   800
#define VERTICAL_LINES      600
#define PIXEL_NUM_OF_BYTES  4

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(){
    XDma_wirte_sfb dmaw;

    XDma_wirte_sfb_Initialize(&dmaw, 0);
    XDma_wirte_sfb_Set_fb0_V(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_wirte_sfb_Set_fb1_V(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_wirte_sfb_Set_fb2_V(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_wirte_sfb_Start(&dmaw);
    XDma_wirte_sfb_EnableAutoRestart(&dmaw);

    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    mt9d111_axi_lites = (volatile unsigned *)XPAR_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_AXI_IIC_0_BASEADDR;

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

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

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf0, 0x1);      // Changed regster map to IFP page 1
    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x97, 0x20);     // RGB Mode, RGB565

    mt9d111_axi_lites[1] = 0; // One_shot_mode is disabled

}


EDK のXilinx メニューからProgram FPGA を選択して、Ultra96 のFPGA 部分をコンフィギュレーションした。
DMA_Write_sFB_44_181115.png

DMA_Write_sFB_45_181115.png

cam_test プロジェクトのBinaries -> cam_test.elf を右クリックし、右クリックメニューから Run As -> Launch on Hardware (System Debugger) を選択して、アプリケーションを起動した。正常に起動できた。
DMA_Write_sFB_46_181115.png

Vivado Analyzer を開いた。
DMA_Write_sFB_47_181115.png

AXI4-Stream と AXI4-Master のプロトコルを観察したところ、トランザクションが無かった。
DMA_Write_sFB_48_181115.png

これだけでは、よく分からないので、オシロスコープでクロックが出ているか?カメラの信号が出ているか?を見ることにする。
  1. 2018年11月16日 04:58 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

mjpg-streamerを使ってUltra96に付けたUSBカメラの画像をストリーミングする

Ultra96 にUSBカメラを付けて、その画像をパソコンにストリーミングできたら、ミニ・ロボットカーに付けて白線の画像を取得できそう。ということでやってみた。

参考にさせていただくのは、”Webカメラを使ってUbuntuで動画をストリーミング配信(mjpg-streamer使用)&Home Assistantで監視”と”RasPi:MJPG-streamer動画配信で遊んでみた♬”だ。

最初に lsusb をやってみたが、コマンドがなかった。
Ultra96_opencv_41_181113.png

lsusb command not found”を見ると usbutils をインストールすれば lsusb が使えるようだ。
sudo apt install usbutils
lsusb

Ultra96_opencv_42_181113.png

どうやら Alcor Micro Corp. というのがUSBカメラのようだ。
なお、形状は少し違うが、”iBUFFALO マイク内蔵120万画素Webカメラ HD720p対応モデル ブラック BSWHD06MBK”を使用している。これは新しいバージョンなんだろう?たぶん。
Ultra96_opencv_43_181113.png

sudo apt-get install subversion libjpeg-dev imagemagick
Ultra96_opencv_44_181113.png
Ultra96_opencv_45_181113.png

svn checkout svn://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer
Ultra96_opencv_46_181113.png
Ultra96_opencv_47_181113.png

cd mjpg-streamer/mjpg-streamer/
make

Ultra96_opencv_48_181113.png
Ultra96_opencv_49_181113.png

sudo make install
Ultra96_opencv_50_181113.png

start_server.sh を作成した。”RasPi:MJPG-streamer動画配信で遊んでみた♬”を参考にした。
Ultra96_opencv_55_181114.png

#!/bin/sh

PORT="8080" #ポート番号
ID="fpga"
PW="fpga"
SIZE="640x480" #画面サイズ
FRAMERATE="20" #フレームレート
export LD_LIBRARY_PATH=/usr/local/lib
mjpg_streamer \
    -i "input_uvc.so -f $FRAMERATE -r $SIZE -d /dev/video0 -y -n" \
    -o "output_http.so -w /usr/local/www -p $PORT -c $ID:$PW"


start_server.sh のパーミッションを変更して、起動した。
chmod +x start_server.sh
./start_server.sh

しかし、

ERROR opening V4L interface: Permission denied
Init v4L2 failed !! exit fatal

だった。
Ultra96_opencv_51_181114.png 

これは、たぶん /dev/video0 が開けないのでは?と思い、パーミッションを変更してからstart_server.sh を起動した。
sudo chmod 666 /dev/video0
./start_server.sh &

Ultra96_opencv_52_181114.png

今度はうまく行った。
<Ultra96 のIPアドレス>:8080 をChrome で見るとWebページが見えた。
Stream タブをクリックするとカメラ画像が見えた。カメラ画像がストリーミングされている。
Ultra96_opencv_53_181114.png

このときのネットワークの受信は約 300 KB/sec 程度になっているようだ。
Ultra96_opencv_54_181114.png
  1. 2018年11月14日 05:03 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 のDebian にOpenCV 3.4.3 をインストール3

Ultra96 のDebian にOpenCV 3.4.3 をインストール2”の続き。

前回は、demo.py からいろいろなOpenCV のサンプルを起動できるようになった。今回は、環境を整備して ffmpeg とかも入れてみようと思う。

参考にするのは、”ラズパイにOpenCVをインストールする方法”だ。

まずは、環境を整備しよう。
sudo apt-get install build-essential cmake pkg-config
Ultra96_opencv_29_181111.png

インストール済みだった。

sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
Ultra96_opencv_30_181111.png

これらもインストール済みか、インストール候補が無かった。

v4l をインストールする。
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
Ultra96_opencv_31_181111.png
Ultra96_opencv_32_181111.png

これは、一部だがインストールされた。

sudo apt-get install libxvidcore-dev libx264
Ultra96_opencv_33_181111.png

これもインストールされなかった。

cmake を行った。
cmake -DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DINSTALL_PYTHON_EXAMPLES=ON \
-DINSTALL_C_EXAMPLES=ON \
-DPYTHON_EXECUTABLE=/usr/bin/python3 \
-DBUILD_EXAMPLES=ON \
-DWITH_GTK=ON \
-DWITH_FFMPEG=ON ..

Ultra96_opencv_36_181111.png

設定値を示す。

--     Applications:                tests perf_tests examples apps
--     Documentation:               NO
--     Non-free algorithms:         NO
-- 
--   GUI: 
--     GTK+:                        YES (ver 2.24.31)
--       GThread :                  YES (ver 2.50.3)
--       GtkGlExt:                  NO
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/aarch64-linux-gnu/libz.so (ver 1.2.8)
--     JPEG:                        libjpeg-turbo (ver 1.5.3-62)
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         /usr/lib/aarch64-linux-gnu/libpng.so (ver 1.6.28)
--     TIFF:                        build (ver 42 - 4.0.9)
--     JPEG 2000:                   build (ver 1.900.1)
--     OpenEXR:                     build (ver 1.7.1)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
-- 
--   Video I/O:
--     DC1394:                      NO
--     FFMPEG:                      YES
--       avcodec:                   YES (ver 57.64.101)
--       avformat:                  YES (ver 57.56.101)
--       avutil:                    YES (ver 55.34.101)
--       swscale:                   YES (ver 4.2.100)
--       avresample:                NO
--     GStreamer:                   NO
--     libv4l/libv4l2:              NO
--     v4l/v4l2:                    linux/videodev2.h
-- 
--   Parallel framework:            pthreads
-- 
--   Trace:                         YES (built-in)
-- 
--   Other third-party libraries:
--     Lapack:                      NO
--     Eigen:                       NO
--     Custom HAL:                  YES (carotene (ver 0.0.1))
--     Protobuf:                    build (3.5.1)
-- 
--   OpenCL:                        YES (no extra features)
--     Include path:                /home/fpga/opencv-3.4.3/3rdparty/include/opencl/1.2
--     Link libraries:              Dynamic load
-- 
--   Python 3:
--     Interpreter:                 /usr/bin/python3 (ver 3.5.3)
--     Libraries:                   /usr/lib/aarch64-linux-gnu/libpython3.5m.so (ver 3.5.3)
--     numpy:                       /usr/lib/python3/dist-packages/numpy/core/include (ver 1.12.1)
--     packages path:               lib/python3.5/dist-packages
-- 
--   Python (for build):            /usr/bin/python3
-- 
--   Java:                          
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
-- 
--   Matlab:                        NO
-- 
--   Install to:                    /usr/local
-- -----------------------------------------------------------------


make -j4
Ultra96_opencv_37_181111.png
Ultra96_opencv_38_181111.png

sudo make install
sudo ldconfig

Ultra96_opencv_39_181111.png
Ultra96_opencv_40_181111.png

デモのasift.py で無いと言われたので、libcanberra-gtk-module をインストールした。
sudo apt-get install libcanberra-gtk-module
  1. 2018年11月13日 04:19 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 のDebian にOpenCV 3.4.3 をインストール2

Ultra96 のDebian にOpenCV 3.4.3 をインストール1”の続き。

前回は、Ultra96 にOpenCV 3.4.3 をインストールして、demo.py が起動したが、cv.namedWindow('edge') でエラーになった。今回は、その続きをやってみよう。

さて、cv.namedWindow('edge') でエラーになったときのメッセージにも書いてあるように、libgtk2.0-dev と pkg-config をインストールしよう。
sudo apt install libgtk2.0-dev pkg-config
Ultra96_opencv_19_181110.png

下の画像では、ディレクトリが違うが、~/opencv-3.4.3/build ディレクトリに行って、cmake を再度行った。この辺りは、”[c++] OpenCV GTK + 2.xエラー”を参考にした。
cmake -DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DINSTALL_PYTHON_EXAMPLES=ON \
-DINSTALL_C_EXAMPLES=OFF \
-DPYTHON_EXECUTABLE=/usr/bin/python3 \
-DBUILD_EXAMPLES=ON \
-DWITH_GTK=ON ..

Ultra96_opencv_20_181110.png

cmake のログを見ると、GUI のGTK+がYES になっている。これで大丈夫そうだ。
Ultra96_opencv_21_181110.png

次に、make を行ったが、4プロセッサ使ってみたが、ビルド成功した。
make -j4
Ultra96_opencv_22_181111.png

sudo make install
sudo ldconfig

Ultra96_opencv_23_181111.png

~/opencv-3.4.3/samples/python ディレクトリで
python3 demo.py
を実行した。
OpenCV Demo ウインドウが立ち上がった。
Ultra96_opencv_24_181111.png

edge.py を Run すると、edge ウインドウが立ち上がった。成功だ。
Ultra96_opencv_25_181111.png

その時のターミナルの様子を示す。
Ultra96_opencv_26_181111.png

まだ、V4L のエラーが出ているが、camera をオープンできないというエラーの様だから大丈夫かな?

次に、facedetect.py を起動してみた。
Ultra96_opencv_27_181111.png

すると、facedetect ウインドウが立ち上がった。こっちも成功だ。
Ultra96_opencv_28_181111.png
  1. 2018年11月12日 05:27 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 のDebian にOpenCV 3.4.3 をインストール1

Ultra96 のDebian にOpenCV 3.4.3 をインストールしてみたいということでやってみた。

hackster.io の ”Caffein-AI-tor”を参考にして、Ultra96 のDebian にOpenCV 3.4.3 をインストールすることにした。

最初にOpenCV 3.4.3 をダウンロードした。
wget -O opencv.zip https://github.com/opencv/opencv/archive/3.4.3.zip
Ultra96_opencv_1_181110.png

zip ファイルを unzip したが、unzip がインストールされていなかった。
unzip opencv.zip
sudo apt install unzip

Ultra96_opencv_2_181110.png

もう一度、unzip を行った。
unzip opencv.zip
Ultra96_opencv_3_181110.png
Ultra96_opencv_4_181110.png

opencv-3.4.3 ディレクトリに入って、build ディレクトリを作った。build ディレクトリに入って、 cmake した。
cd opencv-3.4.3/
ls
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DINSTALL_PYTHON_EXAMPLES=ON \
-DINSTALL_C_EXAMPLES=OFF \
-DPYTHON_EXECUTABLE=/usr/bin/python3 \
-DBUILD_EXAMPLES=ON ..

Ultra96_opencv_5_181110.png

cmake が無かったので、インストールした。
sudo apt install cmake
Ultra96_opencv_6_181110.png

もう一度、cmake を行った。
Ultra96_opencv_7_181110.png
Ultra96_opencv_8_181110.png

2つのプロセッサを使用して make した。
ビルドは成功した。
make -j2
Ultra96_opencv_9_181110.png
Ultra96_opencv_10_181110.png

sudo make install
Ultra96_opencv_11_181110.png
Ultra96_opencv_12_181110.png

sudo ldconfig
Ultra96_opencv_13_181110.png

Python のサンプルを動かしてみよう。
cd ~/opencv-3.4.3/samples/python
python demo.py

を実行したが、”No module named cv2”と言われてしまう。今、OpenCV をインストールしたので、そんなことはないはず。
検索すると”ImportError: No module named cv2”を見つけた。これによると、パスを追加する必要があるようだ。
export PYTHONPATH=/usr/local/lib/python3.5/dist-packages:$PYTHONPATH
これは、.bashrc にも追加しておいた。
もう一度、python3 demo.py
したところ、”No module named '_tkinter' ”になってしまった。
Ultra96_opencv_14_181110.png

もう一度、検索すると、”python3 で _tkinter を import したい”がヒットした。
それによると python3-tk をインストールする必要があるようだ。
sudo apt install python3-tk
Ultra96_opencv_15_181110.png

python3 demo.py
Ultra96_opencv_16_181110.png

今度は、GUI が立ち上がった。
Ultra96_opencv_17_181110.png

edge.py を起動した。(後にわかったのだが、edge.py だけ選んでRun すれば良かった)
Ultra96_opencv_17_181110.png

cv.namedWindow('edge') でエラーになった。
Ultra96_opencv_18_181110.png

(追記)
なお、Ultra96 のDebian に入るときは、X を持ってこれるように
ssh ”IP アドレス” -X -l fpga
コマンドを使用しています。
更に、Ulra96 のDebian には、”Ultra96 で ikwzm さんのDebian9 Root File Systemを動かしてみる3”での設定を行っています。
  1. 2018年11月11日 03:56 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力6(Vivado 2018.2のcam_test_182プロジェクト3)

Ultra96用PMOD拡張ボードでカメラ入力5(Vivado 2018.2のcam_test_182プロジェクト2)”の続き。

前回は、Ultra96 ボードの低速拡張コネクタにPMOD 変換基板を付けて、MT9D111 カメラを接続する回路の論理合成、インプリメンテーション、ビットストリームの生成を行ったが、タイミング・エラーが出てしまった。今回は、そのタイミング・エラーを解消したい。

最初に、Open Implemented Design をクリックして、タイミング・エラーの内容を確認する。
Timing タブのInter-Clock Paths にエラーが出ている。Inter-Clock Paths -> clk_pl_0 to pclk にエラーがある。
Setup -3.431ns (10) をクリックしてエラー内容を表示する。
すると、mt9d111_inf_axis_0 の信号間のセットアップ時間のエラーだということが分かる。init_done 関係なので、最初の電源立ち上がりのときの1発出る信号だ。
DMA_Write_sFB_31_181109.png

次に、Inter-Clock Paths -> pclk to clk_pl_0 にもエラーがある。こちらは ila 関係のエラーだということがわかった。Vivado Analyzer で pclk の信号を clk_pl_0 でサンプルしているようだ。これは仕方ない。
DMA_Write_sFB_32_181109.png

clk_pl_0 to pclk のエラーだけ問題ないか?を調べよう。
Reports メニューからTiming -> Report CDC... を選択して、Clock Domain Closing について調べてみよう。

clk_pl_0 to pclk のレポートを設定した。
DMA_Write_sFB_33_181109.png

結果として Unsafe はないので、大丈夫のようだ。
DMA_Write_sFB_34_181109.png

DMA_Write_sFB_35_181109.png

それでは、次に、Open Implemented Design のEdit Timing Constrains をクリックして、False Path を設定しよう。
DMA_Write_sFB_36_181109.png

clk_pl_0 から pclk へのFalse Path の設定。
DMA_Write_sFB_37_181109.png

pclk から clk_pl_0 へのFalse Path の設定。
DMA_Write_sFB_38_181109.png

2つのFalse Path を設定した。
DMA_Write_sFB_39_181109.png

この制約をセーブして、Implemented Design を終了した。
cam_test.xdc にFalse Path が追加されている。
DMA_Write_sFB_40_181109.png

もう一度、cam_test.xdc をセーブして、論理合成、インプリメンテーション、ビットストリームの生成をやり直した。
結果は、タイミング・エラーが無くなった。
DMA_Write_sFB_41_181109.png
  1. 2018年11月09日 05:35 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力5(Vivado 2018.2のcam_test_182プロジェクト2)

Ultra96用PMOD拡張ボードでカメラ入力4(Vivado 2018.2のcam_test_182プロジェクト1)”の続き。

前回は、Ultra96 ボードの低速拡張コネクタにPMOD 変換基板を付けて、MT9D111 カメラを接続する回路のブロック・デザインを作成し、HDL ラッパー・ファイルを生成し、制約ファイルを作成した。今回は、論理合成、インプリメンテーション、ビットストリームの生成を行うが、エラーが出てしまっている。

まずは、MT9D111 の信号や、AXI4-Stream 、AXI4-Master インターフェースにVivado Analyzer を設定した。
DMA_Write_sFB_24_181107.png

論理合成、インプリメンテーション、ビットストリームの生成を行ったときに以下の様なダイアログが表示された。
DMA_Write_sFB_25_181107.png

そして、カメラのPCLK がクロックを入力するための入力ポートじゃないというエラーが出てしまった。
DMA_Write_sFB_27_181107.png

[Place 30-675] Sub-optimal placement for a global clock-capable IO pin and BUFG pair.If this sub optimal condition is acceptable for this design, you may use the CLOCK_DEDICATED_ROUTE constraint in the .xdc file to demote this message to a WARNING. However, the use of this override is highly discouraged. These examples can be used directly in the .xdc file to override this clock rule.
    < set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF_inst/O] >

    pclk_IBUF_inst/IBUFCTRL_INST (IBUFCTRL.O) is locked to IOB_X0Y106
     pclk_IBUF_BUFG_inst (BUFGCE.I) is provisionally placed by clockplacer on BUFGCE_HDIO_X0Y4

    The above error could possibly be related to other connected instances. Following is a list of 
    all the related clock rules and their respective instances.

    Clock Rule: rule_bufgce_bufg_conflict
    Status: PASS 
    Rule Description: Only one of the 2 available sites (BUFGCE or BUFGCE_DIV/BUFGCTRL) in a pair can be
    used at the same time
     and pclk_IBUF_BUFG_inst (BUFGCE.O) is provisionally placed by clockplacer on BUFGCE_HDIO_X0Y4


結局、制約ファイルに

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF_inst/O]

を追加すれば、通るはず。制約ファイルに追加した。

その後、もう一度、論理合成、インプリメンテーション、ビットストリームの生成を行った。またエラーがでて、今度は、IOスタンダードが設定されていないというエラーだった。これは、制約ファイルのすべての信号にIO信号規則のLVCOMS18 を設定した。

更に、MT9D111 のI2C インターフェースを制御するためのAXI_IIC IP を追加するのを忘れていたため、追加した。
現在のブロック・デザインを示す。
DMA_Write_sFB_28_181108.png

Address Editor を示す。
最初の s_axi_lite が mt9d111_inf_axis で、s_axi_AXILiteS が DMA_Write_sFB で、最後のS_AXI が axi_iic になっている。しかし、インスタンス名が表示されるときと、今回のようにポート名が表示されるときの違いは何なのだろうか?設定が違っているのか?
DMA_Write_sFB_29_181108.png

現在の cam_test.xdc を示す。

set_property PACKAGE_PIN G7 [get_ports pclk]
set_property PACKAGE_PIN G6 [get_ports {cam_data[7]}]
set_property PACKAGE_PIN D5 [get_ports {cam_data[6]}]
set_property PACKAGE_PIN E6 [get_ports {cam_data[5]}]
set_property PACKAGE_PIN C7 [get_ports {cam_data[4]}]
set_property PACKAGE_PIN E5 [get_ports {cam_data[3]}]
set_property PACKAGE_PIN B6 [get_ports {cam_data[2]}]
set_property PACKAGE_PIN D6 [get_ports {cam_data[1]}]
set_property PACKAGE_PIN C5 [get_ports {cam_data[0]}]


set_property PACKAGE_PIN G5 [get_ports href]
set_property PACKAGE_PIN F7 [get_ports standby]
set_property PACKAGE_PIN F8 [get_ports vsync]
set_property PACKAGE_PIN A7 [get_ports xck]

set_property PACKAGE_PIN D7 [get_ports iic_rtl_scl_io]
set_property PACKAGE_PIN F6 [get_ports iic_rtl_sda_io]

create_clock -period 13.700 -name pclk -waveform {0.000 6.850} [get_ports pclk]
set_input_delay -clock [get_clocks pclk] 10.800 [get_ports {{cam_data[0]} {cam_data[1]} {cam_data[2]} {cam_data[3]} {cam_data[4]} {cam_data[5]} {cam_data[6]} {cam_data[7]} href pclk vsync}]

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF_inst/O]

set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[6]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[5]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[4]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {cam_data[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports pclk]
set_property IOSTANDARD LVCMOS18 [get_ports href]
set_property IOSTANDARD LVCMOS18 [get_ports standby]
set_property IOSTANDARD LVCMOS18 [get_ports vsync]
set_property IOSTANDARD LVCMOS18 [get_ports xck]

set_property IOSTANDARD LVCMOS18 [get_ports iic_rtl_scl_io]
set_property IOSTANDARD LVCMOS18 [get_ports iic_rtl_sda_io]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets clk]


これで、再々度、論理合成、インプリメンテーション、ビットストリームの生成を行った。エラーは無かったが、タイミング・エラーになってしまった。
DMA_Write_sFB_30_181108.png
  1. 2018年11月08日 05:24 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力4(Vivado 2018.2のcam_test_182プロジェクト1)

Ultra96用PMOD拡張ボードでカメラ入力3(DMA_Write_sFB IPの作成)”の続き。

前回はVivado HLS 2018.4 でAXI4-Stream をDDR4 SDRAM にDMA するDMA_Write sFB を作成した。これで、カメラのインターフェースIP とDMA IP が揃ったので、今回は、それらを使用して、Vivado 2018.2 で cam_test_182 プロジェクトを作成していこう。

最初にカメラのインターフェースIP の mt9d111_inf_axis だが、ODDR プリミティブを使用していて、それがZynq UltraScale+ MPSoC にないという不具合が発生していた。
これは、ODDRE1 プリミティブに変更した。
DMA_Write_sFB_10_181106.png

    // MT9D111 へのクロックを出力 (xclk)
    ODDRE1 #(
        .IS_C_INVERTED(1'b0), // Optional inversion for C
        .IS_D1_INVERTED(1'b0), // Unsupported, do not use
        .IS_D2_INVERTED(1'b0), // Unsupported, do not use
        .SIM_DEVICE("ULTRASCALE"),
        .SRVAL(1'b0) // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
    ) ODDR_inst (
        .Q(xclk), // 1-bit DDR output
        .C(pclk_from_pll), // 1-bit clock input
        .D1(1'b1), // 1-bit data input (positive edge)
        .D2(1'b0), // 1-bit data input (negative edge)
        .SR(1'b0) // 1-bit reset
    );


そしてもう一度、Re-Package IP を行った。
DMA_Write_sFB_11_181106.png

Vivado 2018.2 でUltra96v1 ボード・ファイルを使用して、 cam_test_182 プロジェクトを作成した。

cam_test_182 プロジェクトのディレクトリに mt9d111_inf_axis と DMA_Write_sFB IP を追加した。
DMA_Write_sFB_12_181106.png

IP Catalog を開いて、2つのIP を追加した。
DMA_Write_sFB_13_181106.png

DMA_Write_sFB_14_181106.png

cam_test ブロック・デザインを作成し、Zynq UltraScale+ MPSoC を追加した。
DMA_Write_sFB_15_181106.png

Zynq UltraScale+ MPSoC をダブルクリックして開き、Zynq UltraScale+ MPSoC のダイアログで PL へのクロックを修正する。
Clock Configuration を選択し、Output Clocks をクリックし、Enable Manual Mode のチェックボックスを外す。
PL1 のチェックボックスを入れて、Source をIOPLL にして、Requested Freq (MHz) を 72 に変更する。
DMA_Write_sFB_16_181107.png

PS-PL Configuration をクリックし、PS-PL Interface -> Master Interface のAXI HPM0- FPD と Slave Interface の AXI HPC0 FPD にチェックを入れる。
DMA_Write_sFB_17_181107.png

これで設定は終了したので、OK ボタンをクリックする。
設定後のZynq UltraScale+ MPSoC を示す。
DMA_Write_sFB_18_181107.png

mt9d111_inf_axis と DMA_Write_sFB IP を追加し、自動配線した。
DMA_Write_sFB_19_181107.png

残っている配線を接続し、外部ポートを設定し、一応、ブロック・デザインが完成した。
DMA_Write_sFB_20_181107.png

Address Editor を示す。なお、IP 名が表示されていないが、 s_axi_lite が mt9d111_inf_axis の方だ。
DMA_Write_sFB_21_181107.png

回路は完成したが、テスト用の回路なので、Vivado Analyzer を仕込んだ。
DMA_Write_sFB_24_181107.png

HDL Wrapper を作成した。
DMA_Write_sFB_22_181107.png

最後に制約ファイルの cam_test.xdc を作成した。
DMA_Write_sFB_23_181107.png

set_property PACKAGE_PIN G7 [get_ports pclk]
set_property PACKAGE_PIN G6 [get_ports {cam_data[7]}]
set_property PACKAGE_PIN D5 [get_ports {cam_data[6]}]
set_property PACKAGE_PIN E6 [get_ports {cam_data[5]}]
set_property PACKAGE_PIN C7 [get_ports {cam_data[4]}]
set_property PACKAGE_PIN E5 [get_ports {cam_data[3]}]
set_property PACKAGE_PIN B6 [get_ports {cam_data[2]}]
set_property PACKAGE_PIN D6 [get_ports {cam_data[1]}]
set_property PACKAGE_PIN C5 [get_ports {cam_data[0]}]


set_property PACKAGE_PIN G5 [get_ports href]
set_property PACKAGE_PIN F7 [get_ports standby]
set_property PACKAGE_PIN F8 [get_ports vsync]
set_property PACKAGE_PIN A7 [get_ports xck]

set_property PACKAGE_PIN D7 [get_ports iic_rtl_scl_io]
set_property PACKAGE_PIN F6 [get_ports iic_rtl_sda_io]

create_clock -period 27.777 -name pclk -waveform {0.000 13.889} [get_ports pclk]

  1. 2018年11月07日 05:36 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力3(DMA_Write_sFB IPの作成)

Ultra96用PMOD拡張ボードでカメラ入力2(mt9d111_inf_axis IP の作成2)”の続きだけど、”Ultra96実践勉強会で作ったVivado HLS 2018.2 のDMA Write IP”の続きでもある。

(2018/11/21 : 追記)ここでのDMA_Write_sFB のソースコードは間違っています。正しく動作するコードは
Ultra96用PMOD拡張ボードでカメラ入力9(Vivado 2018.2のcam_test_182プロジェクト6)”と
Ultra96用PMOD拡張ボードでカメラ入力10(Vivado 2018.2のcam_test_182プロジェクト7)”をご覧ください。


ソースコードは、”Ultra96実践勉強会で作ったVivado HLS 2018.2 のDMA Write IP”に貼ってある。ソースコードのバグフィックスができたので、DMA した画像は出てきたが、C/RTL 協調シミュレーションがエラーになってしまう。なお、バグフィックスのために参考にさせていただいたのは、”OpenCV の Mat のデータを直接いじる”だ。これで、Mat の書き換え方法がわかった。ありがとうございました。

Vivado HLS 2018.2 を使用したDMA_Write sFB プロジェクトを示す。
DMA_Write_sFB_1_181105.png

C シミュレーションを行った。
DMA_Write_sFB_3_181106.png

DMA されたFrame Buffer から生成したBMP ファイルに画像がコピーされているのが分かる。
DMA_Write_sFB_8_181106.png

なお、デバックの結果によると、cvMat2AXIvideo(src, src_axi); でMat フォーマットをAXI4-Stream にしたときのdata エレメントのバイト・アサインは、0x00RRGGBB になるようだ。上のバイト・レーンからRed, Green, Blue になっていた。

次に、C コードの合成を行った。
DMA_Write_sFB_4_181106.png
DMA_Write_sFB_5_181106.png

Estimated は 8.75 ns で問題ない。Latency は min 480011 クロックで、max が 1440031 クロックだった。これは、800 x 600 ピクセルの 1 画面の 480000 ピクセルから、3 画面の 1440000 ピクセルまでということだ。11 クロックほど追加されているだけなので、問題ない。

C/RTL 協調シミュレーションをしてみたが、エラーで終了してしまった。原因は良くわからない?
DMA_Write_sFB_6_181106.png

Export RTL を行ってIP 化した。
DMA_Write_sFB_7_181106.png

問題なさそう。
DMA_Write_sFB_9_181106.png
  1. 2018年11月06日 04:45 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96実践勉強会で作ったVivado HLS 2018.2 のDMA Write IP

11/3(土)にUltra96(UltraZed)実践勉強会に行ってきました。
運営のVengineer さん、一緒にグループになった皆さん、参加した皆さん、会場を提供していただいたAVNETの皆さん、ありがとうございました。
グループで行ったことは、自分のやりたかったことになりました。グループの皆さん、私のわがままに付き合っていただいて、ありがとうございました。
実際にやったことは、”Ultra96の低速拡張コネクタからカメラ入力”にまとめてあります。
Ultra96 の低速拡張コネクタをPMOD に変換する変換基板を作ったので、そこにMT9D111 カメラを接続してDisplayPort に出力したい。しかし、DisplayPort への出力方法が分からないので、とりあえずPSに接続されているDDR4 SDRAM にFrame Buffer として出力、PS のプロセッサでカメラの画像データを読み込みたいというものでした。
MT9D111 のインターフェースIP はすでに作ってあったので、それを使用して、Vivado HLS 2018.2 でカメラ・データのAXI4-Stream をDMA でFrame Buffer に書き込むDMA Write IP を作成しました。そして、それらを使用して、Vivado 2018.2 でカメラ・データを読み込んで、Frame Buffer に書くプロジェクトをコンパイルしたのですが、プリミティブ・エラーが出て終了になりました。これは、MT9D111 のインターフェースIP にZynq 用のDDR 出力のプリミティブが使用されていたためです。
なお、”UltraScale アーキテクチャ ライブラリ ガイド UG974 (v2018.1) 2018 年 4 月 4 日”の411 ページによるとODDRE1 を使えば良さそうです。

この Ultra96 勉強会でやったことをブログに書こうと思ったのですが、Windows 10 で開発したDMA Write IP をUbuntu 18.04 のVivado HLS 2018.2 でC シミュレーションしたところ動作しなかったです。これは、以前から知ってはいたのだが、デバックしてこなかったので、この際、テストベンチをOpenCV で書き換えようと思ってやっていたら、ハマってしまいました。
なかなかうまく行かないですね。
とりあえず途中経過を書いておきます。

(2018/11/21 : 追記)ここでのDMA_Write_sFB のソースコードは間違っています。正しく動作するコードは
Ultra96用PMOD拡張ボードでカメラ入力9(Vivado 2018.2のcam_test_182プロジェクト6)”と
Ultra96用PMOD拡張ボードでカメラ入力10(Vivado 2018.2のcam_test_182プロジェクト7)”をご覧ください。


Vivado HLS 2018.2 の DMA_Write_sFB プロジェクトです。
DMA_Write_sFB_1_181105.png

C シミュレーションをすると黒い画像ファイルが出力されちゃいます。
DMA_Write_sFB_2_181105.png

(2018/11/05:修正)ソースコードのバグフィックスをしました。
現在のDMA_Write_sFB_tb.cpp です。

// DMA_Write_sFB_tb.cpp
// 2018/11/03 by marsee
//

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

#include "DMA_Write_sFB.h"

//#define MAX_FRAME_NUMBER 3
#define MAX_FRAME_NUMBER 1 // for C/RTL CoSimulation

int DMA_Wirte_sFB(AXI_STREAM & ins,
    volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
    volatile ap_uint<2> &active_frame, int max_fb);

int main()
{
    using namespace cv;

    AXI_STREAM ins;
    AP_AXIU32 pix;

    ap_uint<2> active_frame;
    int *frame_buffer;

    // OpenCV で 画像を読み込む
    Mat src = imread("bmp_file0.bmp");
    AXI_STREAM src_axi, dst_axi;

    // Mat フォーマットから AXI4 Stream へ変換、3画面分
    for(int i=0; i<MAX_FRAME_NUMBER; i++){
        cvMat2AXIvideo(src, src_axi);
        for (int y=0; y<MAX_HEIGHT; y++){
            for (int x=0; x<MAX_WIDTH; x++){
                src_axi >> pix;
                ins << pix;
            }
        }
    }

    // frame buffer をアロケートする、3倍の領域を取ってそれを3つに分ける
    if ((frame_buffer =(int *)malloc(MAX_FRAME_NUMBER * sizeof(int) * (MAX_WIDTH * MAX_HEIGHT))) == NULL){
        fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n");
        exit(1);
    }

    DMA_Wirte_sFB(ins, (volatile ap_int<32> *)frame_buffer,
        (volatile ap_int<32> *)&frame_buffer[MAX_WIDTH * MAX_HEIGHT],
        (volatile ap_int<32> *)&frame_buffer[2 * (MAX_WIDTH * MAX_HEIGHT)],
        active_frame, MAX_FRAME_NUMBER);

    // AXI4 Stream から Mat フォーマットへ変換
    // dst は宣言時にサイズとカラー・フォーマットを定義する必要がある
    Mat dst[MAX_FRAME_NUMBER];
    for(int i=0; i<MAX_FRAME_NUMBER; i++){
        dst[i] = Mat(src.rows, src.cols, CV_8UC3);
    }

    // dst[i] にframe_bufferから画像データをロード
    for(int i=0; i<MAX_FRAME_NUMBER; i++){
        Mat_<Vec3b> dst_vec3b = Mat_<Vec3b>(dst[i]);
        for(int y=0; y<dst[i].rows; y++){
            for(int x=0; x<dst[i].cols; x++){
                Vec3b pixel;
                int rgb = frame_buffer[i*(MAX_WIDTH * MAX_HEIGHT)+y*MAX_WIDTH+x];
                pixel[0] = (rgb & 0xff); // blue
                pixel[1] = (rgb & 0xff00) >> 8; // green
                pixel[2] = (rgb & 0xff0000) >> 16; // red
                dst_vec3b(y,x) = pixel;
            }
        }
    }

    // DMAされたデータをBMPフィルに書き込む
    char output_file[] = "dma_result0.bmp";
    for (int i=0; i<MAX_FRAME_NUMBER; i++){
        switch (i){
            case 0:
                strcpy(output_file,"dma_result0.bmp");
                break;
            case 1:
                strcpy(output_file,"dma_result1.bmp");
                break;
            case 2:
                strcpy(output_file,"dma_result2.bmp");
                break;
        }
        // Mat フォーマットからファイルに書き込み
        imwrite(output_file, dst[i]);
    }

    //free(frame_buffer);
    return 0;
}


DMA_Write_sFB.h です。

// DMA_Write_sFB.h
// 2018/11/04 by marsee
//

#ifndef __DMA_WRITE_SFB_H__
#define __DMA_WRITE_SFB_H__

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

#define MAX_WIDTH 800
#define MAX_HEIGHT 600

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

#endif


DMA_Write_sFB.cpp を示す。

// DMA_Write_sFB.cpp
// DMA Write IP which can change the number of frame buffers
// 2018/11/02 by marsee
//

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

#include "DMA_Write_sFB.h"

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

    AP_AXIU32 pix;
    volatile ap_int<32> *fb;
    int max_fb_chk;

    if (max_fb > 3)
        max_fb_chk = 3;
    else
        max_fb_chk = max_fb;

    LOOP_MAIN: for (int i=0; i<max_fb_chk; i++){
#pragma HLS LOOP_TRIPCOUNT min=1 max=3 avg=3
        switch (i){
        case 0:
            fb = fb0;
            break;
        case 1:
            fb = fb1;
            break;
        default: // i == 2
            fb = fb2;
            break;
        }
        active_frame = i;

        LOOP_WAIT: do { // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
            ins >> pix;
        } while(pix.user == 0);

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

                fb[(y*MAX_WIDTH)+x] = pix.data;
            }
        }
    }
    return(0);
}

  1. 2018年11月05日 05:43 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

『ビブリア古書堂の事件手帖』(映画)を見てきました

今日、『ビブリア古書堂の事件手帖』(映画)を見てきました。
おばあさんの回想シーンが多すぎて、視点が分散されている気がしました。あまり良くなかったです。
  1. 2018年11月04日 20:43 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ultra96 USB-to-JTAG/UART Pod が来ました

Ultra96 USB-to-JTAG/UART Pod がAvnet から配送されてきました。
Ultra96_USB2JTAG_1_1811102.jpg

Ultra96 USB-to-JTAG/UART Pod の表です。
ついてきた一枚のみのマニュアルには、ドライバが自動的にインストールされないので、FT2232HのドライバをURLからインストールするように書いてありました。
Ultra96_USB2JTAG_3_1811102.jpg

裏面です。
Ultra96_USB2JTAG_2_1811102.jpg

通常は現在使用している@ciniml さんの変換基板を使用したJTAGとUART で十分使えているのですが、ノートパソコンだと、USBポートが1つで済むUltra96 USB-to-JTAG/UART Pod がありがたいです。
  1. 2018年11月02日 06:55 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードでカメラ入力2(mt9d111_inf_axis IP の作成2)

Ultra96用PMOD拡張ボードでカメラ入力1(mt9d111_inf_axis IP の作成1)”の続き。

前回は、Ultra96用PMOD拡張ボードにMT9D111を接続して、Frame Buffer に書き込むプロジェクトを作成したい。ということで、カメラのMT9D111 のインターフェース用IP を作り始めた。手始めにカメラのデータとAXI4-Stream のデータの橋渡しをする pixel_fifo という名前の非同期FIFO を生成した。今回は、pixel_fifo を使用したカメラのMT9D111 のインターフェース用IP mt9d111_inf_axis を作成する。

次に、Verilog HDL と VHDL のファイルをVivado プロジェクトに追加した。
disp_timing_parameters.vh, mt9d111_axi_lite_slave.v, mt9d111_cam_cont.v, mt9d111_inf_axims.vhd
Vivado プロジェクトの様子を示す。
mt9d111_axis_mpsoc_7_181030.png

Simulation 用のファイルも追加した。
mt9d111_axis_mpsoc_8_181030.png

mt9d111_axis_mpsoc ディレクトリの様子も示す。hdl ディレクトリの下にVerilog と VHDL のディレクトリがあってHDL ファイルがある。Simulation ディレクトリの下には、シミュレーション用のHDL ファイルが入っている。
mt9d111_axis_mpsoc_9_181030.png

さて、プロジェクトが出来たので、IP 化を行う。
Tools メニューからCreate and Package New IP... を選択した。
Create and Package New IP ダイアログが開く。Next > ボタンをクリックする。
mt9d111_axis_mpsoc_10_181030.png

Create Peripheral, Package IP or Package a Block Design が開いた。
デフォルトのまま、Next > ボタンをクリックする。
mt9d111_axis_mpsoc_11_181030.png

Package Your Current Project で、デフォルトのまま、Next > ボタンをクリックする。
mt9d111_axis_mpsoc_12_181030.png

Summary が表示された。Finish ボタンをクリックする。
mt9d111_axis_mpsoc_13_181030.png

Package IP ウインドウが開く。
最後のReview and Package 画面で、Edit packaging settings をクリックする。
mt9d111_axis_mpsoc_14_181030.png

Settings ダイアログが開く。
Automatic Behavior のAfter Packing のCreate archive of IP にチェックを入れる。
mt9d111_axis_mpsoc_15_181030.png

Review and Package 画面で、Package IP ボタンをクリックして、IP 化を行った。

mt9d111_axis_mpsoc ディレクトリに user.org_user_mt9d111_inf_axis_1.0.zip が生成された。
mt9d111_axis_mpsoc_16_181030.png

Package IP ウインドウの各画面を示す。
Identification
mt9d111_axis_mpsoc_17_181031.png

Compatibility 。なんか画面が表示されない?
mt9d111_axis_mpsoc_18_181031.png

File Groups
mt9d111_axis_mpsoc_19_181031.png

Customization Parameters
mt9d111_axis_mpsoc_20_181031.png

Ports and Interfaces
mt9d111_axis_mpsoc_21_181031.png

Addressing and Memory
mt9d111_axis_mpsoc_22_181031.png

Customization GUI
mt9d111_axis_mpsoc_23_181031.png

Review and Package 。一回パッケージ化しているので、Re-Package IP になっている。
mt9d111_axis_mpsoc_24_181031.png
  1. 2018年11月01日 06:26 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0