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

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

FPGAの部屋

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

Ultra96用Yocto Linuxのビルド

Ultra96 のDisplayPort がベアメタルで動かないし、めどが立たないので、Ultra96 用のYocto Linux をビルドしてみることにした。参考にするのは、ひでみさんの薄い本の「超苦労したFPGAの薄い本 Yocto Projectと立ち上げ編」だ。なお、「超苦労したFPGAの薄い本(高位合成とリコンフィグ編)」もあって、そちらも購入済みだ。

さて、Ultra96 用のYocto をビルドしよう。なお、手順は「超苦労したFPGAの薄い本 Yocto Projectと立ち上げ編」に書いてあるので、詳しくは書かない。本を参照のこと。

download_meta.sh を実行して、ダウンロードし、poky ディレクトリに cd して、
source ./oe-init-build-env ../build_zynqmp
を実行した。(ここは、本の記述と違っている)

bblayers.conf と local.conf を書き換えて
bitbake core-image-minimal
でYocto をビルドした。
その結果、bblayers.conf の

DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
IMAGE_INSTALL_append = " dhcp"

をコメントアウトしないとビルドが通らなかった。

ビルドが順調に通っているようなので、時間かかると思って寝た。そして、次の朝に起きてみたらUbuntu が再起動していた。
どうしたこと?ということで、ログインして再度
source ./oe-init_build-env ../build_zynqmp
bitbake core-image-minimal
したら、ビルドは終了していたみたいだ。
Ultra96_Yocto_1_180831.png
Ultra96_Yocto_2_180831.png
Ultra96_Yocto_3_180831.png

masaaki@masaaki-H110M4-M01:~/Ultra96_Yocto/poky$ source ./oe-init-build-env ../build_zynqmp

### Shell environment set up for builds. ###

You can now run 'bitbake <target>'

Common targets are:
    core-image-minimal
    core-image-sato
    meta-toolchain
    meta-ide-support

You can also run generated qemu images with a command like 'runqemu qemux86'
masaaki@masaaki-H110M4-M01:~/Ultra96_Yocto/build_zynqmp$ bitbake core-image-minimal
Loading cache: 100% |############################################| Time: 0:00:00
Loaded 2102 entries from dependency cache.
Parsing recipes: 100% |##########################################| Time: 0:00:00
Parsing of 1470 .bb files complete (1469 cached, 1 parsed). 2103 targets, 321 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION           = "1.38.0"
BUILD_SYS            = "x86_64-linux"
NATIVELSBSTRING      = "universal"
TARGET_SYS           = "aarch64-poky-linux"
MACHINE              = "zcu102-zynqmp"
DISTRO               = "poky"
DISTRO_VERSION       = "2.5.1"
TUNE_FEATURES        = "aarch64"
TARGET_FPU           = ""
meta                 
meta-poky            
meta-yocto-bsp       = "sumo:45ef387cc54a0584807e05a952e1e4681ec4c664"
meta-oe              = "sumo:b0950aeff5b630256bb5e25ca15f4d59c115e7c1"
meta-xilinx-bsp      
meta-xilinx-contrib  = "sumo:5fccc46503e468ed024185ed032891799a31db58"

Initialising tasks: 100% |#######################################| Time: 0:00:02
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
WARNING: core-image-minimal-1.0-r0 do_image_wic: Manifest /home/masaaki/Ultra96_Yocto/build_zynqmp/tmp/sstate-control/manifest-x86_64_aarch64-zynqmp-pmu-gcc-cross-microblazeel.populate_sysroot not found in x86_64_aarch64 (variant '')?
WARNING: core-image-minimal-1.0-r0 do_image_wic: Manifest /home/masaaki/Ultra96_Yocto/build_zynqmp/tmp/sstate-control/manifest-x86_64_aarch64-zynqmp-pmu-binutils-cross-microblazeel.populate_sysroot not found in x86_64_aarch64 (variant '')?
WARNING: core-image-minimal-1.0-r0 do_image_complete: Manifest /home/masaaki/Ultra96_Yocto/build_zynqmp/tmp/sstate-control/manifest-x86_64_aarch64-zynqmp-pmu-gcc-cross-microblazeel.populate_sysroot not found in x86_64_aarch64 (variant '')?
WARNING: core-image-minimal-1.0-r0 do_image_complete: Manifest /home/masaaki/Ultra96_Yocto/build_zynqmp/tmp/sstate-control/manifest-x86_64_aarch64-zynqmp-pmu-binutils-cross-microblazeel.populate_sysroot not found in x86_64_aarch64 (variant '')?
NOTE: Tasks Summary: Attempted 3454 tasks of which 2725 didn't need to be rerun and all succeeded.

Summary: There were 4 WARNING messages shown.


ビルドの生成物を示す。
Ultra96_Yocto_4_180831.png
Ultra96_Yocto_5_180831.png
Ultra96_Yocto_6_180831.png

Image
Image--4.14-xilinx-v2018.1+git0+4ac76ffacb-r0-zcu102-zynqmp-20180830124849.bin
Image--4.14-xilinx-v2018.1+git0+4ac76ffacb-r0-zynqmp-zcu102-rev1.0-20180830124849.dtb
Image-zcu102-zynqmp.bin
Image-zynqmp-zcu102-rev1.0.dtb
arm-trusted-firmware--1.4-xilinx-v2018.1+gitAUTOINC+df4a7e97d5-r0-20180830180835.bin
arm-trusted-firmware--1.4-xilinx-v2018.1+gitAUTOINC+df4a7e97d5-r0-20180830180835.elf
arm-trusted-firmware--1.4-xilinx-v2018.1+gitAUTOINC+df4a7e97d5-r0-20180830180835.ub
arm-trusted-firmware.bin
arm-trusted-firmware.elf
arm-trusted-firmware.ub
atf-uboot.ub
boot.bin
boot.bin-zcu102-zynqmp
boot.bin-zcu102-zynqmp-v2018.01-xilinx-v2018.1+gitAUTOINC+949e5cb9a7-r0
core-image-minimal-zcu102-zynqmp-20180830180835.qemuboot.conf
core-image-minimal-zcu102-zynqmp-20180830180835.rootfs.cramfs
core-image-minimal-zcu102-zynqmp-20180830180835.rootfs.manifest
core-image-minimal-zcu102-zynqmp-20180830180835.rootfs.tar.gz
core-image-minimal-zcu102-zynqmp-20180830180835.rootfs.wic.qemu-sd
core-image-minimal-zcu102-zynqmp-20180830180835.testdata.json
core-image-minimal-zcu102-zynqmp.cramfs
core-image-minimal-zcu102-zynqmp.manifest
core-image-minimal-zcu102-zynqmp.qemuboot.conf
core-image-minimal-zcu102-zynqmp.tar.gz
core-image-minimal-zcu102-zynqmp.testdata.json
core-image-minimal-zcu102-zynqmp.wic.qemu-sd
modules--4.14-xilinx-v2018.1+git0+4ac76ffacb-r0-zcu102-zynqmp-20180830124849.tgz
modules-zcu102-zynqmp.tgz
pmu-firmware--v2018.1+gitAUTOINC+aaa566bc3f-r0-zcu102-zynqmp-20180830180835.bin
pmu-firmware--v2018.1+gitAUTOINC+aaa566bc3f-r0-zcu102-zynqmp-20180830180835.elf
pmu-firmware-zcu102-zynqmp.bin
pmu-firmware-zcu102-zynqmp.elf
pmu-zcu102-zynqmp.bin
pmu-zcu102-zynqmp.elf
qemu-hw-devicetrees
u-boot-zcu102-zynqmp-v2018.01-xilinx-v2018.1+gitAUTOINC+949e5cb9a7-r0.bin
u-boot-zcu102-zynqmp-v2018.01-xilinx-v2018.1+gitAUTOINC+949e5cb9a7-r0.elf
u-boot-zcu102-zynqmp.bin
u-boot-zcu102-zynqmp.elf
u-boot.bin
u-boot.elf
uEnv.txt
zynqmp-zcu102-rev1.0.dtb

  1. 2018年08月31日 04:55 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Duplicate IP の製作2(Vivado HLS プロジェクト)

Duplicate IP の製作1(ソースコード)”の続き。

前回は、1 つの HLS ストリームを 2 つにするDuplicate IP のソースコードを示した。今回は、そのソースコードを使用して、Vivado HLS 2018.2 のプロジェクトを作成して、IP 化まで行う。

Vivado HLS 2018.2 の duplicate プロジェクトを示す。
split_1_180829.png

C シミュレーションを行った。結果を示す。
split_2_180829.png

No Error だった。2つのHLS ストリームが同一だった。

C コードの合成を行った。
split_3_180829.png

Estimated は 5.403 ns で十分だ。
Latency も 784 ピクセルなので、 790 クロックということは、ほとんど 1 ピクセル / クロックになっている。
リソース使用量は、FF が 106 個、LUT が 464 個だった。
次に、Detail -> Instance の grp_split_template_fu_186 をクリックして、split_template の結果を見てみよう。
split_4_180829.png

こちらのLatency は 789 クロックだった。
リソース使用量は、FF が 103 個、LUT が 341 個だった。

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

Latency は 795 クロックだった。

C/RTL 協調シミュレーションの波形を示す。
split_6_180829.png

制御信号がほとんど一直線で良さそうだ。

Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れている。
split_7_180829.png

CP achieved post-implementation も 4.348 ns で問題ない。
  1. 2018年08月30日 05:02 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Duplicate IP の製作1(ソースコード)

SqueezeNet4mnist をVivado HLSのテンプレートで実装しようと思ったときに、1つのHLSストリームを 2 つのHLSストリームに分ける Duplicate IP と 2 つのHLSストリームを 1 つのHLSストリームにする Concatenate IP が必要となる。
今回は、Duplicate IP を作ってみよう。

まずは、duplicate_template.h を貼っておく。

// duplicate_template.h
// 2018/08/23 by marsee
//

#ifndef __DUPLICATE_TEMPLATE_H___
#define __DUPLICATE_TEMPLATE_H___

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

#include "layer_general.h"

#define TO_LITERAL(x) #x
#define PRAGMA_HLS(tok) _Pragma(TO_LITERAL(HLS tok)) // @hiyuhさんから

template<
    const size_t IN_W,     // 入力のビット幅、2つの入力のビット幅と小数点位置は合わせる
    const size_t IN_I,     // 入力の小数点位置
    const size_t NUMBER_OF_IN_CHANNELS,
    const size_t HORIZONTAL_PIXEL_WIDTH,
    const size_t VERTICAL_PIXEL_WIDTH
>int duplicate_template(hls::stream<ap_fixed_axis<IN_W,IN_I,NUMBER_OF_IN_CHANNELS,1> >&ins,
    hls::stream<ap_fixed_axis<IN_W,IN_I,NUMBER_OF_IN_CHANNELS,1> >&outs0,
    hls::stream<ap_fixed_axis<IN_W,IN_I,NUMBER_OF_IN_CHANNELS,1> >&outs1
){
    ap_fixed_axis<IN_W,IN_I,NUMBER_OF_IN_CHANNELS,1> in;
    ap_fixed_axis<IN_W,IN_I,NUMBER_OF_IN_CHANNELS,1> out;

    Loop1 : do { // user が 1になった時にスタートする
#pragma HLS PIPELINE II=1
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> in;
    } while(in.user == 0);

    Loop_y : for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        Loop_x : for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
            if(!(x==0 && y==0)){
                ins >> in;
            }

            Loop_cp : for(int i=0; i<NUMBER_OF_IN_CHANNELS; i++){
                if(i<NUMBER_OF_IN_CHANNELS){
                    out.data[i] = in.data[i];
                }
            }

            out.user = in.user;
            out.last = in.last;

            outs0 << out;
            outs1 << out;
        }
    }
    return(0);
}

#endif


HLSストリームを 2 つのHLSストリームに分けるだけの記述になっている。

次に、duplicate_template.h をインスタンスする duplicate1.cpp を貼っておく。

// duplicate1.cpp
// 2018/08/23 by marsee
//

#include "duplicate_template.h"

int duplicate1(hls::stream<ap_fixed_axis<16,6,2,1> >& ins,
        hls::stream<ap_fixed_axis<16,6,2,1> >& outs0,
        hls::stream<ap_fixed_axis<16,6,2,1> >& outs1){
    return(duplicate_template<16,6,2,28,28>(ins, outs0, outs1));
}



最後にテストベンチの duplicate1_tb.cpp を貼っておく。

// duplicate1_tb.cpp
// 2018/08/23 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "layer_general.h"

static const size_t NW = 16;
static const size_t NI = 6;
static const size_t NUMBER_OF_KERNEL = 2;
static const size_t HORIZONTAL_PIXEL_WIDTH = 28;
static const size_t VERTICAL_PIXEL_WIDTH = 28;

int duplicate1(hls::stream<ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> >& ins,
        hls::stream<ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> >& outs0,
        hls::stream<ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> >& outs1);

int main(){
    using namespace std;

    hls::stream<ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> > ins;
    hls::stream<ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> > outs0;
    hls::stream<ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> > outs1;
    ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> in;
    ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> out0;
    ap_fixed_axis<NW,NI,NUMBER_OF_KERNEL,1> out1;

    typedef ap_fixed<NW,NI,AP_TRN,AP_WRAP> ap_fixed_type;

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        in.user = 0;
        for(int k=0; k<NUMBER_OF_KERNEL; k++){
            in.data[k] = ap_fixed_type(float(k+i)/100.0);
        }
        ins << in;
    }

    // 1 画面分のデータを insに入力する
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(int i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            for(int k=0; k<NUMBER_OF_KERNEL; k++){
                in.data[k] = ap_fixed_type((float)(k+HORIZONTAL_PIXEL_WIDTH*j+i)/100.0);
            }

            if (j==0 && i==0){    // 最初のデータの時に TUSER を 1 にする
                in.user = 1;
            } else {
                in.user = 0;
            }

            if (i == HORIZONTAL_PIXEL_WIDTH-1){ // 行の最後でTLASTをアサートする
                in.last = 1;
            } else {
                in.last = 0;
            }
            ins << in;
        }
    }

    duplicate1(ins, outs0, outs1);

    // outs0 と outs1 を比較する
    int error = 0;
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(int i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            outs0 >> out0;
            outs1 >> out1;
            for(int k=0; k<NUMBER_OF_KERNEL; k++){
                if(out0.data[k] != out1.data[k]){
                    printf("Error : out0.data[%d] = %f, out1.data[%d] = %f\n", k, float(out0.data[k]), k, float(out1.data[k]));
                    error = 1;
                }
            }

            if(j==0 && i==0){
                if(out0.user==1 && out1.user==1) ;
                else{
                    printf("j==0 && i==0 : out0.user = %d, out1.user = %d\n", out0.user, out1.user);
                    error = 1;
                }
            } else {
                if(out0.user==0 && out1.user==0) ;
                else{
                    printf("j!=0 || i!=0 : out0.user = %d, out1.user = %d\n", out0.user, out1.user);
                    error = 1;
                }
            }

            if(i == HORIZONTAL_PIXEL_WIDTH-1){
                if(out0.last==1 && out1.last==1) ;
                else{
                    printf("Horizontal last data : out0.last = %d, out1.last = %d\n", out0.last, out1.last);
                    error = 1;
                }
            }
        }
    }
    if(error == 0)
        printf("No Error\n");

    return(0);
}


テストベンチはHLSストリームのデータを用意して duplicate1 を呼び出して、出力された 2 つのHLSストリームの outs0, outs1 を比べて同一かどうか?をテストするテストベンチとなっている。
  1. 2018年08月29日 05:17 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST 3(層の統計情報とC ヘッダ・ファイルへの出力)

SqueezeNet for MNIST 2”の続き。

前回は、model accuracy と model loss を示し、model.summary() を示した。今回は、層の統計情報を取って、各層の重みとバイアスのC ヘッダ・ファイルを出力する。

畳み込み層の重みをCヘッダファイルに書き出すPython コードは”TensorFlow + Kerasを使ってみた9(畳み込み層の重みをC のヘッダに変換)”のPython コードを使用した。
畳み込み層バイアスをCヘッダファイルに書き出すPython コードは”TensorFlow + Kerasを使ってみた10(バイアスをC のヘッダに変換)”のPython コードを使用した。

それから、層の統計情報出力し、重みとバイアスをC ヘッダ・ファイルに出力した。
squeezenet4mnist_11_180828.png
squeezenet4mnist_12_180828.png

Python コードを貼っておく。

# Convolution layerの中間出力を取り出す 
from keras.models import Model
import numpy as np

for num in range(1, 27):
    conv_layer_name = 'conv2d_' + str(num)

    conv_layer = model.get_layer(conv_layer_name)
    conv_layer_wb = conv_layer.get_weights()

    conv_layer_model = Model(inputs=model.input,
                                     outputs=model.get_layer(conv_layer_name).output)
    conv_output = conv_layer_model.predict(x_test, verbose=1)

    conv_layer_weight = conv_layer_wb[0]
    conv_layer_bias = conv_layer_wb[1]

    print(conv_layer_name)
    print(conv_layer_weight.shape)
    print(conv_layer_weight.transpose(3,2,0,1).shape)
    print(conv_layer_bias.shape)
    print(conv_output.shape)

    print("np.max(conv_layer_weight) = {0}".format(np.max(conv_layer_weight)))
    print("np.min(conv_layer_weight) = {0}".format(np.min(conv_layer_weight))) 
    abs_conv_layer_weight = np.absolute(conv_layer_weight)
    print("np.max(abs_conv_layer_weight) = {0}".format(np.max(abs_conv_layer_weight)))
    print("np.min(abs_conv_layer_weight) = {0}".format(np.min(abs_conv_layer_weight))) 

    print("np.max(conv_layer_bias) = {0}".format(np.max(conv_layer_bias)))
    print("np.min(conv_layer_bias) = {0}".format(np.min(conv_layer_bias))) 
    abs_conv_layer_bias = np.absolute(conv_layer_bias)
    print("np.max(abs_conv_layer_bias) = {0}".format(np.max(abs_conv_layer_bias)))
    print("np.min(abs_conv_layer_bias) = {0}".format(np.min(abs_conv_layer_bias))) 

    print("conv_output = {0}".format(conv_output.shape))
    print("np.std(conv_output) = {0}".format(np.std(conv_output)))
    print("np.max(conv_output) = {0}".format(np.max(conv_output)))
    print("np.min(conv_output) = {0}".format(np.min(conv_output))) 

    abs_conv_output = np.absolute(conv_output)
    print("np.max(abs_conv) = {0}".format(np.max(abs_conv_output)))
    print("np.min(abs_conv) = {0}".format(np.min(abs_conv_output))) 
    print("")
    
    # 2018/06/05 修正 畳み込み層の重みの配列は(カーネルサイズh,カーネルサイズw, 入力チャネル, 出力チャネル)ということなので、Pythonコードを修正した。@NORA__0013 さんありがとうございました。

    MAGNIFICATION_CONV = 2 ** (9-1)
    fwrite_conv_weight(conv_layer_weight.transpose(3,2,0,1), 'conv'+str(num)+'_weight.h', 'conv'+str(num)+'_fweight', 'conv'+str(num)+'_weight', MAGNIFICATION_CONV)

    fwrite_bias(conv_layer_bias, 'conv'+str(num)+'_bias.h', 'conv'+str(num)+'_fbias', 'conv'+str(num)+'_bias', MAGNIFICATION_CONV)


生成された重みとバイアスを示す。
squeezenet4mnist_13_180828.png

全統計情報を示す。

10000/10000 [==============================] - 1s 137us/step
conv2d_1
(3, 3, 1, 96)
(96, 1, 3, 3)
(96,)
(10000, 13, 13, 96)
np.max(conv_layer_weight) = 0.23241539299488068
np.min(conv_layer_weight) = -0.2830057442188263
np.max(abs_conv_layer_weight) = 0.2830057442188263
np.min(abs_conv_layer_weight) = 0.00018287629063706845
np.max(conv_layer_bias) = 0.19594410061836243
np.min(conv_layer_bias) = -0.06709111481904984
np.max(abs_conv_layer_bias) = 0.19594410061836243
np.min(abs_conv_layer_bias) = 0.0003071741375606507
conv_output = (10000, 13, 13, 96)
np.std(conv_output) = 0.1008128821849823
np.max(conv_output) = 0.657059371471405
np.min(conv_output) = -0.7351041436195374
np.max(abs_conv) = 0.7351041436195374
np.min(abs_conv) = 1.3969838619232178e-09

10000/10000 [==============================] - 1s 84us/step
conv2d_2
(1, 1, 96, 16)
(16, 96, 1, 1)
(16,)
(10000, 6, 6, 16)
np.max(conv_layer_weight) = 0.41374555230140686
np.min(conv_layer_weight) = -0.4286271035671234
np.max(abs_conv_layer_weight) = 0.4286271035671234
np.min(abs_conv_layer_weight) = 0.00025720358826220036
np.max(conv_layer_bias) = 0.07645587623119354
np.min(conv_layer_bias) = -0.04433523118495941
np.max(abs_conv_layer_bias) = 0.07645587623119354
np.min(abs_conv_layer_bias) = 0.0009641082142479718
conv_output = (10000, 6, 6, 16)
np.std(conv_output) = 0.29928353428840637
np.max(conv_output) = 1.535873293876648
np.min(conv_output) = -1.057706356048584
np.max(abs_conv) = 1.535873293876648
np.min(abs_conv) = 1.825392246246338e-07

10000/10000 [==============================] - 1s 111us/step
conv2d_3
(1, 1, 16, 64)
(64, 16, 1, 1)
(64,)
(10000, 6, 6, 64)
np.max(conv_layer_weight) = 0.3813319504261017
np.min(conv_layer_weight) = -0.3624926209449768
np.max(abs_conv_layer_weight) = 0.3813319504261017
np.min(abs_conv_layer_weight) = 0.0003253854811191559
np.max(conv_layer_bias) = 0.08430161327123642
np.min(conv_layer_bias) = -0.06795598566532135
np.max(abs_conv_layer_bias) = 0.08430161327123642
np.min(abs_conv_layer_bias) = 0.0005309522384777665
conv_output = (10000, 6, 6, 64)
np.std(conv_output) = 0.19837331771850586
np.max(conv_output) = 1.1776185035705566
np.min(conv_output) = -0.9223350882530212
np.max(abs_conv) = 1.1776185035705566
np.min(abs_conv) = 7.450580596923828e-09

10000/10000 [==============================] - 1s 107us/step
conv2d_4
(3, 3, 16, 64)
(64, 16, 3, 3)
(64,)
(10000, 6, 6, 64)
np.max(conv_layer_weight) = 0.23302672803401947
np.min(conv_layer_weight) = -0.23958751559257507
np.max(abs_conv_layer_weight) = 0.23958751559257507
np.min(abs_conv_layer_weight) = 3.953342002205318e-06
np.max(conv_layer_bias) = 0.09260329604148865
np.min(conv_layer_bias) = -0.07423409074544907
np.max(abs_conv_layer_bias) = 0.09260329604148865
np.min(abs_conv_layer_bias) = 4.278140841051936e-05
conv_output = (10000, 6, 6, 64)
np.std(conv_output) = 0.3154037594795227
np.max(conv_output) = 1.8085815906524658
np.min(conv_output) = -2.099088191986084
np.max(abs_conv) = 2.099088191986084
np.min(abs_conv) = 2.2351741790771484e-08

10000/10000 [==============================] - 1s 109us/step
conv2d_5
(1, 1, 128, 16)
(16, 128, 1, 1)
(16,)
(10000, 6, 6, 16)
np.max(conv_layer_weight) = 0.3283624053001404
np.min(conv_layer_weight) = -0.32311302423477173
np.max(abs_conv_layer_weight) = 0.3283624053001404
np.min(abs_conv_layer_weight) = 9.099296585191041e-05
np.max(conv_layer_bias) = 0.11211202293634415
np.min(conv_layer_bias) = -0.023712079972028732
np.max(abs_conv_layer_bias) = 0.11211202293634415
np.min(abs_conv_layer_bias) = 0.00019536164472810924
conv_output = (10000, 6, 6, 16)
np.std(conv_output) = 0.39457967877388
np.max(conv_output) = 3.2098631858825684
np.min(conv_output) = -1.4322690963745117
np.max(abs_conv) = 3.2098631858825684
np.min(abs_conv) = 2.9802322387695312e-08

10000/10000 [==============================] - 1s 116us/step
conv2d_6
(1, 1, 16, 64)
(64, 16, 1, 1)
(64,)
(10000, 6, 6, 64)
np.max(conv_layer_weight) = 0.3472273051738739
np.min(conv_layer_weight) = -0.3461221754550934
np.max(abs_conv_layer_weight) = 0.3472273051738739
np.min(abs_conv_layer_weight) = 2.151904845959507e-05
np.max(conv_layer_bias) = 0.11182372272014618
np.min(conv_layer_bias) = -0.07308819890022278
np.max(abs_conv_layer_bias) = 0.11182372272014618
np.min(abs_conv_layer_bias) = 9.089573723031208e-05
conv_output = (10000, 6, 6, 64)
np.std(conv_output) = 0.28788891434669495
np.max(conv_output) = 2.15021014213562
np.min(conv_output) = -1.765142560005188
np.max(abs_conv) = 2.15021014213562
np.min(abs_conv) = 1.4901161193847656e-08

10000/10000 [==============================] - 1s 134us/step
conv2d_7
(3, 3, 16, 64)
(64, 16, 3, 3)
(64,)
(10000, 6, 6, 64)
np.max(conv_layer_weight) = 0.25860607624053955
np.min(conv_layer_weight) = -0.22963279485702515
np.max(abs_conv_layer_weight) = 0.25860607624053955
np.min(abs_conv_layer_weight) = 5.8508041547611356e-05
np.max(conv_layer_bias) = 0.08639949560165405
np.min(conv_layer_bias) = -0.08458155393600464
np.max(abs_conv_layer_bias) = 0.08639949560165405
np.min(abs_conv_layer_bias) = 8.820320363156497e-05
conv_output = (10000, 6, 6, 64)
np.std(conv_output) = 0.4426092207431793
np.max(conv_output) = 2.844907522201538
np.min(conv_output) = -2.9819791316986084
np.max(abs_conv) = 2.9819791316986084
np.min(abs_conv) = 1.1175870895385742e-08

10000/10000 [==============================] - 1s 142us/step
conv2d_8
(1, 1, 128, 32)
(32, 128, 1, 1)
(32,)
(10000, 6, 6, 32)
np.max(conv_layer_weight) = 0.3010956645011902
np.min(conv_layer_weight) = -0.31097307801246643
np.max(abs_conv_layer_weight) = 0.31097307801246643
np.min(abs_conv_layer_weight) = 4.14710957556963e-05
np.max(conv_layer_bias) = 0.11694670468568802
np.min(conv_layer_bias) = -0.049082059413194656
np.max(abs_conv_layer_bias) = 0.11694670468568802
np.min(abs_conv_layer_bias) = 0.00034066737862303853
conv_output = (10000, 6, 6, 32)
np.std(conv_output) = 0.4840845465660095
np.max(conv_output) = 2.9063262939453125
np.min(conv_output) = -3.1062679290771484
np.max(abs_conv) = 3.1062679290771484
np.min(abs_conv) = 7.182825356721878e-08

10000/10000 [==============================] - 2s 157us/step
conv2d_9
(1, 1, 32, 128)
(128, 32, 1, 1)
(128,)
(10000, 6, 6, 128)
np.max(conv_layer_weight) = 0.2580183744430542
np.min(conv_layer_weight) = -0.2867690324783325
np.max(abs_conv_layer_weight) = 0.2867690324783325
np.min(abs_conv_layer_weight) = 5.197449354454875e-06
np.max(conv_layer_bias) = 0.08810567855834961
np.min(conv_layer_bias) = -0.10537270456552505
np.max(abs_conv_layer_bias) = 0.10537270456552505
np.min(abs_conv_layer_bias) = 0.0009785539004951715
conv_output = (10000, 6, 6, 128)
np.std(conv_output) = 0.21309173107147217
np.max(conv_output) = 1.4621883630752563
np.min(conv_output) = -1.9276840686798096
np.max(abs_conv) = 1.9276840686798096
np.min(abs_conv) = 1.862645149230957e-09

10000/10000 [==============================] - 2s 198us/step
conv2d_10
(3, 3, 32, 128)
(128, 32, 3, 3)
(128,)
(10000, 6, 6, 128)
np.max(conv_layer_weight) = 0.24369853734970093
np.min(conv_layer_weight) = -0.23873521387577057
np.max(abs_conv_layer_weight) = 0.24369853734970093
np.min(abs_conv_layer_weight) = 2.737535396590829e-06
np.max(conv_layer_bias) = 0.06724698841571808
np.min(conv_layer_bias) = -0.08158554136753082
np.max(abs_conv_layer_bias) = 0.08158554136753082
np.min(abs_conv_layer_bias) = 0.00012395322846714407
conv_output = (10000, 6, 6, 128)
np.std(conv_output) = 0.4583068788051605
np.max(conv_output) = 3.0841262340545654
np.min(conv_output) = -3.095609426498413
np.max(abs_conv) = 3.095609426498413
np.min(abs_conv) = 5.587935447692871e-09

10000/10000 [==============================] - 2s 208us/step
conv2d_11
(1, 1, 256, 32)
(32, 256, 1, 1)
(32,)
(10000, 3, 3, 32)
np.max(conv_layer_weight) = 0.2613295018672943
np.min(conv_layer_weight) = -0.2657088041305542
np.max(abs_conv_layer_weight) = 0.2657088041305542
np.min(abs_conv_layer_weight) = 6.479893636424094e-05
np.max(conv_layer_bias) = 0.08481862396001816
np.min(conv_layer_bias) = -0.04361288622021675
np.max(abs_conv_layer_bias) = 0.08481862396001816
np.min(abs_conv_layer_bias) = 0.0018431995995342731
conv_output = (10000, 3, 3, 32)
np.std(conv_output) = 0.6534223556518555
np.max(conv_output) = 4.2715630531311035
np.min(conv_output) = -3.003734827041626
np.max(abs_conv) = 4.2715630531311035
np.min(abs_conv) = 6.174668669700623e-07

10000/10000 [==============================] - 2s 233us/step
conv2d_12
(1, 1, 32, 128)
(128, 32, 1, 1)
(128,)
(10000, 3, 3, 128)
np.max(conv_layer_weight) = 0.24686792492866516
np.min(conv_layer_weight) = -0.245181143283844
np.max(abs_conv_layer_weight) = 0.24686792492866516
np.min(abs_conv_layer_weight) = 0.00010391152318334207
np.max(conv_layer_bias) = 0.1275489628314972
np.min(conv_layer_bias) = -0.09533561766147614
np.max(abs_conv_layer_bias) = 0.1275489628314972
np.min(abs_conv_layer_bias) = 0.0002949666231870651
conv_output = (10000, 3, 3, 128)
np.std(conv_output) = 0.30596160888671875
np.max(conv_output) = 2.30812931060791
np.min(conv_output) = -1.7490240335464478
np.max(abs_conv) = 2.30812931060791
np.min(abs_conv) = 6.332993507385254e-08

10000/10000 [==============================] - 2s 231us/step
conv2d_13
(3, 3, 32, 128)
(128, 32, 3, 3)
(128,)
(10000, 3, 3, 128)
np.max(conv_layer_weight) = 0.16889545321464539
np.min(conv_layer_weight) = -0.1818806380033493
np.max(abs_conv_layer_weight) = 0.1818806380033493
np.min(abs_conv_layer_weight) = 5.960464477539063e-08
np.max(conv_layer_bias) = 0.10003684461116791
np.min(conv_layer_bias) = -0.07217587530612946
np.max(abs_conv_layer_bias) = 0.10003684461116791
np.min(abs_conv_layer_bias) = 6.108602974563837e-06
conv_output = (10000, 3, 3, 128)
np.std(conv_output) = 0.38053178787231445
np.max(conv_output) = 2.981738805770874
np.min(conv_output) = -2.0631744861602783
np.max(abs_conv) = 2.981738805770874
np.min(abs_conv) = 4.470348358154297e-08

10000/10000 [==============================] - 2s 229us/step
conv2d_14
(1, 1, 256, 48)
(48, 256, 1, 1)
(48,)
(10000, 3, 3, 48)
np.max(conv_layer_weight) = 0.22013017535209656
np.min(conv_layer_weight) = -0.2426384836435318
np.max(abs_conv_layer_weight) = 0.2426384836435318
np.min(abs_conv_layer_weight) = 5.409237928688526e-06
np.max(conv_layer_bias) = 0.127075657248497
np.min(conv_layer_bias) = -0.07448185980319977
np.max(abs_conv_layer_bias) = 0.127075657248497
np.min(abs_conv_layer_bias) = 6.410764763131738e-05
conv_output = (10000, 3, 3, 48)
np.std(conv_output) = 0.4870619773864746
np.max(conv_output) = 4.841851711273193
np.min(conv_output) = -3.36439847946167
np.max(abs_conv) = 4.841851711273193
np.min(abs_conv) = 5.21540641784668e-07

10000/10000 [==============================] - 2s 246us/step
conv2d_15
(1, 1, 48, 192)
(192, 48, 1, 1)
(192,)
(10000, 3, 3, 192)
np.max(conv_layer_weight) = 0.2446354627609253
np.min(conv_layer_weight) = -0.212723970413208
np.max(abs_conv_layer_weight) = 0.2446354627609253
np.min(abs_conv_layer_weight) = 1.650952617637813e-05
np.max(conv_layer_bias) = 0.10810786485671997
np.min(conv_layer_bias) = -0.11747808754444122
np.max(abs_conv_layer_bias) = 0.11747808754444122
np.min(abs_conv_layer_bias) = 0.0001598717353772372
conv_output = (10000, 3, 3, 192)
np.std(conv_output) = 0.2135731279850006
np.max(conv_output) = 2.3861021995544434
np.min(conv_output) = -1.382702112197876
np.max(abs_conv) = 2.3861021995544434
np.min(abs_conv) = 7.450580596923828e-09

10000/10000 [==============================] - 3s 274us/step
conv2d_16
(3, 3, 48, 192)
(192, 48, 3, 3)
(192,)
(10000, 3, 3, 192)
np.max(conv_layer_weight) = 0.1449326127767563
np.min(conv_layer_weight) = -0.13954271376132965
np.max(abs_conv_layer_weight) = 0.1449326127767563
np.min(abs_conv_layer_weight) = 4.5239175960887223e-08
np.max(conv_layer_bias) = 0.0911775752902031
np.min(conv_layer_bias) = -0.07379891723394394
np.max(abs_conv_layer_bias) = 0.0911775752902031
np.min(abs_conv_layer_bias) = 7.930440187919885e-05
conv_output = (10000, 3, 3, 192)
np.std(conv_output) = 0.26481249928474426
np.max(conv_output) = 2.032439708709717
np.min(conv_output) = -2.2265918254852295
np.max(abs_conv) = 2.2265918254852295
np.min(abs_conv) = 7.450580596923828e-09

10000/10000 [==============================] - 3s 278us/step
conv2d_17
(1, 1, 384, 48)
(48, 384, 1, 1)
(48,)
(10000, 3, 3, 48)
np.max(conv_layer_weight) = 0.18762683868408203
np.min(conv_layer_weight) = -0.17972998321056366
np.max(abs_conv_layer_weight) = 0.18762683868408203
np.min(abs_conv_layer_weight) = 2.5248411475331523e-05
np.max(conv_layer_bias) = 0.1976175457239151
np.min(conv_layer_bias) = -0.056839194148778915
np.max(abs_conv_layer_bias) = 0.1976175457239151
np.min(abs_conv_layer_bias) = 8.029816672205925e-05
conv_output = (10000, 3, 3, 48)
np.std(conv_output) = 0.4208807051181793
np.max(conv_output) = 4.762706756591797
np.min(conv_output) = -2.9888551235198975
np.max(abs_conv) = 4.762706756591797
np.min(abs_conv) = 7.450580596923828e-09

10000/10000 [==============================] - 3s 304us/step
conv2d_18
(1, 1, 48, 192)
(192, 48, 1, 1)
(192,)
(10000, 3, 3, 192)
np.max(conv_layer_weight) = 0.2371293008327484
np.min(conv_layer_weight) = -0.2002277970314026
np.max(abs_conv_layer_weight) = 0.2371293008327484
np.min(abs_conv_layer_weight) = 1.3661010598298162e-06
np.max(conv_layer_bias) = 0.11516989022493362
np.min(conv_layer_bias) = -0.11722267419099808
np.max(abs_conv_layer_bias) = 0.11722267419099808
np.min(abs_conv_layer_bias) = 0.0005882936529815197
conv_output = (10000, 3, 3, 192)
np.std(conv_output) = 0.18415993452072144
np.max(conv_output) = 1.7632944583892822
np.min(conv_output) = -1.28092360496521
np.max(abs_conv) = 1.7632944583892822
np.min(abs_conv) = 1.1175870895385742e-08

10000/10000 [==============================] - 3s 308us/step
conv2d_19
(3, 3, 48, 192)
(192, 48, 3, 3)
(192,)
(10000, 3, 3, 192)
np.max(conv_layer_weight) = 0.12958909571170807
np.min(conv_layer_weight) = -0.15907122194766998
np.max(abs_conv_layer_weight) = 0.15907122194766998
np.min(abs_conv_layer_weight) = 1.0321384280587154e-07
np.max(conv_layer_bias) = 0.11025165766477585
np.min(conv_layer_bias) = -0.10412546247243881
np.max(abs_conv_layer_bias) = 0.11025165766477585
np.min(abs_conv_layer_bias) = 0.0005223090411163867
conv_output = (10000, 3, 3, 192)
np.std(conv_output) = 0.2775069773197174
np.max(conv_output) = 2.5127899646759033
np.min(conv_output) = -2.445796489715576
np.max(abs_conv) = 2.5127899646759033
np.min(abs_conv) = 3.725290298461914e-08

10000/10000 [==============================] - 3s 323us/step
conv2d_20
(1, 1, 384, 64)
(64, 384, 1, 1)
(64,)
(10000, 3, 3, 64)
np.max(conv_layer_weight) = 0.17044414579868317
np.min(conv_layer_weight) = -0.1799185425043106
np.max(abs_conv_layer_weight) = 0.1799185425043106
np.min(abs_conv_layer_weight) = 1.3735225365962833e-06
np.max(conv_layer_bias) = 0.11707722395658493
np.min(conv_layer_bias) = -0.07737477868795395
np.max(abs_conv_layer_bias) = 0.11707722395658493
np.min(abs_conv_layer_bias) = 0.0006104373605921865
conv_output = (10000, 3, 3, 64)
np.std(conv_output) = 0.373676598072052
np.max(conv_output) = 3.9217896461486816
np.min(conv_output) = -2.750190496444702
np.max(abs_conv) = 3.9217896461486816
np.min(abs_conv) = 2.0116567611694336e-07

10000/10000 [==============================] - 3s 333us/step
conv2d_21
(1, 1, 64, 256)
(256, 64, 1, 1)
(256,)
(10000, 3, 3, 256)
np.max(conv_layer_weight) = 0.18047918379306793
np.min(conv_layer_weight) = -0.17668132483959198
np.max(abs_conv_layer_weight) = 0.18047918379306793
np.min(abs_conv_layer_weight) = 1.4669767551822588e-06
np.max(conv_layer_bias) = 0.04918604716658592
np.min(conv_layer_bias) = -0.10770349204540253
np.max(abs_conv_layer_bias) = 0.10770349204540253
np.min(abs_conv_layer_bias) = 0.00023276149295270443
conv_output = (10000, 3, 3, 256)
np.std(conv_output) = 0.1407841295003891
np.max(conv_output) = 1.3393429517745972
np.min(conv_output) = -1.2819019556045532
np.max(abs_conv) = 1.3393429517745972
np.min(abs_conv) = 1.862645149230957e-09

10000/10000 [==============================] - 4s 381us/step
conv2d_22
(3, 3, 64, 256)
(256, 64, 3, 3)
(256,)
(10000, 3, 3, 256)
np.max(conv_layer_weight) = 0.16038639843463898
np.min(conv_layer_weight) = -0.15026776492595673
np.max(abs_conv_layer_weight) = 0.16038639843463898
np.min(abs_conv_layer_weight) = 1.719431566016283e-07
np.max(conv_layer_bias) = 0.05694166570901871
np.min(conv_layer_bias) = -0.07688959687948227
np.max(abs_conv_layer_bias) = 0.07688959687948227
np.min(abs_conv_layer_bias) = 0.0001346934586763382
conv_output = (10000, 3, 3, 256)
np.std(conv_output) = 0.31745824217796326
np.max(conv_output) = 3.5984885692596436
np.min(conv_output) = -2.2447152137756348
np.max(abs_conv) = 3.5984885692596436
np.min(abs_conv) = 7.334165275096893e-08

10000/10000 [==============================] - 4s 384us/step
conv2d_23
(1, 1, 512, 64)
(64, 512, 1, 1)
(64,)
(10000, 1, 1, 64)
np.max(conv_layer_weight) = 0.19756470620632172
np.min(conv_layer_weight) = -0.19377626478672028
np.max(abs_conv_layer_weight) = 0.19756470620632172
np.min(abs_conv_layer_weight) = 1.454010543966433e-06
np.max(conv_layer_bias) = 0.08133905380964279
np.min(conv_layer_bias) = -0.0322188101708889
np.max(abs_conv_layer_bias) = 0.08133905380964279
np.min(abs_conv_layer_bias) = 0.001015845569781959
conv_output = (10000, 1, 1, 64)
np.std(conv_output) = 0.9502997398376465
np.max(conv_output) = 6.56773042678833
np.min(conv_output) = -3.0976979732513428
np.max(abs_conv) = 6.56773042678833
np.min(abs_conv) = 6.351619958877563e-07

10000/10000 [==============================] - 4s 392us/step
conv2d_24
(1, 1, 64, 256)
(256, 64, 1, 1)
(256,)
(10000, 1, 1, 256)
np.max(conv_layer_weight) = 0.2581574618816376
np.min(conv_layer_weight) = -0.21347056329250336
np.max(abs_conv_layer_weight) = 0.2581574618816376
np.min(abs_conv_layer_weight) = 7.390540758933639e-06
np.max(conv_layer_bias) = 0.09020012617111206
np.min(conv_layer_bias) = -0.06578623503446579
np.max(abs_conv_layer_bias) = 0.09020012617111206
np.min(abs_conv_layer_bias) = 7.086795812938362e-05
conv_output = (10000, 1, 1, 256)
np.std(conv_output) = 0.649179220199585
np.max(conv_output) = 3.7935266494750977
np.min(conv_output) = -3.0759589672088623
np.max(abs_conv) = 3.7935266494750977
np.min(abs_conv) = 6.146728992462158e-08

10000/10000 [==============================] - 4s 406us/step
conv2d_25
(3, 3, 64, 256)
(256, 64, 3, 3)
(256,)
(10000, 1, 1, 256)
np.max(conv_layer_weight) = 0.17148838937282562
np.min(conv_layer_weight) = -0.13356263935565948
np.max(abs_conv_layer_weight) = 0.17148838937282562
np.min(abs_conv_layer_weight) = 1.862645149230957e-07
np.max(conv_layer_bias) = 0.11338628083467484
np.min(conv_layer_bias) = -0.05885875225067139
np.max(abs_conv_layer_bias) = 0.11338628083467484
np.min(abs_conv_layer_bias) = 2.0896652131341398e-05
conv_output = (10000, 1, 1, 256)
np.std(conv_output) = 0.4251912832260132
np.max(conv_output) = 2.2752349376678467
np.min(conv_output) = -1.4251927137374878
np.max(abs_conv) = 2.2752349376678467
np.min(abs_conv) = 2.4959444999694824e-07

10000/10000 [==============================] - 4s 416us/step
conv2d_26
(1, 1, 512, 10)
(10, 512, 1, 1)
(10,)
(10000, 1, 1, 10)
np.max(conv_layer_weight) = 0.2454858422279358
np.min(conv_layer_weight) = -0.24298278987407684
np.max(abs_conv_layer_weight) = 0.2454858422279358
np.min(abs_conv_layer_weight) = 5.791342118754983e-06
np.max(conv_layer_bias) = 0.05678941309452057
np.min(conv_layer_bias) = -0.04499662294983864
np.max(abs_conv_layer_bias) = 0.05678941309452057
np.min(abs_conv_layer_bias) = 0.001525017200037837
conv_output = (10000, 1, 1, 10)
np.std(conv_output) = 4.045248031616211
np.max(conv_output) = 13.264505386352539
np.min(conv_output) = -17.079362869262695
np.max(abs_conv) = 17.079362869262695
np.min(abs_conv) = 6.483122706413269e-05


  1. 2018年08月28日 05:25 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

ZYBOt のコースの写真撮影用アプリケーションソフトの開発

ZYBOt の白線間走行テストを”白線追従用CNNを使用したZYBOtの白線追従走行3(走行テスト)”でやってみたが、あまりうまくコースを走ることができなかった。そこで、コースの写真を撮って再度学習を行うことにした。そのためには、写真をBMP ファイルにするアプリケーションソフトが必要だ。
ZYBO Z7-20上のUbuntu 14.04でカメラ画像をBMPファイルに変換する”で cam_caputre_bmp.cpp を作ってある。このアプリの欠点は、BMP ファイルを作りまくるので画像表示ソフトで次の画像を表示しなくてはいけないところだ。良さそうなところを写真撮る場合に同じファイル名に書き続けて、画像表示ソフトが自動更新してくれると疑似的なストリーミング画像のようになるので、それをやってみたい。ただし、Micro SD カードが死んでしまうので、コマンドを入れたときにそうしたいと思う。
ZYBO Z7-20上のUbuntu 14.04でカメラ画像をBMPファイルに変換する”の cam_capture_bmp.cpp をアップデートする。

アップデートした cam_capture_bmp.cpp を貼っておく。

//
// cam_capture_bmp.cpp
// 2016/08/19 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
//
// 2018/08/26 : Added 'e' command 
//

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

#include "bmp_header.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(FILE *fbmp, volatile unsigned int *frame_buffer, BMP24FORMAT **bmp_data);

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 i, j;
    int file_no = -1;
    FILE *fbmp;
    BMP24FORMAT **bmp_data; // 24 bits Date of BMP files (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES)

    int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9, fd10;
    volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
    volatile unsigned *dmaw4gabor_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;

    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_bmp [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
        exit(0);
    }

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

    // dmaw4gabor_0 (UIO1)
    fd1 = open("/dev/uio1", O_RDWR); // dmaw4gabor_0 interface AXI4 Lite Slave
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (dmaw4gabor_0) open error\n");
        exit(-1);
    }
    dmaw4gabor_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!dmaw4gabor_0){
        fprintf(stderr, "dmaw4gabor_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[18] = 0x80000000// 0x48 = 0x80000000, disable
    axis_switch_1[19] = 0x80000000// 0x4C = 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/class/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd10 == -1){
        fprintf(stderr, "/sys/class/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);
    
    // DMAW4Gabor Initialization sequence
    dmaw4gabor_0[6] = (unsigned int)phys_addr; // Data signal of frame_buffer0
    dmaw4gabor_0[8] = (unsigned int)phys_addr+SVGA_ALL_DISP_ADDRESS; // Data signal of frame_buffer1
    dmaw4gabor_0[0] = 0x1// ap_start = 1
    dmaw4gabor_0[0] = 0x80// auto_restart = 1

    // bitmap display controller settings
    bmdc_axi_lites0[0] = (unsigned int)phys_addr; // Bitmap Display Controller 0 start
    bmdc_axi_lites1[0] = (unsigned int)phys_addr; // Bitmap Display Controller 1 start
    mt9d111_inf_axis_0[0] = (unsigned 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;


    // allocated the memory for bmp file
    if ((bmp_data=(BMP24FORMAT **)malloc(sizeof(BMP24FORMAT *)*SVGA_VERTICAL_LINES)) == NULL){
        fprintf(stderr, "Can not allocate memory of the first dimension of SVGA_VERTICAL_LINES of bmp_data\n");
        exit(1);
    }
    for (i=0; i<SVGA_VERTICAL_LINES; i++){
        if ((bmp_data[i]=(BMP24FORMAT *)malloc(sizeof(BMP24FORMAT) * SVGA_HORIZONTAL_PIXELS)) == NULL){
            fprintf(stderr, "Can not allocate %d th memory of the first dimension of bmp_data\n", i);
            exit(1);
        }
    }
   
    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);
                if ((fbmp=fopen(bmp_file, "wb")) == NULL){
                    fprintf(stderr, "Cannot open %s in binary mode\n", bmp_file);
                    exit(1);
                }
                WriteBMPfile(fbmp, frame_buffer_bmdc, bmp_data);
                fclose(fbmp);
                
                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);
                if ((fbmp=fopen(bmp_file, "wb")) == NULL){
                    fprintf(stderr, "Cannot open %s in binary mode\n", bmp_file);
                    exit(1);
                }
                WriteBMPfile(fbmp, frame_buffer_bmdc, bmp_data);
                fclose(fbmp);
                
                printf("file No. = %d\n", file_no);

                break;
        }
        c = getc(stdin);
    }

    for(i=0; i<SVGA_VERTICAL_LINES; i++){
        free(bmp_data[i]);
    }
    free(bmp_data);
    
    munmap((void *)bmdc_axi_lites0, 0x10000);
    munmap((void *)bmdc_axi_lites1, 0x10000);
    munmap((void *)dmaw4gabor_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);
}

int WriteBMPfile(FILE *fbmp, volatile unsigned *frame_buffer, BMP24FORMAT **bmp_data){
    BITMAPFILEHEADER bmpfh; // file header for a bmp file
    BITMAPINFOHEADER bmpih; // INFO header for BMP file

    // Copy the camera color data of the bmp_data (data of BMP when its starts from lower left)
    for (int i=0; i<SVGA_VERTICAL_LINES; i++){
        for (int j=0; j<SVGA_HORIZONTAL_PIXELS; j++){
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].red = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j]>>16)&0xff;
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].green = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j]>>8)&0xff;
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].blue = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j])&0xff;
        }
    }

    // Assign a value to the file header of the BMP file
    bmpfh.bfType = 0x4d42;
    bmpfh.bfSize = SVGA_HORIZONTAL_PIXELS*SVGA_VERTICAL_LINES*3+54;
    bmpfh.bfReserved1 = 0;
    bmpfh.bfReserved2 = 0;
    bmpfh.bfOffBits = 0x36;

    // Assign a value to the INFO header of the BMP file
    bmpih.biSize = 0x28;
    bmpih.biWidth = SVGA_HORIZONTAL_PIXELS;
    bmpih.biHeight = SVGA_VERTICAL_LINES;
    bmpih.biPlanes = 0x1;
    bmpih.biBitCount = 24;
    bmpih.biCompression = 0;
    bmpih.biSizeImage = 0;
    bmpih.biXPixPerMeter = 3779;
    bmpih.biYPixPerMeter = 3779;
    bmpih.biClrUsed = 0;
    bmpih.biClrImporant = 0;

    // Writing of BMP file header
    fwrite(&bmpfh.bfType, sizeof(char), 2, fbmp);
    fwrite(&bmpfh.bfSize, sizeof(long), 1, fbmp);
    fwrite(&bmpfh.bfReserved1, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfReserved2, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfOffBits, sizeof(long), 1, fbmp);

    // Writing of BMP INFO header
    fwrite(&bmpih, sizeof(BITMAPINFOHEADER), 1, fbmp);

    // Writing of bmp_data
    for (int i=0; i<SVGA_VERTICAL_LINES; i++) {
        for (int j=0; j<SVGA_HORIZONTAL_PIXELS; j++) {
            fputc((int)bmp_data[i][j].blue, fbmp);
            fputc((int)bmp_data[i][j].green, fbmp);
            fputc((int)bmp_data[i][j].red, fbmp);
        }
    }
}


w コマンドだと名前の番号を +1 した名前で BMP ファイルを作るが、e コマンドだと同じ名前で BMP ファイルを書き込む。

gcc -o cam_capture_bmp cam_capture_bmp.cpp
でコンパイルは通って、cam_capture_bmp 実行ファイルができた。

cam_capture_bmp を使うときは、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
で、デバイスツリーを読み込んで、
sudo chmod 666 /dev/uio*
sudo chmod 666 /dev/udmabuf*

するのだが、chmod を uio_set のシェル・スクリプトに書いておいたので、これを実行する。
su
./uio_set
exit

bmp_files ディレクトリに cam_capture_bmp を入れておいたので、そこに cd する。
cd bmp_files
ZYBOt_34_180827.png

画像表示ソフトは現在表示している画像が更新したら、表示を自動的に更新してくれるソフトが良いので、そういうソフトを探したところ、Geeqie を使うことにした。

さて、cam_capture_bmp を起動して、BMPファイルを作ってみよう。
./cam_caputre_bmp

w
を入力すると、bmp_file0.bmp が作成される。
ZYBOt_35_180827.png

ZYBOt_36_180827.png

nautilus の bmp_file0.bmp をダブルクリックすると、Geeqie が起動する。
ZYBOt_37_180827.png

e
コマンドを押すと、同じ bmp_file0.bmp に画像が保存されて、Geeqie の画像が自動的に更新される。
ZYBOt_38_180827.png

ZYBOt_39_180827.png

これで、ちょうど良い場所を見つけてコースの写真を撮ることができるようになった。
なお、nautilus や Geeqie などは、X サーバーをWindows で立ち上げているので、Windows 上で見えている。よって、コースの写真を撮るときはノートパソコンにこれらの画像を表示させてコースの写真を撮ることができるので、とっても便利だと思う。

(追加)
Geeqie のインストールは
sudo apt install geeqie
でできた。
  1. 2018年08月27日 05:26 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

「ちいさな英雄―カニとタマゴと透明人間」、「ペンギン・ハイウェイ」を見てきました

昨日は、「ちいさな英雄―カニとタマゴと透明人間」を見てきて、今日、「ペンギン・ハイウェイ」を見てきました。

昨日の「ちいさな英雄―カニとタマゴと透明人間」は、3つの短編が集まっていたのだが、やはり20分では短すぎると感じましたね。タマゴが一番良かったかな?
「ペンギン・ハイウェイ」はとっても面白かった。昨日のカニもアニメに水が流れるところとかをCGで作っていたみたいだが、これもそうしているのだろう?日本のアニメでも+CGが増えてきたのかな?
原作読もうかな?
  1. 2018年08月26日 14:21 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ultra96のDisplayPort テスト用回路2

Ultra96のDisplayPort テスト用回路1”の続き。

Ultra96のDisplayPort テスト用回路1”の回路にILA を付けてデバックというか、video_test IP のビデオ信号が出ているのかどうか?を確かめてみた。
Ultra96_DP_22_180825.png

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

Vivado Analyer を起動した。
Ultra96_DP_24_180825.png

データも問題無い様だ。
Ultra96_DP_25_180825.png

hsync も 1 パルス出ている。
Ultra96_DP_26_180825.png

vsync も 1 パルス出ている。
Ultra96_DP_27_180825.png

SDK で DP_test.elf を走らせてみたけど、画面でない。。。
Ultra96_DP_28_180826.png

DP_test.c を示す。

/* * DP_test.c * *  Created on: 2018/08/22 *      Author: Masaaki */

#include "xstatus.h"
#include <xavbuf_hw.h>
#include <xavbuf.h>
#include <stdint.h>

int main(){
    XAVBuf dp;
    volatile uint32_t *addr;

    printf("Hello World\n");

    XAVBuf_CfgInitialize(&dp, (u32)XAVBUF_BASEADDR, (u16)0);
    XAVBuf_Initialize(&dp);

    XAVBuf_InputVideoSelect(&dp, XAVBUF_VIDSTREAM1_LIVE, XAVBUF_VIDSTREAM2_NONLIVE_GFX);
    XAVBuf_InputAudioSelect(&dp, XAVBUF_AUDSTREAM1_NONLIVE, XAVBUF_AUDSTREAM2_AUDIOGFX);

    XAVBuf_SetBlenderAlpha(&dp, 0x801);

    XAVBuf_SetAudioVideoClkSrc(&dp, XAVBUF_PL_CLK, XAVBUF_PL_CLK);

    if(XAVBuf_SetInputLiveVideoFormat(&dp, RGB_8BPC) != XST_SUCCESS){
        printf("XAVBuf_SetInputNonLiveVideoFormat() error\n");
        exit(1);
    }
    XAVBuf_EnableVideoBuffers(&dp, 1);

    printf("Hello World2\n");

    return(0);
}


毎回、”Hello World”と”Hello World2”が表示されているので、間のコードは実行されているようだ。
  1. 2018年08月26日 07:29 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96のベアメタル・アプリケーションソフトが1回しか動作しないときの解決法

Ultra96のDisplayPort テスト用回路1”で、1度アプリケーションソフトを起動して動作し、もう1度、起動したときに 99 % で止まってアプリが起動できない現象が起きた。

どうやってもう一度、アプリを起動できるか?わからなかったのだが、またまた @ciniml さんに怪しそうなところを教えてもらった。いつもありがとうございます。

いろいろと試行してみたところ、どこを設定すれば良いかが分かった。

DP_test プロジェクトを選択して、Project メニューから Properties を選択する。

Properties for DP_test が開く。
System Debugger using Debug_DP_test.elf on Local をダブルクリックして開く。
Ultra96_DP_100_180825.png

Edit Configuration ダイアログが開く。
Reset entire system にチェックを入れる。同時にProgram FPGA にもチェックが入るので、そこはチェックを外す そのままにする。(Reset entire system するとPL の回路がクリアされるか、クロックが供給されなくなるようです。Lチカができなくなりました。よって、再度Program FPGA する必要があるようです)
Ultra96_DP_101_180825.png

これで、何度でもアプリケーションソフトを起動することができるようになった。
  1. 2018年08月25日 21:03 |
  2. SDK
  3. | トラックバック:0
  4. | コメント:0

Ultra96のDisplayPort テスト用回路1

Ultra96のDisplayPort テストパターン生成用IPの作製”で作ったIP を”DPDMA の examples をやってみる”で作ったVivado 2018.2 で作った dt_test プロジェクトを改造して入れてみることにした。

dp_test プロジェクトを示す。
Ultra96_DP_13_180824.png

ブロックデザインを示す。
Ultra96_DP_14_180824.png

Ultra96のDisplayPort テストパターン生成用IPの作製”で作ったvideo_out IP と本当に dp_video_ref_clk が出ているのかを確認するために”Ultra96用PMOD拡張ボードのPMOD端子のテストのために8ビットカウンタのLチカを作る2”で使用した”Ultra96用PMOD拡張ボードのPMOD端子のテストのために8ビットカウンタのLチカを作る”の ex_board_test IP を入れてある。
また dp_live_gfx_alpha_in[7:0] に接続した xlconstant_0 の定数値はとりあえずは、128 を設定した。

これで、論理合成、インプリメンテーション、ビットストリームの生成を行った。結果を示す。
Ultra96_DP_15_180824.png
Ultra96_DP_16_180824.png

ハードウェアをエクスポートし、SDK を立ち上げた。
DP_test アプリケーションソフトを変更して、Hello World を表示するだけのソフトウェアを書いた。
なお、”SDKでstdin, stdout に割り当てられるデバイスを変更”で psu_uart_1 に変更してある。Ultra96 の J6 3 ピンヘッダは uart 1 ということで stdin, stdout を変更した。
また、”SDKでインクルード・パスを追加する方法”で、F:\Xilinx\SDK\2018.2\data\embeddedsw\XilinxProcessorIPLib\drivers フォルダへのパスを追加した。

実験環境だが、@ciniml さんのJTAG 変換基板と UART 変換基板を使わせて頂いている。ありがとうございます。
Ultra96_DP_21_180825.jpg

表示することができた mini DP - VGA 変換ケーブルを使用しているが、不安なので、mini DP - HDMI アクティブ変換ケーブルを購入した。

さて、SDK の画面を貼っておく。
Ultra96_DP_17_180824.png

Program FPGA を行って、ソフトウェアを走らせたところ、最初の文字化けはあるのだが、Hello World が表示された。
Ultra96_DP_18_180824.png

LEDが点滅していたので、dp_video_ref_clk クロックも出ているようだ。

なお、もう一度、このソフトウェアを起動すると 99 % で止まってしまって、ソフトウェアが起動しない。
Ultra96_DP_20_180825.png

2 回目はいつもこうなる。
対処方法は、Ultra96 の電源OFF して、もう一度、やり直しだ。
どこかおかしいのかな?
  1. 2018年08月25日 04:48 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST 2

SqueezeNet for MNIST 1”の続き。

前回は、SqueezeNet for MNIST の学習を行った。今回は、model accuracy と model loss を示し、model.summary() を示す。

model accuracy と model loss を示す。
squeezenet4mnist_6_180824.png

大体良さそうだ。

model.summary() を示す。
squeezenet4mnist_7_180824.png
squeezenet4mnist_8_180824.png
squeezenet4mnist_9_180824.png
squeezenet4mnist_10_180824.png
  1. 2018年08月24日 05:36 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Ultra96のDisplayPort テストパターン生成用IPの作製

Ultra96のDisplayPort にテストパターンを表示するIP を作製しようということで、Vivado HLS 2018.2 で以前作った”Vivado HLS 2014.4 でディスプレイ・コントローラを作る1(高位合成、C/RTLコシミュレーション)”を参照しながら、HD解像度のテストパターンを表示するIP を作製しよう。

テストパターンは4色で左上が赤、右上が緑、左下が青、右下が白となっている。
ソースコードの video_test.cpp を示す。なおHD解像度のタイミングは”VESA DMT 信号タイミング一覧”を参照した。

// video_test.cpp
// 2018/08/21 by marsee
// DisplayPortのLive Video Interfaceに入れるテストパターン(HD解像度)
// 画面を4分割した第1象限は赤、第2象限は緑、第3象限は青、第4象限は白を表示する
//

#include <ap_int.h>

// HD 解像度
#define H_ACTIVE_VIDEO    1920
#define H_FRONT_PORCH    88
#define H_SYNC_PULSE    1 // 44, DPのLive Video Interfaceのタイミングチャートより1パルスにした
#define H_BACK_PORCH    (148 + 43) // 同期信号を1パルスにした分をバックポーチに加算
#define H_SUM            (H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH)

#define V_ACTIVE_VIDEO    1080
#define V_FRONT_PORCH    4
#define V_SYNC_PULSE    1 // 5, DPのLive Video Interfaceのタイミングチャートより1パルスにした
#define V_BACK_PORCH    (36 + 4) // 同期信号を1パルスにした分をバックポーチに加算
#define V_SUM            (V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH)

void video_test(ap_uint<36> *video_out, ap_uint<1> *display_enable, ap_uint<1> *hsync, ap_uint<1> *vsync){
#pragma HLS INTERFACE ap_none register port=video_out
#pragma HLS INTERFACE ap_none register port=display_enable
#pragma HLS INTERFACE ap_none register port=hsync
#pragma HLS INTERFACE ap_none register port=vsync
#pragma HLS INTERFACE ap_ctrl_none port=return

    ap_uint<16> h_count, v_count;

    for (v_count=0; v_count<V_SUM; v_count++){
        for (h_count=0; h_count<H_SUM; h_count++){
#pragma HLS PIPELINE II=1
            if (h_count >= (H_ACTIVE_VIDEO +H_FRONT_PORCH) && h_count < (H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE))
                *hsync = 1;
            else
                *hsync = 0;

            if (v_count >= (V_ACTIVE_VIDEO + V_FRONT_PORCH) && v_count < (V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE) && h_count==0)
                *vsync = 1;
            else
                *vsync = 0;

            if (h_count < H_ACTIVE_VIDEO && v_count < V_ACTIVE_VIDEO)
                *display_enable = 1;
            else
                *display_enable = 0;

            if (v_count < V_ACTIVE_VIDEO/2){
                if (h_count < H_ACTIVE_VIDEO/2){
                    *video_out = 0xff0000000; // red = 0xff
                } else if (h_count < H_ACTIVE_VIDEO){
                    *video_out = 0x000ff0000; // green = 0xff
                } else {
                    *video_out = 0x000000000;
                }
            } else if (v_count < V_ACTIVE_VIDEO){
                if (h_count < H_ACTIVE_VIDEO/2){
                    *video_out = 0x000000ff0; // blue = 0xff
                } else if (h_count < H_ACTIVE_VIDEO){
                    *video_out = 0xff0ff0ff0; // red=0xff, green=0xff, blue=0xff
                } else {
                    *video_out = 0x000000000;
                }
            } else {
                *video_out = 0x000000000;
            }
        }
    }
}


次にテストベンチの video_test_tb.cpp を示す。

// video_test_tb.cpp
// 2018/08/21 by marsee
//

#include <ap_int.h>

void video_test(ap_uint<36> *video_out, ap_uint<1> *display_enable, ap_uint<1> *hsync, ap_uint<1> *vsync);

int main(){
    ap_uint<36> video_outb, *video_out;
    ap_uint<1> deb, *display_enable;
    ap_uint<1> hb, *hsync;
    ap_uint<1> vb, *vsync;

    video_out = &video_outb;
    display_enable = &deb;
    hsync = &hb;
    vsync = &vb;

    video_test(video_out, display_enable, hsync, vsync);
    video_test(video_out, display_enable, hsync, vsync);

    return(0);
}


C コードの合成を行った。
video_out_1_180821.png

Target が 6.70 ns で、Estimated は 3.023 ns だった。さすがにUltraScale+ は性能が良いね。助かる。。。
Latency は 2475002 クロックだった。
Loop1 のLatency は 2475000 クロックだった。これは、(1920+88+44+148) * (1080+4+5+36) = 2475000 クロックなので、ぴったりだ。
リソース使用量は FF が 77 個、LUT は 560 個だった。

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

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

拡大してみよう。1行の中央で video_out の値が変化しているのが見える。
video_out_4_180821.png

hsync を拡大してみよう。1クロック分 1 になっていることが分かる。
video_out_5_180821.png

vsync を拡大してみる。こちらも 1 クロック分になっているのが分かる。
video_out_6_180821.png

ブロック・レベルのインターフェースを消すために、

#pragma HLS INTERFACE ap_ctrl_none port=return

に変更した。
video_out_7_180821.png

もう一度、C コードの合成を行った。
video_out_8_180821.png

結果は前と同じだった。
合成された結果のVHDLファイルを見ると、制御信号は削除されていた。

entity video_test is
port (
    ap_clk : IN STD_LOGIC;
    ap_rst : IN STD_LOGIC;
    video_out_V : OUT STD_LOGIC_VECTOR (35 downto 0);
    display_enable_V : OUT STD_LOGIC_VECTOR (0 downto 0);
    hsync_V : OUT STD_LOGIC_VECTOR (0 downto 0);
    vsync_V : OUT STD_LOGIC_VECTOR (0 downto 0) );
end;



Export RTLを行った。ただし、Vivado synthesis, place and route にチェックを入れてある。
video_out_9_180821.png

LUT を 53 個、FF を 54 個使用している。
  1. 2018年08月22日 05:24 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

白線追従用CNNを使用したZYBOtの白線追従走行3(走行テスト)

白線追従用CNNを使用したZYBOtの白線追従走行2(準備編2)”の続き。

昨日、テスターが来て、配線チェックをしたのだが、PMOD HB5の配線ミスが見つかった。修正してwl_tracing_cnn を走らせたところ、ZYBOt は走った。しかし、カーブが曲がれない。良い感じに曲がるところもあるのだが、特に鋭角には曲がれない。

また、後ろ車輪用の棒も通常は良いのだが、白線のビニルテープにかかると進まなくなってしまうので、自在キャスターに変えたほうが良さそうだ。

とにかく、今の道路で学習してみようと思う。
学習も以前の学習方法では、問題があるのが分かっているので、修正を試みよう。。。
  1. 2018年08月20日 06:43 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

白線追従用CNNを使用したZYBOtの白線追従走行2(準備編2)

白線追従用CNNを使用したZYBOtの白線追従走行1(準備編)”の続き。

”ikwzm さんの fclkcfg による Zynq のPS の fclk の設定2”でデバイスツリーからPS の fclk のClock Source を変更できるようになって、クロック周波数の設定がうまく行くようになった。

そこで、wl_tracing_cnn を起動して動作するかどうか?を確認してみよう。

まずは、ZYBOt 起動後なので、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
を実行した。
次に、/dev/uio* と /dev/udmabuf0 をすべての人がR/W できるように設定する。
sudo chmod 666 /dev/uio*
sudo chmod 666 /dev/udmabuf0

これで、すべてのユーザーが書き込みできるので、ユーザーモードで wl_tracing_cnn を起動できる。
cd build
./wl_tracing_cnn

ZYBOt_32_180819.png

wl_tracing_cnn が起動した。
ZYBOt_33_180819.png

VGA ポートにもカメラ画像が出力されている。問題無い様だ。

wl_tracing_cnn.cpp を貼っておく。

// wl_tracing_cnn.cpp
// 2017/12/27 by marsee
// 2018/08/18 : "phys_addr of udmabuf0" bug fix
//

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

#include "xpwm.h"
#include "xdmar4resize_gray.h"
#include "xresize_gray.h"
#include "xcurve_conv_nn2_axis3.h"

#define CMA_START_ADDRESS 0x17800000
#define VIDEO_BUFFER_START_ADDRESS  0x18000000  // Limit 0x18800000, 800*600*4 = 2MBytes * 2

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

#define DEBUG
//#define MOTOR_OFF

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

// Motor
//
void motor_settings(XPwm *motorLp, XPwm *motorRp){
    XPwm_DisableAutoRestart(motorLp);
    while(!XPwm_IsIdle(motorLp)) ;
    XPwm_Start(motorLp);
    XPwm_EnableAutoRestart(motorLp);
    
    XPwm_DisableAutoRestart(motorRp);
    while(!XPwm_IsIdle(motorRp)) ;
    XPwm_Start(motorRp);
    XPwm_EnableAutoRestart(motorRp);
}

void Stopped_Zybot(XPwm *motorLp, XPwm *motorRp){
    XPwm_Set_sw_late_V(motorLp, 0);
    XPwm_Set_sw_late_V(motorRp, 0);
}


int main()
{
    int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9, fd10;
    volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
    volatile unsigned *dmaw4gabor_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;
    char  attr[1024];
    unsigned long  phys_addr;
    int i;
    XDmar4resize_gray xdmar;
    XResize_gray resg;
    XCurve_conv_nn2_axis3 stcnn;
    XPwm motorL, motorR;
    XPwm *motorLp, *motorRp;
    
    motorLp = &motorL;
    motorRp = &motorR;

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

    // dmaw4gabor_0 (UIO1)
    fd1 = open("/dev/uio1", O_RDWR); // dmaw4gabor_0 interface AXI4 Lite Slave
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (dmaw4gabor_0) open error\n");
        exit(-1);
    }
    dmaw4gabor_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!dmaw4gabor_0){
        fprintf(stderr, "dmaw4gabor_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[18] = 0x80000000// 0x48 = 0x80000000, disable
    axis_switch_1[19] = 0x80000000// 0x4C = 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/class/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd10 == -1){
        fprintf(stderr, "/sys/class/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);
    
    // DMAW4Gabor Initialization sequence
    dmaw4gabor_0[6] = (unsigned int)phys_addr; // Data signal of frame_buffer0
    dmaw4gabor_0[8] = (unsigned int)phys_addr+ALL_DISP_ADDRESS; // Data signal of frame_buffer1
    dmaw4gabor_0[0] = 0x1// ap_start = 1
    dmaw4gabor_0[0] = 0x80// auto_restart = 1

    // bitmap display controller settings
    bmdc_axi_lites0[0] = (unsigned int)phys_addr; // Bitmap Display Controller 0 start
    bmdc_axi_lites1[0] = (unsigned int)phys_addr; // Bitmap Display Controller 1 start
    mt9d111_inf_axis_0[0] = (unsigned 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;

    // Initialization of xdmar4resize_gray, xresize_gray, XCurve_conv_nn2_axis3
    if(XDmar4resize_gray_Initialize(&xdmar, "dmar4resize_gray_0") != XST_SUCCESS){
        fprintf(stderr, "dmar4resize_gray_0 open error\n");
        exit(-1);
    }
    if(XResize_gray_Initialize(&resg, "resize_gray_0") != XST_SUCCESS){
        fprintf(stderr, "resize_gray_0 open error\n");
        exit(-1);
    }
    if(XCurve_conv_nn2_axis3_Initialize(&stcnn, "curve_conv_nn2_axis3_0") != XST_SUCCESS){
        fprintf(stderr, "curve_conv_nn2_axis3 open error\n");
        exit(-1);
    }

    XDmar4resize_gray_Set_frame_buffer0(&xdmar ,(unsigned int)phys_addr);
    XDmar4resize_gray_Set_frame_buffer1(&xdmar ,(unsigned int)phys_addr+ALL_DISP_ADDRESS);
    XDmar4resize_gray_Start(&xdmar);
    XDmar4resize_gray_EnableAutoRestart(&xdmar);

    XResize_gray_Start(&resg);
    XResize_gray_EnableAutoRestart(&resg);

    XCurve_conv_nn2_axis3_Start(&stcnn);
    XCurve_conv_nn2_axis3_EnableAutoRestart(&stcnn);

    // Initialization of motor
    if (XPwm_Initialize(motorLp, "pwm_0") != XST_SUCCESS){
        fprintf(stderr,"pwm_0 (Left) open error\n");
        exit(-1);
    }
    if (XPwm_Initialize(motorRp, "pwm_1") != XST_SUCCESS){
        fprintf(stderr,"pwm_1 (Right) open error\n");
        exit(-1);
    }
    // The Motors is rotated in the forward direction.
    XPwm_Set_sw_late_V(motorLp, 0);
    XPwm_Set_dir_V(motorLp, 1);

    XPwm_Set_sw_late_V(motorRp, 0);
    XPwm_Set_dir_V(motorRp, 0);

    motor_settings(motorLp, motorRp);

    // main loop
    printf("White line Tracking start. \n");
    while(1){
        usleep(10000); // 10 ms Wait

        while(!XCurve_conv_nn2_axis3_Get_outs_V_vld(&stcnn)) ;
        switch((int)XCurve_conv_nn2_axis3_Get_outs_V(&stcnn)){
            case 0 : // left turn
#ifndef MOTOR_OFF
                XPwm_Set_sw_late_V(&motorL, 10);
                XPwm_Set_sw_late_V(&motorR, 25);
#endif
#ifdef DEBUG
                printf("Left turn\n"); fflush(stdout);
#endif
                break;
            case 1 : // straight
#ifndef MOTOR_OFF
                XPwm_Set_sw_late_V(&motorL, 20);
                XPwm_Set_sw_late_V(&motorR, 20);
#endif
#ifdef DEBUG
                printf("Go straight\n"); fflush(stdout);
#endif
                break;
            default : // 2, right turn
#ifndef MOTOR_OFF
                XPwm_Set_sw_late_V(&motorL, 25);
                XPwm_Set_sw_late_V(&motorR, 10);
#endif
#ifdef DEBUG
                printf("Right turn\n"); fflush(stdout);
#endif
        }
    }


    munmap((void *)bmdc_axi_lites0, 0x10000);
    munmap((void *)bmdc_axi_lites1, 0x10000);
    munmap((void *)dmaw4gabor_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. 2018年08月19日 10:13 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

ikwzm さんの fclkcfg による Zynq のPS の fclk の設定2

ikwzm さんの fclkcfg による Zynq のPS の fclk の設定”の続き。

前回は、ZYBO_BOOT つまり、ブート用のFAT32 フォーマットのMicro SD カードのパーティションで、uEnv.txt (u-boot の設定ファイル)を編集して、各 fclk の Clock Source を設定した。そのため、デバイスツリーで fclk を設定したときに正しい値を設定することができた。
今回は、新しく ikwzm さんにバージョンアップして頂いた新しい fclkcfg (fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb)を使用して、デバイスツリーから Clock Source を変更することができるかどうか?を確かめる。

最初に今までの uEnv.txt に戻した。
ZYBOt_22_180819.png

リブートして、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
すると、以前同様に、ずれたクロック周波数が設定される。
ZYBOt_23_180819.png

ZYBOt_24_180819.png

ずれたクロック周波数が設定されているということを覚えておいて欲しい。

ikwzm/FPGA-SoC-Linux を git clone して比べてみると、fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb が新しくなっていたけれど、dtbocfg-4.14.34-armv7-fpga_0.0.6-1_armhf.deb と udmabuf-4.14.34-armv7-fpga_1.2.3-1_armhf.deb も新しくなっていた。
ZYBOt_25_180819.png

この3つを ZYBOt の ~/debian ディレクトリに SFTP した。
ZYBOt_26_180819.png


sudo dpkg -i dtbocfg-4.14.34-armv7-fpga_0.0.6-1_armhf.deb
ZYBOt_27_180819.png

sudo dpkg -i fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb
sudo dpkg -i udmabuf-4.14.34-armv7-fpga_1.2.3-1_armhf.deb

ZYBOt_28_180819.png

FPGA Clock Configuration Device Driver を見ながら devicetree.dts を変更した。
"armpll" は <&clkc 0>、"ddrpll" は <&clkc 1>、"iopll" は <&clkc 2> だそうだ。
ZYBOt_29_180819.png

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba/fpga-region0";
        #address-cells = <0x1>;
        #size-cells = <0x1>;

        __overlay__ {
            #address-cells = <0x1>;
            #size-cells = <0x1>;

            firmware-name = "ZYBO_0_wrapper.bin";

            mt9d111_axi_iic@41600000 {
                compatible = "generic-uio";
                reg = < 0x41600000 0x10000>;
            };
            dmaw4gabor_0@43cb0000 {
                compatible = "generic-uio";
                reg = < 0x43cb0000 0x10000 >;
            };
            axis_switch_0@43c10000 {
                compatible = "generic-uio";
                reg = < 0x43c10000 0x10000 >;
            };
            axis_switch_1@43c20000 {
                compatible = "generic-uio";
                reg = < 0x43c20000 0x10000 >;
            };
            lap_filter_axis_0@43c30000 {
                compatible = "generic-uio";
                reg = < 0x43c30000 0x10000>;
            };    
            mt9d111_inf_axis_0@43C40000 {
                compatible = "generic-uio";
                reg = < 0x43C40000 0x10000>;
            };
            bitmap_disp_cntrler_axi_master_0@43c00000 {
                compatible = "generic-uio";
                reg = < 0x43c00000 0x10000>;
            };
            bitmap_disp_cntrler_axi_master_1@43c50000 {
                compatible = "generic-uio";
                reg = < 0x43c50000 0x10000>;
            };
            axi_gpio_0@41200000 {
                compatible = "generic-uio";
                reg = < 0x41200000 0x10000>;
            };
            frame_buffer_bmdc@17800000 {
                compatible = "generic-uio";
                reg = < 0x17800000 0x1000000>;
            };
            pwm_0@43c60000 {
                compatible = "generic-uio";
                reg = < 0x43c60000 0x10000>;
            };
            pwm_1@43c70000 {
                compatible = "generic-uio";
                reg = < 0x43c70000 0x10000>;
            };
            motor_monitor_0@43c80000 {
                compatible = "generic-uio";
                reg = < 0x43c80000 0x10000>;
            };
            motor_monitor_1@43c90000 {
                compatible = "generic-uio";
                reg = < 0x43c90000 0x10000>;
            };
            dmar4resize_gray_0@43ca0000 {
                compatible = "generic-uio";
                reg = < 0x43ca0000 0x10000>;
            };
            rgb2hsv_0@43cc0000 {
                compatible = "generic-uio";
                reg = < 0x43cc0000 0x10000>;
            };
            ultrasoninc_sensor_inf_0@43cd0000 {
                compatible = "generic-uio";
                reg = < 0x43cd0000 0x10000>;
            };
            resize_gray_0@43ce0000 {
                compatible = "generic-uio";
                reg = < 0x43ce0000 0x10000>;
            };
            curve_conv_nn2_axis3_0@43cf0000 {
                compatible = "generic-uio";
                reg = < 0x43cf0000 0x10000>;
            };

            pow2-udmabuf0 {
                compatible  = "ikwzm,udmabuf-0.10.a";
                device-name = "udmabuf0";
                size = <0x00600000>;
            };

            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 15>, <&clkc 2>;
                insert-rate    = "100000000";
                insert-enable = <1>;
            };
            fclk1 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 16>, <&clkc 2>;
                insert-rate    = "40000000";
                insert-enable = <1>;
            };
            fclk2 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 17>, <&clkc 2>;
                insert-rate    = "72000000";
                insert-enable = <1>;
            };
            fclk3 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 18>, <&clkc 0>;
                insert-rate    = "65000000";
                insert-enable = <1>;
            };
        };
    } ;
} ;


最初は fclk* のところの &clkc がエラーになってしまっていたのだが、ikwzm さんに教えてもらって、devicetree.dts の最初の「/dts-v1/;」を「/dts-v1/;/plugin/;」に変更したら、&clkc が通るようになった。
ikwzm さんによると

「大元のデバイスツリーを作るときに dtc に -@ か --symbols を付けるとシンボル情報を含んだ dtb が出来ます。/plugin/; はそのシンボル情報を使うことを意味します。昔は dtc に -@ が無かったので出来なかったのですが。」

だそうだ。いつもありがとうございます。

さて、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
を行った。
ZYBOt_30_180819.png

シリアル・コンソールを見ると、正常な周波数が設定されている。成功だ。
ZYBOt_31_180819.png

なお、
sudo dtbocfg.rb -r wl_tracing_cnn
で、デバイスツリーに書かれたデバイス・ドライバが外れて、もう一度、sudo dtbocfg.rb -i できるようになる。

つまり、Debian が起動中にいろいろなハードウェアを取替えて試すことができる。とっても便利だと思う。

(追加)
cd /sys/devices/soc0/amba/amba\:fpga-region0/
ls

すると、デバイスツリーに書いたデバイスが見える。
ZYBOt_16_180818.png

cd /sys/class
ls

すると、fclkcfg, udamebuf, uio が見える。
ZYBOt_17_180818.png
  1. 2018年08月19日 08:31 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

ikwzm さんの fclkcfg による Zynq のPS の fclk の設定

白線追従用CNNを使用したZYBOtの白線追従走行1(準備編)”の続き。

前回は、デバイスツリー・ソース・ファイルを書いて、ビットストリームのFPGAへのロードやUIO の設定、udmabuf のロード、fclk の設定を行ったが、fclk の設定値が想定していた値と違ってしまった。
これは、ikwzm さんにお聞きしたところ、fclk1 などのClock Source が違っていたからということだった。Clock Source には、ARMPLL、DDRPLL、IOPLL の3種類あるが、どれを選ぶかで、周波数の設定値に対して、実際の値の偏差が発生するかどうか?が決まる。
このfclkcfg のバージョンでは、デバイスツリーのロード時にClock Source を変更することはできないので、u-boot 時にClock Source を変更するということだ。なお、現在のfclkcfg (fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb)では、デバイスツリーにClock Source を書くことができるので、後でやってみよう。

さて、ZYBO に挿入するMicro SD カードのZYBO_BOOT パーティションの uEnv.tst の fpga_set_cmd を以下の様に書き換えた。

fpga_set_cmd=run slcr_unlock_cmd && mw.l 0xF8000170 0x00100A00 && mw.l 0xF8000180 0x00100A00 && mw.l 0xF8000190 0x00100A00 && mw.l 0xF80001A0 0x00100A20 && run slcr_lock_cmd


U-Boot から Zynq の PLクロックとリセット信号を制御する”を参照すると、最初の fclk0 の値の設定は、”0xF8000170 0x00100A00”で、DIVISOR1 が 1 で、DIVISOR0 が 10 で、Clock Source はIOPLL ということを示す。デバイスツリーでDIVISOR の倍率は変更できるので、全部の fclk がDIVISOR1 が 1 で、DIVISOR0 が 10 だが、最後の fclk3 だけは Clock Source が ARMPLL になっている。
ZYBOt_18_180818.png

ZYBOt_19_180818.png

これでZYBOt のDebian をブートして、~/zybot/wl_tracing_cnn ディレクトリに行って、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
でデバイスツリーで示されるドライバをロードした。
ZYBOt_20_180818.png

シリアル・コンソールを見ると、設定通りの周波数が出ている。成功だ。
ZYBOt_21_180818.png
  1. 2018年08月19日 05:12 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

白線追従用CNNを使用したZYBOtの白線追従走行1(準備編)

ZYBOt用のMicro SDカードを作成”でZYBOt 用のDebian を起動するMicro SD カードを作成することができた。今回は、デバイスツリーやビットストリーム、ZYBOt を走らせるためのアプリケーションソフトの用意をして、デバイスドライバをロードしてみよう。

まずは、FPGAにロードするためのビットストリームの容易だが、通常のビットファイルではだめで、.bin に変換する必要がある。
Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法”からfpga-bit-to-bin.py をもらってきて、ZYBO_0_wrapper.bit を変換して ZYBO_0_wrapper.bin を作成した。
python fpga-bit-to-bin.py --flip .\ZYBO_0_wrapper.bit .\ZYBO_0_wrapper.bin
ZYBOt_8_180817.png

次に、Address Editor を参考に、devicetree.dts を作成した。
なおクロックの設定は、”ikwzm さんの構築したPYNQ ボード用DebianでのPS出力クロックfclkの設定方法”を参照した。
ZYBOt_9_180818.png

/dts-v1/;
/ {
    fragment@0 {
        target-path = "/amba/fpga-region0";
        #address-cells = <0x1>;
        #size-cells = <0x1>;

        __overlay__ {
            #address-cells = <0x1>;
            #size-cells = <0x1>;

            firmware-name = "ZYBO_0_wrapper.bin";

            mt9d111_axi_iic@41600000 {
                compatible = "generic-uio";
                reg = < 0x41600000 0x10000>;
            };
            dmaw4gabor_0@43cb0000 {
                compatible = "generic-uio";
                reg = < 0x43cb0000 0x10000 >;
            };
            axis_switch_0@43c10000 {
                compatible = "generic-uio";
                reg = < 0x43c10000 0x10000 >;
            };
            axis_switch_1@43c20000 {
                compatible = "generic-uio";
                reg = < 0x43c20000 0x10000 >;
            };
            lap_filter_axis_0@43c30000 {
                compatible = "generic-uio";
                reg = < 0x43c30000 0x10000>;
            };    
            mt9d111_inf_axis_0@43C40000 {
                compatible = "generic-uio";
                reg = < 0x43C40000 0x10000>;
            };
            bitmap_disp_cntrler_axi_master_0@43c00000 {
                compatible = "generic-uio";
                reg = < 0x43c00000 0x10000>;
            };
            bitmap_disp_cntrler_axi_master_1@43c50000 {
                compatible = "generic-uio";
                reg = < 0x43c50000 0x10000>;
            };
            axi_gpio_0@41200000 {
                compatible = "generic-uio";
                reg = < 0x41200000 0x10000>;
            };
            frame_buffer_bmdc@17800000 {
                compatible = "generic-uio";
                reg = < 0x17800000 0x1000000>;
            };
            pwm_0@43c60000 {
                compatible = "generic-uio";
                reg = < 0x43c60000 0x10000>;
            };
            pwm_1@43c70000 {
                compatible = "generic-uio";
                reg = < 0x43c70000 0x10000>;
            };
            motor_monitor_0@43c80000 {
                compatible = "generic-uio";
                reg = < 0x43c80000 0x10000>;
            };
            motor_monitor_1@43c90000 {
                compatible = "generic-uio";
                reg = < 0x43c90000 0x10000>;
            };
            dmar4resize_gray_0@43ca0000 {
                compatible = "generic-uio";
                reg = < 0x43ca0000 0x10000>;
            };
            rgb2hsv_0@43cc0000 {
                compatible = "generic-uio";
                reg = < 0x43cc0000 0x10000>;
            };
            ultrasoninc_sensor_inf_0@43cd0000 {
                compatible = "generic-uio";
                reg = < 0x43cd0000 0x10000>;
            };
            resize_gray_0@43ce0000 {
                compatible = "generic-uio";
                reg = < 0x43ce0000 0x10000>;
            };
            curve_conv_nn2_axis3_0@43cf0000 {
                compatible = "generic-uio";
                reg = < 0x43cf0000 0x10000>;
            };

            pow2-udmabuf0 {
                compatible  = "ikwzm,udmabuf-0.10.a";
                device-name = "udmabuf0";
                size = <0x00600000>;
            };

            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <1 15>;
                insert-rate    = "100000000";
                insert-enable = <1>;
            };
            fclk1 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <1 16>;
                insert-rate    = "40000000";
                insert-enable = <1>;
            };
            fclk2 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <1 17>;
                insert-rate    = "72000000";
                insert-enable = <1>;
            };
            fclk3 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <1 18>;
                insert-rate    = "65000000";
                insert-enable = <1>;
            };
        };
    } ;
} ;


ZYBOt のDebian のfpga ユーザーのホーム・ディレクトリ下に zybot/wl_tracing_cnn ディレクトリを作成した。そのディレクトリにWinSCP でFTP で ZYBO_0_wrapper.bin と devicetree.dts を書き込んだ。
build ディレクトリを作って、Vivado HLS で作成したIP のドライバとwl_tracing_cnn.cpp と Makefile を”カーブ、直線用白線間走行用畳み込みニューラルネットワーク18(ミニ・ロボットカーでの走行テスト)”からコピペした。
ZYBOt_10_180818.png

make
を行った。
wl_tracing_cnn ができた。
ZYBOt_11_180818.png

sudo cp ZYBO_0_wrapper.bin /lib/firmware/
で、ZYBO_0_wrapper.bin を /lib/firmware/ ディレクトリにコピペした。
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
でデバイスツリーで示されるドライバをロードした。
ZYBOt_12_180818.png

コンソールに出た表示を示す。
ZYBOt_13_180818.png

[ 2112.992998] fpga_manager fpga0: writing ZYBO_0_wrapper.bin to Xilinx Zynq FPGA Manager
[ 2113.068111] udmabuf amba:fpga-region0:pow2-udmabuf0: driver probe start.
[ 2113.089995] alloc_contig_range: [1f100, 1f700) PFNs busy
[ 2113.099904] alloc_contig_range: [1f200, 1f800) PFNs busy
[ 2113.121499] alloc_contig_range: [1f200, 1f900) PFNs busy
[ 2113.130406] alloc_contig_range: [1f400, 1fa00) PFNs busy
[ 2113.141038] alloc_contig_range: [1f400, 1fb00) PFNs busy
[ 2113.154205] alloc_contig_range: [1f600, 1fc00) PFNs busy
[ 2113.183723] udmabuf udmabuf0: driver installed
[ 2113.188148] udmabuf udmabuf0: major number = 245
[ 2113.192866] udmabuf udmabuf0: minor number = 0
[ 2113.197527] udmabuf udmabuf0: phys address = 0x1f700000
[ 2113.202857] udmabuf udmabuf0: buffer size = 6291456
[ 2113.208019] udmabuf udmabuf0: dma coherent = 0
[ 2113.212572] udmabuf amba:fpga-region0:pow2-udmabuf0: driver installed.
[ 2113.221307] fclkcfg amba:fpga-region0:fclk0: driver installed.
[ 2113.228467] fclkcfg amba:fpga-region0:fclk0: device name : fclk0
[ 2113.234667] fclkcfg amba:fpga-region0:fclk0: clock name : fclk0
[ 2113.242843] fclkcfg amba:fpga-region0:fclk0: clock rate : 100000000
[ 2113.250352] fclkcfg amba:fpga-region0:fclk0: clock enabled : 1
[ 2113.258386] fclkcfg amba:fpga-region0:fclk1: driver installed.
[ 2113.264157] fclkcfg amba:fpga-region0:fclk1: device name : fclk1
[ 2113.272683] fclkcfg amba:fpga-region0:fclk1: clock name : fclk1
[ 2113.278958] fclkcfg amba:fpga-region0:fclk1: clock rate : 38888889
[ 2113.285413] fclkcfg amba:fpga-region0:fclk1: clock enabled : 1
[ 2113.295553] fclkcfg amba:fpga-region0:fclk2: driver installed.
[ 2113.301408] fclkcfg amba:fpga-region0:fclk2: device name : fclk2
[ 2113.307651] fclkcfg amba:fpga-region0:fclk2: clock name : fclk2
[ 2113.313850] fclkcfg amba:fpga-region0:fclk2: clock rate : 68421053
[ 2113.320440] fclkcfg amba:fpga-region0:fclk2: clock enabled : 1
[ 2113.327543] fclkcfg amba:fpga-region0:fclk3: driver installed.
[ 2113.333792] fclkcfg amba:fpga-region0:fclk3: device name : fclk3
[ 2113.340138] fclkcfg amba:fpga-region0:fclk3: clock name : fclk3
[ 2113.346338] fclkcfg amba:fpga-region0:fclk3: clock rate : 62500000
[ 2113.352906] fclkcfg amba:fpga-region0:fclk3: clock enabled : 1


PS の FCLK の設定を示す。
ZYBOt_15_180818.png

fclk0 は 100 MHz でぴったりなのだが、fclk1 は 40 MHz のところ、約 38.9 MHz 、fclk2 は 72 MHz のところ、約 68.4 MHz 、fclk3 は 65 MHz のところ、62.5 MHz だった。
fclk0 は良いのだが、その他のクロックはずれすぎている。それに Clock Source も IO PLL, ARM PLL, DDR PLL と変更したい。
  1. 2018年08月18日 05:06 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

ZYBOt用のMicro SDカードを作成

ZYBOt 用のMicro SDカードを作成している。
今までは、古いLinux Kernel 3.xx を使っていたが、ikwzm さんの”FPGA+SoC+Linux+Device Tree Overlay+FPGA Region(ブートイメージの提供)”に移行することにした。
このZYBO 用の Linux Kernel Version v4.14.34 と Debian9(stretch) Root File System を使わせて頂こうと思う。
これらは、すでにVivado HLS 勉強会の9回目の資料としてインストールとサンプル・デザインは作ってある。その資料に従って構築していく。
Micro SD カードは、”Format SD-Card for ZYNQ(ZYBO/ZYBO-Z7/PYNQ-Z1)”の通りに作成した。Micro SD カードに何かデータが入っていても初期化される。私のやり方は、””FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる2(Micro SDカードの準備)”参照。

ROOT_FS にDebian9 のRoot File System を書いて、ZYBO_BOOT に target/zynq-zybo/boot/* の内容を書いた。
Micro SD カードをZYBO に挿入して、Ubuntu のマシンから gtkterm を立ち上げてZYBO でDebian 9 を立ち上げた。
debian ディレクトリの下の xxxxx.deb パッケージをすべてインストールした。詳しいやり方は、”FPGA+SoC+Linux+Device Tree Overlay+FPGA Region(ブートイメージの提供)”を参照のこと。

LANケーブルを接続し、
ip addr show
でDHCP のIP アドレスを確認して、Ubuntu のターミナルから
ssh IPアドレス -X -l fpga
でログインした。
sudo apt update
sudo apt upgrede

nautilus をインストール
sudo apt install nautilus

nautilus を立ち上げても起動しないので、ikwzm さんに教えて頂いた xbase-clients と xterm をインストール
sudo apt-get install xbase-clients xterm

これで、nautilus は起動したが、日本語になっているようで文字がトーフになってしまう。
検索してみるとロケールを日本語にしているのに、日本語フォントが入っていないのが問題ということだった。
対処方法として、梅フォントをインストールした。
sudo apt-get install fonts-vlgothic
sudo apt-get install fonts-horai-umefont
sudo apt-get install fonts-umeplus

これで、ZYBO-Z7-20 に日本語フォントが入った。
nautilus &
で起動するときちんと日本語が見えた。
ZYBOt4MsdC_1_180817.png
  1. 2018年08月17日 10:55 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

ZYBOt のコースを作った

昨日はZYBOt のコースを作った。
サイドパーツ付きジョイントマット 32枚セット」に「ヤマト ビニールテープ 38mm幅 5巻 NO200-38-5-5PR 白」で白線を引いた。白線の中心同士の間隔は 28 cm とした。

出来上がったコースの写真を示す。
ZYBOt_4_180817.jpg

ZYBOt_5_180817.jpg

窓際のコーナーを曲がれるかな?という懸念がある。

モーターの +12 V 系の配線も 0.75 mm2 の平行ビニル線を買ってきて配線した。
とりあえずは、「SODIAL(R)5ペア EC5バナナプラグ ブレットコネクタメス+オスRC ESC LIPOバッテリー/モータ」が来ていないので、カーバッテリー用の巨大なクリップで接続している。
ZYBOt_6_180817.jpg

ZYBOt_7_180817.jpg
  1. 2018年08月17日 04:35 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

ZYBOtを製作した

昨日、家用ZYBOtを製作した。
まだ、「SODIAL(R)5ペア EC5バナナプラグ ブレットコネクタメス+オスRC ESC LIPOバッテリー/モータ」が来ていないので、モーターをドライブする+12V 用のコネクタが来ていないので、+12V 系は接続できていない。
あと、「Pmod HB5: H-bridge Driver with Feedback Inputs」の拡張ケーブルの接続は適当に接続してしまったので、コネクタの向きが違っているかもしれない?後で確認する。(2018/08/22:追記 これでHB5への配線はこれで合っています。テスタで確かめました)
ZYBOt_1_180816.jpg

ZYBOt_2_180816.jpg

ZYBOt_3_180816.jpg

サイドパーツ付きジョイントマット 32枚セット」が届いているので、これを床に引いて、「ヤマト ビニールテープ 38mm幅 5巻 NO200-38-5-5PR 白」で白線を引く予定だ。
  1. 2018年08月16日 07:05 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

インクレディブル・ファミリー(映画)を見てきました

本当に久しぶりに下の娘とインクレディブル・ファミリー(映画)を見てきました。今回も楽しめました。
  1. 2018年08月15日 20:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ultra96 ボードのDisplayPort について

Ultra96 ボードのDisplayPort を使いたいと思っているがなかなか難しい。

Zynq UltraScale+ MPSoC テクニカル リファレンス マニュアル UG1085 (v1.4) 2017 年 2 月 2 日」の 772 ページ「DisplayPort コ ン ト ローラーの概要」を見ると、DPDMA で PS だけでメモリから画像データをDMA して表示する方法と、Live Video Interface を使用してPL からビデオ信号を入力する方法がある。
Zynq UltraScale+ MPSoC テクニカル リファレンス マニュアル UG1085 (v1.4) 2017 年 2 月 2 日」の 775 ページの「図 33‐1: DisplayPort コ ン ト ローラー内のデー タ フロー」と 776 ページの「図 33‐2: DisplayPort コ ン ト ローラーのビデオ レンダリング パイプラインのブロ ッ ク図」を引用する。
Ultra96_DP_8_180815.jpg

Ultra96_DP_9_180815.jpg

そのうちの、DPDMA のサンプルを「DPDMA の examples をやってみる」でやってみたのだが、うまく行っていない。。。

もう1つのLive Video Interface だが、これは、下表のような信号をPL から入力する。「Zynq UltraScale+ MPSoC テクニカル リファレンス マニュアル UG1085 (v1.4) 2017 年 2 月 2 日」の 780 ページの「 33‐2: ライブ イン ターフ ェ イスの PS‐PL イ ン ターフ ェ イス信号」を引用する。
Ultra96_DP_10_180815.jpg

これらの信号のブロックデザイン中のZynq Ultrascale+ MPSoC に表示する方法を書いておく。
ブロックデザイン中のZYNQ Ultrascale+ MPSoC をダブルクリックして設定ダイアログを開く。
Page Navigator のPS-PL Configuration をクリックしてGeneral -> Ohters を開き、Live Video を 0 から 1 に変更する。
Ultra96_DP_11_180815.jpg

ブロックデザインの Zynq Ultrascale+ MPSoC を見ると dp_live_video の信号が追加されている。
Ultra96_DP_12_180815.jpg
  1. 2018年08月15日 06:47 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

SDKでstdin, stdout に割り当てられるデバイスを変更

SDK でstdin, stdout に割り当てられるデバイスを変更する方法を書いておく。

SDK で xxx_bsp フォルダの system.mss をダブルクリックして、system.mss を開く。
Modify this BSP's Settings ボタンをクリックする。
SDK_stdin_out_1_180815.jpg

Board Support Package Settings ダイアログが開く。
左のOverview -> standalone をクリックする。
SDK_stdin_out_2_180815.jpg

standalone 画面で、stdin のValue をクリックすると、stdin にできるデバイスがプルダウン・メニューで選択できる。
SDK_stdin_out_3_180815.jpg

stdin, stdout 共に psu_uart_1 に設定変更した。
SDK_stdin_out_4_180815.jpg

これで、OK ボタンをクリックすると、リビルドした。

Ultra96 の uart_0 はブルートゥースに接続されて、端子に出ているのは、uart_1 ということで、端子からUART出力する場合には設定変更が必要となる。
まだ、UARTアダプタをはんだ付けしてないので、はんだ付けして試してみよう。
  1. 2018年08月15日 05:30 |
  2. SDK
  3. | トラックバック:0
  4. | コメント:0

DPDMA の examples をやってみる

Ultra96 の DisplayPort を使えるようにしようとして奮闘しているが、”ZynqMP Standalone DisplayPort Driver”のドライバがXilinx\SDK\2018.2\data\embeddedsw\XilinxProcessorIPLib\drivers フォルダにあるということで、dpdma_v1_1/examples を確かめてみることにした。
Ultra96_DP_7_180814.jpg

Xilinx\SDK\2018.2\data\embeddedsw\XilinxProcessorIPLib\drivers フォルダをインクルード・パスに追加する必要があるが、それは”SDKでインクルード・パスを追加する方法”で解決済みだ。

Vivado 2018.2 の DP_test プロジェクトを示す。
Ultra96_DP_1_180814.jpg

DP_test ブロックデザインを示す。
Ultra96_DP_2_180814.jpg

インプリメンテーション結果を示す。
Ultra96_DP_3_180814.jpg
Ultra96_DP_4_180814.jpg

ハードウェアをエクスポートし、SDK を起動した。

空のアプリケーション・プロジェクトを作成し、dpdma_v1_1/examples のファイルを追加した。
ビルドが通ったので、FPGA をコンフィギュレーションし、elf ファイルを起動した。
Ultra96_DP_6_180814.jpg

Ultra96 のMini DisplayPort にMini DisplayPort - VGA変換器をかませて、ディスプレイに接続したところ、信号は出ているようだが、画面は真っ暗だった。ディスプレイの同期範囲から外れているのかな?
xdpdma_video_example.c の一部を引用する。

void InitRunConfig(Run_Config *RunCfgPtr)
{
    /* Initial configuration parameters. */
        RunCfgPtr->DpPsuPtr   = &DpPsu;
        RunCfgPtr->IntrPtr   = &Intr;
        RunCfgPtr->AVBufPtr  = &AVBuf;
        RunCfgPtr->DpDmaPtr  = &DpDma;
        RunCfgPtr->VideoMode = XVIDC_VM_1920x1080_60_P;
        RunCfgPtr->Bpc         = XVIDC_BPC_8;
        RunCfgPtr->ColorEncode            = XDPPSU_CENC_RGB;
        RunCfgPtr->UseMaxCfgCaps        = 1;
        RunCfgPtr->LaneCount            = LANE_COUNT_2;
        RunCfgPtr->LinkRate                = LINK_RATE_540GBPS;
        RunCfgPtr->EnSynchClkMode        = 0;
        RunCfgPtr->UseMaxLaneCount        = 1;
        RunCfgPtr->UseMaxLinkRate        = 1;
}


HD 解像度のはずなんだが、ストリームを送り込む必要があるのかな?
  1. 2018年08月14日 07:54 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

SDKでインクルード・パスを追加する方法

SDK でベアメタルのドライバをインクルードできずに困っていた。
SDK で検索しても全くヒットしなかったが Eclipse で検索すると、「Eclipse のビルドとインクルードの設定」がヒットした。

Eclipse のビルドとインクルードの設定」によると、プロジェクトを右クリックして、右クリックメニューから一番下のProperties を選択する。

Properties ダイアログのC/C++ General を開いて、Paths and Symbols をクリックする。

Includes タブで Add... ボタンをクリックして、インクルード・パスを追加したいパスを追加する。

F:\Xilinx\SDK\2018.2\data\embeddedsw\XilinxProcessorIPLib\drivers フォルダへのパスを追加した。これで各種ドライバへのインクルード・パスが設定できた。
Ultra96_DP_5_180814.jpg

これで、SDK でアプリケーション・プロジェクトを作り直さなくても、ドライバへのインクルード・パスが設定できた。
  1. 2018年08月14日 05:20 |
  2. SDK
  3. | トラックバック:0
  4. | コメント:0

「Keras Tutorial : Using pre-trained Imagenet models」を試してみる

Keras Tutorial : Using pre-trained Imagenet models」を試してみようと思う。このページでは、ImagNet で事前に学習させた各ネットワークの重みやバイアスを使用して、vgg_model、inception_model、resnet_model、mobilenet_model の実力を探る企画のようだ。

Jupyter Notebook で試してみたので、それを貼っておく。
imagenet_models_1_180813.png
imagenet_models_2_180813.png
imagenet_models_3_180813.png
imagenet_models_4_180813.png
imagenet_models_5_180813.png
imagenet_models_6_180813.png
imagenet_models_7_180813.png
imagenet_models_8_180813.png
imagenet_models_9_180813.png
imagenet_models_10_180813.png
imagenet_models_11_180813.png
imagenet_models_12_180813.png
  1. 2018年08月13日 07:05 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST 1

Squeezenet をFPGA に実装したいので、重みとバイアスを C のヘッダにしたいと思っているのだが、ImagkeNetの画像を使って学習するのも大変だけど、ImagkeNetの画像を集めて学習する方法を探っていた。その時に、SqueezeNet for MNIST を見つけた。とりあえず、MNISTのデータだったらKeras に標準で付いているし、手始めにこれをやってみることにした。それにLicense も Apache License 2.0 なので、都合が良い。
なお、統計情報を取る必要性から Activation を分けた。ReLU は独立した Activation に分けてある。
変更したSqueezeNet for MNISTを示す。なお、こちらの環境に合わせてある。
squeezenet4mnist_1_180811.png
squeezenet4mnist_2_180811.png
squeezenet4mnist_3_180811.png
squeezenet4mnist_5_180811.png

約 98.5 % の精度が出ている。

# SqueezeNet for MNIST
# 2018/08/02 by marsee
# Keras / Tensorflowで始めるディープラーニング入門 https://qiita.com/yampy/items/706d44417c433e68db0d
# のPythonコードを再利用させて頂いている
# https://www.kaggle.com/somshubramajumdar/squeezenet-for-mnist (Apache License 2.0)を引用して
# Keras 2に変更し独自のコードを加えた

import keras
from keras.datasets import mnist
from keras import backend as K
import pandas as pd
import numpy as np 
from keras.models import Model, Input
from keras.layers import Dense, Dropout, Flatten, Concatenate
from keras.layers import Conv2D, MaxPooling2D, Activation, AveragePooling2D
import keras.utils.np_utils as kutils

batch_size = 128
num_classes = 10
epochs = 5

img_rows, img_cols = 28, 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()

#Kerasのバックエンドで動くTensorFlowとTheanoでは入力チャンネルの順番が違うので場合分けして書いています
if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)

# Setup of SqueezeNet (http://arxiv.org/abs/1602.07360), which offers similar performance
# to AlexNet, while using drastically fewer parameters. Tested on CIFAR10, it also performs
# well on MNIST problem

# Uses the latest keras 1.0.2 Functional API

input_layer = Input(shape=(28, 28, 1), name="input")

#conv 1
conv1 = Conv2D(96, (3, 3), padding="valid", kernel_initializer="glorot_uniform", strides=(2, 2))(input_layer)
relu1 = Activation(activation='relu')(conv1)

#maxpool 1
maxpool1 = MaxPooling2D(pool_size=(2,2))(relu1)

#fire 1
fire2_squeeze = Conv2D(16, (1, 1), padding="same", kernel_initializer="glorot_uniform")(maxpool1)
relu2_squeeze = Activation(activation='relu')(fire2_squeeze)

fire2_expand1 = Conv2D(64, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu2_squeeze)
relu2_expand1 = Activation(activation='relu')(fire2_expand1)
fire2_expand2 = Conv2D(64, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu2_squeeze)
relu2_expand2 = Activation(activation='relu')(fire2_expand2)

merge1 = Concatenate()([relu2_expand1, relu2_expand2])
fire2 = Activation("linear")(merge1)

#fire 2
fire3_squeeze = Conv2D(16, (1, 1),  padding="same", kernel_initializer="glorot_uniform")(fire2)
relu3_squeeze = Activation(activation='relu')(fire3_squeeze)

fire3_expand1 = Conv2D(64, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu3_squeeze)
relu3_expand1 = Activation(activation='relu')(fire3_expand1)
fire3_expand2 = Conv2D(64, (3, 3),  padding="same", kernel_initializer="glorot_uniform")(relu3_squeeze)
relu3_expand2 = Activation(activation='relu')(fire3_expand2)

merge2 = Concatenate()([relu3_expand1, relu3_expand2])
fire3 = Activation("linear")(merge2)

#fire 3
fire4_squeeze = Conv2D(32, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire3)
relu4_squeeze = Activation(activation='relu')(fire4_squeeze)

fire4_expand1 = Conv2D(128, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu4_squeeze)
relu4_expand1 = Activation(activation='relu')(fire4_expand1)
fire4_expand2 = Conv2D(128, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu4_squeeze)
relu4_expand2 = Activation(activation='relu')(fire4_expand2)

merge3 = Concatenate()([relu4_expand1, relu4_expand2])
fire4 = Activation("linear")(merge3)

#maxpool 4
maxpool4 = MaxPooling2D((2,2))(fire4)

#fire 5
fire5_squeeze = Conv2D(32, (1, 1), padding="same", kernel_initializer="glorot_uniform")(maxpool4)
relu5_squeeze = Activation(activation='relu')(fire5_squeeze)

fire5_expand1 = Conv2D(128, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu5_squeeze)
relu5_expand1 = Activation(activation='relu')(fire5_expand1)
fire5_expand2 = Conv2D(128, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu5_squeeze)
relu5_expand2 = Activation(activation='relu')(fire5_expand2)

merge5 = Concatenate()([relu5_expand1, relu5_expand2])
fire5 = Activation("linear")(merge5)

#fire 6
fire6_squeeze = Conv2D(48, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire5)
relu6_squeeze = Activation(activation='relu')(fire6_squeeze)

fire6_expand1 = Conv2D(192, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu6_squeeze)
relu6_expand1 = Activation(activation='relu')(fire6_expand1)
fire6_expand2 = Conv2D(192, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu6_squeeze)
relu6_expand2 = Activation(activation='relu')(fire6_expand2)

merge6 = Concatenate()([relu6_expand1, relu6_expand2])
fire6 = Activation("linear")(merge6)

#fire 7
fire7_squeeze = Conv2D(48, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire6)
relu7_squeeze = Activation(activation='relu')(fire7_squeeze)

fire7_expand1 = Conv2D(192, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu7_squeeze)
relu7_expand1 = Activation(activation='relu')(fire7_expand1)
fire7_expand2 = Conv2D(192, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu7_squeeze)
relu7_expand2 = Activation(activation='relu')(fire7_expand2)

merge7 = Concatenate()([relu7_expand1, relu7_expand2])
fire7 =Activation("linear")(merge7)

#fire 8
fire8_squeeze = Conv2D(64, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire7)
relu8_squeeze = Activation(activation='relu')(fire8_squeeze)

fire8_expand1 = Conv2D(256, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu8_squeeze)
relu8_expand1 = Activation(activation='relu')(fire8_expand1)
fire8_expand2 = Conv2D(256, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu8_squeeze)
relu8_expand2 = Activation(activation='relu')(fire8_expand2)

merge8 = Concatenate()([relu8_expand1, relu8_expand2])
fire8 = Activation("linear")(merge8)

#maxpool 8
maxpool8 = MaxPooling2D((2,2))(fire8)

#fire 9
fire9_squeeze = Conv2D(64, (1, 1),  padding="same", kernel_initializer="glorot_uniform")(maxpool8)
relu9_squeeze = Activation(activation='relu')(fire9_squeeze)

fire9_expand1 = Conv2D(256, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu9_squeeze)
relu9_expand1 = Activation(activation='relu')(fire9_expand1)
fire9_expand2 = Conv2D(256, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu9_squeeze)
relu9_expand2 = Activation(activation='relu')(fire9_expand2)

merge8 = Concatenate()([relu9_expand1, relu9_expand2])
fire9 = Activation("linear")(merge8)
fire9_dropout = Dropout(0.5)(fire9)

#conv 10
conv10 = Conv2D(10, (1, 1), padding="valid", kernel_initializer="glorot_uniform")(fire9_dropout)

# The original SqueezeNet has this avgpool1 as well. But since MNIST images are smaller (1,28,28)
# than the CIFAR10 images (3,224,224), AveragePooling2D reduces the image size to (10,0,0), 
# crashing the script.

#avgpool 1
#avgpool10 = AveragePooling2D((13,13))(conv10)

flatten = Flatten()(conv10)

softmax = Dense(10, activation="softmax")(flatten)

model = Model(inputs=input_layer, outputs=softmax)


model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
          verbose=1, validation_data=(x_test, y_test))

  1. 2018年08月11日 13:31 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Kerasで学習した重みとバイアスを使用した白線間走行用CNNのVivado プロジェクト1

だいぶ前になってしまったが、”Kerasで学習した重みとバイアスを使用した白線間走行用CNNをIPにする2”で、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク13(AXI4 Stream版CNN IP 1)”の curve_conv_nn2_axis3 プロジェクトを利用して、curve_conv_nn2_axis3_k プロジェクトを作成し、Export RTLでIP 化を行った。

今回は、そのIP を使用して、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク15(Vivadoプロジェクト)”のVivado プロジェクトをバージョン 2018.2 に変更し、curve_conv_nn2_axis3 を”Kerasで学習した重みとバイアスを使用した白線間走行用CNNをIPにする2”で作成したIP と交換して、ZYBO_0_182_9_k フォルダに保存した。

ZYBO_0_182_9_k フォルダのVivado 2018.2 プロジェクトを示す。
keras_curve_line_14_1808010.png

、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク15(Vivadoプロジェクト)”のVivado プロジェクトと同じだが、もう一度、ブロックデザイン、Address Editor を示す。
keras_curve_line_15_1808010.png
keras_curve_line_16_1808010.png

keras_curve_line_18_1808010.png

camera_module のブロックデザインを示す。
keras_curve_line_17_1808010.png

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

タイミングエラーが出ている。
Open Implemented Design を開いて、原因を見てみよう。
keras_curve_line_20_1808010.png

やはり、curve_conv_nn2_axi3 IP でタイミングエラーが出ている。

もう一度、”Kerasで学習した重みとバイアスを使用した白線間走行用CNNをIPにする2”に戻って、Uncertainty を 2 ns に設定して、C コードの合成を行った。結果を示す。
keras_curve_line_21_1808010.png
keras_curve_line_22_1808010.png

Estimated は9.634 ns で前よりも悪くなっているが、Vivado での解析結果を見ないと何とも言えない。
Latency は、178833 クロックが 194745 クロックに延びているが、まだ、1.95 ms なので問題ない。
リソース使用量はFF と LUT が多少増えている。

Export RTLで IP 化を行った。結果を示す。
keras_curve_line_23_1808010.png

CP achiveved post-implementation が 7.937 ns になった。これで大丈夫だろう?

Vivadoプロジェクトで、curve_conv_nn2_axi3 IP を入れ替えて、もう一度、論理合成、インプリメンテーション、ビットストリームの生成を行った。結果を示す。
keras_curve_line_24_1808010.png

今度はタイミング制約を満足している。
  1. 2018年08月10日 06:47 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

2つのHLSストリームを同時に入力して演算してHLSストリーム出力2

2つのHLSストリームを同時に入力して演算してHLSストリーム出力”の続き。

前回は、2つのHLSストリームを同時に入力して演算してHLSストリーム出力したいということで、コードを書いてみたが、スタート部分がシリアライズされていた。今回は、そこも並列動作させてみよう。

今回のソースコード two_hls_stream2.cpp を示す。

// two_hls_streams2.cpp
// 2018/08/07 by marsee
//

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

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

int two_hls_streams(hls::stream<ap_axis<32,1,1,1> >& ins0,
        hls::stream<ap_axis<32,1,1,1> >& ins1,
        hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS DATAFLOW
    hls::stream<ap_axis<32,1,1,1> > out0;
    hls::stream<ap_axis<32,1,1,1> > out1;
    ap_axis<32,1,1,1> in_val0;
    ap_axis<32,1,1,1> in_val1;
    ap_axis<32,1,1,1> out_val;

    ins_hls_stream(ins0, out0);
    ins_hls_stream(ins1, out1);

    Loop1 : for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        out0 >> in_val0;
        out1 >> in_val1;

        out_val.data = in_val0.data * in_val1.data;
        out_val.user = in_val0.user;
        out_val.last = in_val0.last;
        outs << out_val;
    }
    return(0);
}

int ins_hls_stream(hls::stream<ap_axis<32,1,1,1> >& ins,
    hls::stream<ap_axis<32,1,1,1> >& outs){
    ap_axis<32,1,1,1> in_val;
    ap_axis<32,1,1,1> out_val;

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

    Loop2 : for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        if(i != 0){
            ins >> in_val;
        }
        out_val.data = in_val.data;
        out_val.user = in_val.user;
        out_val.last = in_val.last;
        outs << out_val;
    }
    return(0);

}


つまり、スタート部分を関数にして、2つの入力に対してそれぞれ関数をコールする。そして、その関数をDATAFLOW 指示子で並列動作されるというコンセプトだ。

まずは、この two_hls_stream2 プロジェクトを示す。
two_hls_streams_8_180808.png

これで C シミュレーションを行った。
two_hls_streams_9_180808.png

問題無い様だ。

C コードの合成を行った。
two_hls_streams_10_180808.png

Latency は 17 クロック、Interval は 15 クロックだった。前回のLatency は 16 クロックだった。
リソース使用量は、DSP48E は変わらないが、FF と LUT が増えている。特にLUT は 375 個だったところが、1185 個に増えた。

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

20 クロックだった。前回は 21 クロックだった。

C/RTL 協調シミュレーションの波形を示す。
two_hls_streams_12_180808.png
two_hls_streams_13_180808.png
two_hls_streams_14_180808.png

スタート部分もシリアライズされていないで、並列動作しているようだ。
  1. 2018年08月09日 05:08 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

2つのHLSストリームを同時に入力して演算してHLSストリーム出力

2つのHLSストリームを同時に入力して演算してHLSストリーム出力したい。これは、2つの畳み込み演算を1つにまとめる機能を持ったIPをVivado HLSで作るために必要となる。
ただし、C やC++ は並列動作が想定されていないので、どうなるか分からない。

まずは、ソースファイルの two_hls_streams.cpp を示す。

// two_hls_streams.cpp
// 2018/08/07 by marsee
//

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

int two_hls_streams(hls::stream<ap_axis<32,1,1,1> >& ins0,
    hls::stream<ap_axis<32,1,1,1> >& ins1,
    hls::stream<ap_axis<32,1,1,1> >& outs){
    ap_axis<32,1,1,1> in_val0;
    ap_axis<32,1,1,1> in_val1;
    ap_axis<32,1,1,1> out_val;

    Loop1 : do {    // user が 1になった時にスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins0 >> in_val0;
    } while(in_val0.user == 0);

    Loop2 : do {    // user が 1になった時にスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins1 >> in_val1;
    } while(in_val1.user == 0);

    Loop3 : for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        if(i != 0){
            ins0 >> in_val0;
            ins1 >> in_val1;
        }
        out_val.data = in_val0.data * in_val1.data;
        out_val.user = in_val0.user;
        out_val.last = in_val0.last;
        outs << out_val;
    }
    return(0);
}


ins0 のスタートを待った後に、ins1 のスタートを待って、ins0 と ins1 を乗算して、outs にHLSストリーム出力している。
次に、テストベンチの two_hls_streams_tb.cpp を示す。

// two_hls_streams_tb.cpp
// 2018/08/07 by marsee
//

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

int two_hls_streams(hls::stream<ap_axis<32,1,1,1> >& ins0,
    hls::stream<ap_axis<32,1,1,1> >& ins1,
    hls::stream<ap_axis<32,1,1,1> >& outs);

int main(){
    hls::stream<ap_axis<32,1,1,1> > ins0;
    hls::stream<ap_axis<32,1,1,1> > ins1;
    hls::stream<ap_axis<32,1,1,1> > outs;
    ap_axis<32,1,1,1> in_val0;
    ap_axis<32,1,1,1> in_val1;
    ap_axis<32,1,1,1> out_val;

    for(int i=0; i<2; i++){ // dummy
        in_val0.data = i;
        in_val0.user = 0;
        in_val0.last = 0;
        ins0 << in_val0;
    }

    for(int i=0; i<3; i++){ // dummy
        in_val1.data = i;
        in_val1.user = 0;
        in_val1.last = 0;
        ins1 << in_val1;
    }

    for(int i=0; i<10; i++){
        in_val0.data = i;
        in_val1.data = i+1;
        if(i == 0){
            in_val0.user = 1;
            in_val1.user = 1;
        }else{
            in_val0.user = 0;
            in_val1.user = 0;
        }
        if(i == 9){
            in_val0.last = 1;
            in_val1.last = 1;
        }else{
            in_val0.last = 0;
            in_val1.last = 0;
        }
        ins0 << in_val0;
        ins1 << in_val1;
    }

    two_hls_streams(ins0, ins1, outs);

    for(int i=0; i<10; i++){
        outs >> out_val;
        std::cout << "outs[" << i << "].data = " << out_val.data
                << " .user = " << out_val.user << " .last = " << out_val.last
                << std::endl;
    }

    return(0);
}


Vivado HLS 2018.2 の two_hls_streams プロジェクトを作成した。
two_hls_streams_1_180808.png

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

C コードの合成を行った。
two_hls_streams_3_180808.png

Estimated は8.510 ns でLatency は 16 クロックだった。

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

Latency は 21 クロックだった。

C/RTL 協調シミュレーション波形を示す。
two_hls_streams_5_180808.png
two_hls_streams_6_180808.png
two_hls_streams_7_180808.png

ins0 のスタートを検出したら ins1 のスタートを検出している。つまり、シリアライズされているので、ここを並列動作させた方が良かな?
とりあえずは、演算本体部分はins0 と ins1 を同時に読んで演算を行っているようだ。
  1. 2018年08月08日 05:21 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードの波形を確認

Ultra96用PMOD拡張ボードの波形を確認した。

まずは、Ultra96 から波形を出力してPMOD 端子で波形を確認した。最初に、360 Ωで +3.3V にプルアップした。
波形は、”Ultra96用PMOD拡張ボードのPMOD端子のテストのために8ビットカウンタのLチカを作る2”から出力している。検査したポートはHD_GPIO_8 とした。波形を示す。
Ultra96_ext_board_37_180806.jpg

波形のH 部分の電圧は 2.80 V だった。100 MHz のオシロスコープにパッシブプローブなので、立ち上がりは良く分からないかも?ある程度早く立ち上がっているみたいだ。

同じ、Ultra96 から波形を出力してPMOD 端子で波形を確認した。今度は、プルアップ抵抗を 1 kΩ とした。
Ultra96_ext_board_38_180806.jpg

立ち上がりはそれほど変化ないのだが(100 MHz のオシロスコープにパッシブプローブで分からないだけかも?)、H の電圧が 2.4 V になってしまっている。

次に、PMOD から Ultra96 への信号だが、こちらは 1.8 V LVCMOS 信号レベルだ。
下の様に、+3.3 V で古い 1 MHz のクロック発振器を動作させている。それをプルアップ抵抗が付いていないPMOD 端子に入れている。今回入力するポートは HD_GPIO_0 とした。やっている様子を示す。
Ultra96_ext_board_39_180806.jpg

波形を示す。
Ultra96_ext_board_40_180806.jpg

CH2 がPMOD 端子のところの波形で、CH1 が 2mm コネクタのところの 1.8 V の波形だ。きちんと 1.8 V の波形が出力されている。PMOD から Ultra96 への信号ではプルアップ抵抗は要らないみたいだ。

拡大してみよう。
Ultra96_ext_board_41_180806.jpg

立ち上がりも、良く分からないが、大丈夫ではないだろうか?

と言う訳で、STANBY と SCL , SCA , XCLK のところに、プルアップ抵抗 1 kΩ を付けてテストすることにした。これで、行けるのではないか?と思う。XCLK は 72 MHz で心配だが、回路ができたら波形を観察してみよう。ダメだったら、360 Ωに交換する。
Ultra96_ext_board_43_180807.jpg
Ultra96_ext_board_44_180807.jpg

これでうまく行ったら基板を改版する。

なお、@ciniml さんに頂いたJTAG の変換基板を使用してJTAG を使っている。@ciniml さん、ありがとうございました。
Ultra96_ext_board_42_180806.jpg
  1. 2018年08月07日 04:25 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0
»