FC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンター (cache)FPGAの部屋 画像処理

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

FPGAの部屋

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

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路27(VIOで8ビットのデータを取得)

昨日、Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路をFPGA-CAFEに持って行って、デモしてきた。画質は悪いが、ある程度、評価はしてもらえたかと思う。更には、Make Tokyou Meeting 06でデモ出来れば?と思っている。

現在は、DE0用にSCCBインターフェース回路をVerilogに変換中だが、Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路でも、現在は4ビット品質の画像しかディスプレイに出力していないので、8ビットの品質を見るためにVIOでYUVのデータを取得して、BMPファイルに変換して、画質を見てみた。(”Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路22(ソフトでYUV-RGB変換)”参照)
前回のChipScopeのVIOを追加したプロジェクトを改造して、SCCBインターフェース回路を入れた。そして、tclのデータ収集スクリプトを動かして、YUVのデータを取得した。それを、YUV-RGB変換、BMPフォーマット変換ソフトにかけて、BMPファイルにした。そうしたところ、黒のところに緑が出てしまうことがあって、おかしかった。そういえば、前回も黒の縁に緑が出ていた。
CamDispCntrler_DDR2_pict_14_100903.jpg

前回のソフトウェアをよく見てみたところ、YUV-RGB変換のところで値がマイナスになった時のアンダーフロー対応と256よりも値が大きくなった時の飽和処理がなかった事に気がついた。これを修正したCコードを下に示す。

        for (j=0; j<4; j++){
            r_int = (Y[j]<<8) + V[j]*359 - 45952;
            g_int = (Y[j]<<8) - V[j]*183 - U[j]*88 + 34688;
            b_int = (Y[j]<<8) + U[j]*454 - 58112;
            if (r_int <0)
                red = 0;
            else if (((r_int)>>8)>=256)
                red = 0xff;
            else
                red = (r_int)>>8;

            if (g_int<0)
                green = 0;
            else if (((g_int)>>8)>=256)
                green = 0xff;
            else
                green = (g_int)>>8;

            if (b_int<0)
                blue = 0;
            else if (((b_int)>>8)>=256)
                blue = 0xff;
            else
                blue = (b_int)>>8;

            cam_red[(int)(i/640)][(int)((i%640)+j)] = red;
            cam_green[(int)(i/640)][(int)((i%640)+j)]  = green;
            cam_blue[(int)(i/640)][(int)((i%640)+j)] = blue;
        }


これで、再度、以前の取得画像をBMPファイルに変換した。
CamDispCntrler_DDR2_pict_22_100920.jpg

黒のエッジに入っている緑色は無くなった。やはりアンダーフローだったのではないか?と思う。
次に今回取得した画像をBMPファイルに変換した。
CamDispCntrler_DDR2_pict_23_100920.jpg

やはり色は綺麗に見えている。だが、右下のフローリングの模様がブロックノイズぽい。実際に画面に出力してみないとわからないと思う。やはり、DACかDVIトランスミッタのICを付けてみたい。。。

  1. 2010年09月20日 04:14 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:9

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路26(YUV-RGB変換も写った)

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路25(カラー画像が見えた)”ではRGB444フォーマットでCMOSカメラから出力されたデータをディスプレイに表示した。
以前からやっている、CMOSカメラからYUV422で出力されたデータをYUV-RGB変換回路を通して、ディスプレイに出力する回路をやってみた。LinuxのOV7670のドライバを参考にRGB444の設定部分をYUV422フォーマットの物に入れ替えた。そうして、インプリメントして表示してみると、今度はYUV422の方もディスプレイに表示することができた。良かった~。
でも、よく見ると、YUV422の方がRGB444よりもフレームごとに画素の値がすこし違っている感じがする。RGB444の方が画像がきれいだ。やはり、RGB444で行くことにする。
現在は4ビットだが、8ビットで表示するとどうなるんだろう?データをパソコンに送ることを考えると、データが8ビット長のモードを実験しておいたほうが良いと思う。

なお、DDR2 SDRAMはメモリがたくさんあるので、スライドスイッチの切り替えで8画面保存して置けるように回路を変更した。ディスプレイをみんなで見ながらキャプチャするのも楽しい。。。
  1. 2010年09月14日 05:44 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路25(カラー画像が見えた)

前回、RGB444モードにしたが、やはり、ピンクぽい色は解消されず、また色もあまり出ていないようだった。OV7670でいろいろ検索しているとLinuxのOV7670のドライバを発見した。(くりさんにもコメントで教えていただきました。ありがとうございました。)
ov7670.cのregval_list ov7670_default_regs[]を見たところ強烈に多い設定がされていた。こんなに設定する必要があるの!!!ということで、しょうがないので、がんばって、SCCBレジスタ設定用のデータファイル (SCCB_reg_values.data) に変換した。(全部で、128個のレジスタに値を書き込みました)
最初に全部くらい入れるとディスプレイ画面が真っ暗になってしまう。おかしいということで、1/2法で1/2ずつにしていって原因を特定した。そうしたら、PLLの設定がされているのが原因だということがわかった。input clockX4倍とかになっていたので、バイパスに設定した。これで画面が出るようになった。
今度は少しずつ戻していって、画面の色の様子を確かめた。途中で画像が青くなってしまった。なぜ~?と思って、いろいろなところを写してみたが、どうやら、青が赤と入れ替わっているようだった。そこで、VGA_Display_Controller でRとBのビットフィールドを入れ替えたら、ちゃんと色が出るようになった。やったー!!!うれしいです。苦労しただけに。。。下に画像を示す。
CamDispCntrler_DDR2_pict_18_100912.jpg

家のちらかっているリビングです。まあまあの色が出ていると思います。壁をみるとRGB各4ビットということがわかると思う。その他はまあまあの写りになっているのではないでしょうか?

しかし、まだ疑問が残る。。。OV7670のマニュアルでは、8ビット幅のデータ出力から、4ビットずつxR,GBと出てくるはずなのに、どうもxB,GRと出ているように見える。そこで、赤と青の物を写して、OV7670から出てくる信号がどう変化するかを、ChipScope Proで観測してみることにした。
まずは青いものとして、青い表紙のクリアファイルを写してみた。直接写すと、照明が写って白飛びする。ファイルの表紙が半透明なので、透過させて写すと良い感じになった。(下の写真)
CamDispCntrler_DDR2_pict_19_100912.jpg

これを、CMOSカメラのフレームの最初の部分にトリガをかけてChipScope Proで見た。それを下の図に示す。
CamDispCntrler_DDR2_46_100911.png

上の図でmaster_syncがCMOSカメラのフレームの最初の部分を示す同期信号だ。cam_href_2dが1の時にcam_data_2dに有効なデータが出ている。その8ビットデータは、cam_cont_afifo/dinで16ビットに変換されて、wr_enが1の時に有効な16ビットデータとなって非同期FIFOに書かれている。これを見ると、最初のcam_cont_afifo/dinの有効なデータは4943であるので、xRGB (各4ビット) とすれば、青いものを写しているのに、Rの方がBより値が大きくなっている。やはり、xBGRの順のようだ。やはり、データーシートが間違っているのか?
次に、VGA_Display_Controllerでも見てみた。これは、CMOSカメラで見た時と異なった時間の値を取っているので、値が異なる。
CamDispCntrler_DDR2_47_100911.png

h_v_is_zero_node が1の時にVGA_Display_Controllerのフレームがスタートする。(h_count, v_count = 0) rd_enが1の時にcamd_afifo_inst_doutに画像データが出てくる。最初のデータは3933だ。当然ながら、ここでもxBGRの順番になっているようだ。

次に青だけでは評価できないので、赤もやってみた。なかなか良いのが無かったが、赤っぽいクリアファイルがあったのでやってみた。下に写真を示す。
CamDispCntrler_DDR2_pict_20_100912.jpg

VGA_Display_Controllerで見た時のChipScope Proの波形を下に示す。
CamDispCntrler_DDR2_48_100911.png

最初のデータは7879となっていて、やはり、xBGRを示しているようだ。
ということで、やはり、データーシートがおかしいという結論になった。
応援していただいた皆様、twitterでもいろいろアドバスをいただいて、本当にありがとうございました。下に現在のSpartan3 Starter Kitの様子の写真を示す。
CamDispCntrler_DDR2_pict_21_100912.jpg

SCCBインターフェースへの配線は変換基板のヘッダから接続コードでSpartan3 Starter KitのTXヘッダに接続されている。SCCBインターフェースの動作周波数は100KHzなので、動作に問題はないようだ。

次は、YUV-RGB変換をもう一度試してみるのと、DDR2 SDRAMコントローラにOVLアサーションを入れてみたい。論理合成できるはずなので、それも試してみたい。
DE0に移植してみたい。SOPC Builderのマスタデバイスは、長船さんとかぶるので、次のFPGA技術がでた後の課題として残しておいて、自作のSDR SDRAMコントローラで試してみたい。VHDLでもシミュレーション、インプリメントができることが実証されたので、VHDLでも良いよね?(しまった。これはAlteraの話でしたね。AlteraもコンパイルはVHDL, Verilog混在環境で行けるのでしょうか?ModelSim AEは混在環境だめですよね?)
変換基板をCADで設計してみたいな。需要はあるのだろうか?

ともかく今日は、こんどこそ、ジブリ美術館に奥さんと娘と行ってきます。(8月に一度行こうとしたのだが、娘の具合が悪くなって、飯田橋駅で引き返してきた。。。)
  1. 2010年09月12日 04:38 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路24(RGB444モード)

いままで、デフォルトのYUVモードでYUV-RGB変換回路を通して、RGB4ビット分をSpartan-3A Starter KitのVGAポートから出力していた。今回は、SCCBインターフェース回路を付けて、CMOSカメラを制御できるようになった。そこで、CMOSカメラをRGB444モード(RGBが4ビットずつのデータとして出力されるモード)に設定して、そのRGBをそのままSpartan-3A Starter KitのVGAポートから出力することにした。
やってみた結果は、やはり、ピンクぽかった。おかしいのは、赤を見ると緑に見える。
CamDispCntrler_DDR2_pict_15_100910.jpg

いろいろその他の設定をしてみたが、あまり変化がなかった。ちなみに元の色はこんな色だ。
CamDispCntrler_DDR2_pict_16_100910.jpg

赤と緑を取り替えると、緑がかっているが、すこしはそれらしい色になる。少し色がおかしいが、これが一番まともだな?
CamDispCntrler_DDR2_pict_17_100910.jpg

どうしようかな?やはり、CMOSカメラがおかしいのだろうか?設定がおかしいとしても、BやRのゲインをいじったつもりでもあまり変化がない?AGCやAWB、AECを切ってみたのだが、やはり、あまり変化がないんだよな~???

aitendoのもう1つのカメラモジュール、カメラモジュール(OV9655)[CAMERA130W-OV9655]にしてみようかな?これだと、ピン配置が違うので、もう1度変換基板を作る必要があるな。。。それにモジュール回路図を見るとCMOSカメラのDVDDの1.8Vがどうなっているか書いていない!!! aitendoに問い合わせ中。

そういえばディスプレイがおかしいということはないかな?RGBはパソコンからつないで使ったことないし、DVIのみだしね。他にディスプレイで確かめてみようか?でも、白黒がうまく出ているから、おかしくないよな?白黒はRGB同じ値を入れているんだから、RGBどれかがおかしくても白黒にならないはず。。。
  1. 2010年09月10日 05:09 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:5

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路23(SCCBインタフェース回路)

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路22(ソフトでYUV-RGB変換)”でVIOで取り込んだデータをBMPファイルにしてみたが、やはり、色がおかしかった。そこで、CMOSカメラの設定を行うSCCBインタフェース回路を実装することになった。SCCBインタフェース回路は、”SCCBインタフェース回路の実装1(タイミングチャート)”からの実装で、もうすでに出来上がっている。これを使えばOKのはず。。。ということで実装しようとしたら、VHDLで書いてあるのだった。よしそれでは、Verilogに変換しようと思ったが、面倒だ。そうだ、もしかしてISimにすれば、以前混在シミュレーションもできた(”ISimでOVLのVHDL, Verilog混在シミュレーション(ISimでシミュレーション)”)ので、大丈夫なはず。。。
それにISEもVHDL, Verilog混在環境で行けたはずということで、やってみることにした。
Project NavigatorのDesignウインドウのHierarchyにNew Source...からSCCBインターフェース回路をプロジェクトに追加した。
CamDispCntrler_DDR2_42_100907.png

プロジェクトに入れることができた。これで論理合成、インプリメントをすると問題なく、パスした。
CamDispCntrler_DDR2_43_100907.png

FPGA Editorでコンポーネントがあるかどうか見てみたが問題ない様だった。下の図に、FPGA Editorのリストウインドウを示す。
CamDispCntrler_DDR2_44_100907.png

次は、ISimでシミュレーションしてみる。
  1. 2010年09月07日 05:40 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路22(ソフトでYUV-RGB変換)

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路21(VIO、tcl)”で取得したYUVの値を使って、ソフトウェアでRGBに変換し、BMPフォーマットに直して、パソコンで見てみた。
使った言語はCで、ツールはVisual Studio 2010だった。久しぶりに、しかも新しいバージョンのVisual Studio使ったので戸惑ってしまった。下図のように開発している。
CamDispCntrler_DDR2_40_100903.png

YUV-RGB変換式は下図のものを使用している。

red = (char)((int)(((Y[j]<<8) + V[j]*359 - 45952)>>8)&0xff);
green = (char)(((int)((Y[j]<<8) - V[j]*183 - U[j]*88 + 34688)>>8)&0xff);
blue = (char)((int)(((Y[j]<<8) + U[j]*454 - 58112)>>8)&0xff);


まだスタック関係でバグっているが、取り敢えずBMPファイルが出力できたので良しとする。(どこがバグっているか、わかったら教えてください)
CamDispCntrler_DDR2_41_100903.png

下にCのプログラムを示す。(追記:エラーが出ないように修正しました。武内さん、ありがとうございました

// Camera_Capture.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#pragma warning(disable:4996)

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

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
    char cam_file[100];
    char **cam_red, **cam_green, **cam_blue; // 640*480ピクセル
    BITMAPFILEHEADER bmpfh; // BMPファイルのファイルヘッダ
    BITMAPINFOHEADER bmpih; // BMPファイルのINFOヘッダ
    BMP24FORMAT **bmp_data; // 24ビットのBMPファイルのデータ 640*480
    FILE *fcam, *fbmp;
    int i, j, k;
    char temp_buf[100], temp_buf2[100];
    int U[4], V[4], Y[4];
    char *str;
    unsigned int UVY[8];
    char red, green, blue;

    // 引数の処理
    if (argc == 1) { // 引数なし
        strcpy_s(cam_file, "camera_capture_data.txt");
    } else if (argc == 2){ // 
        strcpy_s(cam_file, (const char *)argv[1]);
    } else {
        fprintf(stderr, "Camera2BMP <camera_capture_data.txt>\n");
        exit(1);
    }

    // メモリをアロケートする
    if ((cam_red =(char **)malloc(sizeof(char *) * 480)) == NULL){
        fprintf(stderr, "cam_redの1次元目480のメモリを確保できません\n");
        exit(1);
    }
    if ((cam_green =(char **)malloc(sizeof(char *) * 480)) == NULL){
        fprintf(stderr, "cam_greenの1次元目480のメモリを確保できません\n");
        exit(1);
    }
    if ((cam_blue =(char **)malloc(sizeof(char *) * 480)) == NULL){
        fprintf(stderr, "cam_blueの1次元目480のメモリを確保できません\n");
        exit(1);
    }
    for (i=0; i<480; i++){
        if ((cam_red[i]=(char *)malloc(sizeof(char) * 640)) == NULL){
            fprintf(stderr, "cam_redの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }
    for (i=0; i<480; i++){
        if ((cam_green[i]=(char *)malloc(sizeof(char) * 640)) == NULL){
            fprintf(stderr, "cam_greenの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }
    for (i=0; i<480; i++){
        if ((cam_blue[i]=(char *)malloc(sizeof(char) * 640)) == NULL){
            fprintf(stderr, "cam_blueの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }
    if ((bmp_data=(BMP24FORMAT **)malloc(sizeof(BMP24FORMAT *)*480)) == NULL){
        fprintf(stderr, "bmp_dataの1次元目の480のメモリを確保できません\n");
        exit(1);
    }
    for (i=0; i<480; i++){
        if ((bmp_data[i]=(BMP24FORMAT *)malloc(sizeof(BMP24FORMAT) * 640)) == NULL){
            fprintf(stderr, "bmp_dataの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }

    // cam_fileをtext readモードでオープン
    if ((fcam = fopen(cam_file, "rt")) == NULL) {
            fprintf(stderr, "Can't Open %s\n", cam_file);
            exit(1);
    }
    // cam_fileの読み込み
    for (i=0; i<307200; i=i+4){
        if ((k=fscanf(fcam,"%s\n", temp_buf)) == EOF){
            fprintf(stderr, "%s のデータが足りない。%d\n", cam_file, i);
            exit(1);
        } else if (k == 0){
            fprintf(stderr, "%s のデータフォーマットがエラー\n", cam_file);
            exit(1);
        }

        for (str=temp_buf, j=0; j<8; str+=2, j++){
            strncpy(temp_buf2, str, 2); // 2文字コピー
            temp_buf2[2] = '\n';
            sscanf(temp_buf2, "%x\n", &UVY[j]);
        }
        U[0]=UVY[0];
        Y[0]=UVY[1];
        V[0]=UVY[2];
        Y[1]=UVY[3];
        U[2]=UVY[4];
        Y[2]=UVY[5];
        V[2]=UVY[6];
        Y[3]=UVY[7];

        U[1] = U[0]; V[1] = V[0];
        U[3] = U[2]; V[3] = V[2];
        for (j=0; j<4; j++){
            red = (char)((int)(((Y[j]<<8) + V[j]*359 - 45952)>>8)&0xff);
            green = (char)(((int)((Y[j]<<8) - V[j]*183 - U[j]*88 + 34688)>>8)&0xff);
            blue = (char)((int)(((Y[j]<<8) + U[j]*454 - 58112)>>8)&0xff);
            cam_red[(int)(i/640)][(int)((i%640)+j)] = red;
            cam_green[(int)(i/640)][(int)((i%640)+j)]  = green;
            cam_blue[(int)(i/640)][(int)((i%640)+j)] = blue;
        }
    }
    // cam_dataに読み込んだカメラのカラーデータをbmp_dataにをコピー(その際にBMPのデータは左下から始まる)
    for (i=0; i<480; i++){
        for (j=0; j<640; j++){
            bmp_data[479-i][j].red = cam_red[i][j];
            bmp_data[479-i][j].green = cam_green[i][j];
            bmp_data[479-i][j].blue = cam_blue[i][j];
        }
    }
    fclose(fcam);

    // BMPファイルのファイルヘッダに値を代入
    bmpfh.bfType = 0x4d42;
    bmpfh.bfSize = 640*480*3+54;
    bmpfh.bfReserved1 = 0;
    bmpfh.bfReserved2 = 0;
    bmpfh.bfOffBits = 0x36;
    // BMPファイルのINFOヘッダに値を代入
    bmpih.biSize = 0x28;
    bmpih.biWidth = 640;
    bmpih.biHeight = 480;
    bmpih.biPlanes = 0x1;
    bmpih.biBitCount = 24;
    bmpih.biCompression = 0;
    bmpih.biSizeImage = 0;
    bmpih.biXPixPerMeter = 3779;
    bmpih.biYPixPerMeter = 3779;
    bmpih.biClrUsed = 0;
    bmpih.biClrImporant = 0;
    
    // bmpファイルに書き出す
    if ((fbmp=fopen("cam_bmp_file.bmp""wb")) == NULL){
        fprintf(stderr, "cam_bmp_file.bmpがバイナリライトモードで開けません\n");
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfh.bfType, sizeof(char), 2, fbmp);
    fwrite(&bmpfh.bfSize, sizeof(long), 1, fbmp);
    fwrite(&bmpfh.bfReserved1, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfReserved2, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfOffBits, sizeof(long), 1, fbmp);
    // BMPファイルのINFOヘッダの書き込み
    fwrite(&bmpih, sizeof(BITMAPINFOHEADER), 1, fbmp);
    // bmp_dataの書き込み
    for (i=0; i<480; i++) {
        for (j=0; j<640; j++) {
            fputc((int)bmp_data[i][j].blue, fbmp);
            fputc((int)bmp_data[i][j].green, fbmp);
            fputc((int)bmp_data[i][j].red, fbmp);
        }
    }
    fclose(fbmp);
    for(i=0; i<480; i++){
        free(cam_red[i]);
        free(cam_green[i]);
        free(cam_blue[i]);
        free(bmp_data[i]);
    }
    free(cam_red);
    free(cam_green);
    free(cam_blue);
    free(bmp_data);
    
    return 0;
}



BMP用のヘッダは、”BMP ファイルフォーマット”さんから頂いてきたもので、下に示すようなヘッダとなっている。

// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//

#pragma once

#include "targetver.h"

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



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

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

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


これで、(エラーがまだ出ているが)変換したBMPファイルを下に示す。(大きいので、JPEGに変換してあります)
CamDispCntrler_DDR2_pict_14_100903.jpg

やはり色がおかしいようだ。全体にピンクぽくなっている。
次は、SCCBを接続して、RGB444モードにしてデータを取り込んでみよう。
  1. 2010年09月03日 05:56 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:19

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路21(VIO、tcl)

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路にChipScope ProのVIOを入れて、tclでデータを取得してみることにした。
最初に、回路を変更して、VIOのIPを挿入した。sw0, sw1の2つのスイッチを使用して、sw0が1の時に連続的にCMOSカメラからの画像を取り込むが、sw0が0の時は、CMOSカメラからの画像を取り込まない。結果として、最後のCMOSカメラの画像をずっと表示することになる。つまりデジカメ機能をつけた訳だ。(前回説明済み)次に、DDR2 SDRAMのアドレス入力をVGAコントローラとVIOのSYNC_INに切り替えるスイッチを付けた。それがsw1だ。通常は0で、VGAコントローラのアドレスをDDR2 SDRAMに入力する。これで正常にディスプレイに画像が表示される。次に1にすると、VIOのSYNC_INのアドレスをDDR2 SDRAMに入力する。このモードは、VIOからアドレスを入力して、画像データを取得する場合に使用する。
使用方法としては、sw0を1、sw1を0にしておいて、画像データをディスプレイに表示して、良さそうな画像になったら、sw0を0にして、画像データを取得する。これで静止画が取れたので、sw1を1にして、VIOのSYNC_INからDDR2 SDRAMにアドレスを与える。
SRAMと違って、DDR2 SDRAMは、アドレスを与えるだけではデータは出てこないので、SYNC_INから与えるアドレスデータが違っていたら、DDR2 SDRAMコントローラにアドレスのライト・イネーブルパルスを送るようにしている。出てきたデータはラッチされて、VIOのSYNC_OUTに出てくるので、VIOコンソールに出力するか、tclでファイルに落とす。
下に変更したVerilog ソースを示す。VIOについては、前回のリンクを参照。

    SW_Controller #(
        .frequency_KHz(25000))
    SW_CONT_inst(
        .clk(clk_cam),
        .reset(reset_cam),
        .sw0(sw0),
        .sw1(sw1),
        .sw0_out(capture_ena),
        .sw1_out(vio_on)
    );
    
    CamCaptICON CamCaptICON_inst (
        .CONTROL0(control0) // INOUT BUS [35:0]
    );
    CamCaptVIO CamCaptVIO_inst (
        .CONTROL(control0), // INOUT BUS [35:0]
        .CLK(clk_ddr2), // IN
        .SYNC_IN(sync_in), // IN BUS [63:0]
        .SYNC_OUT(sync_out) // OUT BUS [24:0]
    );

    // sync_outの変化を検知してvio_addr_we を出力する
    always @(posedge clk_ddr2) begin
        if (reset_ddr2) begin
            sync_out_reg1 <= 25'd0;
            sync_out_reg2 <= 25'd0;
        end else begin
            sync_out_reg1 <= sync_out;
            sync_out_reg2 <= sync_out_reg1;
        end
    end
    always @* begin
        if (sync_out_reg1 != sync_out_reg2) // 以前の値と異なるとき
            vio_addr_we <= 1'b1;
        else
            vio_addr_we <= 1'b0;
    end
    
    // first_dword VIOの最初の32ビット
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            first_dword <= 1'b1;
        else begin
            if (vio_on && ddr2_rddata_valid)
                first_dword <= 1'b0;
            else
                first_dword <= 1'b1;
        end
    end
    // sync_in 処理
    always @(posedge clk_ddr2) begin
        if (reset_ddr2)
            sync_in <= 64'd0;
        else begin
            if (vio_on & first_dword && ddr2_rddata_valid) begin
                sync_in[63:32] <= ddr2_output_data;
            end
            if (vio_on & ~first_dword && ddr2_rddata_valid) begin
                sync_in[31:0] <= ddr2_output_data;
            end
        end
    end


これで、ChipScope ProのAnalyzerを立ち上げて、VIOコンソールを見た。その様子を下図に示す。
CamDispCntrler_DDR2_36_100831.png

アドレスが0 (SYNC_IN) の時のデータ (SYNC_OUT) が表示されている。これをSYNC_IN(アドレス)を4に変更すると、アドレス4のデータがSYNC_OUTに表示される。
CamDispCntrler_DDR2_37_100831.png

ちなみにSYNC_OUTのデータは4画素分となる。8ビットずつUVVYUVVYと入っているはずだ。これはDDR2 SDRAMのデータ幅16ビットと粒度4で決まってしまう。

つぎにtclスクリプトを書いて、データを取得してみた。試しに34個のデータを取得した。下にコマンド・プロンプトの画面を示す。
CamDispCntrler_DDR2_38_100901.png

アドレス00000と00004の値が上のVIOコンソールに表示された値と同じ値になっているのがわかると思う。これで、同時にcamera_capture_data.txtという名前のファイルに値が書かれる。
CamDispCntrler_DDR2_39_100901.png

これで、UYまたはVYの16ビットデータを307200個取れれば、画像データをすべて取得できる。

(追記)画像データの取得が終わりました。21分程度かかりました。
  1. 2010年09月01日 05:23 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0
FC2 Analyzer