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

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

FPGAの部屋

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

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