FC2カウンター FPGAの部屋 ZYBO

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

FPGAの部屋

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

ZYBO 上のOpenCV で白線検出3(Canny フィルタのみの場合)

ZYBO 上のOpenCV で白線検出2(equalizeHist() を使用した場合2)”の続き。

今回は前回のコードはそのままに、10行目の”#define HIST”をコメントアウトして、equalizeHist() を使用しないで、Canny フィルタのみで白線検出を行うことにする。なお、Canny フィルタのスレッショルドは、試行錯誤して、最適化したつもりだ。

最初に、test_1080p.bmp からやってみた。
Lane-Detecting_75_160529.png

白線検出の経過時間は 0.221 sec 程度だった。前回よりも 0.057 sec 速かった。
白線検出結果を示す。
Lane-Detecting_76_160529.jpg

白線検出ができてる。なお、source ウインドウは今回はカラーで取り込んでいる。

次に road_1.jpg の結果を示す。
Lane-Detecting_77_160529.png

白線検出の経過時間は 0.416 sec 程度だった。前回は、source ウインドウは白黒だが、0.638 sec 程度だった。
白線検出結果を示す。
Lane-Detecting_78_160529.jpg

次に road_2.jpg の結果を示す。
Lane-Detecting_79_160529.png

白線検出の経過時間は 0.414 sec 程度だった。前回は、source ウインドウは白黒だが、1.290 sec 程度だった。大幅に速くなっている。これだったら使えそうだ。1秒回に 2 回は判定できる。
白線検出結果を示す。
Lane-Detecting_80_160529.jpg

次に road_3.jpg の結果を示す。
Lane-Detecting_81_160529.png

白線検出の経過時間は 0.394 sec 程度だった。前回は、source ウインドウは白黒だが、1.300 sec 程度だった。こちらも大幅に速くなっている。
白線検出結果を示す。
Lane-Detecting_82_160529.jpg

最後に、road_4.jpg の結果を示す。
Lane-Detecting_83_160529.png

白線検出の経過時間は 0.320 sec 程度だった。前回は、source ウインドウは白黒だが、0.604 sec 程度だった。
白線検出結果を示す。
Lane-Detecting_84_160529.jpg

全体に白線検出の速度は上がっている。equalizeHist() を外したおかげもあるが、HoughLines() で検出する直線の数が経過時間に影響するようだ。
  1. 2016年05月29日 05:31 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出2(equalizeHist() を使用した場合2)

”ZYBO 上のOpenCV で白線検出1(equalizeHist() を使用した場合)”の続き。

前回は、equalizeHist() を使用し、Canny フィルタを掛けて、HoughLine 変換で道路の白線検出を行った。しかし、画像を読み込む時点で白黒画像に変換していた。ハードウェアでは、カメラで撮影した画像を白黒変換して、Canny フィルタを掛ける予定なので、白黒画像変換の部分の経過時間も測る必要がある。それでC++ ソースコードを修正した。更に、白黒画像変換+Canny フィルタの経過時間を測定した。

Hough_example.cpp を下に示す。

// Line Detection by Hough Line Transform
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <sys/time.h>

#define HIST

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat src;
    
    if (argc >= 1){
        src = imread(argv[1]);
    } else {
        printf("Usage : HoughLine_example <read_file_name>\n");
        exit(1);
    }

    Mat dst, cdst;
    Mat src_g;
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

    cvtColor(src, src_g, CV_BGR2GRAY);
#ifdef HIST
    Mat eqst;
    equalizeHist(src_g, eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    //Canny(src_g, dst, 50, 200, 3); // Normal
    Canny(src_g, dst, 2003003); // Normal2
#endif

    //gettimeofday(&end_time, NULL);
    
    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    gettimeofday(&end_time, NULL);
    
    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    
    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }

#ifdef HIST
    imshow("equalizeHist", eqst);
#endif
    imshow("Canny", dst);
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    waitKey();
    waitKey();
    waitKey();
    
    return 0;
}


./Hough_example test_1080p.bmp コマンドを実行した。
Lane-Detecting_72_160527.png

白線検出の経過時間は 0.278 sec 程度だった。前回は 0.273 sec だったので、約 5 ms 程度、白黒変換にかかることが分かった。

白線検出結果を示す。結果は前回と同じだが、source ウインドウがカラーなのが分かる。
Lane-Detecting_73_160527.jpg

次に、白黒画像変換+Canny フィルタの経過時間を測定する。
現在の”gettimeofday(&end_time, NULL);”の行をコメントアウトして、現在コメントになっている同様の行のコメントを外した。もう一度コンパイルして、やってみた。

すると、白黒画像変換+Canny フィルタの経過時間は、57 ms くらいのようだ。
Lane-Detecting_74_160527.png
  1. 2016年05月27日 04:07 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出1(equalizeHist() を使用した場合)

Vivado HLS を使用した車の白線検出9(Canny フィルタ3)”で、大体Vivado HLS による C シミュレーションでは白線検出が出来てきたと思うので、本命のZYBO のOpenCV 環境でまずはソフトウェアで、どのくらいの速度で白線検出をできるかどうかをテストしてみた。

ZYBO のUbuntu 14.04 LTS 上のOpenCV 2.4.10 で白線検出のテストを行った。
白線検出用のアプリケーションの HoughLine_example.cpp を示す。最初は、equalizeHist() を行う設定でやってみた。
Lane-Detecting_71_160526.png

// Line Detection by Hough Line Transform
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <sys/time.h>

#define HIST

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat src;
    
    if (argc >= 1){
        src = imread(argv[1], 0);
    } else {
        printf("Usage : HoughLine_example <read_file_name>\n");
        exit(1);
    }

    Mat dst, cdst;
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

#ifdef HIST
    Mat eqst;
    equalizeHist(src, eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    Canny(src, dst, 502003); // Normal
    //Canny(src, dst, 200, 300, 3); // Normal2
#endif

    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    gettimeofday(&end_time, NULL);
    
    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    
    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }

#ifdef HIST
    imshow("equalizeHist", eqst);
#endif
    imshow("Canny", dst);
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    waitKey();
    waitKey();
    waitKey();
    waitKey();
    
    return 0;
}


このアプリケーションを使用して、最初に test_1080p.bmp の白線検出をやってみた。
Lane-Detecting_61_160526.png

白線検出の経過時間は0.273 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_62_160526.jpg

良さそうだ。

次に、自分で撮影した4つの写真の白線検出結果を見た。

まずは、 road_1.jpg の白線検出を行った。
Lane-Detecting_63_160526.png

白線検出の経過時間は0.638 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_64_160526.jpg

良さそうではあるが、電線の影を検出している。

次に、road_2.jpg の白線検出を行った。
Lane-Detecting_65_160526.png

白線検出の経過時間は1.290 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_66_160526.jpg

road_1.jpg の方が逆光で、road_2.jpg の方が順光だからか?道路のちょっとした凸凹までエッジとして検出されているので、Hough変換で相当な量の直線を検出したようだ。

road_3.jpg の白線検出を行った。road_3.jpg は road_2.jpg の反対のレーンから撮影した写真なので、road_2.jpg の結果と同じような傾向になるはずだ。
Lane-Detecting_67_160526.png 

白線検出の経過時間は 1.300 sec 程度だった。下に白線検出結果を示す。
Lane-Detecting_68_160526.jpg

やはり、 road_2.jpg と同様の結果になった。

最後に、road_4.jpg の白線検出を行った。同様に、road_4.jpg は road_1.jpg と同様の写真である。
Lane-Detecting_69_160526.png

白線検出の経過時間は、0.604 程度だった。下に白線検出結果を示す。
Lane-Detecting_70_160526.jpg

road_2.jpg と road_3.jpg の白線検出が酷い気がする。equalizeHist() を使用すると、現在のパラメータでは、このカメラの順光時のアスファルト舗装の細かい凸凹がよく見えるようになってしまう。

どうやら、Hough 変換の実行時間は検出した本数が多いほど、遅くなっているのでは?と思う。
  1. 2016年05月26日 04:49 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力9(プロジェクト休止)

AXI VDMAのMM2Sを使用してビデオ出力8(シミュレーション4)”の続き。

前回、シミュレーションで、AXI GPIO をVTC の aresetn に追加して、1 フレーム目にAXI VMDA のMM2S が出力された。
今回は実機でVivado Analyzer を使って実際にどうなっているかを確かめてみた。

ZYBO ででVivado Analyzer を使って波形を見てみたが、MM2S は当然ながら、プロジェクトの元にしたS2MM も全く動いていなかった。VTC のビデオ信号も出ていない。VTC は v_axi4s_vid_out_0 の vtg_ce から VTC の gen_clken に行く線を削除して、VTC の gen_clken を 1 固定にするとVTC のビデオ信号は出力された。

やはり、どうにもAXI VDMA は相性が悪いみたいで、どうもうまく行かない。”AXI VDMA を使用したカメラ表示システムのフレームレートを 5 fps から 15 fps にする”で自作のビットマップ・ディスプレイ・コントローラを使って、15 fps にはできているので、これで良いことにする。但し、シングル・フレーム・バッファなので、どうしてもジャギーは出てしまうのだが。。。
これは、後で、トリプル・フレーム・バッファ・バージョンを作ることにする。 s2mm_frame_ptr_out(5:0) があるので、どのフレーム・バッファを使用してるか分かるようなので、それを使えば、自作ビットマップ・ディスプレイ・コントローラでもフレーム同期ができるだろう。”AXI Video Direct Memory Access v6.2 LogiCORE IP Product Guide Vivado Design Suite PG020 November 18, 2015 ”参照
AXI VDMA をもう一度やるときは、S2MM 専用AXI VDMA とMM2S 専用AXI VDMA を用意することにする。

次からは自動車の白線検出をOpenCV で実装してからVivado HLS でハードウェア化してみようと思う。
  1. 2016年05月10日 05:21 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力8(シミュレーション4)

AXI VDMAのMM2Sを使用してビデオ出力7(実機でテスト)”の続き。

前回はZYBOを使って実機でテストしてみたが、画像は出力されなかった。今回はシミュレーションをもう一度やってみた。

前回のシミュレーションでは、AXI VDMA の設定がVTC のfsync_out (これが、AXI VDMA の mm2s_fsync に接続されている)が出た後だったので、MM2S のスタートが 1 フレーム後になってしまった。今回は、VTC のリセットにAXI GPIO を接続して、AXI VDMA の設定が終了してからVTC のリセットを外すことにする。

video_module にAXI GPIO を追加して、出力をVTC の resetn に入力した。
全体のブロックデザインを示す。
AXI_VDMA_MM2S_42_160507.png

video_module を示す。なお、camera_module は変更がない。
AXI_VDMA_MM2S_43_160507.png

アドレスマップを示す。
AXI_VDMA_MM2S_44_160507.png

AXI GPIO は 0x40000000 番地からマップされている。

これでシミュレーションを行った。AXI GPIO の出力を 1 にするのは、AXI VDMA が設定終了後にしてある。

gpio_io_o が 1 になった時に、AXI VDMA の mm2s_fsync にパルスが入っているのが分かる。
AXI_VDMA_MM2S_39_160507.png

これで、1 フレーム目から MM2S もスタートした。S2MM もスタートしている。画像データ転送が両方向とも問題ない。
AXI_VDMA_MM2S_40_160507.png

でもVGA 出力は出ていない。
AXI_VDMA_MM2S_41_160507.png

AXI4-Stream to Video Out v4.0 LogiCORE IP Product Guide Vivado Design Suite PG044 November 18, 2015
の 32 ページによると locked は 4 フレームかかるらしいので、シミュレーションでは見えないかもしれない?

最後にレジスタの設定リスト vdma_reg_set.txt を示す。

44a00000
0000008B
44a0005c
00000000
44a00060
00000000
44a00064
00000000
44a00058
00000c80
44a00054
00000c80
44a00050
00000258
44a00030
00000003
44a000ac
00000000
44a000B0
00000000
44a000B4
00000000
44a000a8
00000c80
44a000a4
00000c80
44a000a0
00000258
44a20040
00000000
44a20044
80000000
44a20000
00000002
44a10040
00000000
44a10000
00000002
44a40000
00000000
44a40004
00000000
40000000
00000001
ffffffff

  1. 2016年05月07日 20:21 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力7(実機でテスト)

AXI VDMAのMM2Sを使用してビデオ出力6(インプリメントしたがエラー)”の続き。

前回はビットストリームの生成まで出来たので、今回は、アプリケーションを作って、ZYBOの実機でテストした。

ビットストリームの生成ができたので、ハードウェアをエクスポートして、SDKを立ち上げた。

cam_disp_axis.c を AXI VDMA の MM2S を使う仕様に変更して、ZYBO実機でテストしてみたが、何も表示されない。ビデオ信号が出ていない感じだ。もう一度、シミュレーションに戻ってやり直してみようと思う。その場合は、VTC のリセットにGPIO を入れて、任意のタイミングでVTC のリセットを外せるようにして、最初のフレームからAXI VDMA のMM2S が動作する状況にしたいと思う。

SDK を示す。
AXI_VDMA_MM2S_38_160506.png

修正した cam_disp_axis.c を示す。

// cam_disp_axis.c
// 2015/06/14 by marsee
// 2016/05/06 : Supporting to the MM2S of AXI VDMA
//
// Refered to Xilinx\SDK\2015.1\data\embeddedsw\XilinxProcessorIPLib\drivers\axivdma_v5_1\doc\html\api
// Refered to https://github.com/elitezhe/Atyls-VDMA-one-in-one-out/blob/master/SDK/colorbar/src/helloworld.c
// Refered to http://www.xilinx.com/support/documentation/ip_documentation/axi_vdma/v6_2/pg020_axi_vdma.pdf
// Refered to http://forums.xilinx.com/t5/Embedded-Processor-System-Design/Axi-VDMA-on-Digilent-Atlys/td-p/297019/page/2
// Refered to https://forums.xilinx.com/xlnx/attachments/xlnx/zaps/5096/1/helloworld.c
//
// normal camera out
//

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.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

static XAxiVdma_DmaSetup Vdma0_WriteCfg, Vdma0_ReadCfg;

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(){
    // malloc frame buffer
    // unsigned int *frame_buffer = (unsigned int *)malloc(HORIZONTAL_PIXELS * VERTICAL_LINES * PIXEL_NUM_OF_BYTES * NUMBER_OF_WRITE_FRAMES);

    // AXI VDMA Initialization sequence
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;

    XAxiVdma0_Config = XAxiVdma_LookupConfig(XPAR_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
    if (XAxiVdma0_Config == NULL){
        fprintf(stderr, "No AXI VDMA found\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() failed\n");
        return(-1);
    }

    // AXI VDMA Write Settings
    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.

    Vdma0_WriteCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_WriteCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_WriteCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_WriteCfg.FrameDelay = 0// Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_WriteCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_WriteCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_WriteCfg.PointNum = 0// No Gen-Lock
    Vdma0_WriteCfg.EnableFrameCounter = 0// Endless transfers
    Vdma0_WriteCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed (XAXIVDMA_WRITE)\n");
        return(-1);
    }

    // AXI VDMA Read Settings
    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_READ);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_READ)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_READ); // Set the number of frame store buffers to use.

    Vdma0_ReadCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_ReadCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_ReadCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_ReadCfg.FrameDelay = 0// Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_ReadCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_ReadCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_ReadCfg.PointNum = 0// No Gen-Lock
    Vdma0_ReadCfg.EnableFrameCounter = 0// Endless transfers
    Vdma0_ReadCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_READ, &Vdma0_ReadCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed (XAXIVDMA_READ)\n");
        return(-1);
    }

    // Frame buffer address set
    unsigned int frame_addr = (unsigned int)FRAME_BUFFER_ADDRESS;
    int i;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma0_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        Vdma0_ReadCfg.FrameStoreStartAddr[i] = frame_addr;
        frame_addr += HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * VERTICAL_LINES;
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed (XAXIVDMA_WRITE)\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_READ, Vdma0_ReadCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed (XAXIVDMA_READ)\n");
        return(-1);
    }

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_MODULE_AXIS_SWITCH_1_BASEADDR+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_MODULE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_MODULE_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_MODULE_AXIS_SWITCH_1_DEVICE_ID+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_MODULE_AXIS_SWITCH_1_DEVICE_ID), 0x2); // Commit registers

    // VDMA start
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed (XAXIVDMA_WRITE)\n");
        return(-1);
    }
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_READ);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed (XAXIVDMA_READ)\n");
        return(-1);
    }

    // mt9d111_inf_axis_0, axi_iic_0
    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_MODULE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_MODULE_AXI_IIC_0_BASEADDR;

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

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

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 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年05月06日 06:13 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

AXI VDMAのMM2Sを使用してビデオ出力6(インプリメントしたがエラー)

AXI VDMAのMM2Sを使用してビデオ出力5(シミュレーション3)”の続き。

前回、v_axis_vid_out IP が出力していないのが不安ではあるが、AXI VDMA からは出力が出ているので、ZYBO 実機で試してみようということで、ブロックデザインを修正して論理合成、インプリメントしてみたが、エラーが出てしまった。

シミュレーションを元にブロックデザインを修正した。ブロックデザインを示す。
AXI_VDMA_MM2S_27_160505.png

AXI_VDMA_MM2S_28_160505.png

AXI_VDMA_MM2S_29_160505.png

これでビットストリームの生成を行ったところ、route_design でエラーが出てしまった。
AXI_VDMA_MM2S_30_160505.png

MMCM のVCO の周波数が 200 MHz で動作範囲の 600 MHz ~ 1200 MHz に入らないというエラーだった。

rgb2dvi IP の設定を見てみた。TDMS clock range は >= 120 MHz になっているが、< 120 MHz でも同様にダメだった。
AXI_VDMA_MM2S_31_160505.png

rgb2dvi を右クリックして、右クリックメニューから Edit in IP Packager を選択して、IP を編集した。

rgb2dvi のプロジェクトを開いて、rgb2dvi.vhd を開くと、kClkRange には >= 40 MHz の設定があるけど、これが表に出ていないことが分かった。ちなみに、kClkRange の値は5倍されて、入力クロックの動作周波数に掛けられるので、40 MHz x ( 3 x 5) = 600 MHz で MMCM の VCO の動作範囲に入る。
AXI_VDMA_MM2S_32_160505.png

Package IP の Customization Parameters を見ると、kClkRange の Value Validation List に 40 MHz が無いので、追加すればよい。
AXI_VDMA_MM2S_33_160505.png

kClkRange の Value Validation List をダブルクリックするとダイアログが開いたので、 >= 40 MHz (SVGA の 3 を追加した。
AXI_VDMA_MM2S_34_160505.png

Package IP の Customization Parameters に戻ると、 >= 40 MHz (SVGA が増えていた。
AXI_VDMA_MM2S_35_160505.png

rgb2dvi IP を再パッケージして、元のプロジェクトに戻った。

Tool メニュー -> Report -> Report IP Status を選択して、IP Status を表示して、IP をアップグレードした。

rgb2dvi IP をダブルクリックすると、設定画面が開いたので、>= 40 MHz (SVGA のラジオボタンをクリックして選択した。
AXI_VDMA_MM2S_36_160505.png

もう一度ビットストリームの生成を行った。今度は成功した。
AXI_VDMA_MM2S_37_160505.png
  1. 2016年05月05日 06:27 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0
»