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

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

FPGAの部屋

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

MT9D111をコードを伸ばしてステレオ・カメラにする4(AXI IICの設定)

MT9D111をコードを伸ばしてステレオ・カメラにする3(SCL, SDAの波形計測2)”の続き。

MT9D111に延長コードを接続すると、I2C が通らないという問題におるさんやくりさんから、延長コードをつけたことによってSCL が 1 の間に SDA の値を確定させておくというI2C の規格に違反してしまっているのでは?というアドバイスを頂いた。(おるさんのコメントくりさんのコメント)コメントありがとうございました。
I2C(SCCB)のプロトコルについては、”SCCBインタフェース回路の実装1(タイミングチャート)”参照のこと。

波形を見ても、SCL の立下りとSDA の立下りは同時に見える。
stereo_cam_7_161026.jpg

そこでXilinx 社のAXI IIC IP でどうやって、SDAを遅延させるかを調査したが、単純にVivado 2016.3 でブロックデザインのAXI IIC をダブルクリックしたらSDA Inertial delay 設定があった。。。
stereo_cam_11_161030.png

AXI クロックでのディレイ設定だそうなので、100 クロックにしました。これで、 10 ns X 100 = 1 us SDA が SCL に対して遅延するはず。。。

SDA Inertial delay を 100 クロック入れても、MT9D111 カメラ・インターフェース基板を直付けの場合は、カメラ画像表示に問題は無かった。延長コードを入れた結果は月曜日に書く予定だ。

Inertial delay は慣性遅延で、この長さ以上の信号でないと無くなるようにする機能の様だった。つまり受信にしか関係ないのだろう?これを入れても出力は変化が無かった。

でも、デフォルト状態でも、SCLの立下りに対して、SDAは 70 ns 程遅れているようです。
stereo_cam_12_161028.jpg
  1. 2016年10月30日 04:14 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

MT9D111をコードを伸ばしてステレオ・カメラにする3(SCL, SDAの波形計測2)

MT9D111をコードを伸ばしてステレオ・カメラにする2(SCL, SDAの波形計測)”の続き。

前回はZYBOから 15 cm 程度の延長コードを使用して、MT9D111のカメラ・インターフェース基板に接続し、カメラの表示を試みたが、I2Cが通らずにうまく表示することができなかった。使用している延長コードはDigilent 社の2x6 Pin to Dual 6-pin Cable なのだが、そこにノイズが乗っているようなのだ。そこで、2つの方法を試した。

1.Digilent 社の2x6 Pin to Dual 6-pin Cable を使用するが、SCL とSDA がコネクタの端なので、1つ延長ケーブルをずらせて差し込んでSCL とSDA はオスーメスのジャンプワイヤーで接続する。

2.aitendo の 10Pメスーメスケーブル3本で接続する。PMOD 12 ピン2つなので、SCL, SDAを接続するコネクタは他のと6本分の余裕を取っている。

1.をやってみた。接続写真を示す。
stereo_cam_8_161028.jpg

3 回は正常に画像が見えたが、4 回目からI2C が通らなくなった。確か 6 回程度やった。SCL, SDAの波形を示す。下がSCL だ。
stereo_cam_9_161028.jpg

2.をやってみた。最初の1回のみ正常に表示されて、後、3 回程度は正常に表示されなかった。
こちらはSCL, SDAの波形は見ていない。
接続写真を撮るのを忘れてしまったので、aitendo の 10Pメスーメスケーブル3本の写真を示す。
stereo_cam_10_161028.jpg

こうなると、おるさんの仰る様に、I2C の波形自体がギリギリのスペックなのかな???
  1. 2016年10月28日 22:34 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

MT9D111をコードを伸ばしてステレオ・カメラにする3(I2CリピータIO付きカメラ・インターフェース基板)

MT9D111をコードを伸ばしてステレオ・カメラにする2(SCL, SDAの波形計測)”の続き。

秋月電子のI2C リピーターIC の PCA9515AD を使ったカメラ・モジュールのインターフェース基板をKiCad で作成した。
I2CリピータIC を実装しない場合は、R1, R2 に 0 Ω抵抗を実装してZYBO とMT9D111 のカメラ・モジュールのSCL とSDA を直結する。つまり、R1, R2 と U1, R3, R4 は排他的に実装する。
回路図を示す。(2018/11/03:追記)注意:回路図は間違っています。PMODの電源とGNDのピンが反対です。
MT9D111_inf2_1_161028.png

次に、FreeRouter で配線を行って、ベタを塗りつぶした基板図面を示す。
MT9D111_inf2_2_161028.png

なお、ZYBO の4つのPMODコネクタの2つずつに2つのカメラ・インターフェース基板を実装できるように幅を5.0 cm から 4.5 cm に縮小した。
明日、もう一度確認して間違いがなければ発注してしようと思う。

それとは別に、配線コードを変えてやってみようと思っている。今の配線コードはDigilent 社の2x6 Pin to Dual 6-pin Cable で、全部の配線がまとまっているが、aitendo のメス―メス・ケーブルを持っていたと思うので、それで接続してみようと思う。
  1. 2016年10月28日 08:07 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:5

2台の Zybot での隊列走行1(構想編)

今まで作ってきたRGB2HSV変換IP を使って、2台のZybot で隊列走行をさせたいと思う。それではどのようにやるか?を検討していこう。

HSV でのH (色相)は、0~360 までの円で表されるので、0 と 180 の距離が一番離れている。S = V = 255 とすると H = 0 は R=255, G = 0, B = 0 つまり赤であり、H =180 は R = 0, G = 255, B = 255 の水色である。

つまり、水色の四角の内側に赤い四角を書いて、水色の四角の中の赤い四角の大きさや位置を検出しようと思っている。これで多少明るさが変化してもH を測定していれば明るさの変化に強くなる。
こんな感じだ。
platoon_1_161027.png

この水色四角の中の赤の四角を大きさや位置を追跡して隊列走行させようと思う。つまり、この図形をZybot の後ろに付けることにする。

下の写真のように、図形の一部が暗いとする。
platoon_2_161027.jpg

それでも、rgb2hsv_ho.elf を実行すると、S = V = 255 としてH を変換したときのH には多少違いがあるだけだ。つまり、暗い影があってもあまり影響はないはずだ。
platoon_3_161027.jpg

これを使って、隊列走行をさせたいと思っている。
  1. 2016年10月27日 04:32 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

MT9D111をコードを伸ばしてステレオ・カメラにする2(SCL, SDAの波形計測)

MT9D111をコードを伸ばしてステレオ・カメラにする1”の続き。

今回は、SCL, SDAの波形をオシロスコープで計測した。測定ポイントはコードを延ばした先のカメラ・インターフェース基板のコネクタ部分だ。
stereo_cam_1_161026.jpg

まずは、MT9D111 のプルアップ抵抗が 5KΩの場合で、カメラ・インターフェース基板をZYBO のPMOD コネクタに直付けの場合。
stereo_cam_4_161026.jpg

この時は、I2C が通って正常にカメラ画像が表示されていた。


次に、MT9D111 のプルアップ抵抗が 5KΩの場合で、カメラ・インターフェース基板をZYBO のPMOD コネクタから 15 cm程度のコードで延長した場合。
stereo_cam_5_161026.jpg

I2C が通っていなくて、カメラ画像が正常に表示されない。


MT9D111 のプルアップ抵抗が 10 KΩの場合で、カメラ・インターフェース基板をZYBO のPMOD コネクタに直付けの場合。
stereo_cam_7_161026.jpg

この時は、I2C が通って正常にカメラ画像が表示されていた。


MT9D111 のプルアップ抵抗が 10 KΩの場合で、カメラ・インターフェース基板をZYBO のPMOD コネクタから 15 cm程度のコードで延長した場合。
stereo_cam_6_161026.jpg

I2C が通っていなくて、カメラ画像が正常に表示されない。


コードで延長すると、I2C 波形立ち上がり、立下りはコード延長の影響は感じないが、ノイズが増えている。

試しに、SCL, SDAに 100 pF のコンデンサをGNDと並列に入れてみたが、カメラ・インターフェース基板をZYBO のPMOD コネクタに直付けしても I2C が通らなかった。
  1. 2016年10月26日 20:42 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:6

MT9D111をコードを伸ばしてステレオ・カメラにする1(I2Cのプルアップ抵抗)

Zybot にMT9D111 カメラ・モジュールを搭載しているが、インターフェース基板をZYBO に直付けしている。ステレオ・カメラにするためには、延長コードをつけてカメラ・モジュールを 15 cm 程度延ばす必要がある。
stereo_cam_1_161026.jpg

このようにカメラ・モジュールを延長するとI2C が通らなくなって、カメラ・モジュールに設定が行かなくなってYUV のままになってしまい、正常にカメラ画像が映らない。
そこで、ツィッターでI2Cのプルアップ抵抗を小さくしてはどうか?という提案があったので、やってみた。
プルアップ抵抗はすでにカメラ・モジュールに搭載されているので、それを変更することになる。
カメラ・モジュールは日昇テクノロジーのMT9D111なのだ。その回路図はここにある。
R1 と R2 が 10KΩなので、これを小さくしたい。カメラの基板を示す。
stereo_cam_2_161026.jpg

R1 と R2 の上に 1608 の 10KΩを載せた。その写真を示す。
stereo_cam_3_161026.jpg

R1 と R2 のマーキングが違っているのがわかるだろうか?これで、5KΩになっているはずだ。

これでやってみたが、最初はカメラ画像も表示されていい感じと思ったのだが、そのうちに失敗するようになってしまった。確率的には1/3 は失敗かな?

そこで、I2Cの設定ルーチンを100回、回したが、やはり設定できないことがある。やはりだめだ。

次に、R1 と R2 にもう1つ 10KΩを載せて、合成抵抗を 3.33KΩにしてみたが、これは全く設定が通らない。

と言う訳で、I2Cの抵抗を小さくしてもカメラ・モジュールの設定はうまく行かないようだ。

次にFPGAの出力電流値を変えてみた。出力電流値を小さくすると、ドライブ能力が減って、波形がなだらかになる。出力電流値を増やすとその逆だ。

R1 と R2 の抵抗を 5Kオームにしておいて実験した。
I2C の出力電流値を 4mA にしてみたが、(標準値は 12mA)I2C の設定は通らなくなった。
I2C の出力電流値を 16mA にしてみた。こちらのほうが 12mA よりも少し良いようだったが、やはり、失敗するときがある。

やはり、I2C のプルアップ抵抗を変更してもだめなので、秋月電子のI2C リピーターIC の PCA9515AD を使ってカメラ・モジュールのインターフェース基板を作ってみようと思う。

追加
I2Cのプルアップ抵抗が 10KΩの時だが、I2Cのクロック周波数を変更してI2C の設定が通るかどうか?やってみた。(15 cmのコードを付けた状態)
100KHz が通常なので、75KHzにしてもダメ、50KHz もダメ、25KHz もダメ、10KHz もダメだった。
それでは、ということで、200KHz にしてみたがやはりだめだった。

2016/10/27:追加
I2Cのプルアップ抵抗をマニュアルにある 1.5 KΩに近くしてみたが、やはり 15 cm のコードを通すとダメだった。カメラ・インターフェース基板直付けはOK。
  1. 2016年10月26日 05:24 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:2

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加4(RGB2HSV)

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加3(SDK2)”の続き。

Vivado 2016.2 からVivado 2016.3 へアップグレード”でVivado 2016.3 にアップグレードできた。
今回は、HSV2RGB変換をARMプロセッサで動作するソフトウェアとして実装して結果を確認し、次にHSV2RGB変換時にS = V = 255 としてH を変換して結果を確認した。

SDK の画面を示す。
rgb2hsv_37_161026.png

cam_disp_lgh.elf を起動した結果を示す。元のカメラ画像だ。
rgb2hsv_34_161026.jpg

次に、HSV2RGB変換をARMプロセッサで動作するソフトウェア rgf2hsv_rev.c を実行した結果を示す。
rgb2hsv_35_161026.jpg

原画像との間に差は分からない。

HSV2RGB変換時にS = V = 255 としてH を変換するソフトウェア rgb2hsv_ho.c を実行した結果を示す。
rgb2hsv_36_161026.jpg

オレンジ色のブロアーも光が当たって白くなってしまったところは色が変わってしまうので注意が必要のようだ。

rgb2hsv_rev.c を貼っておく。

/* * rgb2hsv_rev.c * *  Created on: 2016/10/24 *      Author: Masaaki */
// ソフトウェアでHSV2RGB変換を行う

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

#include "xgabor_filter_lh.h"
#include "xdmaw4gabor.h"

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

#define FRAME_BUFFER_ADDRESS 0x10000000
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

int main(){
    XGabor_filter_lh gabf;
    XDmaw4gabor xdma4g;

    XRgb2hsv_Initialize(&gabf, 0);
    XRgb2hsv_Start(&gabf);
    XRgb2hsv_EnableAutoRestart(&gabf);

    int i, j;
    int max, min;
    int h, s, v;
    int r, g, b;
    volatile int *fb_hsv, *fb_rgb;

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

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

    // DMAW4Gabor Address set
    XDmaw4gabor_Initialize(&xdma4g, 0);
    XDmaw4gabor_Set_frame_buffer0(&xdma4g, FRAME_BUFFER_ADDRESS);
    XDmaw4gabor_Set_frame_buffer1(&xdma4g, FRAME_BUFFER_ADDRESS);

    // Bitmap display Controller Address set
    volatile int *bmdc0_axi_lites;
    volatile int *bmdc1_axi_lites;

    bmdc0_axi_lites = (volatile int *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    bmdc1_axi_lites = (volatile int *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_1_BASEADDR;

    bmdc0_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS+ALL_DISP_ADDRESS); // Bitmap Display Controller 0 start
    bmdc1_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS+ALL_DISP_ADDRESS); // Bitmap Display Controller 1 start
    //bmdc0_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS); // Bitmap Display Controller 0 start
    //bmdc1_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS); // Bitmap Display Controller 1 start

    fb_hsv = (volatile int *)FRAME_BUFFER_ADDRESS;
    fb_rgb = (volatile int *)((unsigned int)FRAME_BUFFER_ADDRESS+(unsigned int)ALL_DISP_ADDRESS);

    while(1){
        for(j=0; j<VERTICAL_LINES; j++){
            for(i=0; i<HORIZONTAL_PIXELS; i++){
                h = (fb_hsv[HORIZONTAL_PIXELS*j+i]/65536) & 0x1ff;
                s = (fb_hsv[HORIZONTAL_PIXELS*j+i]/256) & 0xff;
                v = fb_hsv[HORIZONTAL_PIXELS*j+i] & 0xff;

                max = v;
                min = max - (int)(((float)s/255.0)*(float)max + 0.5); // 0.5は四捨五入

                if(h>=0 && h<60){
                    r = max;
                    g = (int)(((float)h/60.0)*(float)(max-min)+0.5) + min;
                    b = min;
                }else if(h>=60 && h<120){
                    r = (int)(((120.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
                    g = max;
                    b = min;
                }else if(h>=120 && h<180){
                    r = min;
                    g = max;
                    b = (int)((((float)h-120.0)/60.0)*((float)(max-min))+0.5) + min;
                }else if(h>=180 && h<240){
                    r = min;
                    g = (int)(((240.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
                    b = max;
                }else if(h>=240 && h<300){
                    r = (int)((((float)h-240.0)/60.0)*((float)(max-min))+0.5) + min;
                    g = min;
                    b = max;
                }else{// if(h<=300 && h<=360){
                    r = max;
                    g = min;
                    b = (int)(((360.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
                }
                fb_rgb[HORIZONTAL_PIXELS*j+i] = (r&0xff)*65536 | (g&0xff)*256 | b&0xff;
            }
        }
        Xil_DCacheFlush();
        sleep(1);
    }

    return 0;
}


rgb2hsv_ho.c を貼っておく。

/* * rgb2hsv_ho.c * *  Created on: 2016/10/24 *      Author: ono */
// ソフトウェアでHSV2RGB変換するのだが、S=V=255として変換する。Hだけを変換。

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

#include "xgabor_filter_lh.h"
#include "xdmaw4gabor.h"

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

#define FRAME_BUFFER_ADDRESS 0x10000000
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

int main(){
    XGabor_filter_lh gabf;
    XDmaw4gabor xdma4g;

    XRgb2hsv_Initialize(&gabf, 0);
    XRgb2hsv_Start(&gabf);
    XRgb2hsv_EnableAutoRestart(&gabf);

    int i, j;
    int max, min;
    int h, s, v;
    int r, g, b;
    volatile int *fb_hsv, *fb_rgb;

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

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

    // DMAW4Gabor Address set
    XDmaw4gabor_Initialize(&xdma4g, 0);
    XDmaw4gabor_Set_frame_buffer0(&xdma4g, FRAME_BUFFER_ADDRESS);
    XDmaw4gabor_Set_frame_buffer1(&xdma4g, FRAME_BUFFER_ADDRESS);

    // Bitmap display Controller Address set
    volatile int *bmdc0_axi_lites;
    volatile int *bmdc1_axi_lites;

    bmdc0_axi_lites = (volatile int *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    bmdc1_axi_lites = (volatile int *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_1_BASEADDR;

    bmdc0_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS+ALL_DISP_ADDRESS); // Bitmap Display Controller 0 start
    bmdc1_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS+ALL_DISP_ADDRESS); // Bitmap Display Controller 1 start
    //bmdc0_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS); // Bitmap Display Controller 0 start
    //bmdc1_axi_lites[0] = (unsigned int)(FRAME_BUFFER_ADDRESS); // Bitmap Display Controller 1 start

    fb_hsv = (volatile int *)FRAME_BUFFER_ADDRESS;
    fb_rgb = (volatile int *)((unsigned int)FRAME_BUFFER_ADDRESS+(unsigned int)ALL_DISP_ADDRESS);

    while(1){
        for(j=0; j<VERTICAL_LINES; j++){
            for(i=0; i<HORIZONTAL_PIXELS; i++){
                h = (fb_hsv[HORIZONTAL_PIXELS*j+i]/65536) & 0x1ff;

                max = 255;
                min = 0;

                if(h>=0 && h<60){
                    r = max;
                    g = (int)(((float)h/60.0)*(float)(max-min)+0.5) + min;
                    b = min;
                }else if(h>=60 && h<120){
                    r = (int)(((120.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
                    g = max;
                    b = min;
                }else if(h>=120 && h<180){
                    r = min;
                    g = max;
                    b = (int)((((float)h-120.0)/60.0)*((float)(max-min))+0.5) + min;
                }else if(h>=180 && h<240){
                    r = min;
                    g = (int)(((240.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
                    b = max;
                }else if(h>=240 && h<300){
                    r = (int)((((float)h-240.0)/60.0)*((float)(max-min))+0.5) + min;
                    g = min;
                    b = max;
                }else{// if(h<=300 && h<=360){
                    r = max;
                    g = min;
                    b = (int)(((360.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
                }
                fb_rgb[HORIZONTAL_PIXELS*j+i] = (r&0xff)*65536 | (g&0xff)*256 | b&0xff;
            }
        }
        Xil_DCacheFlush();
        sleep(1);
    }

    return 0;
}

  1. 2016年10月26日 04:57 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Vivado 2016.2 からVivado 2016.3 へアップグレード

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加3(SDK2)”でVivado 2016.3 への乗り換えはあきらめたはずだったが、ツィッターで複数に人に新規作成してアップグレードすることを勧められたのもあって、プロジェクトを新規作成してVivado 2016.3 へアップグレードすることにした。道のりは結構長かったです。。。

ブロックデザインを新規作成するととっても面倒なので、ブロックデザインを作成するTCLスクリプトを出力して、ブロックデザインを自動生成してもらおう。

最初に、Vivado 2016.2 のZYBO_0_162_6 フォルダのプロジェクトを開き、ブロックデザインを開いた。

File メニュー -> Export -> Export Block Design... を選択した。
vivado_2016_3_35_161024.png

Export Block Design ダイアログ。ZYBO_0.tcl という名前で出力される。
vivado_2016_3_36_161024.png

Vivado 2016.3 で ZYBO_0_163_6 プロジェクトを新規作成した。
vivado_2016_3_37_161024.png

先ほど出力したZYBO_0.tcl をZYBO_0_163_6 フォルダにコピー&ペーストした。
vivado_2016_3_38_161024.png

ZYBO_0.tcl を開いて、「set scripts_vivado_version 2016.2」を「set scripts_vivado_version 2016.3」に変更して、セーブした。
vivado_2016_3_39_161024.png

Vivado 2016.2 のZYBO_0_162_6 フォルダのIP フォルダをすべてZYBO_0_163_6 フォルダにコピーした。
vivado_2016_3_40_161024.png

IP Catalog を開いて、Add Repository を行った。先ほどコピー&ペーストしたIP をすべて選択した。
vivado_2016_3_41_161024.png

IP Catalog にすべてのIP が登録できた。
vivado_2016_3_42_161024.png

Tcl Console を開いて、ZYBO_0_163_6 フォルダに cd し、

source ZYBO_0.tcl

を起動した。
vivado_2016_3_43_161024.png

ZYBO_0 ブロックデザインが完成した。
vivado_2016_3_44_161024.png

Refresh IP Catalog をクリックした。
IP Status が表示された。すべてUpgrade できているのかな?
vivado_2016_3_45_161024.png

ZYBO_0 ブロックデザインのHDL Wapper を生成した。
vivado_2016_3_46_161024.png

ZYBO_0.xdc を新規作成して、ZYBO_0_162_6 フォルダのプロジェクトのXDC ファイルの中身をコピー&ペーストした。
vivado_2016_3_47_161024.png

論理合成、インプリメント、ビットストリームの生成を行った。
論理合成は、multiple block runs が最初に走って、各IP ごとに論理合成しているようだ。後で、AXI_IIC IP を更新して論理合成すると、そのIP だけを合成しているようだった。更新時の論理合成時間の短縮が図れているようだった。
vivado_2016_3_48_161024.png

インプリメントでエラー発生。LUT が足りないと言われている。どこかで見たエラーだ。
vivado_2016_3_49_161024.png

Utilization を見てみるとやはりAXI Interconnect のLUT 占有率が大きい。
vivado_2016_3_50_161024.png

Vivado 2016.2 のプロジェクトをVivado 2016.3 にアップグレードすると動作しなかった2(解決編)”と同様に、AXI Interconnect を削除して、もう一度、Run Connection Automation でAXI Interconnect を入れなおすとインプリメントが通った。ビットストリームの生成も行った。結果を示す。
vivado_2016_3_51_161024.png

ハードウェアをエクスポートして、SDK を立ち上げ、cam_disp_lgh アプリケーション・プロジェクトを新規作成した。

cam_disp_lgh.c を作成した。

ZYBO にビットストリームをダウンロードして、cam_disp_lgh.elf を起動したところ、カメラ画像が表示された。
vivado_2016_3_52_161024.png

長かったが、やっとVivado 2016.3 に移行できた。
IP を更新したときの論理合成が速くなっているようなので、やはりVivado 2016.3 を使いたい。でもバグがたくさんあるものとして注意深く使うことにしよう。

最後に、cam_disp_lgh.c を貼っておく。

/* * cam_disp_lgh.c * *  Created on: 2016/10/22 *      Author: Masaaki */

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

#include "xdmaw4gabor.h"

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

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

#define FRAME_BUFFER_ADDRESS 0x10000000
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES)

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XDmaw4gabor xdma4g;

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

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

    XDmaw4gabor_Initialize(&xdma4g, 0);
    XDmaw4gabor_Set_frame_buffer0(&xdma4g, FRAME_BUFFER_ADDRESS);
    XDmaw4gabor_Set_frame_buffer1(&xdma4g, FRAME_BUFFER_ADDRESS);
    XDmaw4gabor_Start(&xdma4g);
    XDmaw4gabor_EnableAutoRestart(&xdma4g);

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

    bmdc0_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    bmdc1_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_1_BASEADDR;
    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;

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

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

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

    mt9d111_axi_lites[1] = 0// One_shot_mode is disabled

    return(0);
}

  1. 2016年10月25日 04:30 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加3(SDK2)

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加2(SDK)”の続き。

前回はRGB2HSV IP のドライバがSDKのハードウエア プラットフォームに入っていなかった。今回はRGB2HSV IP のドライバをSDKのハードウエア プラットフォームに入れてみることにした。

まずは、RGB2HSV IP のドライバをSDKのハードウエア プラットフォームにドラック・アンド・ドロップした。
rgb2hsv_23_161023.jpg

File and Folder Operation ダイアログが表示された。
rgb2hsv_24_161023.jpg

RGB2HSV IP のドライバのフォルダがあると言っているので、No をクリックした。
rgb2hsv_25_161023.jpg

SDK に戻ってみるとRGB2HSV IP のドライバがすでに入っていることになっていた。どうして?
rgb2hsv_26_161023.jpg

これでも rgb2hsv.c がコンパイルエラーなので、ドライバのソースを rgb2hsv プロジェクトの src フォルダに入れてみた。
rgb2hsv_27_161023.jpg

File Operation ダイアログが表示された。
rgb2hsv_28_161023.jpg

rgb2hsv_sint.c の XPAR_XRGB2HSV_NUM_INSTANCES が無い様だ。
rgb2hsv_29_161023.jpg

xparameters.h を見ると、XPAR_XRGB2HSV_NUM_INSTANCES がない。これではエラーになってしまう。
rgb2hsv_30_161023.jpg

rgb2hsv_bsp を Re-generate してもxparameter.h に変化はない。つまり、ハードウエア プラットフォームがおかしいのだろう?
どうしようもないな。。。

ということで、Vivado 2016.2 に戻ることにした。
Vivado 2016.2 でRGB2HSV IP を追加した。
rgb2hsv_32_161024.png

SDK の rgb2hsv_bsp の xparameters.h には、XPAR_XRGB2HSV_NUM_INSTANCES の define があった。
rgb2hsv_33_161024.png

rgb2hsv.c のコンパイルも問題なく通って、画像が表示された。
rgb2hsv_31_161024.jpg

とってもサイケデリックな絵になっている。
これは、HSV の画像を無理やり、RGBの画像として表示しているからだ。

仕方がないので、今度からはVivado HLS は2016.3 を使って、Vivado は 2016.2 を使うことにしようと思う。

Vivado 2016.2 からVivado 2016.3 へアップグレード”でVivado 2016.3 へ移行することができました。
  1. 2016年10月25日 03:50 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加2(SDK)

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加1”の続き。

前回はVivado 2016.3 のバグに悩みながらもRGB2HSV IP をZYBO_0_163_6 フォルダのプロジェクトに追加して、論理合成、インプリメント、ビットストリームの生成を行うことができた。
今回は、SDKを起動してアプリケーション・ソフトウェアを作成して、RGB2HSV IP を使ってみよう。

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

まずは、カメラ画像を表示するためのcam_disp_lgh アプリケーション・プロジェクトを作成して、cam_disp_lgh.c を作成した。
FPGAにビットストリームをダウンロードしてから、cam_disp_lgh アプリケーションを起動するとカメラ画像が表示された。
rgb2hsv_18_161023.jpg

次に、ラプラシアンフィルタを通した画像を表示するための lap_fil_on アプリケーション・プロジェクトを作成して、lap_fil_on.c を作成した。lap_fil_on アプリケーションを起動するとラプラシアンフィルタを通した画像が表示された。
rgb2hsv_19_161023.jpg

ガボール・フィルタを通した画像を表示するための gabor_disp アプリケーション・プロジェクトを作成して、gabor_disp.c を作成した。lgabor_disp アプリケーションを起動するガボール・フィルタ左白線用を通した画像が表示された。
rgb2hsv_20_161023.jpg

ガボール・フィルタ右白線用画像を表示するための gabor_right アプリケーション・プロジェクトを作成して、gabor_right.c を作成した。lgabor_right アプリケーションを起動するガボール・フィルタ右白線用を通した画像が表示された。
rgb2hsv_21_161023.jpg

本命のRGB2HSV を通した画像を表示するために rgb2hsv アプリケーション・プロジェクトを作成して、rgb2hsv.c を作成したら、エラーになってしまった。よく見ると rgb2hsv のドライバが入っていない。
rgb2hsv_22_161023.jpg

Vivado 2016.3 バグが多いな。。。困ったもんだ。
  1. 2016年10月23日 05:36 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Vivadoを使用してZYBO_0_163_6フォルダのプロジェクトにRGB2HSV IPを追加1

Vivado HLS でRGB2HSV IPを作る5(性能とリソース使用量)”の続き。

前回は、RGB2HSVの合成結果について考察した。今回は、Vivado HLS 2016.3 で 800 x 600 ピクセルの解像度に切り替えて、RGB2HSV をC コードから合成してから、IP 化を行う。そのRGB2HSV IP をZYBO_0_163_6 フォルダのVivado 2016.3 プロジェクトに追加する。

まずは、Vivado HLS 2016.3 で 800 x 600 ピクセルの解像度に切り替えて、RGB2HSV をC コードから合成してから、IP 化を行った。
(注: rgb2hsv() のブロックレベルのインターフェースをAXI4-Lite に対応させるために

#pragma HLS INTERFACE s_axilite port=return

の指示子を追加した)
vivado_2016_3_33_161019.png

camera_interface モジュールのaxis_switch_1 と axis_switch_0 のAXI4-Stream ポートを1つ追加して、RGB2HSV IP を追加した。
vivado_2016_3_27_161019.png

ブロックデザイン全体を示す。
vivado_2016_3_26_161019.png

Address Editorを示す。
vivado_2016_3_28_161019.png

論理合成、インプリメント、ビットストリームの生成を行ったところ、タイミングエラーが発生してしまった。
Open Implemented Design を開いて、タイミングエラーを詳しく見た。
clk_fpga_0 の Setup が -3.942 ns になっている。
vivado_2016_3_29_161019.png

最初のPath 1 をダブルクリックした。
Path 1 の詳しいタイミングレポートが表示された。
vivado_2016_3_30_161019.png

それを見ると axis_switch_0 に関するパスが多い。

FPGA チップ上のグラフィカルなクリティカルパスの図を示す。
vivado_2016_3_31_161019.png

このタイミングエラーの対策は、axis_switch_0 をダブルクリックして、Pipeline Resisters -> Enable input pipeline register をYes にすれば良いはずだが、以前にやったような気がする。”Zybot で Gabor filter を使うためのZYBO_0_5 プロジェクト1”で行ったはずなのだが、また、Vivado 2016.2 から Vivado 2016.3 へのアップグレードでなくなってしまったのか?
ZYBO_0_162_5 フォルダのVivado 2016.2 のプロジェクトを開くとPipeline Resisters -> Enable input pipeline register をYes になっていた。やはり、Vivado 2016.2 から Vivado 2016.3 へのアップグレードでなくなってしまったようだ。
やはり、Vivado 2016.2 から Vivado 2016.3 へのアップグレードはとっても怪しい。。。
もう1度やってみたが、アップグレード時ではなかったようだ。分かった。
axis_switch_0のスレーブ・インターフェース数を変えると Enable input pipeline register がNo に戻ってしまう。

もう一度、camera_interface モジュールのaxis_switch_0 をダブルクリックして、Pipeline Resisters -> Enable input pipeline register をYes にした。
vivado_2016_3_32_161019.png

もう一度、論理合成、インプリメント、ビットストリームの生成を行った。タイミングエラーは無くなった。
vivado_2016_3_34_161021.png

とりあえず、RGB2HSV IP をZybot のプロジェクトに追加したが、RGB2HSV IP に切り替えると画像は見られないので、どうしようか?と思っている。
ARM プロセッサで、HSV2RGB 変換して、画像を見るか?それともハードウエアをもう少し変更してカメラ画像も見られるようにするか?
まずは、ARM プロセッサでHSV2RGB 変換してみようかな?
  1. 2016年10月21日 04:56 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Vivado 2016.2 のプロジェクトをVivado 2016.3 にアップグレードすると動作しなかった2(解決編)

Vivado 2016.2 のプロジェクトをVivado 2016.3 にアップグレードすると動作しなかった”の続き。

前回は、ZYBO_0_5 プロジェクトをVivado 2016.2 からVivado 2016.3 にアップグレードすると、回路が動作しなかった。今回は原因を追究してみた。

まずは、論理合成後の使用率を比べてみた。
Vivado 2016.3 の論理合成後の使用率を示す。
vivado_2016_3_14_161019.png

LUT、LUTRAM と FF の使用率が高い。

次に、Vivado 2016.2 の論理合成後の使用率を示す。
vivado_2016_3_15_161019.png

hiyuh さんのアドバイスで各IP ごとの使用率を見た。
Open Synthesized Design をクリックして、Report Utilization をクリックした。
上の図がVivado 2016.3 、下の図がVivado 2016.2 のReport Utilization を示している。
vivado_2016_3_16_161019.png
vivado_2016_3_17_161019.png

AXI Interconnect の prcessing_system7_0_axi_periph の使用率が全く違う。Vivado 2016.3 では、Silce LUTsは8057、Slice Resisters は11112 だが、Vivado 2016.2 では、Silce LUTsは910、Slice Resisters は743 だ。違いすぎる。

そこで、prcessing_system7_0_axi_periph をダブルクリックしてMinimize Area にしてみたが、Silce LUTs が 6000 程度にしかならなかった。
vivado_2016_3_18_161019.png

次に、 prcessing_system7_0_axi_periph をいったん削除して、Run Connection Automation をクリックして、もう一度、インスタンスすることにした。下の図は、削除したところだ。
vivado_2016_3_19_161019.png

Run Connection Automation ダイアログで、All Automation にチェックを入れて、すべてのAXI4 Lite インターフェースを接続した。
vivado_2016_3_20_161019.png

ブロックデザインの完成図。prcessing_system7_0_axi_periph は名前が ps7_0_axi_periph になった。
vivado_2016_3_21_161019.png

論理合成後の使用率は正常に戻ったようだ。それでも多少、Vivado 2016.2 よりも使用率が大きい。
vivado_2016_3_22_161019.png

AXI Interconnect の ps7_0_axi_periph の使用率も正常に戻った。
vivado_2016_3_23_161019.png

インプリメント、ビットストリームの生成を行った。正常に終了した。使用率も正常だ。
vivado_2016_3_24_161019.png

ハードウェアをエクスポートして、SDK を立ちあがた。
ハードウエア・プラットフォームが新しく生成されたので、古いハードウエア・プラットフォームとアプリケーション・プロジェクトを削除して、cam_disp_axis プロジェクトを新規作成した。
vivado_2016_3_25_161019.png

ZYBO にビットストリームをダウンロードして、アプリを起動すると、待望のカメラ画像がディスプレイに表示された。
やっと、うまく行った。

今回のAXI Interconnect は、Master ポートが14 で、Slave ポートが 1 の大きいものだったので、アップグレードしたときにおかしくなったのかもしれない?
ポート数が少ないものはうまく行っていた。いずれにせよ。アップグレード・ツールのバグなんじゃないか?と思う。
  1. 2016年10月20日 04:56 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS でRGB2HSV IPを作る5(性能とリソース使用量)

Vivado HLS でRGB2HSV IPを作る4(C ソースコード)”の続き。

今回は、”Vivado HLS でRGB2HSV IPを作る4(C ソースコード)”で C コードの合成を行って、性能とリソース使用量を考える。

まずは、”Vivado HLS でRGB2HSV IPを作る4(C ソースコード)”の rgb2hsv() を 合成した。
結果を示す。
rgb2hsv_16_161019.png

640 * 480 ピクセルの画像を使用している。よって、640 * 480 = 307200 なので、ほぼ 1 クロックで 1 ピクセルを処理できている。

Vivado HLS でRGB2HSV IPを作る1(UNROLL指示子による性能向上)”にも書いた通り(C ソースコードは間違っているが)、「#pragma HLS UNROLL factor=2」を使って、タイミングエラーを解消はできたが、リソースは2倍程度になってしまった。

ここで、そのリソース使用量の 33 % を受け入れてしまうこともできるが、もう一度立ち止まって仕様を考えてみよう。
RGB2HSV IP はカメラの画像出力ののAXI4-Stream と メモリへのAXI4-Stream to AXI4 Master Write の間に入れる。カメラ画像出力は800 x 600 なので、ピクセルは40MHz の動作クロックで処理される。これは、25 ns となる。しかも、カメラのフレームレートは 15 fps なので、25 ns の1/4 のスピードで処理できれば良いということだ。
つまり、100 MHz の動作周波数はRGB2HSVに必要ないので、設定する周波数を落とすことができる。
つまり、Target を 25 ns にして、「#pragma HLS UNROLL factor=2」を外して合成してみた。
結果を示す。
rgb2hsv_17_161019.png

ここで、Latency は 6144006 になった。
6144006 / (640 * 480) ≒ 20 なので、1ピクセル処理するのに20クロック必要だ。これでは、使用に耐えないが、Vivado HLSで作ると簡単にパラメータを変えられるとことが良いと思う。
  1. 2016年10月19日 04:33 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado 2016.2 のプロジェクトをVivado 2016.3 にアップグレードすると動作しなかった

Vivado 2016.2 で作ってある
Zybot で Gabor filter を使うためのZYBO_0_5 プロジェクト1
Zybot で Gabor filter を使うためのZYBO_0_5 プロジェクト2
のプロジェクトをフォルダごと丸ごとコピーして、ペーストし、フォルダの名前を ZYBO_0_162_5 から ZYBO_0_163_5 に変更した。

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

ZYBO_0_163_5 のフォルダのVivado のプロジェクト・ファイルをVivado 2016.3 で開いて、IP をアップグレードした。IP のアドレスも同一だった。
Vivado 2016.2 のAddress Editor を示す。
vivado_2016_3_11_161018.png

Vivado 2016.3 のAddress Editor を示す。
vivado_2016_3_10_161017.png

Vivado 2016.3 で論理合成、インプリメント、ビットストリームの生成を行った。
ハードウェアをエクスポートして、SDK を起動した。
ハードウェアプラットフォームが新規作成されていたので、cam_disp3_axis アプリケーション・プロジェクトを作り直した。
ビットストリームをダウンロードして、ソフトウェアをRun したが動作しなかった。
ZYBO の電源をOFFして、もう一度、ビットストリームをダウンロードして、ソフトウェアをDebug Run したが、やはり動かない。
どうやら、ビットマップ・ディスプレイ・コントローラ 0 のレジスタに値を書き込むところでエラーになっているようだ。
vivado_2016_3_9_161017.png

もう一度、Vivado 2016.2 のSDKを立ち上げて、ビットストリームをダウンロードして、ソフトウェアをRun したら、問題なく動作してカメラ画像をVGA 出力で見ることができている。
vivado_2016_3_12_161018.png

なんででしょう?
もっと他のプロジェクトをアップグレードして、動作するかどうか?を見る必要があるだろう?
Vivado 2016.3 で新規にプロジェクトを作ってみて、動作するかを見る必要もあるだろう?
  1. 2016年10月18日 04:35 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.3 での変更点

Vivado HLS 2016.3 の私が気が付いた主な変更点を書いておこうと思う。

最初の変更点は”Vivado 2016.3が出ました”でも書いたが、ARMプロセッサ・シングルコアのxc7z014s, xc7z007s などがFPGAのラインナップとして加わったことだ。

次の変更点は、Dataflow viewer が Analysis に追加されたことだ。
FASTX コーナー検出の改良2(threshold をソフトウェアで変更可能にする)”のVivado HLS 2016.3 プロジェクトで説明する。
このプロジェクトでC コードの合成を行い、Analysis 画面に変更した。
Module Hierarchy ウインドのimage_filter にマークが変更になっていた。image_filter を右クリックすると、Open Schedule Viewer と Open Dataflow Viewer が選べるようになっている。
vivado_2016_3_2_161017.png

Open Schedule Viewer を選ぶと、今までのAnalysis 画面だった。
Open Dataflow Viewer を選ぶと、新しいDataflow View が開いた。
vivado_2016_3_3_161017.png
vivado_2016_3_4_161017.png

さらに、青い矢印にカーソルをフォーカスすると、そのモジュールのポート情報が表示された。
vivado_2016_3_5_161017.png


3番目は、IP 化のExports RTL だ。
Export RTL ボタンをクリックした後のExport RTL ダイアログに”Vivado synthesis” と”Vivado synthesis, place and route”のチェックボックスが増えている。
まずは、”Vivado synthesis”にチェックを入れたときの結果を示す。
vivado_2016_3_7_161017.png

論理合成後のタイミングレポートが追加になっている。Vivado synthesis を行って、タイミングを検証しているようだ。

次に、”Vivado synthesis, place and route”をチェックして、Export RTL を実行した。
vivado_2016_3_8_161017.png

論理合成後のタイミングレポートと配置配線後のタイミングレポートが追加されていた。

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

「ハドソン川の奇跡(映画)」を見てきました

ハドソン川の奇跡(映画)」を見てきました。この映画も面白かったんですが、シンゴジラ、君の名は、聲の形が良すぎました。
  1. 2016年10月16日 20:57 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS でRGB2HSV IPを作る4(C ソースコード)

Vivado HLS でRGB2HSV IPを作る3(H の表現方法)”の続き。

今回は現在のC ソースコードを貼っておこうと思う。

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

// rgb2hsv.h
// 2016/10/06 by marsee
//

#ifndef __RGB2HSV_H__
#define __RGB2HSV_H__

//#define HORIZONTAL_PIXEL_WIDTH    800
//#define VERTICAL_PIXEL_WIDTH    600

#define HORIZONTAL_PIXEL_WIDTH    640
#define VERTICAL_PIXEL_WIDTH    480

//#define HORIZONTAL_PIXEL_WIDTH    64
//#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#endif


次に、rgb2hsv.cpp を貼っておく。

// rgb2hsv.cpp
// 2016/10/06 by marsee
//

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

#include "rgb2hsv.h"

#define MAG 8 // 小数点以下のビット幅

int rgb2hsv(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE axis port=ins
    ap_axis<32,1,1,1> pix;
    int r, g, b;
    int h, s, v;
    int max, min;
    int hsv;

    do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> pix;
    }while(pix.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 UNROLL factor=2
#pragma HLS PIPELINE II=1
            if(!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            b = pix.data & 0xff;
            g = (pix.data>>8) & 0xff;
            r = (pix.data>>16) & 0xff;

            // h と max, min を求める
            if(r==g && g==b && r==b){
                max = r; // 8倍
                min = r;
            }else if(r>=g && r>=b){ // r が最大
                max = r;
                if(g>=b)
                    min = b;
                else
                    min = g;
            }else if(g>=r && g>=b){ // g が最大
                max = g;
                if(r>=b)
                    min = b;
                else
                    min = r;
            }else// b が最大
                max = b;
                if(r>=g)
                    min = g;
                else
                    min = r;
            }
            if(max-min == 0)
                h = 0;
            else if(max == r)
                h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
            else if(max == g)
                h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
            else // if(max == b)
                h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保

            if(h < 0)
                h += 360<<MAG;
            h += 1<<(MAG-1); // +0.5、四捨五入
            h >>= MAG; // 桁を戻す

            if(max == 0)
                s = 0;
            else
                s = (((max - min)<<MAG)/max) * 255// MAGビットシフトして精度を確保

            s += 1<<(MAG-1); // +0.5、四捨五入
            s >>= MAG; // 桁を戻す

            v = max;

            hsv = (h&0x1ff)*65536 + (s&0xff)*256 + (v&0xff);

            pix.data = hsv;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                pix.user = 1;
            else
                pix.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }

    return(0);
}


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

// rgb2hsv_tb.cpp
// 2016/10/09
//

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

#include "rgb2hsv.h"
#include "bmp_header.h"

#define BMP_FILE_NAME   "road_1.bmp"
#define SQUARE_ERROR_LIMIT    4 // 2乗誤差のエラー限界、この数以上はエラーとする

#define H    0
#define S    1
#define V    2

int rgb2hsv(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
int rgb2hsv_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, int *pixel_buf, int select_hsv);

int main(){
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins;
    hls::stream<ap_axis<32,1,1,1> > ins_soft;
    hls::stream<ap_axis<32,1,1,1> > outs;
    hls::stream<ap_axis<32,1,1,1> > outs_soft;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals;
    ap_axis<32,1,1,1> vals_soft;

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

    if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
        fprintf(stderr, "Can't open test.bmp by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

    // ピクセルを入れるメモリをアロケートする
    if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate rd_bmp memory\n");
        exit(1);
    }
    if ((hw_hsv =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_hsv memory\n");
        exit(1);
    }
    if ((sw_hsv =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate sw_hsv memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        pix.user = 0;
        pix.data = i;
        ins << pix;
        ins_soft << pix;
    }

    for(int j=0; j < bmpihr.biHeight; j++){
        for(int i=0; i < bmpihr.biWidth; i++){
            pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];

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

            if (i == bmpihr.biWidth-1// 行の最後でTLASTをアサートする
                pix.last = 1;
            else
                pix.last = 0;

            ins << pix;
            ins_soft << pix;
        }
    }

    rgb2hsv(ins, outs);
    rgb2hsv_soft(ins_soft, outs_soft);

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    for(int j=0; j < bmpihr.biHeight; j++){
        for(int i=0; i < bmpihr.biWidth; i++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_int<32> val = vals.data;
            ap_int<32> val_soft = vals_soft.data;

            hw_hsv[(j*bmpihr.biWidth)+i] = (int)val;
            sw_hsv[(j*bmpihr.biWidth)+i] = (int)val_soft;

            red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
            green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
            blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;

            if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > SQUARE_ERROR_LIMIT || // v の2乗誤差が4よりも大きい
                (double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > SQUARE_ERROR_LIMIT || // s の2乗誤差が4よりも大きい
                (double)pow((double)((val>>16)&0x1ff)-((val_soft>>16)&0x1ff),(double)2) > SQUARE_ERROR_LIMIT){ // h の2乗誤差が4よりも大きい
                printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
                    "HW_h = %d, HW_s = %d, HW_v = %d, SW_h = %d, SW_s = %d, SW_v = %d\n",
                    i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
                    (int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
                //return(1);
            }
            //if (vals.last)
                //cout << "AXI-Stream is end" << endl;
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    if ((fbmpw=fopen("h_hw.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open h_hw.bmp by binary write mode\n");
        exit(1);
    }
    WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, H);

    if ((fbmpw=fopen("s_hw.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open s_hw.bmp by binary write mode\n");
        exit(1);
    }
    WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, S);

    if ((fbmpw=fopen("v_hw.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open v_hw.bmp by binary write mode\n");
        exit(1);
    }
    WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, V);

    if ((fbmpw=fopen("h_sw.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open h_sw.bmp by binary write mode\n");
        exit(1);
    }
    WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, H);

    if ((fbmpw=fopen("s_sw.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open s_sw.bmp by binary write mode\n");
        exit(1);
    }
    WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, S);

    if ((fbmpw=fopen("v_sw.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open v_sw.bmp by binary write mode\n");
        exit(1);
    }
    WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, V);

    free(rd_bmp);
    free(hw_hsv);
    free(sw_hsv);


}

int rgb2hsv_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
    ap_axis<32,1,1,1> pix;
    int r, g, b;
    float h, s;
    int v;
    int max, min;
    int hsv;

    do{
        ins >> pix;
    }while(pix.user == 0);

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

            b = pix.data & 0xff;
            g = (pix.data>>8) & 0xff;
            r = (pix.data>>16) & 0xff;

            // h と max, min を求める
            if(r==g && g==b && r==b){
                max = r;
                min = r;
            }else if(r>=g && r>=b){
                max = r;
                if(g>=b)
                    min = b;
                else
                    min = g;
            }else if(g>=r && g>=b){
                max = g;
                if(r>=b)
                    min = b;
                else
                    min = r;
            }else// b が最大
                max = b;
                if(r>=g)
                    min = g;
                else
                    min = r;
            }
            if(max-min == 0)
                h = 0.0;
            else if(max == r)
                h = 60.0 * ((float)(g-b)/(float)(max-min));
            else if(max == g)
                h = 60.0 * ((float)(b-r)/(float)(max-min)) + 120.0;
            else // if(max == b)
                h = 60.0 * ((float)(r-g)/(float)(max-min)) + 240.0;

            if(h < 0)
                h += 360.0;

            if(max == 0)
                s = 0.0;
            else
                s = (float)(max - min)/(float)max * 255.0;

            v = max;

            hsv = (((int)(h+0.5))&0x1ff)*65536 + (((int)(s+0.5))&0xff)*256 + (v&0xff); // h と s は四捨五入

            pix.data = hsv;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                pix.user = 1;
            else
                pix.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }

    return(0);
}

// SV のうちの1つをblue, green, redの値として同じ値をBMPファイルに書く
// H は S,V の値を255とした時の H の値に対する RGB の値を計算する
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, int *pixel_buf, int select_hsv){
    int h;
    int sv;
    int r, g, b;

    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
    fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
    // RGB データの書き込み、逆順にする
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            switch(select_hsv){
            case H:
                h = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0x1ff;
                if(h>=0 && h<60){
                    r = 255;
                    g = (int)(((float)h/60.0)*255.0+0.5);
                    b = 0;
                }else if(h>=60 && h<120){
                    r = (int)(((120.0-(float)h)/60.0)*255+0.5);
                    g = 255;
                    b = 0;
                }else if(h>=120 && h<180){
                    r = 0;
                    g = 255;
                    b = (int)((((float)h-120.0)/60.0)*255+0.5);
                }else if(h>=180 && h<240){
                    r = 0;
                    g = (int)(((240.0-(float)h)/60.0)*255+0.5);
                    b = 255;
                }else if(h>=240 && h<300){
                    r = (int)((((float)h-240.0)/60.0)*255+0.5);
                    g = 0;
                    b = 255;
                }else// h>=300 && h<=360
                    r = 255;
                    g = 0;
                    b = (int)(((360.0-(float)h)/60.0)*255+0.5);
                }
                break;
            case S:
                sv = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
                break;
            default// case V:
                sv = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
                break;
            }

            if(select_hsv==S || select_hsv==V){
                fputc(sv, fbmpw);
                fputc(sv, fbmpw);
                fputc(sv, fbmpw);
            }else{
                fputc(b, fbmpw);
                fputc(g, fbmpw);
                fputc(r, fbmpw);
            }
        }
    }
    fclose(fbmpw);
}

  1. 2016年10月16日 06:12 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS でRGB2HSV IPを作る3(H の表現方法)

Vivado HLS でRGB2HSV IPを作る2(Cシミュレーション)”の続き。

前回のH(色相)の画像は、 360 までの値を 255 までにスケールを変えて表示していたのだが、360 までということは円なので、0 も赤だが、360 も赤に戻る。これでは、360 までの値を 255 にスケールを変えて表示しても意味がないと思った。HSV2RGB 変換しても元の画像に戻るだけだ。そうだ、S = V = 255 としてH をHSV2RGB 変換すれば色がはっきり見えるはずではないか?ということで、やってみた。

参考にするWeb サイトは例によって”RGBとHSV・HSBの相互変換ツール”と変換計算式”を参考にさせて頂いた。

C のテストベンチのコードのHSV2RGB 変換の部分を示す。S = V = 255 のときは、MAX = 255, MIN = 0 となる。

    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            switch(select_hsv){
            case H:
                h = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0x1ff;
                if(h>=0 && h<60){
                    r = 255;
                    g = (int)(((float)h/60.0)*255.0+0.5);
                    b = 0;
                }else if(h>=60 && h<120){
                    r = (int)(((120.0-(float)h)/60.0)*255+0.5);
                    g = 255;
                    b = 0;
                }else if(h>=120 && h<180){
                    r = 0;
                    g = 255;
                    b = (int)((((float)h-120.0)/60.0)*255+0.5);
                }else if(h>=180 && h<240){
                    r = 0;
                    g = (int)(((240.0-(float)h)/60.0)*255+0.5);
                    b = 255;
                }else if(h>=240 && h<300){
                    r = (int)((((float)h-240.0)/60.0)*255+0.5);
                    g = 0;
                    b = 255;
                }else// h>=300 && h<=360
                    r = 255;
                    g = 0;
                    b = (int)(((360.0-(float)h)/60.0)*255+0.5);
                }
                break;
            case S:
                sv = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
                break;
            default// case V:
                sv = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
                break;
            }


これで、road_1.bmp を RGB2HSV 変換したときの H の画像のハードウェア、つまり固定小数点 8 桁で演算したときの h_hw.bmp と浮動小数点演算の h_sw.bmp を示す。
rgb2hsv_15_161016.png

サイケデリックな絵のようになった。ブロック単位になっているのは、JPEG圧縮のせいではないか?ということをツィッターで教えて頂いた。ありがとうございました。

原画像の道路の写真をもう一度見てみよう。
rgb2hsv_11_161014.jpg

道路は彩度が低く、色相も変化が激しいので、彩度や明度が低いときは色相を信じないほうがよさそうだ。

今まで、追跡マーカーを色相だけで追跡しようとしていたのだが、彩度や明度も考慮する必要がありそうだ。
  1. 2016年10月16日 06:00 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado 2016.3が出ました

Vivado 2016.3 が出ました。

不思議なことに2016/10/15 AM7:30 時点では、まだXilinx Japan のサイトには2016.3 は出ていなくて、www.xilinx.com のダウンロード・サイトにしかVivado 2016.3 ないことです。どうしてでしょう?日本はそう重要ではないということでしょうか?

中国のサイトにもVivado 2016.3 がありました。となると、そういうことかもしれません?

Vivado 2016.3 で何が一番変わったか?というと、と言ってもVivado HLS 2016.3 しかまだ触っていませんが。。。

私的には、プロジェクトを作るときのDevice Selection Dialog で、ARMプロセッサ・シングルコアのxc7z014s, xc7z007s がダイアログに現れるようになったことです。
vivado_2016_3_1_161015.png

Spartan-7 はダイアログになかったので、まだしばらくは出ないのだと思います。

これから、Vivado 2016.3 を使っていこうと思います。
リリース・ノートです。
Vivado Design Suite User Guide Release Notes, Installation, and Licensing
UG973 (v2016.3) October 5, 2016
  1. 2016年10月15日 07:46 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:2

Vivado HLS でRGB2HSV IPを作る2(Cシミュレーション)

Vivado HLS でRGB2HSV IPを作る1(UNROLL指示子による性能向上)”の続き。

前回はUNROLL指示子による性能向上が図れることを示したが、C ソースコードが間違っていた。現在は修正済みだ。
今回は、テストベンチを作成し、C シミュレーションを行った。

どんなテストベンチかというと、BMP画像を読み込んで、RGB2HSV 変換を行い、Hだけの強度の画像としてBMP画像にする。S と V も同様に強度のBMP画像を生成する。

ちなみに、H は色相(Hue)、S は彩度(Saturation)、V は明度(Value)だそうだ。(”RGBとHSV・HSBの相互変換ツールと変換計算式”参照)

rgb2hsv のVivado HLS プロジェクトを示す。
rgb2hsv_5_161014.png

C シミュレーションのレポートを示す。
rgb2hsv_6_161014.png

最初に下図の原画像を用いてRGB2HSV のC シミュレーションを行った。
rgb2hsv_7_161014.png

なお、固定小数点のハードウェア化関数とソフトウェアの浮動小数点数演算との2乗誤差を計測している。現在は 4 より大きいとエラーになるように設定されている。固定小数点の小数点のビット数は現在は 8 に設定されている。

それでは、H(色相)の画像を示す。左の画像が固定小数点のハードウェア化関数の画像で、右の画像がソフトウェアの浮動小数点数演算での画像だ。なお、H は 360 までの値だが、それを 255 までにスケールを変えて表示している。
rgb2hsv_8_161014.png

次に、S(彩度)の画像を示す。
rgb2hsv_9_161014.png

V(明度)の画像を示す。
rgb2hsv_10_161014.png

良さそうだ。

次に道路の写真 road_1.bmp をRGB2HSV 変換した結果を示す。

最初に原画像を示す。
rgb2hsv_11_161014.jpg

H(色相)の画像を示す。左の画像が固定小数点のハードウェア化関数の画像で、右の画像がソフトウェアの浮動小数点数演算での画像だ。
rgb2hsv_12_161014.jpg

次に、S(彩度)の画像を示す。
rgb2hsv_13_161014.jpg

V(明度)の画像を示す。
rgb2hsv_14_161014.jpg
  1. 2016年10月14日 04:59 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

PYNQボードのデバイス・ツリー(devicetree)

Vivado のIP インテグレータでのPS の設定をすることができたので、今度はデバイス・ツリーが分かればLinux でVivado のプロジェクトに追加したIP をLinux でUIO として使うことができる。
今回は、PYNQボードのデバイス・ツリーを探ってみた。

Device Tree についてのまとめ”によると、コンパイル済みのDTB からソースコードのDTS に逆アセンブル(逆コンパイル?)できるということだった。
早速、DTB から DTS に変換してみた。

PYNQボードのMicroSDカードにdevicetree.dtb が入っている。
PYNQ_49_161013.png

そのdevicetree.dtb をUbuntu のフォルダにコピーした。

dtc -I dtb -O dts -o pynq_org.dts devicetree.dtb で pynq_org.dts を作成した。
PYNQ_46_161013.png

pynq_org.dts が作成された。
PYNQ_47_161013.png

pynq_org.dts を開いてみた。
PYNQ_48_161013.png

これで、Linux 上でIP を使うためには、この pynq_org.dts にUIO のエントリを追加していけばよいはずだ。
pynq_org.dts にUIO のエントリはなかったので、PYNQではすべてのIP にドライバを作成してあるのかな?
  1. 2016年10月13日 04:51 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

PYNQボード用PSの設定方法

Vivado のブロックデザインでPS の設定はどうやるのか?というのが疑問だったので、調べてみた。

Digilent 社のPYNQ Z1のページにZynq Presetsがあるので、それをクリックして、pynq_revc.zip をダウンロードした。
PYNQ_36_161012.png

pynq_revC.tcl ファイルがpynq_revc.zip の中に凍結されていた。
PYNQ_37_161012.png

Vivado 2016.2 でpynq_test プロジェクトを作って、pynq_test ブロックデザインを作成して、zynq7 processing system をAdd IP した。
PYNQ_38_161012.png

processing_system7_0 をダブルクリックして開く。
PYNQ_39_161012.png

まだ、PYNQの設定は入っていない。Presets をクリックすると、メニューが出てくるので、Apply Configuration... を選択する。
PYNQ_40_161012.png

pynq_test.tcl を選択する。
PYNQ_41_161012.png

すると、PYNQの設定が入って、UART0, GPIO, SD0, ENET0, QUAD SPI などにチェックが入った。
PYNQ_42_161012.png

Peripheral I/O Pins をクリックして設定を見た。
PYNQ_43_161012.png

DDR Configuration も設定されていた。
PYNQ_44_161012.png

ブロックデザインのprocessing_system7_0 が更新された。
PYNQ_45_161012.png

これで、PYNQのPS を使うことができそうだ。
  1. 2016年10月12日 05:20 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:3

PYNQボード4(OpenCVをインストール)

PYNQボード3(Jupyter Notebook)”の続き。

前回は、PYNQボードのJupyter Notebook を試してみた。今回は、PYNQボードのLinux を確認して、OpenCVをインストールしてみた。

PYNQボードのLinux はUbuntu 15.10 だと起動メッセージに書いてあった。まずはどのような構成になっているかを確認してみることにした。方法は、Ubuntu14.04 のパソコンにPYNQ のMicroSD カードをマウントした。
PYNQ_20_161010.png

84 MB のボリュームと rootfs があった。

PYNQボードのLinux で sudo apt-get update を行った。
PYNQ_21_161010.png

次に、sudo apt-get upgrade を行った。この時点での、MicroSD カードの占有率は 37 %。
PYNQ_22_161010.png

sudo apt-get install nautilus で nautilus をインストールして、Xming を立ち上げてから、nautilus & で起動したら、うまく起動できた。
PYNQ_23_161010.png

gedit もインストールして起動した。
PYNQ_24_161010.png

PYNQボード、使えそうだ。

次からは、Vivado and zybo linux勉強会資料3 を参考に設定した。

最初に、タイムゾーンがUTC になっていたので、JST に変更した。ln -sf /usr/share/zoneinfo/Japan /etc/localtime
PYNQ_25_161010.png

次は、OpenCV 2.4.6.1 をインストールしよう。

OpenCV ディレクトリを作成した。
PYNQ_26_161010.png

opencv_pre_install.sh を作成した。
PYNQ_27_161010.png

./opencv_pre_install.sh を起動する。
PYNQ_28_161010.png

./opencv_pre_install.sh の実行後。
PYNQ_29_161010.png

wget ftp://ftp.jp.netbsd.org/pub/pkgsrc/distfiles/opencv-2.4.6.1.tar.gz で OpenCV 2.4.6.1 をダウンロードした。
PYNQ_30_161010.png

build ディレクトリを作成して、cmake を起動した。
PYNQ_31_161010.png

make
PYNQ_32_161010.png

sudo make install
sudo ldconfig

PYNQ_33_161010.png

df すると 75 % 使用していたので、make clean した。すると 55 % になった。
PYNQ_34_161010.png

サンプルをコンパイルした。
レナ像の顔認識がうまく行った。
./facedetect --cascade="/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml" --nested-cascade="/usr/local/share/OpenCV/haarcascades/haarcascade_eye.xml" --scale=1.3 lena.jpg
PYNQ_35_161010.jpg

  1. 2016年10月11日 05:47 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:3

PYNQボード3(Jupyter Notebook)

PYNQボード2(Linux の起動)”の続き。

前回はLinux を起動して、起動メッセージや、Webページ、Samba の様子を確認した。今回は、PYNQボードで起動しているWebアプリケーションのJupyter Notebook をやってみた。

まずは、PYNQのマニュアルの”Introduction to Jupyter Notebook”からやってみた。

まずは、Jupyter Notebook について、全く知らないので調べてみた。
Jupyter Notebook を使ってみよう”によると、

Jupyter Notebook (読み方は「ジュパイター・ノートブック」または「ジュピター・ノートブック」) とは、ノートブックと呼ばれる形式で作成したプログラムを実行し、実行結果を記録しながら、データの分析作業を進めるためのツールです。

だそうだ。つまり、記録しながら実行もできるよというツールなんだろう?

その他のジュピター・ノートブックの資料を示す。
Windows によさげなノート環境JupyterNotebook環境をつくる
Jupyter Notebookの拡張機能を使ってみる

次に、PYNQのマニュアルの”Introduction to Jupyter Notebook”の手順でジュピター・ノートブックを使ってみた。
PYNQ_13_161009.png

うまく行った。これは便利だ。

次に、”Cortex-A9 programming in Python”をやってみたが、これもうまくいった。

Video using the Base Overlay”をやってみた。これは、PYNQボードのHDMI IN から入れた画像をPython でキャプチャできるそうなので、ZYBO_0 からのカメラ画像を入れてみた。

ZYBO_0 をブートして、カメラ画像をHDMI OUT に出力する。
PYNQ_14_161009.png

Overlay("base.bit").download() でビットファイルがダウンロードできるようだ。これは便利だ。xdevcfg を使っているのだろうか?

Python コードを実行すると、

HDMI is capturing a video source of resolution 1024x768

と表示され、XGA 画像だと認識できている。
PYNQ_15_161009.png

HDMI IN に入力された画像がキャプチャできた。この画像は乱れているように見えるが、XGA画像フォーマットにSVGA の画像を載せているので、このような画像になって正常なのである。
PYNQ_16_161009.jpg

エリア内のGreen を 255 にするPython コードも正常に動作した。
PYNQ_17_161009.jpg

HDMI IN の画像をHDMI OUTに出力しようとしたが、出力できなかった。
PYNQ_18_161009.png

マニュアルによると、対応する解像度は、

Valid resolutions are:

0 : 640x480, 60Hz
1 : 800x600, 60Hz
2 : 1280x720, 60Hz
3 : 1280x1024, 60Hz
4 : 1920x1080, 60Hz

だそうだ。つまり、XGA解像度が無かった。。。
HDMI 入力はあるけど、HDMI 出力は無いようだ。

今までジュピター・ノートブックを試した記録は、test1_161009.ipynb としてセーブした。
  1. 2016年10月11日 05:07 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

「聲の形(映画)」を見てきました

今日は「聲の形(映画)」を見てきました。最初はつまらないかな?と思ってみていたのですが、だんだん良くなってきました。見終わった後は良かったという印象です。「君の名は」とはまた違った良さですね。
  1. 2016年10月10日 20:53 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

PYNQボード2(Linux の起動)

PYNQボード1”の続き。

前回はMicroSD カードに書くイメージをダウンロードした。今回はイメージをMicroSD カードに書いて、PYNQボードでLinux を起動してみよう。

pynq_z1_image_2016_09_14.img をImageWriter で8GB のMicroSD カードに書き込んだ。

PYNQボードにUSBケーブルとLANケーブルを接続した。今回はACアダプタを購入が間に合わなかったため、USBケーブルで電源を供給した。USB 3.0 に接続して、2A 用のUSBケーブルを使えば問題なかった。なお、2A 用のUSBケーブルは100円均一のお店で購入した。

現在のPYNQボードの接続とLED点灯の様子を示す。
PYNQ_12_161009.jpg

現在は9V 1.3AのACアダプタを使用している。

JP5をUSB に設定して、PYNQボードのスイッチON。
Tera Term を立ち上げ、115200 bps, 8bit, 1 Stopbit に設定すると、プロンプトが見えた。
ifconfig コマンドを入れると IP アドレスが見えた。
PYNQ_6_161008.png

DHCP でIP が取れているので、そのIP アドレスでアクセスすることにした。

DHCP のIP アドレス:9090 をブラウザで見ると、jupyter が起動していた。
パスワードに xilinx と入力すると入れた。
PYNQ_8_161008.png

jupyter 画面。
PYNQ_9_161008.png

Samba サーバーが上がっていて、Winodows 10 のエクスプローラのネットワークのPYNQ の xilinx フォルダにID xilinx, password xilinx で入ることができた。
PYNQ_10_161008.png

PYNQ の xilinx フォルダ。
PYNQ_11_161008.png

起動メッセージを貼っておく。

In:    serial@e0000000
Out:   serial@e0000000
Err:   serial@e0000000
Model: Zynq ARTY-Z Development Board
Board: Xilinx Zynq
Net:   ZYNQ GEM: e000b000, phyaddr 1, interface rgmii-id
SF: Detected S25FL128S_64K with page size 256 Bytes, erase size 64 KiB, total 16 MiB

Warning: ethernet@e000b000 using MAC address from ROM
eth0: ethernet@e000b000
Hit any key to stop autoboot:  0
Device: sdhci@e0100000
Manufacturer ID: 74
OEM: 4a60
Name: USD
Tran Speed: 50000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 7.5 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
reading uEnv.txt
** Unable to read file uEnv.txt **
Copying Linux from SD to RAM...
reading uImage
4506400 bytes read in 415 ms (10.4 MiB/s)
reading devicetree.dtb
8936 bytes read in 20 ms (435.5 KiB/s)
## Booting kernel from Legacy Image at 03000000 ...
   Image Name:   Linux-3.17.0-xilinx
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    4506336 Bytes = 4.3 MiB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 02a00000
   Booting using the fdt blob at 0x2a00000
   Loading Kernel Image ... OK
   Loading Device Tree to 1eb18000, end 1eb1d2e7 ... OK

Starting kernel ...

Booting Linux on physical CPU 0x0
Linux version 3.17.0-xilinx (hackwad@xcordevl1) (gcc version 4.9.2 (Sourcery CodeBench Lite 2015.05-17) ) #23 SMP PREEMPT Tue Aug 16 10:40:10 MDT 2016
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: xlnx,zynq-7000
cma: Reserved 128 MiB at 16800000
Memory policy: Data cache writealloc
PERCPU: Embedded 8 pages/cpu @5fb9e000 s8768 r8192 d15808 u32768
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
Kernel command line: console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1
PID hash table entries: 2048 (order: 1, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 379048K/524288K available (6184K kernel code, 363K rwdata, 2228K rodata, 208K init, 255K bss, 145240K reserved, 0K highmem)
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xffc00000 - 0xffe00000   (2048 kB)
    vmalloc : 0x60800000 - 0xff000000   (2536 MB)
    lowmem  : 0x40000000 - 0x60000000   ( 512 MB)
    pkmap   : 0x3fe00000 - 0x40000000   (   2 MB)
    modules : 0x3f000000 - 0x3fe00000   (  14 MB)
      .text : 0x40008000 - 0x4083f31c   (8413 kB)
      .init : 0x40840000 - 0x40874240   ( 209 kB)
      .data : 0x40876000 - 0x408d0ea0   ( 364 kB)
       .bss : 0x408d0ea0 - 0x40910c78   ( 256 kB)
Preemptible hierarchical RCU implementation.
        Dump stacks of tasks blocking RCU-preempt GP.
        RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
NR_IRQS:16 nr_irqs:16 16
L2C: platform provided aux values match the hardware, so have no effect.  Please remove them.
L2C-310 erratum 769419 enabled
L2C-310 enabling early BRESP for Cortex-A9
L2C-310 full line of zeros enabled for Cortex-A9
L2C-310 ID prefetch enabled, offset 1 lines
L2C-310 dynamic clock gating enabled, standby mode enabled
L2C-310 cache controller enabled, 8 ways, 512 kB
L2C-310: CACHE_ID 0x410000c8, AUX_CTRL 0x76360001
slcr mapped to 60804000
zynq_clock_init: clkc starts at 60804100
Zynq clock init
sched_clock: 64 bits at 325MHz, resolution 3ns, wraps every 3383112499200ns
timer #0 at 60806000, irq=43
Console: colour dummy device 80x30
Calibrating delay loop... 1292.69 BogoMIPS (lpj=6463488)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
CPU: Testing write buffer coherency: ok
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x5de6d8 - 0x5de730
CPU1: Booted secondary processor
CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
Brought up 2 CPUs
SMP: Total of 2 processors activated.
CPU: All CPU(s) started in SVC mode.
devtmpfs: initialized
VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
regulator-dummy: no parameters
NET: Registered protocol family 16
DMA: preallocated 256 KiB pool for atomic coherent allocations
cpuidle: using governor ladder
cpuidle: using governor menu
hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
hw-breakpoint: maximum watchpoint size is 4 bytes.
zynq-ocm f800c000.ocmc: ZYNQ OCM pool: 256 KiB @ 0x60880000
VCCPINT: 1000 mV
vgaarb: loaded
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
media: Linux media interface: v0.10
Linux video capture interface: v2.00
pps_core: LinuxPPS API ver. 1 registered
pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
PTP clock support registered
EDAC MC: Ver: 3.0.0
Advanced Linux Sound Architecture Driver Initialized.
cfg80211: Calling CRDA to update world regulatory domain
Switched to clocksource arm_global_timer
NET: Registered protocol family 2
TCP established hash table entries: 4096 (order: 2, 16384 bytes)
TCP bind hash table entries: 4096 (order: 3, 32768 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP: reno registered
UDP hash table entries: 256 (order: 1, 8192 bytes)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available
futex hash table entries: 512 (order: 3, 32768 bytes)
jffs2: version 2.2. (NAND) (SUMMARY)  c 2001-2006 Red Hat, Inc.
msgmni has been set to 996
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
dma-pl330 f8003000.dmac: Loaded driver for PL330 DMAC-2364208
dma-pl330 f8003000.dmac:        DBUFF-128x8bytes Num_Chans-8 Num_Peri-4 Num_Events-16
e0000000.serial: ttyPS0 at MMIO 0xe0000000 (irq = 59, base_baud = 6250000) is a xuartps
console [ttyPS0] enabled
xdevcfg f8007000.devcfg: ioremap 0xf8007000 to 6086a000
[drm] Initialized drm 1.1.0 20060810
brd: module loaded
loop: module loaded
CAN device driver interface
libphy: MACB_mii_bus: probed
macb e000b000.ethernet eth0: Cadence GEM at 0xe000b000 irq 54 (00:18:3e:02:48:48)
macb e000b000.ethernet eth0: attached PHY driver [Generic PHY] (mii_bus:phy_addr=e000b000.etherne:00, irq=-1)
e1000e: Intel(R) PRO/1000 Network Driver - 2.3.2-k
e1000e: Copyright(c) 1999 - 2014 Intel Corporation.
ipw2100: Intel(R) PRO/Wireless 2100 Network Driver, git-1.2.2
ipw2100: Copyright(c) 2003-2006 Intel Corporation
libipw: 802.11 data/management/control stack, git-1.1.13
libipw: Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>
Atmel at76x USB Wireless LAN Driver 0.17 loading
usbcore: registered new interface driver at76c50x-usb
Broadcom 43xx driver loaded [ Features: PNLS ]
Broadcom 43xx-legacy driver loaded [ Features: PLID ]
usbcore: registered new interface driver rtl8187
usbcore: registered new interface driver rtl8192cu
usbcore: registered new interface driver rndis_wlan
usbcore: registered new interface driver lbtf_usb
Intel(R) Wireless WiFi driver for Linux, in-tree:
Copyright(c) 2003- 2014 Intel Corporation
iwl4965: Intel(R) Wireless WiFi 4965 driver for Linux, in-tree:
iwl4965: Copyright(c) 2003-2011 Intel Corporation
iwl3945: Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux, in-tree:s
iwl3945: Copyright(c) 2003-2011 Intel Corporation
usbcore: registered new interface driver brcmfmac
usbcore: registered new interface driver asix
usbcore: registered new interface driver ax88179_178a
usbcore: registered new interface driver cdc_ether
usbcore: registered new interface driver net1080
usbcore: registered new interface driver rndis_host
usbcore: registered new interface driver cdc_subset
usbcore: registered new interface driver zaurus
usbcore: registered new interface driver cdc_ncm
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
ehci-pci: EHCI PCI platform driver
ULPI transceiver vendor/product ID 0x0451/0x1507
Found TI TUSB1210 ULPI transceiver.
ULPI integrity check: passed.
zynq-ehci zynq-ehci.0: Xilinx Zynq USB EHCI Host Controller
zynq-ehci zynq-ehci.0: new USB bus registered, assigned bus number 1
zynq-ehci zynq-ehci.0: irq 53, io mem 0x00000000
zynq-ehci zynq-ehci.0: USB 2.0 started, EHCI 1.00
usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: Xilinx Zynq USB EHCI Host Controller
usb usb1: Manufacturer: Linux 3.17.0-xilinx ehci_hcd
usb usb1: SerialNumber: zynq-ehci.0
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver usb-storage
mousedev: PS/2 mouse device common for all mice
i2c /dev entries driver
cdns-i2c e0004000.i2c: 400 kHz mmio e0004000 irq 57
cdns-wdt f8005000.watchdog: Xilinx Watchdog Timer at 60874000 with timeout 10s
Xilinx Zynq CpuIdle Driver started
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
sdhci-pltfm: SDHCI platform and OF driver helper
sdhci-arasan e0100000.sdhci: No vmmc regulator found
sdhci-arasan e0100000.sdhci: No vqmmc regulator found
mmc0: SDHCI controller on e0100000.sdhci [e0100000.sdhci] using ADMA
ledtrig-cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
xlnk driver initializing
xlnk major 245
xlnk driver loaded
xlnk_pdev is not null
TCP: cubic registered
NET: Registered protocol family 17
can: controller area network core (rev 20120528 abi 9)
NET: Registered protocol family 29
can: raw protocol (rev 20120528)
can: broadcast manager protocol (rev 20120528 t)
can: netlink gateway (rev 20130117) max_hops=1
lib80211: common routines for IEEE802.11 drivers
zynq_pm_ioremap: no compatible node found for 'xlnx,zynq-ddrc-1.0'
zynq_pm_late_init: Unable to map DDRC IO memory.
Registering SWP/SWPB emulation handler
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
ALSA device list:
mmc0: new high speed SDHC card at address 59b4
mmcblk0: mmc0:59b4 USD   7.51 GiB
 mmcblk0: p1 p2
  No soundcards found.
EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext4 filesystem) on device 179:2.
devtmpfs: mounted
Freeing unused kernel memory: 208K (40840000 - 40874000)
!ョX.]Y[イォLWFailed to insert module 'kdbus': Function not implementedted
   ?K袁ムオェノケスオコ・ム。・ムヘz*ケムノスチ・
                             ?・ア        ア5systemd[1]: systemd 225 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTS。ョ^.]Y[イォLWDetected architecture arm.ECCOMP +BLKID -ELFUTILS +KMOD -IDN)
Welcome to Ubuntu 15.10!

systemd-sysv-generator[733]: Overwriting existing symlink /run/systemd/generator。ョ^.]Y[イォLWdisplay-manager.service: Cannot add dependency job, ignoring: Unit di[  OK  ] Started Dispatch Password Requests to Console Directory Watch.h.
[  OK  ] Reached target Encrypted Volumes.es.
[  OK  ] Reached target Remote File Systems (Pre).e).
[  OK  ] Created slice Root Slice.e.
[  OK  ] Listening on Journal Socket.et.
[  OK  ] Created slice User and Session Slice.ce.
[  OK  ] Listening on /dev/initctl Compatibility Named Pipe.pe.
[  OK  ] Created slice System Slice.ce.
[  OK  ] Created slice system-getty.slice.ce.
         Starting Remount Root and Kernel File Systems......
         Starting Nameserver information manager......
[  OK  ] Created slice system-serial\x2dgetty.slice.ce.
[  OK  ] Reached target Slices.es.
         Starting Increase datagram queue length......
[  OK  ] Listening on udev Control Socket.et.
[  OK  ] Listening on udev Kernel Socket.et.
systemd[1]: Starting Create list of required static device nodes for the current         Starting Create list of required st... nodes for the current kernel...
[  OK  ] Listening on Journal Socket (/dev/log).g).
         Starting Load Kernel Modules......
[  OK  ] Started Forward Password Requests to Wall Directory Watch.ch.
         Starting udev Coldplug all Devices......
[  OK  ] Started Remount Root and Kernel File Systems.ms.
[  OK  ] Started Increase datagram queue length.th.
systemd[1]: Started Create list of required static device nodes for the current [  OK  ] Started Create list of required sta...ce nodes for the current kernel.
[  OK  ] Started Load Kernel Modules.es.
[  OK  ] Started Nameserver information manager.er.
[  OK  ] Started udev Coldplug all Devices.es.
         Starting Apply Kernel Variables......
         Starting Create Static Device Nodes in /dev......
[  OK  ] Listening on Syslog Socket.
         Starting Journal Service...
         Starting Load/Save Random Seed...
         Activating swap /var/swap...
[  OK  ] Started Apply Kernel Variables.
[  OK  ] Started Create Static Device Nodes in /dev.
[  OK  ] Started Load/Save Random Seed.
[  OK  ] Started Journal Service.
         Starting Flush Journal to Persistent Storage...
         Starting udev Kernel Device Manager...
[  OK  ] Reached target Local File Systems (Pre).
[  OK  ] Reached target Local File Systems.
[  OK  ] Reached target Remote File Systems.
         Starting Wait for all "auto" /etc/n... up for network-online.target...
         Starting LSB: Raise network interfaces....
[  OK  ] Activated swap /var/swap.
[  OK  ] Started udev Kernel Device Manager.
[  OK  ] Started Flush Journal to Persistent Storage.
         Starting Create Volatile Files and Directories...
[  OK  ] Reached target Swap.
[  OK  ] Started Create Volatile Files and Directories.
         Starting Update UTMP about System Boot/Shutdown...
[  OK  ] Reached target System Time Synchronized.
[  OK  ] Started Update UTMP about System Boot/Shutdown.
[  OK  ] Found device /dev/ttyPS0.
[  OK  ] Started Wait for all "auto" /etc/ne...be up for network-online.target.
[  OK  ] Stopped LSB: Start NTP daemon.
[  OK  ] Started LSB: Raise network interfaces..
[  OK  ] Reached target Network.
[  OK  ] Reached target Network is Online.
[  OK  ] Reached target System Initialization.
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Reached target Sockets.
[  OK  ] Started Trigger resolvconf update for networkd DNS.
[  OK  ] Reached target Paths.
[  OK  ] Reached target Basic System.
         Starting Login Service...
         Starting LSB: start Samba NetBIOS nameserver (nmbd)...
         Starting Permit User Sessions...
         Starting LSB: start Samba daemons for the AD DC...
         Starting LSB: Load kernel modules needed to enable cpufreq scaling...
         Starting LSB: starts/stops the 2ping listener...
[  OK  ] Started Regular background program processing daemon.
         Starting /etc/rc.local Compatibility...
[  OK  ] Started OpenBSD Secure Shell server.
         Starting Enable support for additional executable binary formats...
[  OK  ] Started D-Bus System Message Bus.
         Starting System Logging Service...
[  OK  ] Started Daily Cleanup of Temporary Directories.
[  OK  ] Reached target Timers.
[  OK  ] Started Permit User Sessions.
[  OK  ] Started LSB: starts/stops the 2ping listener.
[  OK  ] Started Enable support for additional executable binary formats.
[  OK  ] Started System Logging Service.
[  OK  ] Started Login Service.
[  OK  ] Started LSB: Load kernel modules needed to enable cpufreq scaling.
[  OK  ] Created slice user-0.slice.
[  OK  ] Started Session c1 of user root.
         Starting User Manager for UID 0...
         Starting LSB: set CPUFreq kernel parameters...
         Starting LSB: Start NTP daemon...
[  OK  ] Started LSB: set CPUFreq kernel parameters.
[  OK  ] Started User Manager for UID 0.
[  OK  ] Started LSB: Start NTP daemon.
rc.local[1503]: /root/2_jupyter_server.sh: Jupyter server started
rc.local[1503]: /root/3_pl_server.sh: Programmable Logic server started
[  OK  ] Started /etc/rc.local Compatibility.
[  OK  ] Started Getty on tty1.
[  OK  ] Started Serial Getty on ttyPS0.
[  OK  ] Reached target Login Prompts.
         Stopping LSB: Start NTP daemon...
[  OK  ] Stopped LSB: Start NTP daemon.
         Starting LSB: Start NTP daemon...
[  OK  ] Started LSB: Start NTP daemon.
         Starting LSB: start Samba SMB/CIFS daemon (smbd)...
         Stopping LSB: Start NTP daemon...
[  OK  ] Stopped LSB: Start NTP daemon.
         Starting LSB: Start NTP daemon...
[  OK  ] Started LSB: Start NTP daemon.
[  OK  ] Started LSB: start Samba daemons for the AD DC.

Ubuntu 15.10 pynq ttyPS0

pynq login: xilinx (automatic login)

Last login: Thu Jan  1 00:00:13 UTC 1970 on ttyPS0
xilinx@pynq:~$


  1. 2016年10月09日 03:47 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

PYNQボード1

昨日、PYNQボードが手に入りました。

箱です。
PYNQ_1_161008.jpg

中を開けると、ピンク色の保護材が入っています。
PYNQ_2_161008.jpg

保護材をとると、基板のパーツの形に保護材を切り抜いてありました。
PYNQ_3_161008.jpg

PYNQボードが出てきました。
PYNQ_4_161008.jpg

本当にピンク色です。

まずは、Micro SD カードにイメージを書く必要があります。

Setup マニュアルを見て、pynq_z1_image_2016_09_14.zip をダウンロードしました。
PYNQ_5_161008.png
  1. 2016年10月08日 04:39 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS でRGB2HSV IPを作る1(UNROLL指示子による性能向上)

Vivado HLS 2016.2 で、RGB2HSV IP を作ろうと思う。

Vivado HLS で rgb2hsv プロジェクトを作成した。
rgb2hsv_1_161007.png

まずは、rgb2hsv.cpp を作成して、C コードの合成を行った。
なお、内側の for ループには、「#pragma HLS PIPELINE II=1」を書いてある。
rgb2hsv_2_161007.png

その結果は、Estimated が 15.52 ns でTarget を満たしていない。Latency も 5760002 で 1 ピクセルに 12 クロックかかっている。
C コードの合成の途中でのレポートを示す。遅延を積算していくと、15.5 ns になるようだ。

WARNING: [SCHED 204-21] Estimated clock period (15.5ns) exceeds the target (target clock period: 10ns, clock uncertainty: 1.25ns, effective delay budget: 8.75ns).
WARNING: [SCHED 204-21] The critical path consists of the following:
    multiplexor before 'phi' operation ('pix.data.V') with incoming values : ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:23) ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:30) ('hsv', rgb2hsv/rgb2hsv.cpp:79) (1.57 ns)
    'phi' operation ('pix.data.V') with incoming values : ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:23) ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:30) ('hsv', rgb2hsv/rgb2hsv.cpp:79) (0 ns)
    'partselect' operation ('min', rgb2hsv/rgb2hsv.cpp:34) (0 ns)
    'icmp' operation ('tmp_8', rgb2hsv/rgb2hsv.cpp:40) (2 ns)
    'or' operation ('or_cond2', rgb2hsv/rgb2hsv.cpp:40) (1.37 ns)
    'or' operation ('sel_tmp2_demorgan', rgb2hsv/rgb2hsv.cpp:37) (1.37 ns)
    'select' operation ('sel_tmp', rgb2hsv/rgb2hsv.cpp:37) (1.37 ns)
    'select' operation ('sel_tmp1', rgb2hsv/rgb2hsv.cpp:48) (1.37 ns)
    'select' operation ('min_5', rgb2hsv/rgb2hsv.cpp:37) (1.37 ns)
    'sub' operation ('tmp_10', rgb2hsv/rgb2hsv.cpp:68) (1.72 ns)
    'sdiv' operation ('tmp_11', rgb2hsv/rgb2hsv.cpp:68) (3.38 ns)


いろいろと指示子を試してみたが、なかなかうまく行かなかった。
昨日、UNROLL指示子の並列数を説明していたのを思い出して、内側の for ループを 2 並列にしてみた。そうすれば、遅延しても、2 クロックに1度データが出れば良いのではないだろうか?
使用する指示子は「#pragma HLS UNROLL factor=2」だ。factor=2 が 2 並列を表す。
rgb2hsv_3_161007.png

C コードの合成の結果を示す。
rgb2hsv_4_161007.png

Estimated は 8.47 ns で Target の範囲内で収まった。Latency も 1 ピクセルで 1 データを処理できる値だ。うまく行ったのではあるが、リソースは倍になってしまった。

rgb2hsv.h を貼っておく。

// rgb2hsv.h
// 2016/10/06 by marsee
//

#ifndef __RGB2HSV_H__
#define __RGB2HSV_H__

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600

//#define HORIZONTAL_PIXEL_WIDTH    64
//#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#endif


rgb2hsv.cpp を貼っておく。まだ、シミュレーションしていないので、正しいかどうか?はまだわからない。それに、小数点以下がない整数でとりあえず作ったので、固定小数点演算にする必要があるだろう。
2016/10/14 追記:このC ソースコードは間違っています。

// rgb2hsv.cpp
// 2016/10/06 by marsee
//

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

#include "rgb2hsv.h"

int rgb2hsv(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE axis port=ins
    ap_axis<32,1,1,1> pix;
    int r, g, b;
    int h, s, v;
    int max, min;
    int hsv;
    int offset;

#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
    {
        ins >> pix;
    }while(pix.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 UNROLL factor=2
#pragma HLS PIPELINE II=1
            if(!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            b = pix.data & 0xff;
            g = (pix.data>>8) & 0xff;
            r = (pix.data>>16) & 0xff;

            // h と max, min を求める
            if(r==g && g==b && r==b){
                max = r;
                min = r;
            }else if(r>=g && r>=b){
                max = r;
                if(g>=b)
                    min = b;
                else
                    min = g;

                offset = 0;
            }else if(g>=r && g>=b){
                max = g;
                if(r>=b)
                    min = b;
                else
                    min = r;

                offset = 120;
            }else// b が最大
                max = b;
                if(r>=g)
                    min = g;
                else
                    min = b;

                offset = 240;
            }
            if(max-min == 0)
                h = 0;
            else
                h = 60 * ((g-b)/(max-min)) + offset;
            if(h < 0)
                h += 360;

            if(max == 0)
                s = 0;
            else
                s = (max - min)/max * 255;

            v = max;

            hsv = (h&0xff)<<16 + (s&0xff)<<8 + (v&0xff);

            pix.data = hsv;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                pix.user = 1;
            else
                pix.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }

    return(0);
}

  1. 2016年10月08日 03:51 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Zybot で隊列走行をさせたい(妄想編)

Zybot をもう1台作成して隊列走行をさせてみたい。

Zybot の後ろにマーカーを置いておいて、そのマーカーを見ながら画像の真ん中に来るように走行制御すればよいのだろうか?
距離はとりあえず超音波距離センサをつけることにした。

マーカーは今のところ板にオレンジの四角か何かを書いておこうかな?と思っている。
オレンジは画像をHSV 変換して色相を見ようかな?

とりあえずVivado HLS でRGB - HSV 変換を作ってみようと思う。

RGBとHSV・HSBの相互変換ツールと変換計算式”あたりが参考になりそうだ。
  1. 2016年10月06日 05:27 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

Zybot で Gabor filter を使うためのZYBO_0_5 プロジェクト5(走行テスト)

Zybot で Gabor filter を使うためのZYBO_0_5 プロジェクト4(実機確認)”の続き。

今日はZybot で白線追従走行用ソフトウェアの wl_tracking_dmaw.c をコンパイルして、Zybot を走らせてみた。
前よりは追従性が上がったようだが、カーブ手前で曲がり始めてしまう気がした。反応が速くなったのは良いのだが、白線追従走行用ソフトウェアのチューニングは必要だ。
それとすぐに白線追従走行ができなくなって、どこかに行ってしまう時もある。それは、最初に真っ直ぐにコースの置かなかった時のようだ。カメラのレンズが望遠すぎるのも問題な気がする。広角用のレンズを探すか、もしくは、携帯用の広角アダプタが付けられないか?調べてみよう。
だが、今度は、左と右の白線検出用のガボール・フィルタをハードウェアで分けたので、判定制御間隔は確実に短くなっている。前の走行よりも細かく制御できているのが、よくわかった。
走行テストのうまく行った様子を示す。


wl_tracing_damw.c を貼っておく。

// wl_tracking_dmaw.cpp
// 2016/09/28 by marsee
//

#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 "xmotor_monitor.h"

#define DIR_LEFT_NORMAL        1
#define DIR_LEFT_REVERSE    0
#define DIR_RIGHT_NORMAL    0
#define DIR_RIGHT_REVERSE    1

#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 GABOR_DETECT_LINE        590
#define GABOR_DETECT_LINE_ADDR    (SVGA_HORIZONTAL_PIXELS * GABOR_DETECT_LINE * PIXEL_NUM_OF_BYTES)
#define GABOR_THRESHOLD            5
#define DIST_THRESHOLD            30

#define LEFT_GABOR_EDGE_OVERFLOW    0
#define RIGHT_GABOR_EDGE_OVERFLOW    (SVGA_HORIZONTAL_PIXELS/2)

#define DEBUG
//#define MOTOR_OFF

// Gobor filter
//
void gabor_fil_on(){
    int fd2, fd3, fd4;
    volatile unsigned *axis_switch_0, *axis_switch_1;
    volatile unsigned *gabor_filter_lh_0;
    int gabor_cntrl;

   // 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);
    }
    
    // gabor_filter_lh_0 (UIo14)
    fd4 = open("/dev/uio14", O_RDWR); // gabor_filter_lh_0 interface AXI4 Lite Slave
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio14 (gabor_filter_lh_0) open error\n");
        exit(-1);
    }
    gabor_filter_lh_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!gabor_filter_lh_0){
        fprintf(stderr, "lap_filter_axis_0 mmap error\n");
        exit(-1);
    }
      
    // axis_switch_1, 1to2 ,Select M01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x80000000// 0x40 = 0x80000000; disable
    axis_switch_1[17] = 0x80000000// 0x44 = 0x80000000; disable
    axis_switch_1[18] = 0// 0x48 = 0;
    axis_switch_1[0] = 0x2// 0x0 = 2; Commit registers
    
    // gabor filter AXIS Start
    gabor_filter_lh_0[0] = 0x01// Start bit set
    gabor_filter_lh_0[0] = 0x80// Auto Restart bit set
    
    // axis_switch_0, 2to1, Select S01_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x2// 0x40 = 0x2;
    axis_switch_0[0] = 0x2// 0x0 = 2; Commit registers

    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)gabor_filter_lh_0, 0x10000);
    
    close(fd2);
    close(fd3);
    close(fd4);   
}

int search_gabor_edge(unsigned int start_addr, unsigned int number, int threshold){
    volatile int *imgaddr, *endaddr;
    int i;
    
    imgaddr = (volatile int *)start_addr;
    
    for (i=0; i<number; i++){
        int c=imgaddr[i] & 0xff;
        //printf("%d\n",c);
        if (c >= threshold){
            break;
        }
    }
    return(i); 
}

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

void motor_initialize(XPwm &motorL, XPwm &motorR, XMotor_monitor &mmL, XMotor_monitor &mmR){
    XPwm *motorLp, *motorRp;
    XMotor_monitor *mmLp, *mmRp;
    
    motorLp = &motorL;
    motorRp = &motorR;
    mmLp = &mmL;
    mmRp = &mmR;
    
    // 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);
    }
    
    
    // Initialization of motor monitor
    if (XMotor_monitor_Initialize(mmLp, "motor_monitor_0") != XST_SUCCESS){
        fprintf(stderr,"motor_monitor_0 (Left) open error\n");
        exit(-1);
    }
    if (XMotor_monitor_Initialize(mmRp, "motor_monitor_1") != XST_SUCCESS){
        fprintf(stderr,"motor_monitor_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);
}

// DMAW4Gabor setting
volatile unsigned *dmaw4g_initialize(int &fd1){
    volatile unsigned *dmaw4gabor_0;

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

    return(dmaw4gabor_0);
}


int main(){
    int fd1;
    volatile unsigned *dmaw4gabor_0;
    XPwm motorL, motorR;
    XMotor_monitor mmL, mmR;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
      int left_wl_edge, right_wl_edge;

    // Gabor filter Initialize
    gabor_fil_on();

    // Motor Initialize
    motor_initialize(motorL, motorR, mmL, mmR);
    
    // DMAW4Gabor Initialize
    dmaw4gabor_0 = dmaw4g_initialize(fd1);

    // udmabuf0
    int fdf = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The cache is disabled. 
    if (fdf == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    volatile unsigned *frame_buffer = (volatile unsigned *)mmap(NULL, 3*SVGA_ALL_DISP_ADDRESS, PROT_READ|PROT_WRITE, MAP_SHARED, fdf, 0);
    if (!frame_buffer){
        fprintf(stderr, "frame_buffer mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf0
    int fdp = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fdp == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fdp, attr, 1024);
    sscanf((const char *)attr, "%lx", &phys_addr);  
    close(fdp);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);
    
    // DMA4Gabor frame_buffer1 setting
    dmaw4gabor_0[8] = (int)phys_addr + SVGA_ALL_DISP_ADDRESS; // Data signal of frame_buffer1

    // main loop
    printf("White line Tracking start. \n");
    while(1){
        // Gabor filter for left white line
        left_wl_edge = SVGA_HORIZONTAL_PIXELS/2 - search_gabor_edge(
            (unsigned int)frame_buffer+GABOR_DETECT_LINE_ADDR, SVGA_HORIZONTAL_PIXELS/2, GABOR_THRESHOLD);

        // Gabor filter for right white line
        right_wl_edge = search_gabor_edge(
            (unsigned int)frame_buffer+SVGA_ALL_DISP_ADDRESS+GABOR_DETECT_LINE_ADDR+(SVGA_HORIZONTAL_PIXELS/2)*PIXEL_NUM_OF_BYTES,
            SVGA_HORIZONTAL_PIXELS/2, GABOR_THRESHOLD);

#ifdef DEBUG
        printf("left_wl_edge = %d, right_wl_edge = %d\n", left_wl_edge, right_wl_edge);
#endif

        if (left_wl_edge == LEFT_GABOR_EDGE_OVERFLOW){
#ifndef MOTOR_OFF
            XPwm_Set_sw_late_V(&motorL, 5);
            XPwm_Set_sw_late_V(&motorR, 35);
#endif
#ifdef DEBUG
            printf("Left gabor edge is overflow\n");
#endif
        } else if (right_wl_edge == RIGHT_GABOR_EDGE_OVERFLOW){
#ifndef MOTOR_OFF
            XPwm_Set_sw_late_V(&motorL, 35);
            XPwm_Set_sw_late_V(&motorR, 5);
#endif
#ifdef DEBUG
            printf("Right gabar edge is overflow\n");
#endif
        } else if ((right_wl_edge - left_wl_edge) > DIST_THRESHOLD){
#ifndef MOTOR_OFF
            XPwm_Set_sw_late_V(&motorL, 25);
            XPwm_Set_sw_late_V(&motorR, 15);
#endif
#ifdef DEBUG
            printf("Right turn\n");
#endif
        } else if ((right_wl_edge - left_wl_edge) < -DIST_THRESHOLD){
#ifndef MOTOR_OFF
            XPwm_Set_sw_late_V(&motorL, 15);
            XPwm_Set_sw_late_V(&motorR, 25);
#endif
#ifdef DEBUG
            printf("Left turn\n");
#endif
        } else if (abs(right_wl_edge - left_wl_edge) <= DIST_THRESHOLD){
#ifndef MOTOR_OFF
            XPwm_Set_sw_late_V(&motorL, 20);
            XPwm_Set_sw_late_V(&motorR, 20);
#endif
#ifdef DEBUG
            printf("Go straight\n");
#endif
        }
    }
}

  1. 2016年10月05日 04:50 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0
»