FC2カウンター FPGAの部屋 Ultra96
FC2ブログ

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

FPGAの部屋

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

Ultra96用ガボールフィルタIP の作成1

Ultra96-V2 にガボールフィルタを実装しようということで、以前、ZYBO 用に作っていたガボールフィルタIP をUltra96用に変更することにした。
以前の記事は、”Zybot による白線間の自動走行1(Gabor fillter の修正、C ソースコード)”だった。

Ultra96用に開発するに当たっては、ガボールフィルタをかけるフィルタ・サイズを row と col を引数に入れて設定できるように変更した。
まずは、Gabor_filter_lh_2.h を貼っておく。

// Gabor_filter_lh_2.h
// 2016/07/24
// 2016/07/25 : 右白線検出用のGabor Filterの重みを追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
// 2016/08/29 : 1回目左白線検出、2回目右白線検出のモードを追加
// 2019/08/22 : 更新
//

#ifndef __Gabor_filter_lh_H__
#define __Gabor_filter_lh_H__

#define ARRAY_SIZE  9

#define RIGHT_WEIGHT    1
#define LEFT_WEIGHT     0
#define L_R_WEIGHT      2

const int gabor_weight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用
    {
        {0,-3,-10,-16,-7,7,10,5,1},
        {-3,-15,-27,-11,32,50,29,5,-2},
        {-11,-24,-5,73,135,95,16,-17,-10},
        {-11,4,85,187,160,14,-72,-52,-14},
        {4,51,135,137,-18,-159,-136,-45,-2},
        {16,50,59,-39,-179,-185,-73,3,13},
        {10,12,-25,-104,-131,-60,15,27,11},
        {1,-7,-31,-48,-24,18,29,14,3},
        {-1,-5,-9,-4,10,16,10,2,-1}
    },
    {
        {1,5,7,1,-12,-17,-10,-3,0},
        {1,11,33,45,21,-16,-27,-15,-4},
        {-8,-5,35,107,131,69,-2,-21,-11},
        {-17,-47,-51,40,169,187,93,13,-7},
        {-8,-54,-134,-147,-18,123,130,58,11},
        {9,-6,-82,-185,-187,-65,36,44,17},
        {11,24,12,-55,-125,-112,-43,1,7},
        {3,14,30,23,-13,-41,-33,-12,-1},
        {0,2,9,17,14,1,-6,-5,-2}
    }
};
const float gabor_fweight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用(float)
    {
        {0.001282,-0.009914,-0.04062,-0.060586,-0.027574,0.026072,0.038427,0.018191,0.003056},
        {-0.012155,-0.057448,-0.104645,-0.042953,0.123263,0.197238,0.114451,0.020448,-0.007239},
        {-0.042252,-0.093065,-0.018911,0.285374,0.525746,0.372687,0.060734,-0.064748,-0.040465},
        {-0.042261,0.015673,0.332798,0.728763,0.625046,0.053591,-0.283076,-0.203293,-0.05608},
        {0.017342,0.198305,0.52554,0.535526,-0.069756,-0.622839,-0.531089,-0.177366,-0.006367},
        {0.060866,0.19708,0.231032,-0.154219,-0.699885,-0.721808,-0.286707,0.013004,0.049249},
        {0.038379,0.04877,-0.098477,-0.404993,-0.510165,-0.233566,0.057894,0.104366,0.041887},
        {0.0047,-0.0278,-0.121277,-0.187262,-0.093276,0.070512,0.113857,0.055799,0.009976},
        {-0.003798,-0.01885,-0.035607,-0.01709,0.037692,0.064268,0.038606,0.007536,-0.002133}
    },
    {
        {0.005562,0.018882,0.028293,0.004499,-0.044995,-0.064838,-0.039469,-0.009822,0.000815},
        {0.002294,0.04108,0.127023,0.175094,0.083025,-0.063755,-0.106402,-0.057798,-0.01406},
        {-0.031269,-0.021096,0.135641,0.417286,0.512467,0.269946,-0.008354,-0.082091,-0.041357},
        {-0.066348,-0.184919,-0.197802,0.15614,0.65976,0.728616,0.361674,0.052074,-0.027152},
        {-0.031146,-0.211178,-0.523777,-0.573856,-0.069756,0.480311,0.506451,0.225223,0.041031},
        {0.035552,-0.023892,-0.320104,-0.723563,-0.728735,-0.253689,0.1391,0.170625,0.067723},
        {0.04216,0.094939,0.047511,-0.216623,-0.488075,-0.437898,-0.168739,0.003336,0.027009},
        {0.012112,0.056596,0.115239,0.090332,-0.05076,-0.158403,-0.127847,-0.046375,-0.004918},
        {-0.00168,0.007437,0.036985,0.067021,0.053689,0.004977,-0.02365,-0.018248,-0.005928}
    }
};

#endif


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

// Gabor_fiter_lh_2.cpp
// 2016/07/23 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
// 2016/08/29 : 1回目左白線検出、2回目右白線検出のモードを追加
// 2019/08/22 : 引数に int row, int col を追加
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "Gabor_filter_lh_2.h"

int conv_rgb2y(int rgb);

int Gabor_filter_lh_2(hls::stream<ap_axis<32,1,1,1> >& ins,
        hls::stream<ap_axis<32,1,1,1> >& outs, int row, int col, ap_uint<2> & RorL){
#pragma HLS INTERFACE s_axilite port=RorL
#pragma HLS INTERFACE s_axilite port=col
#pragma HLS INTERFACE s_axilite port=row
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return

    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> gabor;

    hls::LineBuffer<ARRAY_SIZE-1, 1920, int> linebuf;
    hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;

    int gray_pix, val, i, j, x, y;

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

    for (int k=0; k<2; k++){
        for (y=0; y<row; y++){
#pragma HLS LOOP_TRIPCOUNT min=48 max=1080 avg=600
            for (x=0; x<col; x++){
#pragma HLS LOOP_TRIPCOUNT min=64 max=1920 avg=800          
#pragma HLS PIPELINE II=1
                if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                    ins >> pix;    // AXI4-Stream からの入力

                mbuf.shift_left();    // mbuf の列を1ビット左シフト
                for(i=ARRAY_SIZE-2; i>=0; --i){
                    mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
                }
                gray_pix = conv_rgb2y(pix.data);
                mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);

                // LineBuffer の更新
                linebuf.shift_down(x);
                linebuf.insert_bottom(gray_pix, x);

                // 使用する配列を決定する
                int ano;
                switch (RorL){
                case LEFT_WEIGHT :
                    ano = LEFT_WEIGHT;
                    break;
                case RIGHT_WEIGHT :
                    ano = RIGHT_WEIGHT;
                    break;
                case L_R_WEIGHT :
                    if (k == 0)
                        ano = LEFT_WEIGHT;
                    else
                        ano = RIGHT_WEIGHT;
                    break;
                default :
                    ano = LEFT_WEIGHT;
                    break;
                }

                // Gabor filter の演算
                for (j=0, val=0; j<ARRAY_SIZE-1; j++){
                    for (i=0; i<ARRAY_SIZE-1; i++){
                        val += gabor_weight[ano][j][i] * mbuf(ARRAY_SIZE-1-j,i);
                    }
                }
                val = val/256; // 256倍してあるので、1/256して戻す
                if (val<0)
                    //val = -val; // 絶対値
                    val = 0; // マイナスの値を0に丸める
                else if (val>255)
                    val = 255;

                // Gabor filter・データの書き込み
                gabor.data = (val<<16)+(val<<8)+val;
                // 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
                if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
                    gabor.data = 0;

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

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

                outs << gabor;    // AXI4-Stream へ出力
             }
         }
    }
     return(0);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8; // 256で割る

    return(y);
}


Gabor_filter_lh_2_tb.cpp を貼っておく。

// Gabor_filter_lh_tb.cpp
// 2016/07/24 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
// 2019/08/22 : 引数に int row, int col を追加
//

#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 "Gabor_filter_lh_2.h"
#include "bmp_header.h"

int Gabor_filter_lh_2(hls::stream<ap_axis<32,1,1,1> >& ins,
    hls::stream<ap_axis<32,1,1,1> >& outs, int row, int col, ap_uint<2> & RorL);

int conv_rgb2y_soft(int rgb);
int Gabor_filter_lh_2_soft(hls::stream<ap_axis<32,1,1,1> >& ins, 
    hls::stream<ap_axis<32,1,1,1> >& outs, int row, int col, ap_uint<2> & RorL);

#define CLOCK_PERIOD 10
#define RIGHT_OR_LEFT   L_R_WEIGHT
#define BMP_FILE_NAME   "road_1.bmp"

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;

    int m_seq = 1; // M系列の値
    int i, k;
    int xor_shift;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw, *fbmpwf;
    int *rd_bmp, *hw_gabor, *sw_gabor;
    int blue, green, red;
    ap_uint<2> r_l;
    char fhname[100];
    char fsname[100];

    if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open test.bmp by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 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_gabor =(int *)malloc(2 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_gabor memory\n");
        exit(1);
    }
    if ((sw_gabor =(int *)malloc(2 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_gabor 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;
    }

    // 2画面分を入力する
    for(int k=0; k<2; k++){
        for(int j=0; j < bmpihr.biHeight; j++){
            for(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;
            }
        }
    }

    r_l = (ap_uint<2>)RIGHT_OR_LEFT;
    Gabor_filter_lh_2(ins, outs, bmpihr.biHeight, bmpihr.biWidth, r_l);
    Gabor_filter_lh_2_soft(ins_soft, outs_soft, bmpihr.biHeight, bmpihr.biWidth, r_l);

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    for(k=0; k<2; k++){
        for(int j=0; j < bmpihr.biHeight; j++){
            for(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_gabor[bmpihr.biWidth*bmpihr.biHeight*k+(j*bmpihr.biWidth)+i] = (int)val;
                sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+(j*bmpihr.biWidth)+i] = (int)val_soft;

                //printf("k=%d, j=%d, i=%d\n",k,j,i);
                if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > 4){ // 2乗誤差が4よりも大きい
                    printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %08x, SW = %08x\n", i, j, (int)val, (int)val_soft);
                    //return(1);
                }
                //if (vals.last)
                    //cout << "AXI-Stream is end" << endl;
            }
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ハードウェアのラプラシアンフィルタの結果を temp_gabor0.bmp, temp_gabor1.bmp へ出力する
    for(k=0; k<2; k++){
        if(k == 0){
            if ((fbmpw=fopen("temp_gabor0.bmp", "wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor0.bmp by binary write mode\n");
                exit(1);
            }
        } else {
            if ((fbmpw=fopen("temp_gabor1.bmp", "wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor1.bmp by binary write mode\n");
                exit(1);
            }
        }

        // BMPファイルヘッダの書き込み
        fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
        fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
        fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
        fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
        fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 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++){
                blue = hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
                green = (hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
                red = (hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

                fputc(blue, fbmpw);
                fputc(green, fbmpw);
                fputc(red, fbmpw);
            }
        }
        fclose(fbmpw);
    }

    // ソフトウェアのラプラシアンフィルタの結果を temp_gabor_float0.bmp, temp_gabor_float1.bmp へ出力する
    for(k=0; k<2; k++){
        if (k == 0){
            if ((fbmpwf=fopen("temp_gabor_float0.bmp", "wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor_float0.bmp by binary write mode\n");
                exit(1);
            }
        } else {
            if ((fbmpwf=fopen("temp_gabor_float1.bmp", "wb")) == NULL){
                fprintf(stderr, "Can't open temp_gabor_float1.bmp by binary write mode\n");
                exit(1);
            }
        }

        // BMPファイルヘッダの書き込み
        fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpwf);
        fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpwf);
        fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpwf);
        fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpwf);
        fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpwf);
        fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpwf);
        // RGB データの書き込み、逆順にする
        for (int y=0; y<bmpihr.biHeight; y++){
            for (int x=0; x<bmpihr.biWidth; x++){
                blue = sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
                green = (sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
                red = (sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

                fputc(blue, fbmpwf);
                fputc(green, fbmpwf);
                fputc(red, fbmpwf);
            }
        }
        fclose(fbmpwf);
    }

    free(rd_bmp);
    free(hw_gabor);

    return 0;
}

int Gabor_filter_lh_2_soft(hls::stream<ap_axis<32,1,1,1> >& ins, 
    hls::stream<ap_axis<32,1,1,1> >& outs, int row, int col, ap_uint<2> & RorL){
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> gabor;

    hls::LineBuffer<ARRAY_SIZE-1, 1920, int> linebuf;
    hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;

    int gray_pix, val, i, j, x, y;
    float valf;

    do {    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

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

                mbuf.shift_left();    // mbuf の列を1ビット左シフト
                for(i=ARRAY_SIZE-2; i>=0; --i){
                    mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
                }
                gray_pix = conv_rgb2y_soft(pix.data);
                mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);

                // LineBuffer の更新
                linebuf.shift_down(x);
                linebuf.insert_bottom(gray_pix, x);

                // 使用する配列を決定する
                int ano;
                switch (RorL){
                case LEFT_WEIGHT :
                    ano = LEFT_WEIGHT;
                    break;
                case RIGHT_WEIGHT :
                    ano = RIGHT_WEIGHT;
                    break;
                case L_R_WEIGHT :
                    if (k == 0)
                        ano = LEFT_WEIGHT;
                    else
                        ano = RIGHT_WEIGHT;
                    break;
                default :
                    ano = LEFT_WEIGHT;
                    break;
                }

                // Gabor filter の演算
                for (j=0, valf=0; j<ARRAY_SIZE-1; j++){
                    for (i=0; i<ARRAY_SIZE-1; i++){
                        valf += gabor_fweight[ano][j][i] * (float)mbuf(ARRAY_SIZE-1-j,i);
                    }
                }

                val = (int)valf;
                if (val<0)
                    //val = -val; // 絶対値
                    val = 0; // マイナスの値を0に丸める
                else if (val>255)
                    val = 255;

                // Gabor filter・データの書き込み
                gabor.data = (val<<16)+(val<<8)+val;
                // 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
                if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
                    gabor.data = 0;

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

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

                outs << gabor;    // AXI4-Stream へ出力
             }
         }
    }
     return(0);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8; // 256で割る

    return(y);
}


Vivado 2018.2 の Ultra96用Gabor_filter_lh_2 プロジェクトを示す。
Gabor_filter_lh_2_1_190825.png
  1. 2019年08月26日 04:21 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 でカメラ画像をDisplayPort に出力する3(完成)

Ultra96-V2 でカメラ画像をDisplayPort に出力する2(Ultra96-V2 の環境整備)”の続き。

前回は、bin ファイルを作成し、Ultra96-V2 のDebian を起動して、環境の整備を行った。しかし、fclkcfg でエラーが出てしまい、目的の周波数に pl_clk0 を設定することができなかった。pl_clk0 は 100 MHz に設定されたので、XGA 解像度でカメラ画像をDisplayPort に表示することはできたが、HD 解像度で表示することはできなかった。今回は、ikwzm さんがfclkcfg のバグを修正してくれたので、HD 解像度でのDisplayPort 出力を試してみよう。

ikzwm さんの以下のツィートでfclkcfg を修正していただいたのがわかった。ありがとうございました。

ZynqMP-FPGA-Linux v2019.1.2 を緊急リリースしていただいた。

Ubuntu 18.04 のホストパソコンの方で、ZynqMP-FPGA-Linux にgit pull しようとしたが、うまくアップデートできなかった。
よって、一度削除してからもう一度ダウンロードすることにした。
rm -rf ZynqMP-FPGA-Linux
git clone -b v2019.1.0 git://github.com/ikwzm/ZynqMP-FPGA-Linux
cd ZynqMP-FPGA-Linux
git lfs pull


これだけだと v2019.1.2 になってなかったので、次のコマンドを入力した。
git pull git://github.com/ikwzm/ZynqMP-FPGA-Linux v2019.1.2
cam_dp_V2_24_190819.png

これで変更されたのは、image-4.19.0-xlnx-v2019.1-zynqmp_fpga だけだったので、これだけをMicro SD カードのboot パーティションの同じ名前のファイルと入れ替えた。
cam_dp_V2_23_190819.png

Micro SD カードをUltra96-V2 に入れて、電源ON し、Debian をブートした。
cd example/cam_dp_V2/
./lddtorvary.sh
./cam_dp_ov5642 -r 2
./disp_pattern.sh


すると、DisplayPort にHD 解像度のカメラ画像が表示された。
cam_dp_V2_25_190819.png

cam_dp_V2_26_190819.jpg

./lddtorvary.sh を起動した時のメッセージを示す。
cam_dp_V2_27_190819.png

pl_clk0 は 214285713 Hz だそうだ。うまく設定されているようだ。
なお、pl_clk1 は rpll になっているが、DTS ファイルの<&zynqmp_clk 0x48 &zynqmp_clk 1>の最後の 1 が rpll を示すようだ。ここが 0 だと iopll になる。

cam_dp_ov5642.cpp を貼っておく。

// cam_dp_ov5642.cpp (for Ultra96-V2)
// 2018/12/14 by marsee
//
// This software converts the left and right of the camera image to BMP file.
// -b : bmp file name
// -n : Start File Number
// -h : help
//
// 2018/12/20 : completed.
// I am using the SVGA driver register setting of https://github.com/virajkanwade/rk3188_android_kernel/blob/master/drivers/media/video/ov5642.c
// 2018/12/22 : fixed
// 2018/12/30 : ov5642_inf_axis[0] fixed
// 2019/02/06 : for DisplayPort
// 2019/08/18 : Changed to /dev/uio4 ~ uio9 for Ultra96-V2. by marsee

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

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

#define PIXEL_NUM_OF_BYTES    4
#define NUMBER_OF_WRITE_FRAMES  3

#define SVGA_HORIZONTAL_PIXELS  800
#define SVGA_VERTICAL_LINES     600
#define SVGA_ALL_DISP_ADDRESS   (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define SVGA_3_PICTURES         (SVGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

#define XGA_HORIZONTAL_PIXELS  1024
#define XGA_VERTICAL_LINES     768
#define XGA_ALL_DISP_ADDRESS   (XGA_HORIZONTAL_PIXELS * XGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define XGA_3_PICTURES         (XGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

#define HD_HORIZONTAL_PIXELS  1920
#define HD_VERTICAL_LINES     1080
#define HD_ALL_DISP_ADDRESS   (HD_HORIZONTAL_PIXELS * HD_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define HD_3_PICTURES         (HD_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

int WriteBMPfile(char *bmp_file, volatile unsigned int *frame_buffer, int active_frame, int resolution);

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

void cam_i2x_write_sync(void) {
    // unsigned c;

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

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

int cam_reg_set(volatile unsigned *axi_iic, unsigned int device_addr);

int main(int argc, char *argv[]){
    int opt;
    int c, help_flag=0;
    char bmp_fn[256] = "bmp_file";
    char  attr[1024];
    unsigned long  phys_addr;
    int file_no = -1;
    int fd4, fd5, fd6, fd7, fd8, fd9, fd10, fd11;
    volatile unsigned int *ov5642_inf_axis, *axi_iic, *disp_dmar_axis, *vflip_dma_write;
    volatile unsigned int *axi_gpio_0, *axi_gpio_1;
    volatile unsigned int *frame_buffer;
    int active_frame;
    int resolution;
    int all_disp_addr;
    
    resolution = 1; // XGA
    while ((opt=getopt(argc, argv, "b:n:h:r:")) != -1){
        switch (opt){
            case 'b':
                strcpy(bmp_fn, optarg);
                break;
            case 'n':
                file_no = atoi(optarg);
                printf("file_no = %d\n", file_no+1);
                break;
            case 'r':
                resolution = atoi(optarg);
                break;
            case 'h':
                help_flag = 1;
                break;
        }
    }
    if(resolution == 0){
        printf("SVGA\n");
    } else if(resolution == 1){
        printf("XGA\n");
    } else {
        printf("HD\n");
    }

    if (help_flag == 1){ // help
        printf("Usage : cam_capture [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
        printf("         -r [0|1|2](0:SVGA, 1:XGA, 2:HD)\n");
        exit(0);
    }
       
    // all_disp_addr
    switch(resolution){
        case 0 :
            all_disp_addr = SVGA_ALL_DISP_ADDRESS;
            break;
        case 1 :
            all_disp_addr = XGA_ALL_DISP_ADDRESS;
            break;
        default : // 2
            all_disp_addr = HD_ALL_DISP_ADDRESS;
            break;
    }
    
    // ov5642_inf_axis-uio IP
    fd4 = open("/dev/uio4", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (ov5642_inf_axis) open error\n");
        exit(-1);
    }
    ov5642_inf_axis = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!ov5642_inf_axis){
        fprintf(stderr, "ov5642_inf_axis mmap error\n");
        exit(-1);
    }
    
    // axi_iic-uio IP
    fd5 = open("/dev/uio5", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd5 < 1){
        fprintf(stderr, "/dev/uio5 (axi_iic) open error\n");
        exit(-1);
    }
    axi_iic = (volatile unsigned int *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
    if (!axi_iic){
        fprintf(stderr, "axi_iic mmap error\n");
        exit(-1);
    }

    // disp_dmar_axis-uio IP
    fd6 = open("/dev/uio6", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd6 < 1){
        fprintf(stderr, "/dev/uio6 (disp_dmar_axis) open error\n");
        exit(-1);
    }
    disp_dmar_axis = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
    if (!disp_dmar_axis){
        fprintf(stderr, "disp_dmar_axis mmap error\n");
        exit(-1);
    }

    // vflip_dma_write-uio IP
    fd7 = open("/dev/uio7", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd7 < 1){
        fprintf(stderr, "/dev/uio7 (vflip_dma_write) open error\n");
        exit(-1);
    }
    vflip_dma_write = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
    if (!vflip_dma_write){
        fprintf(stderr, "vflip_dma_write mmap error\n");
        exit(-1);
    }

    // axi_gpio_0-uio IP (init_done output)
    fd8 = open("/dev/uio8", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd8 < 1){
        fprintf(stderr, "/dev/uio8 (axi_gpio_0) open error\n");
        exit(-1);
    }
    axi_gpio_0 = (volatile unsigned int *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
    if (!axi_gpio_0){
        fprintf(stderr, "axi_gpio_0 mmap error\n");
        exit(-1);
    }

    // axi_gpio_1-uio IP (active_frame input)
    fd9 = open("/dev/uio9", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd9 < 1){
        fprintf(stderr, "/dev/uio9 (axi_gpio_1) open error\n");
        exit(-1);
    }
    axi_gpio_1 = (volatile unsigned int *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
    if (!axi_gpio_1){
        fprintf(stderr, "axi_gpio_1 mmap error\n");
        exit(-1);
    }
    
    
    // udmabuf4
    fd10 = open("/dev/udmabuf4", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd10 == -1){
        fprintf(stderr, "/dev/udmabuf4 open error\n");
        exit(-1);
    }
    frame_buffer = (volatile unsigned int *)mmap(NULL, all_disp_addr*NUMBER_OF_WRITE_FRAMES, PROT_READ|PROT_WRITE, MAP_SHARED, fd10, 0);
    if (!frame_buffer){
        fprintf(stderr, "frame_buffer4 mmap error\n");
        exit(-1);
    }
    
    // phys_addr of udmabuf4
    fd11 = open("/sys/class/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd11 == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf4/phys_addr open error\n");
        exit(-1);
    }
    read(fd11, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd11);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    // vflip_dma_write start
    vflip_dma_write[6] = phys_addr; // fb0
    vflip_dma_write[8] = phys_addr+all_disp_addr; // fb1
    vflip_dma_write[10] = phys_addr+2*all_disp_addr; // fb2
    vflip_dma_write[12] = resolution;
    vflip_dma_write[0] = 0x1; // start
    vflip_dma_write[0] = 0x80; // EnableAutoRestart
       
    // CMOS Camera initialize, ov5642
    cam_i2c_init(axi_iic);
    
    cam_reg_set(axi_iic, 0x78); // OV5642 register set

    ov5642_inf_axis[0] = phys_addr; // ov5642 AXI4-Stream Start
    ov5642_inf_axis[1] = 0;
 
     // disp_dmar_axis start
    disp_dmar_axis[4] = phys_addr; // fb0
    disp_dmar_axis[6] = phys_addr+all_disp_addr; // fb1
    disp_dmar_axis[8] = phys_addr+2*all_disp_addr; // fb2
    disp_dmar_axis[10] = resolution;
    axi_gpio_0[0] = 1; // disp_dmar_axis start(init_done = 1)
    
    char bmp_file[256];

    // All 0 set
    int all_disp_frame_index = all_disp_addr/PIXEL_NUM_OF_BYTES*NUMBER_OF_WRITE_FRAMES;
    for (int i=0; i<all_disp_frame_index; i++){
        frame_buffer[i] = 0x0;
    }
    
    // w - writed the left and right eye's bmp files.  q - exit.
    c = getc(stdin);
    while(c != 'q'){
        switch ((char)c) {
            case 'w' : // w - writed a bmp files.
                // writed the frame buffer
                file_no++;
                sprintf(bmp_file, "%s%d.bmp", bmp_fn, file_no);
                active_frame = (int)(axi_gpio_1[0] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame, resolution);
                
                printf("file No. = %d\n", file_no);

                break;
            case 'e' : // e - writed a same bmp files.
                // writed the frame buffer
                if (file_no == -1)
                    file_no = 0;
                
                sprintf(bmp_file, "%s%d.bmp", bmp_fn, file_no);
                active_frame = (int)(axi_gpio_1[0] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame, resolution);
                
                printf("file No. = %d\n", file_no);

                break;
        }
        c = getc(stdin);
    }
    
    munmap((void *)ov5642_inf_axis, 0x1000);
    munmap((void *)axi_iic, 0x1000);
    munmap((void *)disp_dmar_axis, 0x10000);
    munmap((void *)vflip_dma_write, 0x10000);
    munmap((void *)axi_gpio_0, 0x1000);
    munmap((void *)axi_gpio_1, 0x1000);
    munmap((void *)frame_buffer, all_disp_addr*3);
    
    close(fd4);
    close(fd5);
    close(fd6);
    close(fd7);
    close(fd8);
    close(fd9);
    close(fd10);
    
    return(0);
}

int WriteBMPfile(char *bmp_file, volatile unsigned int *frame_buffer, int active_frame, int resolution){
    int read_frame;
    int img_width, img_height;
    
    if (active_frame == 0)
        read_frame = 2;
    else if (active_frame == 1)
        read_frame = 0;
    else // active_frame == 2
        read_frame = 1;
        
    switch(resolution){
        case 0 :
            img_width = SVGA_HORIZONTAL_PIXELS;
            img_height = SVGA_VERTICAL_LINES;
            break;
        case 1 :
            img_width = XGA_HORIZONTAL_PIXELS;
            img_height = XGA_VERTICAL_LINES;
            break;
        default : // case 2 :
            img_width = HD_HORIZONTAL_PIXELS;
            img_height = HD_VERTICAL_LINES;
            break;
    }
    
    int offset_addr = read_frame * img_width * img_height;
    
    cv::Mat img(img_height, img_width, CV_8UC3);

    cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
    for(int y=0; y<img.rows; y++){
        for(int x=0; x<img.cols; x++){
            cv::Vec3b pixel;
            int rgb = frame_buffer[offset_addr+y*img.cols+x];
            pixel[0] = (rgb & 0xff); // blue
            pixel[1] = (rgb & 0xff00) >> 8; // green
            pixel[2] = (rgb & 0xff0000) >> 16; // red
            dst_vec3b(y,x) = pixel;
        }
    }
    
    cv::imwrite(bmp_file, img);
    
    return(0);
}

int cam_reg_set(volatile unsigned *axi_iic, unsigned int device_addr){
    cam_i2c_write(axi_iic, device_addr, 0x3103, 0x93);
    cam_i2c_write(axi_iic, device_addr, 0x3008, 0x82);
    cam_i2c_write(axi_iic, device_addr, 0x3017, 0x7f);
    cam_i2c_write(axi_iic, device_addr, 0x3018, 0xfc);
    cam_i2c_write(axi_iic, device_addr, 0x3810, 0xc2);
    cam_i2c_write(axi_iic, device_addr, 0x3615, 0xf0);
    cam_i2c_write(axi_iic, device_addr, 0x3000, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3001, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3002, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3003, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3000, 0xf8);
    cam_i2c_write(axi_iic, device_addr, 0x3001, 0x48);
    cam_i2c_write(axi_iic, device_addr, 0x3002, 0x5c);
    cam_i2c_write(axi_iic, device_addr, 0x3003, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x3004, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x3005, 0xb7);
    cam_i2c_write(axi_iic, device_addr, 0x3006, 0x43);
    cam_i2c_write(axi_iic, device_addr, 0x3007, 0x37);
    cam_i2c_write(axi_iic, device_addr, 0x3011, 0x08); // 0x08 - 15fps, 0x10 - 30fps
    cam_i2c_write(axi_iic, device_addr, 0x3010, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x460c, 0x22);
    cam_i2c_write(axi_iic, device_addr, 0x3815, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x370d, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x370c, 0xa0);
    cam_i2c_write(axi_iic, device_addr, 0x3602, 0xfc);
    cam_i2c_write(axi_iic, device_addr, 0x3612, 0xff);
    cam_i2c_write(axi_iic, device_addr, 0x3634, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x3613, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3605, 0x7c);
    cam_i2c_write(axi_iic, device_addr, 0x3621, 0x09);
    cam_i2c_write(axi_iic, device_addr, 0x3622, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3604, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x3603, 0xa7);
    cam_i2c_write(axi_iic, device_addr, 0x3603, 0x27);
    cam_i2c_write(axi_iic, device_addr, 0x4000, 0x21);
    cam_i2c_write(axi_iic, device_addr, 0x401d, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x3600, 0x54);
    cam_i2c_write(axi_iic, device_addr, 0x3605, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x3606, 0x3f);
    cam_i2c_write(axi_iic, device_addr, 0x3c01, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5000, 0x4f);
    cam_i2c_write(axi_iic, device_addr, 0x5020, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x5181, 0x79);
    cam_i2c_write(axi_iic, device_addr, 0x5182, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5185, 0x22);
    cam_i2c_write(axi_iic, device_addr, 0x5197, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x5001, 0xff);
    cam_i2c_write(axi_iic, device_addr, 0x5500, 0x0a);
    cam_i2c_write(axi_iic, device_addr, 0x5504, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5505, 0x7f);
    cam_i2c_write(axi_iic, device_addr, 0x5080, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x300e, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x4610, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x471d, 0x05);
    cam_i2c_write(axi_iic, device_addr, 0x4708, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x3710, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x3632, 0x41);
    cam_i2c_write(axi_iic, device_addr, 0x3702, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x3620, 0x37);
    cam_i2c_write(axi_iic, device_addr, 0x3631, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x3808, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x3809, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x380a, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x380b, 0xe0);
    cam_i2c_write(axi_iic, device_addr, 0x380e, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x380f, 0xd0);
    cam_i2c_write(axi_iic, device_addr, 0x501f, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5000, 0x4f);
    cam_i2c_write(axi_iic, device_addr, 0x4300, 0x61); // RGB565
    cam_i2c_write(axi_iic, device_addr, 0x3503, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x3501, 0x73);
    cam_i2c_write(axi_iic, device_addr, 0x3502, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x350b, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3503, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x3824, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x3501, 0x1e);
    cam_i2c_write(axi_iic, device_addr, 0x3502, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x350b, 0x7f);
    cam_i2c_write(axi_iic, device_addr, 0x380c, 0x0c);
    cam_i2c_write(axi_iic, device_addr, 0x380d, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x380e, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x380f, 0xe8);
    cam_i2c_write(axi_iic, device_addr, 0x3a0d, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x3a0e, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x3818, 0xc1);
    cam_i2c_write(axi_iic, device_addr, 0x3705, 0xdb);
    cam_i2c_write(axi_iic, device_addr, 0x370a, 0x81);
    cam_i2c_write(axi_iic, device_addr, 0x3801, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x3621, 0xc7);
    cam_i2c_write(axi_iic, device_addr, 0x3801, 0x50);
    cam_i2c_write(axi_iic, device_addr, 0x3803, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x3827, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x3810, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x3804, 0x05);
    cam_i2c_write(axi_iic, device_addr, 0x3805, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5682, 0x05);
    cam_i2c_write(axi_iic, device_addr, 0x5683, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3806, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x3807, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x5686, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x5687, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x3a00, 0x78);
    cam_i2c_write(axi_iic, device_addr, 0x3a1a, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x3a13, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x3a18, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3a19, 0x7c);
    cam_i2c_write(axi_iic, device_addr, 0x3a08, 0x12);
    cam_i2c_write(axi_iic, device_addr, 0x3a09, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x3a0a, 0x0f);
    cam_i2c_write(axi_iic, device_addr, 0x3a0b, 0xa0);
    cam_i2c_write(axi_iic, device_addr, 0x3004, 0xff);
    cam_i2c_write(axi_iic, device_addr, 0x350c, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x350d, 0xd0);
    cam_i2c_write(axi_iic, device_addr, 0x3500, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3501, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3502, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x350a, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x350b, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3503, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x528a, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x528b, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x528c, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x528d, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x528e, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x528f, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5290, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5292, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5293, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5294, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5295, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5296, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5297, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5298, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5299, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x529a, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529b, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x529c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529d, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x529e, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529f, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x3a0f, 0x3c);
    cam_i2c_write(axi_iic, device_addr, 0x3a10, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x3a1b, 0x3c);
    cam_i2c_write(axi_iic, device_addr, 0x3a1e, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x3a11, 0x70);
    cam_i2c_write(axi_iic, device_addr, 0x3a1f, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x3030, 0x0b);
    cam_i2c_write(axi_iic, device_addr, 0x3a02, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3a03, 0x7d);
    cam_i2c_write(axi_iic, device_addr, 0x3a04, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3a14, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3a15, 0x7d);
    cam_i2c_write(axi_iic, device_addr, 0x3a16, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3a00, 0x78);
    cam_i2c_write(axi_iic, device_addr, 0x3a08, 0x09);
    cam_i2c_write(axi_iic, device_addr, 0x3a09, 0x60);
    cam_i2c_write(axi_iic, device_addr, 0x3a0a, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x3a0b, 0xd0);
    cam_i2c_write(axi_iic, device_addr, 0x3a0d, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x3a0e, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x5193, 0x70);
    cam_i2c_write(axi_iic, device_addr, 0x3620, 0x57);
    cam_i2c_write(axi_iic, device_addr, 0x3703, 0x98);
    cam_i2c_write(axi_iic, device_addr, 0x3704, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x589b, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x589a, 0xc5);
    cam_i2c_write(axi_iic, device_addr, 0x528a, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x528b, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x528c, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x528d, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x528e, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x528f, 0x28);
    cam_i2c_write(axi_iic, device_addr, 0x5290, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5292, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5293, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5294, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5295, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5296, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5297, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5298, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5299, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x529a, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529b, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x529c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529d, 0x28);
    cam_i2c_write(axi_iic, device_addr, 0x529e, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529f, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5282, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5300, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5301, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5302, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5303, 0x7c);
    cam_i2c_write(axi_iic, device_addr, 0x530c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x530d, 0x0c);
    cam_i2c_write(axi_iic, device_addr, 0x530e, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x530f, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5310, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5311, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5308, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5309, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x5304, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5305, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5306, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5307, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5314, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5315, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5319, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5316, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5317, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5318, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5380, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x5381, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5382, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5383, 0x4e);
    cam_i2c_write(axi_iic, device_addr, 0x5384, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5385, 0x0f);
    cam_i2c_write(axi_iic, device_addr, 0x5386, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5387, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5388, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x5389, 0x15);
    cam_i2c_write(axi_iic, device_addr, 0x538a, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538b, 0x31);
    cam_i2c_write(axi_iic, device_addr, 0x538c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538d, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538e, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538f, 0x0f);
    cam_i2c_write(axi_iic, device_addr, 0x5390, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5391, 0xab);
    cam_i2c_write(axi_iic, device_addr, 0x5392, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5393, 0xa2);
    cam_i2c_write(axi_iic, device_addr, 0x5394, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5480, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5481, 0x21);
    cam_i2c_write(axi_iic, device_addr, 0x5482, 0x36);
    cam_i2c_write(axi_iic, device_addr, 0x5483, 0x57);
    cam_i2c_write(axi_iic, device_addr, 0x5484, 0x65);
    cam_i2c_write(axi_iic, device_addr, 0x5485, 0x71);
    cam_i2c_write(axi_iic, device_addr, 0x5486, 0x7d);
    cam_i2c_write(axi_iic, device_addr, 0x5487, 0x87);
    cam_i2c_write(axi_iic, device_addr, 0x5488, 0x91);
    cam_i2c_write(axi_iic, device_addr, 0x5489, 0x9a);
    cam_i2c_write(axi_iic, device_addr, 0x548a, 0xaa);
    cam_i2c_write(axi_iic, device_addr, 0x548b, 0xb8);
    cam_i2c_write(axi_iic, device_addr, 0x548c, 0xcd);
    cam_i2c_write(axi_iic, device_addr, 0x548d, 0xdd);
    cam_i2c_write(axi_iic, device_addr, 0x548e, 0xea);
    cam_i2c_write(axi_iic, device_addr, 0x548f, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5490, 0x05);
    cam_i2c_write(axi_iic, device_addr, 0x5491, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5492, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x5493, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5494, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x5495, 0x60);
    cam_i2c_write(axi_iic, device_addr, 0x5496, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5497, 0xb8);
    cam_i2c_write(axi_iic, device_addr, 0x5498, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5499, 0x86);
    cam_i2c_write(axi_iic, device_addr, 0x549a, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x549b, 0x5b);
    cam_i2c_write(axi_iic, device_addr, 0x549c, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x549d, 0x3b);
    cam_i2c_write(axi_iic, device_addr, 0x549e, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x549f, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x54a0, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x54a1, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x54a2, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54a3, 0xed);
    cam_i2c_write(axi_iic, device_addr, 0x54a4, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54a5, 0xc5);
    cam_i2c_write(axi_iic, device_addr, 0x54a6, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54a7, 0xa5);
    cam_i2c_write(axi_iic, device_addr, 0x54a8, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54a9, 0x6c);
    cam_i2c_write(axi_iic, device_addr, 0x54aa, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54ab, 0x41);
    cam_i2c_write(axi_iic, device_addr, 0x54ac, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54ad, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x54ae, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x54af, 0x16);
    cam_i2c_write(axi_iic, device_addr, 0x3406, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5192, 0x04); // 0x04
    cam_i2c_write(axi_iic, device_addr, 0x5191, 0xf8); // 0xf8
    cam_i2c_write(axi_iic, device_addr, 0x5193, 0x70);
    cam_i2c_write(axi_iic, device_addr, 0x5194, 0xf0);
    cam_i2c_write(axi_iic, device_addr, 0x5195, 0xf0);
    cam_i2c_write(axi_iic, device_addr, 0x518d, 0x3d);
    cam_i2c_write(axi_iic, device_addr, 0x518f, 0x54);
    cam_i2c_write(axi_iic, device_addr, 0x518e, 0x3d);
    cam_i2c_write(axi_iic, device_addr, 0x5190, 0x54);
    cam_i2c_write(axi_iic, device_addr, 0x518b, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x518c, 0xbd);
    cam_i2c_write(axi_iic, device_addr, 0x5187, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x5188, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x5189, 0x6e);
    cam_i2c_write(axi_iic, device_addr, 0x518a, 0x68);
    cam_i2c_write(axi_iic, device_addr, 0x5186, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x5181, 0x50);
    cam_i2c_write(axi_iic, device_addr, 0x5184, 0x25);
    cam_i2c_write(axi_iic, device_addr, 0x5182, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x5183, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5184, 0x25);
    cam_i2c_write(axi_iic, device_addr, 0x5185, 0x24);
    cam_i2c_write(axi_iic, device_addr, 0x5025, 0x82);
    cam_i2c_write(axi_iic, device_addr, 0x5583, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x5584, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x5580, 0x02); // 0x02
    cam_i2c_write(axi_iic, device_addr, 0x3633, 0x07);
    cam_i2c_write(axi_iic, device_addr, 0x3702, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x3703, 0xb2);
    cam_i2c_write(axi_iic, device_addr, 0x3704, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x370b, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x370d, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x3620, 0x52);
    cam_i2c_write(axi_iic, device_addr, 0x3c00, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x5001, 0xFF);
    cam_i2c_write(axi_iic, device_addr, 0x5282, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5300, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5301, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5302, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5303, 0x7c);
    cam_i2c_write(axi_iic, device_addr, 0x530c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x530d, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x530e, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x530f, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5310, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5311, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5308, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5309, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x5304, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5305, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5306, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5307, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5314, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5315, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5319, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5316, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5317, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5318, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5500, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5502, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5503, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x5504, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5505, 0x7f);
    cam_i2c_write(axi_iic, device_addr, 0x5025, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5300, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5301, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5302, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5303, 0x7c);
    cam_i2c_write(axi_iic, device_addr, 0x530c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x530d, 0x0c);
    cam_i2c_write(axi_iic, device_addr, 0x530e, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x530f, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5310, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5311, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5308, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5309, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x5304, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5305, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5306, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5307, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5314, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5315, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x5319, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5316, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5317, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5318, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5380, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x5381, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5382, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5383, 0x1f);
    cam_i2c_write(axi_iic, device_addr, 0x5384, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5385, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x5386, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5387, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5388, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5389, 0xE1);
    cam_i2c_write(axi_iic, device_addr, 0x538A, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538B, 0x2B);
    cam_i2c_write(axi_iic, device_addr, 0x538C, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538D, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538E, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x538F, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5390, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5391, 0xB3);
    cam_i2c_write(axi_iic, device_addr, 0x5392, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5393, 0xA6);
    cam_i2c_write(axi_iic, device_addr, 0x5394, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5480, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5481, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x5482, 0x2a);
    cam_i2c_write(axi_iic, device_addr, 0x5483, 0x49);
    cam_i2c_write(axi_iic, device_addr, 0x5484, 0x56);
    cam_i2c_write(axi_iic, device_addr, 0x5485, 0x62);
    cam_i2c_write(axi_iic, device_addr, 0x5486, 0x6c);
    cam_i2c_write(axi_iic, device_addr, 0x5487, 0x76);
    cam_i2c_write(axi_iic, device_addr, 0x5488, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x5489, 0x88);
    cam_i2c_write(axi_iic, device_addr, 0x548a, 0x96);
    cam_i2c_write(axi_iic, device_addr, 0x548b, 0xa2);
    cam_i2c_write(axi_iic, device_addr, 0x548c, 0xb8);
    cam_i2c_write(axi_iic, device_addr, 0x548d, 0xcc);
    cam_i2c_write(axi_iic, device_addr, 0x548e, 0xe0);
    cam_i2c_write(axi_iic, device_addr, 0x548f, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5490, 0x3);
    cam_i2c_write(axi_iic, device_addr, 0x5491, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x5492, 0x3);
    cam_i2c_write(axi_iic, device_addr, 0x5493, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5494, 0x2);
    cam_i2c_write(axi_iic, device_addr, 0x5495, 0xa0);
    cam_i2c_write(axi_iic, device_addr, 0x5496, 0x2);
    cam_i2c_write(axi_iic, device_addr, 0x5497, 0x48);
    cam_i2c_write(axi_iic, device_addr, 0x5498, 0x2);
    cam_i2c_write(axi_iic, device_addr, 0x5499, 0x26);
    cam_i2c_write(axi_iic, device_addr, 0x549a, 0x2);
    cam_i2c_write(axi_iic, device_addr, 0x549b, 0xb);
    cam_i2c_write(axi_iic, device_addr, 0x549c, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x549d, 0xee);
    cam_i2c_write(axi_iic, device_addr, 0x549e, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x549f, 0xd8);
    cam_i2c_write(axi_iic, device_addr, 0x54a0, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54a1, 0xc7);
    cam_i2c_write(axi_iic, device_addr, 0x54a2, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54a3, 0xb3);
    cam_i2c_write(axi_iic, device_addr, 0x54a4, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54a5, 0x90);
    cam_i2c_write(axi_iic, device_addr, 0x54a6, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54a7, 0x62);
    cam_i2c_write(axi_iic, device_addr, 0x54a8, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54a9, 0x27);
    cam_i2c_write(axi_iic, device_addr, 0x54aa, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54ab, 0x09);
    cam_i2c_write(axi_iic, device_addr, 0x54ac, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x54ad, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x54ae, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x54af, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x54b0, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54b1, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x54b2, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54b3, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x54b4, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x54b5, 0xf0);
    cam_i2c_write(axi_iic, device_addr, 0x54b6, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x54b7, 0xdf);
    cam_i2c_write(axi_iic, device_addr, 0x5583, 0x5d);
    cam_i2c_write(axi_iic, device_addr, 0x5584, 0x5d);
    cam_i2c_write(axi_iic, device_addr, 0x5580, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x5587, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5588, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x558a, 0x09);
    cam_i2c_write(axi_iic, device_addr, 0x5589, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5000, 0xcf);
    cam_i2c_write(axi_iic, device_addr, 0x5800, 0x48);
    cam_i2c_write(axi_iic, device_addr, 0x5801, 0x31);
    cam_i2c_write(axi_iic, device_addr, 0x5802, 0x21);
    cam_i2c_write(axi_iic, device_addr, 0x5803, 0x1b);
    cam_i2c_write(axi_iic, device_addr, 0x5804, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x5805, 0x1e);
    cam_i2c_write(axi_iic, device_addr, 0x5806, 0x29);
    cam_i2c_write(axi_iic, device_addr, 0x5807, 0x38);
    cam_i2c_write(axi_iic, device_addr, 0x5808, 0x26);
    cam_i2c_write(axi_iic, device_addr, 0x5809, 0x17);
    cam_i2c_write(axi_iic, device_addr, 0x580a, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x580b, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x580c, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x580d, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x580e, 0x13);
    cam_i2c_write(axi_iic, device_addr, 0x580f, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x5810, 0x15);
    cam_i2c_write(axi_iic, device_addr, 0x5811, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5812, 0x8);
    cam_i2c_write(axi_iic, device_addr, 0x5813, 0x5);
    cam_i2c_write(axi_iic, device_addr, 0x5814, 0x4);
    cam_i2c_write(axi_iic, device_addr, 0x5815, 0x5);
    cam_i2c_write(axi_iic, device_addr, 0x5816, 0x9);
    cam_i2c_write(axi_iic, device_addr, 0x5817, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5818, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x5819, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x581a, 0x4);
    cam_i2c_write(axi_iic, device_addr, 0x581b, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x581c, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x581d, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x581e, 0x6);
    cam_i2c_write(axi_iic, device_addr, 0x581f, 0x9);
    cam_i2c_write(axi_iic, device_addr, 0x5820, 0x12);
    cam_i2c_write(axi_iic, device_addr, 0x5821, 0xb);
    cam_i2c_write(axi_iic, device_addr, 0x5822, 0x4);
    cam_i2c_write(axi_iic, device_addr, 0x5823, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5824, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5825, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x5826, 0x6);
    cam_i2c_write(axi_iic, device_addr, 0x5827, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x5828, 0x17);
    cam_i2c_write(axi_iic, device_addr, 0x5829, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x582a, 0x9);
    cam_i2c_write(axi_iic, device_addr, 0x582b, 0x6);
    cam_i2c_write(axi_iic, device_addr, 0x582c, 0x5);
    cam_i2c_write(axi_iic, device_addr, 0x582d, 0x6);
    cam_i2c_write(axi_iic, device_addr, 0x582e, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x582f, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x5830, 0x28);
    cam_i2c_write(axi_iic, device_addr, 0x5831, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x5832, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x5833, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x5834, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x5835, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x5836, 0x15);
    cam_i2c_write(axi_iic, device_addr, 0x5837, 0x1d);
    cam_i2c_write(axi_iic, device_addr, 0x5838, 0x6e);
    cam_i2c_write(axi_iic, device_addr, 0x5839, 0x39);
    cam_i2c_write(axi_iic, device_addr, 0x583a, 0x27);
    cam_i2c_write(axi_iic, device_addr, 0x583b, 0x1f);
    cam_i2c_write(axi_iic, device_addr, 0x583c, 0x1e);
    cam_i2c_write(axi_iic, device_addr, 0x583d, 0x23);
    cam_i2c_write(axi_iic, device_addr, 0x583e, 0x2f);
    cam_i2c_write(axi_iic, device_addr, 0x583f, 0x41);
    cam_i2c_write(axi_iic, device_addr, 0x5840, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x5841, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5842, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5843, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5844, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5845, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5846, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5847, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5848, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5849, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x584a, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x584b, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x584c, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x584d, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x584e, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x584f, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5850, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x5851, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x5852, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x5853, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x5854, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5855, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5856, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5857, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x5858, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x5859, 0xe);
    cam_i2c_write(axi_iic, device_addr, 0x585a, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x585b, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x585c, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x585d, 0xa);
    cam_i2c_write(axi_iic, device_addr, 0x585e, 0x9);
    cam_i2c_write(axi_iic, device_addr, 0x585f, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5860, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x5861, 0xb);
    cam_i2c_write(axi_iic, device_addr, 0x5862, 0xd);
    cam_i2c_write(axi_iic, device_addr, 0x5863, 0x7);
    cam_i2c_write(axi_iic, device_addr, 0x5864, 0x17);
    cam_i2c_write(axi_iic, device_addr, 0x5865, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5866, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x5867, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x5868, 0x16);
    cam_i2c_write(axi_iic, device_addr, 0x5869, 0x12);
    cam_i2c_write(axi_iic, device_addr, 0x586a, 0x1b);
    cam_i2c_write(axi_iic, device_addr, 0x586b, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x586c, 0x16);
    cam_i2c_write(axi_iic, device_addr, 0x586d, 0x16);
    cam_i2c_write(axi_iic, device_addr, 0x586e, 0x18);
    cam_i2c_write(axi_iic, device_addr, 0x586f, 0x1f);
    cam_i2c_write(axi_iic, device_addr, 0x5870, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x5871, 0x16);
    cam_i2c_write(axi_iic, device_addr, 0x5872, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x5873, 0xf);
    cam_i2c_write(axi_iic, device_addr, 0x5874, 0x13);
    cam_i2c_write(axi_iic, device_addr, 0x5875, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x5876, 0x1e);
    cam_i2c_write(axi_iic, device_addr, 0x5877, 0x17);
    cam_i2c_write(axi_iic, device_addr, 0x5878, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x5879, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x587a, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x587b, 0x1e);
    cam_i2c_write(axi_iic, device_addr, 0x587c, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x587d, 0x1c);
    cam_i2c_write(axi_iic, device_addr, 0x587e, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x587f, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x5880, 0x1b);
    cam_i2c_write(axi_iic, device_addr, 0x5881, 0x1f);
    cam_i2c_write(axi_iic, device_addr, 0x5882, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5883, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x5884, 0x1d);
    cam_i2c_write(axi_iic, device_addr, 0x5885, 0x1e);
    cam_i2c_write(axi_iic, device_addr, 0x5886, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x5887, 0x1a);
    cam_i2c_write(axi_iic, device_addr, 0x528a, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x528b, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x528c, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x528d, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x528e, 0x40);
    cam_i2c_write(axi_iic, device_addr, 0x528f, 0x50);
    cam_i2c_write(axi_iic, device_addr, 0x5290, 0x60);
    cam_i2c_write(axi_iic, device_addr, 0x5292, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5293, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x5294, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5295, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x5296, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5297, 0x08);
    cam_i2c_write(axi_iic, device_addr, 0x5298, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5299, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x529a, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529b, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x529c, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529d, 0x28);
    cam_i2c_write(axi_iic, device_addr, 0x529e, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x529f, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x5282, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5680, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5681, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5682, 0x05);
    cam_i2c_write(axi_iic, device_addr, 0x5683, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5684, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5685, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x5686, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x5687, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x5180, 0xff);
    cam_i2c_write(axi_iic, device_addr, 0x5181, 0x52);
    cam_i2c_write(axi_iic, device_addr, 0x5182, 0x11);
    cam_i2c_write(axi_iic, device_addr, 0x5183, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5184, 0x25);
    cam_i2c_write(axi_iic, device_addr, 0x5185, 0x24);
    cam_i2c_write(axi_iic, device_addr, 0x5186, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5187, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5188, 0x14);
    cam_i2c_write(axi_iic, device_addr, 0x5189, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x518a, 0x60);
    cam_i2c_write(axi_iic, device_addr, 0x518b, 0xa2);
    cam_i2c_write(axi_iic, device_addr, 0x518c, 0x9c);
    cam_i2c_write(axi_iic, device_addr, 0x518d, 0x36);
    cam_i2c_write(axi_iic, device_addr, 0x518e, 0x34);
    cam_i2c_write(axi_iic, device_addr, 0x518f, 0x54);
    cam_i2c_write(axi_iic, device_addr, 0x5190, 0x4c);
    cam_i2c_write(axi_iic, device_addr, 0x5191, 0xf8);
    cam_i2c_write(axi_iic, device_addr, 0x5192, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x5193, 0x70);
    cam_i2c_write(axi_iic, device_addr, 0x5194, 0xf0);
    cam_i2c_write(axi_iic, device_addr, 0x5195, 0xf0);
    cam_i2c_write(axi_iic, device_addr, 0x5196, 0x03);
    cam_i2c_write(axi_iic, device_addr, 0x5197, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x5198, 0x05);
    cam_i2c_write(axi_iic, device_addr, 0x5199, 0x2f);
    cam_i2c_write(axi_iic, device_addr, 0x519a, 0x04);
    cam_i2c_write(axi_iic, device_addr, 0x519b, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x519c, 0x06);
    cam_i2c_write(axi_iic, device_addr, 0x519d, 0xa0);
    cam_i2c_write(axi_iic, device_addr, 0x519e, 0xa0);
    cam_i2c_write(axi_iic, device_addr, 0x3a0f, 0x3c);
    cam_i2c_write(axi_iic, device_addr, 0x3a10, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x3a1b, 0x3c);
    cam_i2c_write(axi_iic, device_addr, 0x3a1e, 0x30);
    cam_i2c_write(axi_iic, device_addr, 0x3a11, 0x70);
    cam_i2c_write(axi_iic, device_addr, 0x3a1f, 0x10);
    cam_i2c_write(axi_iic, device_addr, 0x3800, 0x1);
    cam_i2c_write(axi_iic, device_addr, 0x3801, 0x50);
    cam_i2c_write(axi_iic, device_addr, 0x3802, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x3803, 0x8);
    cam_i2c_write(axi_iic, device_addr, 0x3804, 0x5);
    cam_i2c_write(axi_iic, device_addr, 0x3805, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x3806, 0x3);
    cam_i2c_write(axi_iic, device_addr, 0x3807, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x3808, 0x3);
    cam_i2c_write(axi_iic, device_addr, 0x3809, 0x20);
    cam_i2c_write(axi_iic, device_addr, 0x380a, 0x2);
    cam_i2c_write(axi_iic, device_addr, 0x380b, 0x58);
    cam_i2c_write(axi_iic, device_addr, 0x380c, 0xc);
    cam_i2c_write(axi_iic, device_addr, 0x380d, 0x80);
    cam_i2c_write(axi_iic, device_addr, 0x380e, 0x3);
    cam_i2c_write(axi_iic, device_addr, 0x380f, 0xe8);
    cam_i2c_write(axi_iic, device_addr, 0x5001, 0x7f);
    cam_i2c_write(axi_iic, device_addr, 0x5680, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5681, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5682, 0x5);
    cam_i2c_write(axi_iic, device_addr, 0x5683, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5684, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5685, 0x0);
    cam_i2c_write(axi_iic, device_addr, 0x5686, 0x3);
    cam_i2c_write(axi_iic, device_addr, 0x5687, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x5687, 0xc0);
    cam_i2c_write(axi_iic, device_addr, 0x3815, 0x02);
    cam_i2c_write(axi_iic, device_addr, 0x3503, 0x00);
    cam_i2c_write(axi_iic, device_addr, 0x3818, 0x81); // No Mirror
    cam_i2c_write(axi_iic, device_addr, 0x3621, 0xa7);
    
    cam_i2c_write(axi_iic, device_addr, 0x4740, 0x21);
    
    cam_i2c_write(axi_iic, device_addr, 0x501e, 0x2a);
    cam_i2c_write(axi_iic, device_addr, 0x5002, 0x78);
    cam_i2c_write(axi_iic, device_addr, 0x501f, 0x01);
    cam_i2c_write(axi_iic, device_addr, 0x4300, 0x61);
    
    return(0);
}

  1. 2019年08月19日 21:20 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 でカメラ画像をDisplayPort に出力する2(Ultra96-V2 の環境整備)

Ultra96-V2 でカメラ画像をDisplayPort に出力する1(ブロックデザイン)”の続き。

前回は、Ultra96-V2 でPMOD 拡張ボードに搭載したOV5642 カメラの画像をUltra96-V2 のDisplayPort から出力したいということで、Ultra96-V1 のブロックデザインの内のZynq UltraScale+ MPSoC のDDR の設定をUltra96-V2 用に変更して、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。今回は、bin ファイルを作成し、Ultra96-V2 のDebian を起動して、環境の整備を行う。

最初に、Vivado 2018.2 でビットストリームが生成できたので、ハードウェアをエクスポートして、SDK を立ち上げた。 cam_dp_183.sdk ディレクトリに新たに cam_dp_wrapper_hw_platform_1 が生成された。
cam_dp_V2_7_190818.png

カメラ画像をDisplayPortに出力する7(binファイルの生成)”の cam_dp_wrapper.bif と bootgen.sh を作成した。bootgen.sh に実行権限を与えて、実行した。
chmod +x bootgen.sh
./bootgen.sh


cam_dp_wrapper.bin が生成された。これをUltra96-V2 の /home/fpga/examples/cam_dp_V2/ ディレクトリにSFTP でアップロードした。
cam_dp_V2_9_190818.png

次に、Ultra96-V2 の /home/fpga/examples/cam_dp_V2/ ディレクトリに入った。
fpga-load.dts を作った。これからのファイルは、”カメラ画像をDisplayPortに出力する8(Ultra96 での準備)”のコードをコピーして作っている。ただし、fclk01-zynqmp.dts は修正してある。
cam_dp_V2_10_190818.png

fclk01-zynqmp.dts を示す。このファイルは、、”カメラ画像をDisplayPortに出力する8(Ultra96 での準備)”のコードを修正してある。(注)画像の pl_clk0 は 200 MHz ですが、コードの方の 220 MHz に修正済みです。
cam_dp_V2_11_190818.png

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        __overlay__ {
            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&zynqmp_clk 0x47 &zynqmp_clk 0>;
                insert-rate   = "220000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
            
            fclk1 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&zynqmp_clk 0x48 &zynqmp_clk 1>;
                insert-rate   = "24000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
        };
    };
};



cam_dp.dts を示す。
cam_dp_V2_12_190818.png

dtc_script.sh を示す。
cam_dp_V2_13_190818.png

lddtovary.sh を示す。
cam_dp_V2_14_190818.png

rmdtovary.sh を示す。
cam_dp_V2_15_190818.png

.sh のファイルに実行権限を与えた。
chmod +x *.sh
cam_dp_V2_16_190818.png

./dtc_script.sh
でDTS ファイルをコンパイルして、DTB ファイルを出力した。
cam_dp_V2_17_190818.png

./lddtovary.sh
を実行してデバイスツリーをロードした。ログを示す。
cam_dp_V2_18_190818.png

fclkcfg でエラーが出ている。

zynqmp_clk_divider_set_rate() set divider failed for pl0_ref_div1, ret = -22


これのせいか? 220 MHz のはずの pl_clk0 が 99999999 Hz になってしまっている。

/sys/class/uio は uio0 〜 uio 9 まであった。この内の uio4 〜 uio9 までが cam_dp.dtb でデバイスツリーに追加した uio だ。
cam_dp_V2_19_190818.png

udmabuf4 もデバイスツリーに追加されていた。
cam_dp_V2_20_190818.png
  1. 2019年08月18日 15:47 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 でカメラ画像をDisplayPort に出力する1(ブロックデザイン)

Ultra96-V2 のDisplayPort にテストパターンを表示する4(テストパターンを表示できた)”でUltra96-V2 でDisplayPort にテストパターンを表示することができた。今回は、Ultra96-V2 でカメラ画像をDisplayPort に出力してみようと思う。

カメラ画像をDisplayPortに出力する7(ブロックデザインの変更)”の cam_dp_183 の Vivado 2018.3 プロジェクトがあるので、ディレクトリごと Ultra96V2 ディレクトリにコピーして、ディレクトリの名前を cam_dp_V2_183 に変更した。
cam_dp_V2_1_190817.png

Vivado 2018.3 で ~/HDL/Ultra96/Ultra96V2/cam_dp_V2_183/ ディレクトリの cam_dp_183 プロジェクトを開いた。
cam_dp_V2_2_190817.png

今回は、ひでみさんの「FPGAの内容が薄い本2」に書かれているが、Ultra96V1 とUltra96V2 の設定の違いを使用して、Ultra96V1 用のプロジェクトをUltra96-V2 用に変換してみよう。

ブロックデザインのZYNQ UltraScale+ IP をダブルクリックして、設定を開き、Page Navigator から DDR Configuration を開く。
cam_dp_V2_3_190817.png

DDR Configuration 画面で、
DRAM Device Capacity (per 32-bit channel) を 16384 MBits
Row Address Count (Bits) を 16
Dual Rank のチェックボックスをのチェックを無し
に変更した。
cam_dp_V2_4_190817.png

Address Editor を示す。
cam_dp_V2_6_190817.png

変更後に論理合成、インプリメンテーション、ビットストリームの生成を行った。
うまく行ったようだ。結果を示す。
cam_dp_V2_5_190817.png
  1. 2019年08月17日 05:32 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 のDisplayPort にテストパターンを表示する4(テストパターンを表示できた)

Ultra96-V2 のDisplayPort にテストパターンを表示する3(各種スクリプト・ファイルやDTS ファイルの用意)”の続き。

前回は、各種スクリプト・ファイルやDTS ファイルを用意し、DTS ファイルをコンパイルしてDTB ファイルに変換した。今回は、つまずきはあったが、テストパターンをDisplayPort に出力することができた。

最初に、pattarn_gen_axis.c を gcc でコンパイルした。
gcc -o pattern_gen_axis pattern_gen_axis.c
次に、displayport_test_xga1_sync.bin を /lib/firmware/ ディレクトリにコピーした。
sudo cp displayport_test_xga1_sync.bin /lib/firmware/
DisplayPort_test_V2_35_190815.png

./lddtovray.sh
を実行したところエラーが発生した。
lddtovray.sh のコマンドを1個ずつ実行していったところ、fclkcfg でエラーが出ているのが分かった。
fclkcfg の DTS ファイルを下に示す。
DisplayPort_test_V2_27_190814.png

だが、ikwzm さんの”ZynqMP 向け Debian/Linux(v2019.1版) でFPGA クロックの周波数の変更に失敗する件”を見ると、fclkcfg の DTS ファイルの書き方が違っている。ikwzm さんがツィッターで教えていただいたのだが、

大元のデバイスツリーのクロックコントローラーのラベル(シンボル)が v2018.2 では &clk だったのが v2019.1 から &zynqmp_clk に変更されちゃいました。

だそうだ。
という訳で、fclk0-zynqmp.dts を書き換えた。

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        __overlay__ {
            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&zynqmp_clk 0x47 &zynqmp_clk 0>;
                insert-rate   = "100000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
        };
    };
};


DisplayPort_test_V2_37_190815.png

./dtc_script.sh
コンパイルしてから、fclkcfg のデバイスツリーをロードしたところ、問題なくロードできた。
下の図に示す。ピンクで囲ったところが、fclkcfg のエラー部分だ。
DisplayPort_test_V2_36_190815.png

DisplayPort_test_V2_38_190815.png

/sys/class/fclk0/ ディレクトリが生成されている。
DisplayPort_test_V2_39_190815.png

uio のデバイスツリーのロードを行った。
sudo mkdir /config/device-tree/overlays/pattern_gen_axis
sudo cp pattern_gen_axis.dtb /config/device-tree/overlays/pattern_gen_axis/dtbo


同様に、/sys/classe/ を見ると、uio0 〜 uio4 があったが、その内の uio4 の name が pattern_gen_axis-uio だった。
DisplayPort_test_V2_40_190815.png

ということは、pattern_gen_axis の uio 番号が違っているので、pattern_gen_axis.c を変更した。
DisplayPort_test_V2_41_190815.png

// pattern_gen_axis.c
// 2019/01/18 by marsee
// 2019/08/15 : Changed to /dev/uio4 for Ultra96-V2. by marsee
//

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

int main(){
    int fd4;
    volatile unsigned *pga;
    int i;

    // uio initialize (uio1)
    fd4 = open("/dev/uio4", O_RDWR|O_SYNC); // pattern_gen_axis IP
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (pattern_gen_axis) open error\n");
        exit(1);
    }
    pga = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!pga){
        fprintf(stderr, "pattern_gen_axis mmap error\n");
        exit(1);
    }

    pga[4] = 768; // v_size
    pga[6] = 1024; // h_size
    pga[8] = 0x1; // init_done = 1
    
    printf("sizeof volatile unsigned = %d\n", sizeof(volatile unsigned));
    
    printf("v_size = %d, h_size = %d, init_done = %d\n", pga[4], pga[6], pga[8]);
    
    munmap((void *)pga, 0x10000);
    close(fd4);
    
    return(0);
}


もう一度、gcc でコンパイルした。
gcc -o pattern_gen_axis pattern_gen_axis.c
pattern_gen_axis を sudo で実行した。
sudo ./pattern_gen_axis
DisplayPort の設定を行った。
./disp_pattern.sh
DisplayPort_test_V2_42_190815.png

しかし、memwrite が無かった。
Ultra96のDisplayPortを使用するためのテスト3(実機テスト)”から memwrite.c にコードを持ってきた。
DisplayPort_test_V2_43_190815.png

gcc -o memwrite memwrite.c
でコンパイルし、実行したところ、DisplayPort にテストパターンが表示された。良かった。。。
DisplayPort_test_V2_44_190815.png

DisplayPort_test_V2_45_190816.jpg
  1. 2019年08月16日 04:29 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 のDisplayPort にテストパターンを表示する2(binファイルの作成)

Ultra96-V2 のDisplayPort にテストパターンを表示する1(プロジェクトの作成)”の続き。

前回は、Ultra96-V2 のボード・ファイルを使用して、Ultra96-V2 のDisplayPort にテストパターンを表示するためのブロックデザインを作成した。今回は、それを論理合成、インプリメンテーション、ビットストリームの生成を行って、bin ファイルを作成する。

ブロックデザインが完成したので、HDL wrapper file を作成し、displayport_test.xdc の制約ファイルを”Ultra96のDisplayPortを使用するためのプロジェクトを作成する1(DisplayPort_test_XGA1_sync)”のプロジェクトからコピーした。
DisplayPort_test_V2_15_190812.png

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

成功したので、ハードウェアをエクスポートして、SDK を起動した。
DisplayPort_test_V2_17_190813.png

これで、 .sdk ディレクトリが生成された。
displayport_test_wrapper_hw_platform_0 ディレクトリから displayport_test_wrapper.bit をDisplayPort_test_XGA1_sync_V2.sdk ディレクトリにコピーした。
Ultra96のDisplayPortを使用するためのプロジェクトを作成する1(DisplayPort_test_XGA1_sync)”のプロジェクトからdisplayport_test_wrapper.bif と bootgen.sh をコピーした。
DisplayPort_test_V2_18_190813.png

./bootgen.sh
を実行すると、displayport_test_xga1_sync.bin が生成された。
DisplayPort_test_V2_19_190813.png

DisplayPort_test_V2_20_190813.png
  1. 2019年08月13日 09:44 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 のDisplayPort にテストパターンを表示する1(プロジェクトの作成)

Ultra96-V2 のDisplayPort にテストパターンを表示してみようということで、”Ultra96のDisplayPortを使用するためのプロジェクトを作成する1(DisplayPort_test_XGA1_sync)”を参照して Vivado 2018.3 の DisplayPort_test_XGA1_sync_V2 プロジェクトを作成した。

Vivado 2018.3 を立ち上げて DisplayPort_test_XGA1_sync_V2 プロジェクトを作成した。途中のダイアログの設定を示す。
まずは、プロジェクトのロケーションとプロジェクト名を示す。
DisplayPort_test_V2_1_190812.png

Ultra96V2 のボード・ファイルを適用する。
DisplayPort_test_V2_2_190812.png

サーマリ。
DisplayPort_test_V2_3_190812.png

DisplayPort_test_XGA1_sync_V2 プロジェクトが作成された。
DisplayPort_test_V2_4_190812.png

Ultra96のDisplayPortを使用するためのプロジェクトを作成する1(DisplayPort_test_XGA1_sync)”のプロジェクトから axi2video_out_IP と pattern_gen_axis_IP をコピーした。
DisplayPort_test_V2_5_190812.png

Zynq UltraScale+ MPSoC をAdd IP した。
DisplayPort_test_V2_6_190812.png

Run Block Automation をクリックした。
表示されたダイアログをデフォルトのまま、OK ボタンをクリックした。PS に設定が入力される。
DisplayPort_test_V2_7_190812.png

Ultra96V2 の設定が反映された。
DisplayPort_test_V2_8_190812.png

Zynq UltraScale+ MPSoC をダブルクリックして設定を行う。
PS-PL Configuration で Live Video を 1 にして、AXI_HPM1FPD のチェックを外した。
DisplayPort_test_V2_9_190812.png

次にDDR Configuration だが、”Ultra96のDisplayPortを使用するためのプロジェクトを作成する1(DisplayPort_test_XGA1_sync)”のDDR Configuration を示す。つまり、Ultra96V1 のDDR の設定だ。
DisplayPort_test_V2_10_190812.png

次に、新しいUltra96V2 にDDR Configuration の設定を示す。ひでみさんの「FPGAの内容が薄い本2」に書かれているが、Ultra96V1 とUltra96V2 の設定の違いを示す。

項目                    Ultra96V1   Ultra96V2
DRAM Device Capacity(per 32-bit channel)  8192 MBits 16384 MBits
Row Address Count(Bits)           15      16
Dual Rank                  チェック  チェック無し


DisplayPort_test_V2_11_190812.png

Clock Configuration では、PL0 を 220 MHz に設定した。
DisplayPort_test_V2_12_190812.png

Zynq UltraScale+ MPSoC はこうなった。
DisplayPort_test_V2_13_190812.png

axi2video_out_IP と pattern_gen_axis_IP をAdd IP して配線した。
DisplayPort_test_V2_14_190812.png

これでブロックデザイン完成。
Address Editor を示す。
DisplayPort_test_V2_26_190814.png
  1. 2019年08月12日 10:18 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0
»