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

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

FPGAの部屋

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

FPGAの部屋のブログの今年を振り返る

今年もこの記事を含めて、37+30+29+29+33+30+28+38+35+36+30+28 = 383 記事書きました。技術的な記事ばかりじゃなく、映画を見たよとか、走ったよという記事もありますが、よく記事を書いたと思います。

記事で書いてきたことは、やはり、畳込みニューラルネットワークをFPGA で実装したという記事が多いです。今年は、「ゼロから作るDeep Learning」の環境から、Keras + TensorFlow の環境に乗り換えることができました。それに、HLS ストリームを使用して、CNN のテンプレートを作ることもできました。このテンプレートを使用するとパラメータを入れてインスタンスするだけで、CNN が構成できるようになりました。
そうそう、白線間走行用CNN で走る Zybot に自宅に作ったコースを走らせるというプロジェクトですが、うまく行かなくて止まっています。来年は、Ultra96 に換装してガボールフィルタを使った自作走行システムで走らせながらCNN の学習データを取得するか?もしくは、自分でラジコンで走らせながら学習データを取得したいですね。そして、その学習データを元に白線間走行用CNN の学習を行ってZybot に白線間を走らせたいです。

それに常用しているVivado HLS 、もうこれなしではIP 作れないと言っても過言ではないかも?です。今年は、筑波大学でVivado HLS のセミナをやったのと、近隣の研究所でVivado HLS のセミナを開催中です。

そうそうUltra96 を使うようになって、低速コネクタに挿入してPMOD に変換する変換基板も作りました。そして、カメラを接続して、BMPファイルを作れるのを確認できました。その過程でOV5642 も使えるようになったのが嬉しかったです。来年はできればコミケなどで頒布したいですね。

2018.3 から SDSoC もWebPACK が出て無料で使えるようになりました。SDSoC はチューニングがVivado HLS ほどできないところはありますが、使っていきたいと思います。

トランジスタ技術11月号に、「手書き数字認識用FPGAニューラル・ネットワーク・システムの製作」という題名で書かせていただきました。付録のDVD にZYBO Z7-20 用のMNIST のCNN を使用した判定システムのVivado プロジェクトが入っています。ただ、使用しているカメラのMT9D111 が廃番になってしまいました。その代わりにOV5642 カメラのシステムを開発中です。
  1. 2018年12月31日 06:03 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

ZYBO Z7-20でのMNISTの実装にOV5642を使用する2

ZYBO Z7-20でのMNISTの実装にOV5642を使用する1”の続き。

前回は、ZYBO Z7-20 のMNIST の実装で、OV5642 を使用してみたいということで、やってみたところ、うまく行かない。mt9d111_inf_axis_0 のAXI4-Stream のトランザクションもないので、mt9d111_inf_axis_0 がおかしいようだということが分かった。今回は、Vivado Analyzer を入れて2日ほど調査したが、原因が分からなかった。やっと今日、その原因が分かったのだった。原因は、アプリケーション・ソフトでのコマンド順によるものだった。

さて、2日間、Vivado Analyzer を入れたり削除したり、いろいろな配線を観察したりしていたのだが、1回だけカメラ画像を表示することができた。だが、その1回だけで、もう何度やってもカメラ画像は表示することができなかった。1回うまく表示できたときのVivado Analyzer の波形を示す。
最初は、AXI-Stream 波形だ。これは、camera-interface 内のカメラ画像のAXI4-Stream 波形をキャプチャしたものだ。 Slot_0 が mt9d111_inf_axis_0 のAXI4-Stream 波形だ。うまく行っているのが分かる。
ZYBO_Z7_OV5642_10_181229.png

うまく行っている時の mt9d111_inf_axis_0 の波形を示す。
ZYBO_Z7_OV5642_11_181229.png

HREF と VSYNC の波形を示す。
ZYBO_Z7_OV5642_12_181230.jpg

カメラ画像を示す。なお、上下は逆になっているが、レジスタでこれしか設定できなかったためで、これで正しい。
ZYBO_Z7_OV5642_13_181230.jpg

しかし、Ultra96 はほぼ同じ回路でカメラ画像を表示できているし、なぜカメラ画像が表示できないか悩んでいた。今朝、私の好きなテレビ東京の路線バスの旅を見終わったら、ひらめいた。アプリケーション・ソフトがまずいのでは?ということだった。
もしかして、MT9D111 よりも大幅に長くなったレジスタ設定ルーチンがだめなのでは?と思い、よく見直してみた。

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

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

cam_reg_set(ov5642_i2c_axi_lites, 0x78); // OV5642 register set

ov5642_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)
ov5642_axi_lites[1] = 0; // One_shot_mode is disabled


ov5642_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; を実行すると、mt9d111_inf_axis のリセットが外れて動作するようになるのだが、最初のリセット解除は上に示す最初の行のコメントアウトされている部分にあった。ここで、リセットが外れて、カメラ画像のキャプチャが開始されるのだが、OV5642では、レジスタ設定を行わないとPCLK も出力されていない状況になっている。なので、非同期FIFO がおかしくなってしまっているのではないか?という仮定をした。そして、上のコードに差し替えるとカメラ画像が毎回表示されるようになった。やはり、クロックが出力されていない状態のため非同期FIFO が狂ってしまったようだ。ちなみにMT9D111 は最初からクロックも出力され、SVGA の設定になっているため、問題なかったようだ。
これで不具合は解消されたが、Ultra96 はなぜ大丈夫なのか?という疑問がある。多分今回と同じコードにしておいたほうが良いと思う。
動作も確認したので、”秋月電子カメラモジュールOV5642を使う15(完成)”のcam_cap_ov5642.cpp を修正した。
  1. 2018年12月30日 15:06 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

ZYBO Z7-20でのMNISTの実装にOV5642を使用する1

Ultra96 のUltra96 用PMOD 拡張ボード経由でOV5642 を使用することができた。
今回は、ZYBO Z7-20 のMNIST の実装で、OV5642 を使用してみたい。

Ultra96 では、MT9D111 のインターフェース用IP をそのまま使用して、OV5642 に行くクロック周波数のXCLK を 24 MHz に下だけだった。ZYBO Z7-20 でもXCLK を 24 MHz にしただけで確かめてみよう。

まずは、MNIST_CNN_Z7 をコピーしてMNIST_Z7_OV5642 ディレクトリとした。
ZYBO_Z7_OV5642_1_181228.png

MNIST_Z7_OV5642 ディレクトリのMNIST_CNN_Z7 プロジェクトを起動して、ZYNQ7 Processing System をダブルクリックして、ダイアログを表示させた。
ダイアログで、Page Navigator の Clock Configuration を選択して、FCLK_CLK2 を 24 MHz に変更した。
ZYBO_Z7_OV5642_2_181228.png

これで、論理合成、インプリメンテーション、ビットストリームの生成を行って、ハードウェアをエクスポートし、SDKを立ち上げてZYBO Z7-20 で確かめてみたが、画面はランダムパターンを表示されていて、カメラ画像を表示していなかった。

そこで、mt9d111_inf_axis_0 の m_axis と axi_vdma_0 の S_AXIS_S2MM 、 axi_vdma_0 の M_AXI_S2MM 、bmd_controller_axim_0 のM_AXI に Debug を指定して、Vivado Analyzer のプローブを仕掛けた。
ZYBO_Z7_OV5642_3_181228.png

ZYBO_Z7_OV5642_4_181228.png

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

タイミングエラーが出ているが、他は問題なさそう。
Implemented Design を開いて、タイミングエラーを見た。
Intra-Clock Paths と Inter-Clock Paths にタイミングエラーが出ていた。
Intra-Clock Paths の方から見ると、clk_fpga_0 の Setup がタイミングエラーだった。
ZYBO_Z7_OV5642_6_181228.png

mnist_conv_nn のところで、-0.177 ns だけタイミングエラーだった。

Inter-Clock Paths のタイミングエラーは、clk_fpga_0 to pclk_buf の間で、 -0.306 ns だった。
ZYBO_Z7_OV5642_7_181228.png

大丈夫そうなので、2つのタイミングエラーは無視して、これでやってみることにした。

まずは、何かアプリケーション・ソフトを起動しないとPL のクロックが出力されないので、SDK を立ち上げてHelloWorld を追加で作成した。アプリ起動時の波形が取りたい場合には、HelloWorld を起動して、PL のクロックを出力させて、Vivado Analyzer を起動してトリガを設定する必要があるためだ。
SDK には、すでにOV5642 用に設定レジスタを設定する cam_reg_set() 関数を追加した mnist_conv_soft_test.cpp が用意されている。
ZYBO_Z7_OV5642_8_181228.png

mnist_conv_soft_test.cpp のバイナリを起動した。

Vivado Analyzer で見ると、bmd_controller_axim_0 のM_AXI はトランザクションが発生しているが、その他はトランザクションが無い。mt9d111_inf_axis_0 のAXI4-Stream のトランザクションもないので、mt9d111_inf_axis_0 がおかしいようだ。最初にOV5642 の波形を調べる必要がありそうだ。
  1. 2018年12月28日 05:33 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードのパーツリスト

Ubuntu 18.04 の Kicad 5.0 でBOM出力”でUltrao96用PMOD拡張ボードのBOM は出したのですが、アカデミック向けにとりあえずはUltra96用PMOD拡張ボードを無料で配布して、具合を見てもらうと思っています。
そのためにパーツ購入リストを作ってみました。
Kicad_BOM_12_181227.png

パーツ購入リストのCSV を貼っておきます。

Ultra96用PMOD拡張ボード・パーツリスト,,,,,,,,
,,,,,,,,
番号,パーツ名,規格,メーカー,販売店,販売店品番,数量,URL,備考
1,プリント基板,,自作,,,,,
2,DC-DCコンバータ(3.3V0.5A),M78AR033-0.5,MINMAX,秋月電子,M-07178,1,http://akizukidenshi.com/catalog/g/gM-07178/,
3,L型ピンソケット 2×10(20P),,,秋月電子,C-05755,2,http://akizukidenshi.com/catalog/g/gC-05755/,2x6に割って使用する
4,チップ積層セラミックコンデンサー 0.1ΜF50V (1608),,,秋月電子,P-13374,5,http://akizukidenshi.com/catalog/g/gP-13374/,40個入りなのでその内の5個
5,チップ積層セラミックコンデンサー 10μF35V (1608),,,秋月電子,P-13161,1,http://akizukidenshi.com/catalog/g/gP-13161/,10個入りなのでその内の1個
6,チップ抵抗 1/10W100kΩ (1608),,,秋月電子,R-06104,4,http://akizukidenshi.com/catalog/g/gR-06104/,2500個入りなのでその内の4個
7,チップ抵抗 1/10W1kΩ (1608),,,秋月電子,R-06102,16,http://akizukidenshi.com/catalog/g/gR-06102/,2500個入りなのでその内の16個
8,2mmピッチピンヘッダ 2×40 (80P),,,秋月電子,C-06075,0.5,http://akizukidenshi.com/catalog/g/gC-06075/,2x20Pが必要なので半分に割る
9,レベル変換IC、LSF0108,LSF0108QPWRQ1,TI,Mouser,595-LSF0108QPWRQ1,2,https://www.mouser.jp/ProductDetail/Texas-Instruments/LSF0108QPWRQ1?qs=%2fha2pyFaduj40xzY0wIIslfiL%252bt2vTPrqJGU6zqxqq4nN97qLcRCZA==,


なお、連続運転や温度変動試験はしていないので、とりあえずは連続運転はご遠慮願います。熱くなっているモジュールは無いので、問題ないとは思いますが。。。
  1. 2018年12月27日 06:53 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ubuntu 18.04 の Kicad 5.0 でBOM出力

BOOTH の「KiCad 5.0入門実習テキスト『KiCad Basics for 5.0』 #マッハ新書」を購入してあるのだが、その 75 ページの「15.1. BOM(部品表)の生成」を参考にして、Ultra96 用PMOD 拡張ボードのBOMを作ってみた。

Ultra96 用PMOD 拡張ボードのKicad プロジェクト Ultra96_ext_board2 を開いて、回路図エディタを立ち上げた。
Kicad_BOM_1_181227.png

回路図エディタが開いた。
Generate Bill of Materials アイコンをクリックした。
Kicad_BOM_2_181227.png

Bill of Materials ダイアログが開いた。
Add Plugin ボタンをクリックして、Plugin を指定する。
Kicad_BOM_3_181227.png

Plugin files: ダイアログが開く。
/usr/share/kicad/plugin/ ディレクトリにある bom2grouped_csv.xsl を選択して、開くボタンをクリックした。
Kicad_BOM_4_181227.png

Plugin name ダイアログが表示された。OK ボタンをクリックした。
Kicad_BOM_5_181227.png

Bill of Materials ダイアログに bom2grouped_csv が登録された。
Kicad_BOM_6_181227.png

Bill of Materials ダイアログの Command line: の "%O" を "%O.csv" に変更して、Generate ボタンをクリックした。
Kicad_BOM_7_181227.png

Generate 後には、Plugin Infomation: にRun comannd が表示された。
Kicad_BOM_8_181227.png

Kicad プロジェクトに Ultra96_ext_board.csv が追加された。
Kicad_BOM_9_181227.png

ここから起動できなったので、ファイルマネージャーで Ultra96_ext_board2 ディレクトリを見たら、Ultra96_ext_board.csv が合ったので、ダブルクリックして起動した。
Kicad_BOM_10_181227.png

LibreOffice でUltra96_ext_board.csv が表示できた。
Kicad_BOM_11_181227.png

BOOTH の「KiCad 5.0入門実習テキスト『KiCad Basics for 5.0』 #マッハ新書」がとてもためになった。その他、便利に参照させてもらっている。
  1. 2018年12月27日 05:40 |
  2. CADツール
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードを使って、PMOD VGAで画像出力3(実機テスト)

Ultra96用PMOD拡張ボードを使って、PMOD VGAで画像出力2(Vivado編)”の続き。

前回は、Vivado 2018.3 で display_cont_Ultra96_183 プロジェクトを作成し、そのプロジェクトのディレクトリに display_cont_ip ディレクトリを作成した。display_cont_ip ディレクトリに前回Vivado HLS で作成したIP をコピーした。そして、論理合成、インプリメンテーション、ビットストリームの生成を行って、ビットファイルが生成された。今回は、生成されたビットファイルをbin ファイルに変換して、Ultra96 ボード上のDebian で動作させてみよう。

最初に ~/HDL/Ultra96/display_cont_Ultra96_183 ディレクトリに display_cont_wrapper.bif を作成した。display_cont_wrapper.bif を示す。

all:
{
    [destination_device = pl] display_cont_wrapper.bit
}


display_cont.bin を生成する。
bootgen -image display_cont_wrapper.bif -arch zynqmp -w -o display_cont.bin
display_Ultra96_13_181223.png

display_cont.bin が生成された。
display_Ultra96_14_181223.png

SFTP でUltra96 のDebian にdisplay_cont.bin をアップロードした。
display_cont.bin を /lib/firmware/ にコピーした。
sudo cp display_cont.bin /lib/firmware/
display_Ultra96_15_181223.png

display_cont.bin が /lib/firmware/ にコピーされた。
display_Ultra96_16_181223.png

fpga-load.dts 、 fclk0-zynqmp.dts 、 lddtovray.sh 、 rmdtovray.sh を作成した。
fpga-load.dts を示す。

/dts-v1/;
/ {
    fragment@0 {
        target-path = "/fpga-full";
        __overlay__ {
            firmware-name = "display_cont.bin";
        };
    };
};


fclk0-zynqmp.dts を示す。

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


lddtovray.sh を示す。

#!/bin/bash

sudo mkdir /config/device-tree/overlays/fpga
sudo cp fpga-load.dtb /config/device-tree/overlays/fpga/dtbo
sudo mkdir /config/device-tree/overlays/fclk0
sudo cp fclk0-zynqmp.dtb /config/device-tree/overlays/fclk0/dtbo


rmdtovray.sh を示す。

#!/bin/bash

sudo rmdir /config/device-tree/overlays/fclk0
sudo rmdir /config/device-tree/overlays/fpga/


display_Ultra96_17_181223.png

fpga-load.dts 、 fclk0-zynqmp.dts をコンパイルする。
display_Ultra96_18_181223.png

pga-load.dtb 、 fclk0-zynqmp.dtb が生成された。
display_Ultra96_19_181223.png

./loddtovray.sh を実行した。
display_Ultra96_20_181223.png

その際のシリアルポートの出力を示す。
display_Ultra96_21_181223.png

PMOD VGA に接続されたディスプレイに画像が表示された。成功だ。
display_Ultra96_24_181226.jpg

Ultra96 ボード、Ultra96 用PMOD 拡張ボード、PMOD VGA の写真を示す。
display_Ultra96_26_181226.jpg

最後に、HREF と VSYNC のオシロスコープの波形を示す。上の黄色の線がHREF で水色の線がVSYNC だ。
display_Ultra96_25_181226.jpg
  1. 2018年12月26日 05:12 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードを使って、PMOD VGAで画像出力2(Vivado編)

Ultra96用PMOD拡張ボードを使って、PMOD VGAで画像出力1(Vivado HLS編)”の続き。

前回は、”秋月電子カメラモジュールOV5642を使う15(完成)”でUltra96 ボードに Ultra96 用PMOD 拡張ボードを付けて、そこに、OV5642 を取り付けてカメラ画像を取得することができた。今回はUltra96 用PMOD 拡張ボードにPMOD VGA を取り付けて画像を出力できるか?を確かめてみよう。ということで、Vivado HLS でSVGA 画像を出力するIP を作成した。今回は、そのIP を使用して、Vivado 2018.3 でプロジェクトを作成しよう。

Vivado 2018.3 で display_cont_Ultra96_183 プロジェクトを作成し、そのプロジェクトのディレクトリに display_cont_ip ディレクトリを作成した。display_cont_ip ディレクトリに前回Vivado HLS で作成したIP をコピーした。

IP カタログを表示して、リポジトリにVivado HLS で作成したIP のDisplay_cont_sub を追加した。

display_cont_Ultra96_183 プロジェクトを示す。
display_Ultra96_6_181223.png

display_cont ブロック・デザインを作成し、IP を追加して完成させた。
display_Ultra96_7_181223.png

PS から出力するクロックは 25 MHz に設定した。
display_Ultra96_8_181223.png

HDL ラッパーを作成した。
display_Ultra96_9_181223.png

論理合成を行った。
次は、Open Synthesized Design を開いて、I/O Planing でパッケージのピンの位置と信号レベルを設定した。
なお設定には、Pmod VGA Reference Manual を参照した。
display_Ultra96_10_181223.png

設定後は、display_cont.xdc としてセーブした。
display_cont.xdc を示す。

set_property PACKAGE_PIN D7 [get_ports {red[0]}]
set_property PACKAGE_PIN F8 [get_ports {red[1]}]
set_property PACKAGE_PIN F7 [get_ports {red[2]}]
set_property PACKAGE_PIN G7 [get_ports {red[3]}]
set_property PACKAGE_PIN F6 [get_ports {blue[0]}]
set_property PACKAGE_PIN G5 [get_ports {blue[1]}]
set_property PACKAGE_PIN A6 [get_ports {blue[2]}]
set_property PACKAGE_PIN A7 [get_ports {blue[3]}]
set_property PACKAGE_PIN G6 [get_ports {green[0]}]
set_property PACKAGE_PIN E6 [get_ports {green[1]}]
set_property PACKAGE_PIN E5 [get_ports {green[2]}]
set_property PACKAGE_PIN D6 [get_ports {green[3]}]
set_property PACKAGE_PIN D5 [get_ports {hsyncx[0]}]
set_property PACKAGE_PIN C7 [get_ports {vsyncx[0]}]

set_property IOSTANDARD LVCMOS18 [get_ports {blue[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {blue[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {blue[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {blue[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {hsyncx[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {vsyncx[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {green[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {green[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {green[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {green[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {red[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {red[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {red[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {red[0]}]


これで必要なすべてのファイルが揃ったので、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。
サマリーを示す。
display_Ultra96_11_181223.png

ハードウェアをエクスポートして、SDK を起動した。
HelloWorld アプリケーション・プロジェクトを作成した。
display_Ultra96_12_181223.png
  1. 2018年12月25日 05:08 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボードを使って、PMOD VGAで画像出力1(Vivado HLS編)

秋月電子カメラモジュールOV5642を使う15(完成)”でUltra96 ボードに Ultra96 用PMOD 拡張ボードを付けて、そこに、OV5642 を取り付けてカメラ画像を取得することができた。今回はUltra96 用PMOD 拡張ボードにPMOD VGA を取り付けて画像を出力できるか?を確かめてみよう。

Vivado HLS 2014.4 でディスプレイ・コントローラを作る1(高位合成、C/RTLコシミュレーション)”のC コードを使用するが、少し改変しよう。ツールは、Vivado HLS 2018.3 を使用してみよう。

まずは、ハードウェア化する display_cont.cpp を貼っておく。ここでのブロックレベルのインターフェースはap_ctrl_none だが、最初は、C/RTL 協調シミュレーションを行うために ap_ctrl_hs に変更した。

// display_cont.cpp
// 2015/06/03 by marsee
//
// 画面を4分割した第1象限は赤、第2象限は緑、第3象限は青、第4象限は白を表示する
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

// SVGA 解像度
#define H_ACTIVE_VIDEO    800
#define H_FRONT_PORCH    40
#define H_SYNC_PULSE    128
#define H_BACK_PORCH    88
#define H_SUM            (H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH)

#define V_ACTIVE_VIDEO    600
#define V_FRONT_PORCH    1
#define V_SYNC_PULSE    4
#define V_BACK_PORCH    23
#define V_SUM            (V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH)

void display_cont_sub(ap_uint<8> *red, ap_uint<8> *green, ap_uint<8> *blue, ap_uint<1> *display_enable, ap_uint<1> *hsyncx, ap_uint<1> *vsyncx){
#pragma HLS INTERFACE ap_none register port=red
#pragma HLS INTERFACE ap_none register port=green
#pragma HLS INTERFACE ap_none register port=blue
#pragma HLS INTERFACE ap_none register port=display_enable
#pragma HLS INTERFACE ap_none register port=hsyncx
#pragma HLS INTERFACE ap_none register port=vsyncx
#pragma HLS INTERFACE ap_ctrl_none port=return

    ap_uint<16> h_count, v_count;

    for (v_count=0; v_count<V_SUM; v_count++){
        for (h_count=0; h_count<H_SUM; h_count++){
#pragma HLS PIPELINE II=1 rewind
            if (h_count >= (H_ACTIVE_VIDEO +H_FRONT_PORCH) && h_count < (H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE))
                *hsyncx = 0;
            else
                *hsyncx = 1;

            if (v_count >= (V_ACTIVE_VIDEO + V_FRONT_PORCH) && v_count < (V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE))
                *vsyncx = 0;
            else
                *vsyncx = 1;

            if (h_count < H_ACTIVE_VIDEO && v_count < V_ACTIVE_VIDEO)
                *display_enable = 1;
            else
                *display_enable = 0;

            if (v_count < V_ACTIVE_VIDEO/2){
                if (h_count < H_ACTIVE_VIDEO/2){
                    *red=0xff; *green=0; *blue=0;
                } else if (h_count < H_ACTIVE_VIDEO){
                    *red=0; *green=0xff; *blue=0;
                } else {
                    *red=0; *green=0; *blue=0;
                }
            } else if (v_count < V_ACTIVE_VIDEO){
                if (h_count < H_ACTIVE_VIDEO/2){
                    *red=0; *green=0; *blue=0xff;
                } else if (h_count < H_ACTIVE_VIDEO){
                    *red=0xff; *green=0xff; *blue=0xff;
                } else {
                    *red=0; *green=0; *blue=0;
                }
            } else {
                *red=0; *green=0; *blue=0;
            }
        }
    }
}


次に、テストベンチの display_cont_tb.cpp を貼っておく。

//
// display_cont_tb.cpp
// 2015/06/03 by marsee
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

void display_cont_sub(ap_uint<8> *red, ap_uint<8> *green, ap_uint<8> *blue, ap_uint<1> *display_enable, ap_uint<1> *hsyncx, ap_uint<1> *vsyncx);
int main(){
    ap_uint<8> redb, *red;
    ap_uint<8> greenb, *green;
    ap_uint<8> blueb, *blue;
    ap_uint<1> deb, *display_enable;
    ap_uint<1> hb, *hsyncx;
    ap_uint<1> vb, *vsyncx;

    red = &redb;
    green = &greenb;
    blue = &blueb;
    display_enable = &deb;
    hsyncx = &hb;
    vsyncx = &vb;

    display_cont_sub(red, green, blue, display_enable, hsyncx, vsyncx);
    display_cont_sub(red, green, blue, display_enable, hsyncx, vsyncx);

    return 0;
}


Vivado HLS 2018.3 のプロジェクトを示す。
display_Ultra96_1_181223.png

合成時のトップファイルを指定した。
display_Ultra96_2_181223.png

合成時の目標遅延を 25 ns に設定した。(SVGA のピクセル・クロック)
display_Ultra96_3_181223.png

C コードの合成を行った。
display_Ultra96_4_181223.png

レイテンシは、min 663168 クロックだった。このSVGA の総ピクセル数は (800+40+128+88)×(600+1+4+23) = 663168 クロックなのでピッタリ合っている。

C/RTL 協調シミュレーションを行った。
display_Ultra96_23_181224.png

レイテンシはC コードの合成時と同じだった。

C/RTL 協調シミュレーションでのシミュレーション波形を示す。
display_Ultra96_22_181224.png

最後に、Export RTL を行った。結果を示す。
display_Ultra96_5_181223.png

動作周波数は全く問題ないレベルだ。
  1. 2018年12月24日 05:51 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2018年12月23日)

FPGAの部屋のまとめサイトを更新しました。
主にUltra96 の記事を追加しました。2018年12月22日までの記事を更新しました。
  1. 2018年12月23日 06:02 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う15(完成)

秋月電子カメラモジュールOV5642を使う14(画像が縦長で横に反転)”の続き。

OV5642 のレジスタ設定では、標準で 0x3818 番地のレジスタ設定が 0xC1 になっていて、横方向がMirror になっている。MT9D111 に比べて撮像素子を 180 度回してマウントしてあるようなので、それを上下に Filp してMirror 無しにしたいのだが、どうしてもレジスタ設定でそうすることができない。よって、Filp は諦めて、Mirror 無しにして、ソフトウェアで読み方を修正することにした。こうすると行は反対になっているが、列のアドレスは単調増加なので、ハードウェアで読む場合に800ピクセルをバーストできる。画像全部は連続してバーストできないが、800 ピクセルごとにアドレスを再設定する、スキャッター・ギャザーDMA を実装すれば比較的簡単にAXI4-Stream にできるだろう。
Mirror 無しの設定は、

0x3818, 0x81
0x3621, 0xA7

となった。この設定は、”linux-imx6/drivers/media/platform/mxc/capture/ov5642.c”を参考にしている。

cam_cap_ov5642.cpp の上下方向を逆にするようにしてコンパイルし、カメラ画像をキャプチャーした結果を示す。
OV5642_70_181222.jpg

いろいろとレジスタ設定をいじってきたが、この辺りで終わりとしたい。
最後に、現在の cam_cap_ov5642.cpp を貼っておく。なお、このコードをコンパイルするには、OpenCV のライブラリが必要だ。詳しくは、”Ultra96 のDebianにインストールしたOpenCV-3.4.3のC++サンプルデザインをコンパイル”を参照のこと。
(2018/12/30:修正) 理由は”ZYBO Z7-20でのMNISTの実装にOV5642を使用する2”を参照のこと。

// cam_cap_ov5642.cpp (for Ultra96)
// 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

#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 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)

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

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 fd1, fd2, fd3, fd10, fd11;
    volatile unsigned int *ov5642_inf_axis, *axi_iic, *DMA_Write_sFB;
    volatile unsigned int *frame_buffer;
    int active_frame;
    
     while ((opt=getopt(argc, argv, "b:n:h")) != -1){
        switch (opt){
            case 'b':
                strcpy(bmp_fn, optarg);
                break;
            case 'n':
                file_no = atoi(optarg);
                break;
            case 'h':
                help_flag = 1;
                break;
        }
    }

    if (help_flag == 1){ // help
        printf("Usage : cam_capture [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
        exit(0);
    }
    
    // ov5642_inf_axis-uio IP
    fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (ov5642_inf_axis) open error\n");
        exit(-1);
    }
    ov5642_inf_axis = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!ov5642_inf_axis){
        fprintf(stderr, "ov5642_inf_axis mmap error\n");
        exit(-1);
    }
    
    // axi_iic-uio IP
    fd2 = open("/dev/uio2", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axi_iic) open error\n");
        exit(-1);
    }
    axi_iic = (volatile unsigned int *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axi_iic){
        fprintf(stderr, "axi_iic mmap error\n");
        exit(-1);
    }

    // DMA_Write_sFB-uio IP
    fd3 = open("/dev/uio3", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (DMA_Write_sFB) open error\n");
        exit(-1);
    }
    DMA_Write_sFB = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!DMA_Write_sFB){
        fprintf(stderr, "DMA_Write_sFB 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, 5760000, 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);
    
    // XDMA_Write_sFB start
    DMA_Write_sFB[6] = phys_addr; // fb0
    DMA_Write_sFB[8] = phys_addr+SVGA_ALL_DISP_ADDRESS; // fb1
    DMA_Write_sFB[10] = phys_addr+2*SVGA_ALL_DISP_ADDRESS; // fb2
    DMA_Write_sFB[0] = 0x1; // start
    DMA_Write_sFB[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;
    
    char bmp_file[256];

    // 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)(DMA_Write_sFB[12] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame);
                
                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)(DMA_Write_sFB[12] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame);
                
                printf("file No. = %d\n", file_no);

                break;
        }
        c = getc(stdin);
    }
    
    munmap((void *)ov5642_inf_axis, 0x1000);
    munmap((void *)axi_iic, 0x1000);
    munmap((void *)DMA_Write_sFB, 0x10000);
    munmap((void *)frame_buffer, 576000);
    
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd10);
    
    return(0);
}

int WriteBMPfile(char *bmp_file, volatile unsigned int *frame_buffer, int active_frame){
    int read_frame;
    
    if (active_frame == 0)
        read_frame = 2;
    else if (active_frame == 1)
        read_frame = 0;
    else // active_frame == 2
        read_frame = 1;
    int offset_addr = read_frame * SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES;
    
    cv::Mat img(SVGA_VERTICAL_LINES, SVGA_HORIZONTAL_PIXELS, 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+((img.rows-1)-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;
        }
    }
    
    imwrite(bmp_file, img);
    //imwrite("test.jpg", 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. 2018年12月22日 05:45 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:3

秋月電子カメラモジュールOV5642を使う14(画像が縦長で横に反転)

秋月電子カメラモジュールOV5642を使う13(カメラ画像が表示できた2)”の続き。

前回は、教えてもらったレジスタ設定を行って、カメラ画像を綺麗な色に表示できた。今回は、数字を映してみると左右に反転して表示されている状況を確認して、カメラからレベル変換IC を通った後の波形を確認した。

数字を映してみると、反転している。
OV5642_69_181221.jpg

だが、0x3818 番地を 0xe0 から 0xa0 に変更すると、画面が真っ暗になってしまう。
もしかしたら走査方向を反転する必要があるのだろうか?

それに、画像を見ると縦に伸びているように感じる?イマイチレジスタ設定がおかしい気がする。。。

とりあえず、カメラから出力している信号のレベル変換ICを通った後での信号を確認してみた。つまり 1.8V レベルの信号だ。
まずは、CH1 が PCLK で、 CH2 が XCLK の波形を示す。
OV5642_65_181221.jpg

XCLK の 23.42 MHz は見えているが、PCLK の 93 MHz は波形が乱れている。パッシブプローブの先に 50cm のIC クリップを付けているので、仕方ないかもしれないが、3.3V CMOSはもっとよく見えた。インピーダンスの関係かもしれない?
改めて見ると、下の23.42 MHz が上の波形に重畳されているようだ。1、2CHでなく、1 CH だけで見る必要があったようだ。

次に CH1 が HREF で、CH2 が VSYNC を示す。
OV5642_66_181221.jpg

これはきちんと見える。
HREF を拡大すると、3.3V CMOS と同じに 16.8 us の幅だった。
OV5642_67_181221.jpg

CH1 が HREF で、CH2 が D2 の波形を示す。CH2 の D2 の波形がCH1 のHREF の波形に重畳されてしまっている。このようにGND が共通なのもあって、他のチャネルの波形が重畳してしまうことがある。これは仕方ないかな?
OV5642_68_181221.jpg

変換したレベル的には問題ないようだ。人に基板を差し上げる前に確認したかったので、安心した。
  1. 2018年12月21日 07:00 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:2

秋月電子カメラモジュールOV5642を使う13(カメラ画像が表示できた2)

秋月電子カメラモジュールOV5642を使う12(カメラ画像が表示できた)”の続き。

前回は、SVGA 解像度のレジスタ設定をいじってカメラ画像を表示させることができたが、色がおかしかった。今回は、教えてもらったレジスタ設定を試して、色も問題なくなった。本当に教えてくれた岩田さんに感謝する。

まずは、”秋月電子カメラモジュールOV5642を使う12(カメラ画像が表示できた)”のコメント欄で岩田さんに OV5642のRGB565 の場合のレジスタ設定を教えていただいた。ありがとうございました。
そのままでは真っ暗になってしまったが、試行錯誤の結果0x5002 ,0xf8 じゃなくて 0x5002 ,0x78 にすればうまく行くということが分かった。
つまり、

0x501e ,0x2a
0x5002 ,0x78
0x501f ,0x01
0x4300 ,0x61

を設定した。

設定後の、build_android の画像を示す。
OV5642_60_181220.jpg

うまく色が出ている。良かった。。。

HREF と VSYNC のオシロスコープ画面を貼っておく。上がHREF で、下がVSYNC だ。
OV5642_59_181219.jpg

HREF を拡大してみよう。
OV5642_61_181220.jpg

PCLK を見てみる。下がPCLK で、上はHREF のままだ。
OV5642_62_181220.jpg

PCLK は 93.599MHz だった。。。

HREF の幅は、 16.8 us だった。
OV5642_63_181220.jpg

計算してみよう。 16.8 us / (800 ピクセル x 2 バイト) = 0.0105 us = 10.5 ns つまり、約 95.24 MHz ということで計算は合っている。Ultra96 用PMOD 拡張ボードは 100 MHz 近くのクロックも伝送できているということにびっくりした。SVGA の 30 fps のカメラ画像になっているはずだ。
なお全ての波形はカメラの端子で計測している。

改版したUltra96 用PMOD 拡張ボードでも確かめてみたが、問題なくカメラ画像が表示できた。
OV5642_64_181220.jpg

最後に cam_cap_ov5642.cpp を貼っておく。

// cam_cap_ov5642.cpp (for Ultra96)
// 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

#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 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)

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

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 fd1, fd2, fd3, fd10, fd11;
    volatile unsigned int *ov5642_inf_axis, *axi_iic, *DMA_Write_sFB;
    volatile unsigned int *frame_buffer;
    int active_frame;
    
     while ((opt=getopt(argc, argv, "b:n:h")) != -1){
        switch (opt){
            case 'b':
                strcpy(bmp_fn, optarg);
                break;
            case 'n':
                file_no = atoi(optarg);
                break;
            case 'h':
                help_flag = 1;
                break;
        }
    }

    if (help_flag == 1){ // help
        printf("Usage : cam_capture [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
        exit(0);
    }
    
    // ov5642_inf_axis-uio IP
    fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (ov5642_inf_axis) open error\n");
        exit(-1);
    }
    ov5642_inf_axis = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!ov5642_inf_axis){
        fprintf(stderr, "ov5642_inf_axis mmap error\n");
        exit(-1);
    }
    
    // axi_iic-uio IP
    fd2 = open("/dev/uio2", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axi_iic) open error\n");
        exit(-1);
    }
    axi_iic = (volatile unsigned int *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axi_iic){
        fprintf(stderr, "axi_iic mmap error\n");
        exit(-1);
    }

    // DMA_Write_sFB-uio IP
    fd3 = open("/dev/uio3", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (DMA_Write_sFB) open error\n");
        exit(-1);
    }
    DMA_Write_sFB = (volatile unsigned int *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!DMA_Write_sFB){
        fprintf(stderr, "DMA_Write_sFB 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, 5760000, 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);
    
    // XDMA_Write_sFB start
    DMA_Write_sFB[6] = phys_addr; // fb0
    DMA_Write_sFB[8] = phys_addr+SVGA_ALL_DISP_ADDRESS; // fb1
    DMA_Write_sFB[10] = phys_addr+2*SVGA_ALL_DISP_ADDRESS; // fb2
    DMA_Write_sFB[0] = 0x1; // start
    DMA_Write_sFB[0] = 0x80; // EnableAutoRestart
    
    ov5642_inf_axis[0] = phys_addr; // ov5642 AXI4-Stream Start
    
    // CMOS Camera initialize, ov5642
    cam_i2c_init(axi_iic);
    
    cam_reg_set(axi_iic, 0x78); // OV5642 register set

    ov5642_inf_axis[1] = 0;
    
    char bmp_file[256];

    // 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)(DMA_Write_sFB[12] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame);
                
                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)(DMA_Write_sFB[12] & 0x3); // Data signal of active_frame_V
                WriteBMPfile(bmp_file, frame_buffer, active_frame);
                
                printf("file No. = %d\n", file_no);

                break;
        }
        c = getc(stdin);
    }
    
    munmap((void *)ov5642_inf_axis, 0x1000);
    munmap((void *)axi_iic, 0x1000);
    munmap((void *)DMA_Write_sFB, 0x10000);
    munmap((void *)frame_buffer, 576000);
    
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd10);
    
    return(0);
}

int WriteBMPfile(char *bmp_file, volatile unsigned int *frame_buffer, int active_frame){
    int read_frame;
    
    if (active_frame == 0)
        read_frame = 2;
    else if (active_frame == 1)
        read_frame = 0;
    else // active_frame == 2
        read_frame = 1;
    int offset_addr = read_frame * SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES;
    
    cv::Mat img(SVGA_VERTICAL_LINES, SVGA_HORIZONTAL_PIXELS, 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;
        }
    }
    
    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, 0x10);
    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, 0xe0); // Flip, Mirror
    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. 2018年12月20日 05:01 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:4

秋月電子カメラモジュールOV5642を使う12(カメラ画像が表示できた)

秋月電子カメラモジュールOV5642を使う11(VGA解像度でテスト)”の続き。

前回は、インターフェース2014年11月号の設定値つまりVGA 解像度で、HREF、VSYNC が出てくるのを確認することができた。今回は、SVGA 解像度のレジスタ設定をいじってカメラ画像を表示させてみよう。

インターフェース2014年11月号の特集を読んでどの辺りがおかしいか?を探ってみた。
0x389C 〜 0x380F の水平と垂直のトータル・サイズを増やしてみた。

cam_i2c_write(axi_iic, device_addr, 0x380c, 0x0d);
cam_i2c_write(axi_iic, device_addr, 0x380d, 0x00);
cam_i2c_write(axi_iic, device_addr, 0x380e, 0x04);
cam_i2c_write(axi_iic, device_addr, 0x380f, 0xe8);


そうすると、画像が表示されるようになった。
OV5642_54_181218.jpg

画像は表示されたがSVGA に比べてVGA くらいの画像しかないし、画像の上下が反転しているし、色味がおかしい。

最初に画像をFlip してMirror してみることにした。Flip しただけだとカメラ画像がひょうじされなくなったからだ。

cam_i2c_write(axi_iic, device_addr, 0x3818, 0xe0); // Flip, Mirror


すると、カメラ画像が反転して、縦はいっぱいに表示されたが、横が同じ幅だったので、縦に伸びてしまった。
OV5642_55_181218.jpg

結構レジスタ設定を決めるのが面倒なので、Android のOV5642のドライバを見つけたので、設定値を頂いてきて、Python で C コードに変換した。
OV5642_57_181219.png

Ultra96 のDebian の~/examples/cam_cap_ov5642/build_android に cam_cap_ov5642.cpp をコピーして、OV5642 の設定レジスタを設定するコードを Android のドライバから生成した C コードに置き換えた。
OV5642_58_181219.png

そして、コンパイルしてカメラ画像を取得した。
OV5642_56_181218.jpg

ちゃんとSVGA の画像になっていたが、色は同じようだった。また、インターフェース2014年11月号の設定では、4 ピクセルを 1 ピクセルに縮めているので、画角が広い。画角が広いほうが良いけど、どうしよう?
とりあえず、色味を合わせてみよう。
うまく行くのだったら、1280 x 720 ピクセルに設定して、真ん中を切り取って 800 x 600 ピクセルにしても良いかもしれない?

最後に、現在のHREF と VSYNC の波形を示す。
OV5642_59_181219.jpg
  1. 2018年12月19日 06:17 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:4

秋月電子カメラモジュールOV5642を使う11(VGA解像度でテスト)

秋月電子カメラモジュールOV5642を使う10(アプリを用意して実機テスト)”の続き。

前回は、アプリケーション・ソフトを作成して、OV5642 を動作させようとしたが、HREF、VSYNC の波形が全く出ていなかった。今回は、インターフェース2014年11月号の設定値つまりVGA 解像度で、HREF、VSYNC が出てくるかどうか?を確かめてみよう。

インターフェース誌の2014年の11月号のダウンロードデータを解凍すると、IF1411T ディレクトリが出てくるが、その下のap1/ov5642 にOV5642-VGA15fps-24MHz.ttl がある。一部を引用する。
OV5642_47_181218.png

これをJupyter Notebook でC コードに変換した。
OV5642_48_181218.png

Ultra96 ボードのDebian で ~/examples/cam_cap_ov5642/build_vga ディレクトリを作成して、cam_cap_ov5642.cpp をコピーして、Jupyter Notebook で出力したVGA 解像度のOV5642のレジスタ設定と入れ替えた。
OV5642_49_181218.png

これを
g++_opencv cam_cap_ov5642.cpp
でコンパイルして、cam_cap_ov5642 実行ファイルを生成した。

さて、実行してみよう。デバイスツリー・オーバレイをロードしてから、cam_cap_ov5642 実行ファイルを実行した。
OV5642_50_181218.png

HREF と VSYNC をオシロスコープで見ると出力されている。
OV5642_45_181218.jpg

HREF を拡大した。
OV5642_46_181218.jpg

インターフェース2014年11月号のVGA 解像度の設定値では、HREF もVSYNC も出力されていることがわかった。次は、自分で設定したSVGA 解像度の設定とRGB565 モードの設定のどこが悪いのか?を検証したい。
  1. 2018年12月18日 04:34 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う10(アプリを用意して実機テスト)

秋月電子カメラモジュールOV5642を使う9(デバイスツリー・オーバレイ用ファイルの整備)”の続き。

前回は、Ultra96 のDebian 上でソフトウェアを起動するために、デバイスツリー・オーバレイ関連のファイルを整備した。今回は、アプリケーション・ソフトを作成して、OV5642 を動作させてみよう。

最初に、cam_cap_ov5642.cpp アプリケーションソフトを作成した。
OV5642_37_181216.png

これを、
g++_opencv cam_cap_ov5642.cpp
でコンパイルして、cam_cap_ov5642 を作成した。
./cam_cap_ov5642 で起動した。
OV5642_43_181216.jpg

ところが、cam_cap_ov5642 を起動しても、XCLK は約 24 MHz の波形が出力されるが、PCLK には何も出力されていなかった。
そこで、OV5642 カメラを設定するI2C の波形を見た。
OV5642_38_181216.jpg

カメラからのACK も 0 で帰ってきているので問題なさそうだ。
OV5642_39_181216.jpg

ところが、送っているデータの値を確認してみると送る予定のデータと異なることが分かった。
cam_cap_ov5642.cpp を確認してみるとバグがあった。バグを修正後のI2C の波形を示す。
OV5642_40_181216.jpg

これでI2C は正常になった。
PCLK を見てみると、約 58.6 MHz が出ていた。
OV5642_41_181216.jpg

OV5642 のレジスタの設定を
cam_i2c_write(axi_iic, device_addr, 0x3011, 0x14);
から
cam_i2c_write(axi_iic, device_addr, 0x3011, 0x08);
に変更すると、PCLK は約 24 MHz となった。これで行くことにする。
OV5642_42_181216.jpg

HREF とVSYNC を見てみたが、出力されていなかった。下図で上がHREF 、したがVSYNC だ。
OV5642_44_181216.jpg

HREF とVSYNC が出力されていないので、私の設定のどこかが悪いのではないだろうか?
インターフェース2014年11月号の設定に戻してみて、HREF とVSYNC が出力されるのか?を見てみよう。
  1. 2018年12月16日 06:15 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボード12(改版した基板に部品を実装した)

Ultra96用PMOD拡張ボード11(改版した基板が届いた)”の続き。

前回届いたUltra96用PMOD拡張基板に部品を実装した。
これでテストできる。
OV5642_35_181215.jpg

OV5642_36_181215.jpg

ボードのスペルが間違っているのは、ご愛嬌ということで許して。。。
もしうまく行ったら欲しい人いるのかな? コミケで売ってみたい。
  1. 2018年12月15日 20:41 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:2

秋月電子カメラモジュールOV5642を使う9(デバイスツリー・オーバレイ用ファイルの整備)

秋月電子カメラモジュールOV5642を使う8(OV5642用Vivadoプロジェクト)”の続き。

前回は、Ultra96 用の cam_test_182 のVivado プロジェクトを少し改変して、OV5642用のVivado プロジェクトを作った。今回は、Debian 上でソフトウェアを起動するために、デバイスツリー・オーバレイ関連のファイルを整備する。

まずは、Ultra96 のDebian を起動して、~/examples/ ディレクトリに行って、 cam_cap_ov5642 ディレクトリを作成した。
cd ~/examples/
mkdir cam_cap_ov5642

OV5642_27_181212.png

nautilus を起動して、cam_capture ディレクトリの内のアプリケーションの実行ファイルの cam_capture 以外を cam_cap_ov5652 ディレクトリにコピーした。
OV5642_28_181212.png

パソコンからUltra96 のDebian に SFTP して、前回作成した cam_test_ov5642.bin をcam_cap_ov5652 ディレクトリにアップロードした。
OV5642_29_181212.png

SFTP したcam_cap_ov5652 ディレクトリの cam_test_ov5642.bin を /lib/firmware/ ディレクトリにコピーした。
sudo cp cam_test_ov5642.bin /lib/firmware/
OV5642_30_181212.png

/lib/firmware/ ディレクトリに cam_test_ov5642.bin がコピーされた。
OV5642_31_181212.png

cam_capture.dtb を削除して、cam_capture.dts を cam_cap_ov5642.dts に名前を変更した。
OV5642_32_181212.png

各dts ファイルを書き換えた。
最初に fpga-load.dts から示す。

/dts-v1/;
/ {
    fragment@0 {
        target-path = "/fpga-full";
        __overlay__ {
            firmware-name = "cam_test_ov5642.bin";
        };
    };
};


fclk01-zynqmp.dts を示す。

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


cam_cap_ov5642.dts を示す。

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        #address-cells = <2>;
        #size-cells = <2>;

        __overlay__ {
            #address-cells = <2>;
            #size-cells = <2>;

            mt9d111_inf_axis-uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0000000 0x0 0x1000>;
            };
            
            axi_iic-uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0001000 0x0 0x1000>;
            };
            
            DMA_Write_sFB-uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0010000 0x0 0x10000>;
            };

            cam_cap_ov5642-udmabuf4 {
                compatible  = "ikwzm,udmabuf-0.10.a";
                device-name = "udmabuf4";
                size = <0x00800000>;
            };
        };
    };
};


各 dts をコンパイルした。
dtc -I dts -O dtb -o fpga-load.dtb fpga-load.dts
dtc -I dts -O dtb -o fclk01-zynqmp.dtb fclk01-zynqmp.dts

OV5642_33_181214.png

dtc -I dts -O dtb -o cam_cap_ov5642.dtb cam_cap_ov5642.dts
OV5642_34_181214.png

各 dts ファイルをコンパイルして dtb ファイルを生成した。

各デバイスツリーをロードするシェルスクリプト lddtovray.sh を示す。

#!/bin/bash

sudo mkdir /config/device-tree/overlays/fpga
sudo cp fpga-load.dtb /config/device-tree/overlays/fpga/dtbo
sudo mkdir /config/device-tree/overlays/fclk01
sudo cp fclk01-zynqmp.dtb /config/device-tree/overlays/fclk01/dtbo
sudo mkdir /config/device-tree/overlays/cam_cap_ov5642
sudo cp cam_cap_ov5642.dtb /config/device-tree/overlays/cam_cap_ov5642/dtbo

sleep 0.5
sudo chmod 666 /dev/uio*
sudo chmod 666 /dev/udmabuf4


各デバイスツリーを削除するシェルスクリプト rmdtovray.sh を示す。

#!/bin/bash

sudo rmdir /config/device-tree/overlays/cam_cap_ov5642/
sudo rmdir /config/device-tree/overlays/fclk01
sudo rmdir /config/device-tree/overlays/fpga/

  1. 2018年12月14日 04:47 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボード11(改版した基板が届いた)

Ultra96用PMOD拡張ボード10(基板の改版3)”の続き。

昨日、改版したUltra96 用PMOD 拡張ボードが届いた。

早速、部品を実装して試してみたい。配送業者にDHL を選んで、基板発注から到着まで 12 日だった。
Ultra96_ext_board2_25_181213.jpg
  1. 2018年12月13日 05:42 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

SDSoC 2018.3 WebPACK が出ています

Xilinx 社のSDSoC 開発環境のダウンロードページにSDSoC 2018.3 WebPACK が出ています。
ついにSDSoC のWebPACK が出たようです。これで、心置きなくSDSoC を使えそうですね。
SDSoC_WebPACK_181213.png

でも、おかしなことに SDSoC 2018.3 のリリース・ノートにWebPACK のことが書いていないです。なぜでしょうか?
まだダウンロードしてインストールしたことないですが、やってみたいと思います。
  1. 2018年12月13日 05:24 |
  2. SDSoC
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う8(OV5642用Vivadoプロジェクト)

秋月電子カメラモジュールOV5642を使う7(OV5642の設定レジスタの設定値2)”の続き。

前回は、OV5642を使用するための設定レジスタの設定値を決定して、Python でC コードに変換した。今回は、Ultra96 用の cam_test_182 のVivado プロジェクトを少し改変して、OV5642用のVivado プロジェクトを作ろう。

まずは、HDL/Ultra96 ディレクトリの cam_test_182 ディレクトリ(Vivado 2018.2 のプロジェクト)をコピーして、ペーストし、名前を cam_test_ov5642_182 に変更した。
OV5642_25_181212.png

cam_test ブロック・デザインを起動して、Zynq UltraScale+ MPSoC をダブルクリックしてダイアログを表示させた。
Page Navigator からClock Configuration を選択し、Output Clocks のPL Fabric Clocks のPL1 を 24 MHz に設定した。
OV5642_21_181211.png

そして、もう一度、Generate BitStream をクリックして、論理合成、インプリメンテーション、ビットストリームを行った。
OV5642_22_181211.png

結果を示す。
OV5642_26_181212.png

問題なさそうだ。
次に、Export Hardware をビットストリーム付で行った。

~/HDL/cam_test_ov5642_182/cam_test_182.sdk/cam_test_wrapper_hw_platform_1 ディレクトリの cam_test_wrapper.bit を上のディレクトリにコピーした。
cam_test_wrapper.bif は”Ultra96用PMOD拡張ボードでカメラ入力11(Debian上でカメラ画像を画像ファイルに1)”で作ってあるので、コマンドを入力して、cam_test_ov5642.bin を作成する。
bootgen -image cam_test_wrapper.bif -arch zynqmp -w -o cam_test_ov5642.bin
OV5642_23_181212.png

cam_test_ov5642.bin が作成された。
OV5642_24_181212.png
  1. 2018年12月12日 05:28 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う7(OV5642の設定レジスタの設定値2)

秋月電子カメラモジュールOV5642を使う6(OV5642の設定レジスタの設定値)”の続き。

前回は、OV5642を使用するための設定レジスタの設定値を半分程度決定した。今回は、OV5642を使用するための設定レジスタの設定値を決定して、Python でC コードに変換してみよう。

OV5642を使用するための設定レジスタの設定値を示す。全部で 322 個になった。これは、インターフェース誌の2014年の11月号のダウンロードデータにOV5642の初期設定レジスタ一覧を示す「表2.pdf」があるので、それの設定値を頂いて、設定値が異なるところを書き換えて、足りない設定値を追加した。変更点は、インターフェースのカメラ画像はVGAだが、私の設定値ではSVGA の 800 x 600 ピクセルであることだ。
OV5642_18_181210.png

現在はLibreOffice Calc で作ってあるので、それを CSV ファイルに変換した。
OV5642_19_181210.png

Python で CSV ファイルを読んで、C コードに変換した。
Python のプログラムを作る際に参考にしたのは、”PythonでCSVの読み書き”だ。
作成したPython コードを貼っておく。

import csv

with open('OV5642_SVGA_regset.csv', 'r') as f:
    reader = csv.reader(f)
    header = next(reader)  # ヘッダーを読み飛ばしたい時
    
    for row in reader:
        print("cam_i2c_write(axi_iic, 0x78, {0}, {1});".format(row[1], row[2]),)


Python だと少ない行数で書けるので、とっても良い。
Jupyter Notebook での実行結果を示す。
OV5642_20_181210.png

これで、OV5642のレジスタ設定用のプログラムも完成した。
  1. 2018年12月11日 04:31 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う6(OV5642の設定レジスタの設定値)

秋月電子カメラモジュールOV5642を使う5(OV5642インターフェースIP)”の続き。

OV5642のインターフェースIP を作ろうとし作ったのだが、設定レジスタの設定により、作成済みのMT9D111 のインターフェースIP と違いが無くなったためMT9D111 のインターフェースIP を使用することにした。今回は、OV5642を使用するための設定レジスタの設定値を決定する。ただしまだ半分くらいだ。

基本的に、OV5642の設定レジスタの設定値はインターフェース誌の2014年11月号の”ウェアラブルの可能性を探る 徹底研究!指先サイズ スーパーカメラ”に基づいているが、インターフェース誌では、640 x 480 ピクセルのVGA のところを 800 x 600 の SVGA でしかも、MT9D111 と同じフォーマットで出力波形を出すという目標があるので、設定レジスタの設定値を1つ1つ確認している。

インターフェース誌の2014年の11月号のダウンロードデータにOV5642の初期設定レジスタ一覧を示す「表2.pdf」があるので、それの設定値を頂いて、設定値が異なるところを書き換えている。
なお、説明は、OV5642 データシートのものをコピペしてある。
一部を引用する。
OV5642_17_181210.png

まだ、半分だが、早急に表を完成させて、その表のデータから設定するC コードを出力するプログラムをPython で作りたい。
  1. 2018年12月10日 05:12 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

AVNET社主催の「ハイパフォーマンス・エクストリームコンピューティング・セミナー」に行ってきました

昨日、AVNET社主催の「ハイパフォーマンス・エクストリームコンピューティング・セミナー」に行ってきました。

やはり、Xilinx 社がクラウドでのFPGA に力を入れているのがよく分かるセミナーでした。
Alveo アクセラレータカードも展示してあって、デモが動いていました。
ALVEO_181208.jpg

デモでニューラルネットワークの画像認識が動作していたのですが、変換時間が1.66 ms くらいで1時間に3000枚程度認識できると表示が出ていましたが計算が合っていません。4つ同時に動いているのかな?と、聞いてみようと思いましたが、聞きそびれました。

セミナもHPC や金融などのセミナでした。
やはり、株の発注をFPGAでやっているんですね。サブ・マイクロ秒というように聞こえました。FPGA で発注判断とかもしちゃうみたいです。CPU介さないようですね。シビアな世界ですが、そのサブ・マイクロ秒サーバー側できちんと順番に受け取れるか?という疑問があります。きっと、サーバーのなるだけ近くにFPGAを置くようにしているのでしょう?場所争いがシビアなんでしょうね。。。

そうそう、7nm プロセスでは、DSP が浮動小数点数演算サポートになるそうです。いよいよIntel のStratix 10 と肩を並べるのですね。

最後の黒田さんのプレゼンは、高位合成のチューニングの勘所をとても詳しく解説してくれました。さすがだなと楽しく拝見していましたが、このセミナでは、詳しく説明しすぎじゃないのかな?と思いながら聞いていました。

懇親会でもいろいろな方にお会い出来てとっても楽しく過ごせました。思いもかけない方にお会いしましたね。

久しぶりのXilinx のセミナで楽しかったです。ありがとうございました。
  1. 2018年12月08日 07:55 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う5(OV5642インターフェースIP)

秋月電子カメラモジュールOV5642を使う4(AXI-Stream Data FIFO のシミュレーション)”の続き。

前回は、、AXI-Stream Data FIFO が使い物になるかどうか?ということで、HDL シミュレーションを行ったところ、うまく行きそうにないということがわかった。(AXI4-Stream の動作としては問題ない)今回は、OV5642のインターフェースIP を作っていこう。

MT9D111 のインターフェースIP を最近作成してある。
Ultra96用PMOD拡張ボードでカメラ入力1(mt9d111_inf_axis IP の作成1)
Ultra96用PMOD拡張ボードでカメラ入力2(mt9d111_inf_axis IP の作成2)

これを改造してOV5642 のインターフェースIP にすることにした。
mt9d111_axis_mpsoc プロジェクトのファイルをコピーして、新規作成した ov5642_axis_mpsoc プロジェクトに追加した。
一応、IP まで作った。
OV5642_15_181206.png

しかし、MT9D111 のデータシートを見ると、今回のOV5642 の設定を適用すると、MT9D111 のタイミングチャートとだいたい同じになる。
MT9D111 カメラのデータシート”1/3.2-Inch System-On-A-Chip (SOC) CMOS Digital Image Sensor MT9D111”の119 ページのFigure 18: Pixel Timing Example とFigure 19: Row Timing and FRAME VALID/LINE_VALID Signals を引用する。
OV5642_16_181206.png

OV5642のPDFデータシートの106、107ページの figure 6-9 と table 6-8 の一部をもう一度、引用する。
OV5642_4_181203.png

今、OV5642 のVSYNC を反転させることにしているので、VSYNC を反転させればMT9D111 のデータ出力のフォーマットとだいたい同一となる。つまり、OV5642 用のインターフェースIP をわざわざ作成しなくても、MT9D111 のインターフェースIP が使えそうだ。ということだ。レジスタ設定用のI2C はXilinx 社のAXI IIC IP を使用しているので、それを使用するソフトウェアで設定を書けば良さそうだ。

せっかく、OV5642 用のインターフェースIP は作ったのだが、MT9D111 のインターフェースIP を使ってOV5642 を使っていくことにしよう。
  1. 2018年12月06日 04:58 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う4(AXI-Stream Data FIFO のシミュレーション)

秋月電子カメラモジュールOV5642を使う3(OV5642インターフェースIPの検討)”の続き。

前回は、OV5642の信号を取り込むOV5642インターフェースIP を検討した。その結果、AXI-Stream Data FIFO とOV5642 の画像データを受け取るVivado HLS のIP の組み合わせで行くことにした。今回は、AXI-Stream Data FIFO が使い物になるかどうか?HDL シミュレーションをしてみよう。

Vivado 2018.2 でUltra96 のボード・ファイルを使用して test1 プロジェクトを作成した。
その中でブロック・デザインを作成し、AXI-Stream Data FIFO をAdd IP した。
OV5642_12_181205.png

ブロック・デザインのVerilog HDL ラッパー・ファイルを作成した。
Verilog HDL ラッパー・ファイルのdesign_1_wrapper.v を示す。

//Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.
//--------------------------------------------------------------------------------
//Tool Version: Vivado v.2018.2 (lin64) Build 2258646 Thu Jun 14 20:02:38 MDT 2018
//Date        : Tue Dec  4 21:21:23 2018
//Host        : masaaki-H110M4-M01 running 64-bit Ubuntu 18.04.1 LTS
//Command     : generate_target design_1_wrapper.bd
//Design      : design_1_wrapper
//Purpose     : IP block netlist
//--------------------------------------------------------------------------------
`timescale 1 ps / 1 ps

module design_1_wrapper
   (M_AXIS_0_tdata,
    M_AXIS_0_tready,
    M_AXIS_0_tuser,
    M_AXIS_0_tvalid,
    S_AXIS_0_tdata,
    S_AXIS_0_tready,
    S_AXIS_0_tuser,
    S_AXIS_0_tvalid,
    axis_data_count_0,
    axis_rd_data_count_0,
    axis_wr_data_count_0,
    m_axis_aclk_0,
    m_axis_aresetn_0,
    s_axis_aclk_0,
    s_axis_aresetn_0);
  output [7:0]M_AXIS_0_tdata;
  input M_AXIS_0_tready;
  output [0:0]M_AXIS_0_tuser;
  output M_AXIS_0_tvalid;
  input [7:0]S_AXIS_0_tdata;
  output S_AXIS_0_tready;
  input [0:0]S_AXIS_0_tuser;
  input S_AXIS_0_tvalid;
  output [31:0]axis_data_count_0;
  output [31:0]axis_rd_data_count_0;
  output [31:0]axis_wr_data_count_0;
  input m_axis_aclk_0;
  input m_axis_aresetn_0;
  input s_axis_aclk_0;
  input s_axis_aresetn_0;

  wire [7:0]M_AXIS_0_tdata;
  wire M_AXIS_0_tready;
  wire [0:0]M_AXIS_0_tuser;
  wire M_AXIS_0_tvalid;
  wire [7:0]S_AXIS_0_tdata;
  wire S_AXIS_0_tready;
  wire [0:0]S_AXIS_0_tuser;
  wire S_AXIS_0_tvalid;
  wire [31:0]axis_data_count_0;
  wire [31:0]axis_rd_data_count_0;
  wire [31:0]axis_wr_data_count_0;
  wire m_axis_aclk_0;
  wire m_axis_aresetn_0;
  wire s_axis_aclk_0;
  wire s_axis_aresetn_0;

  design_1 design_1_i
       (.M_AXIS_0_tdata(M_AXIS_0_tdata),
        .M_AXIS_0_tready(M_AXIS_0_tready),
        .M_AXIS_0_tuser(M_AXIS_0_tuser),
        .M_AXIS_0_tvalid(M_AXIS_0_tvalid),
        .S_AXIS_0_tdata(S_AXIS_0_tdata),
        .S_AXIS_0_tready(S_AXIS_0_tready),
        .S_AXIS_0_tuser(S_AXIS_0_tuser),
        .S_AXIS_0_tvalid(S_AXIS_0_tvalid),
        .axis_data_count_0(axis_data_count_0),
        .axis_rd_data_count_0(axis_rd_data_count_0),
        .axis_wr_data_count_0(axis_wr_data_count_0),
        .m_axis_aclk_0(m_axis_aclk_0),
        .m_axis_aresetn_0(m_axis_aresetn_0),
        .s_axis_aclk_0(s_axis_aclk_0),
        .s_axis_aresetn_0(s_axis_aresetn_0));
endmodule


次に、design_1_wrapper.v をシミュレーションするファイル axis_data_fifo_tb.v を作成した。

// axis_data_fifo_tb.v
// 2018/12/04 by marsee
//

`timescale 1ns / 1ps

module axis_data_fifo_tb;
    wire [7:0]M_AXIS_0_tdata;
    reg M_AXIS_0_tready;
    wire [0:0]M_AXIS_0_tuser;
    wire M_AXIS_0_tvalid;
    reg [7:0]S_AXIS_0_tdata;
    wire S_AXIS_0_tready;
    reg [0:0]S_AXIS_0_tuser;
    reg S_AXIS_0_tvalid;
    wire [31:0]axis_data_count_0;
    wire [31:0]axis_rd_data_count_0;
    wire [31:0]axis_wr_data_count_0;
    reg m_axis_aclk_0;
    reg m_axis_aresetn_0;
    reg s_axis_aclk_0;
    reg s_axis_aresetn_0;

    always #10 s_axis_aclk_0 = ~s_axis_aclk_0;
    always #5 m_axis_aclk_0 = ~m_axis_aclk_0;
    
    initial begin
        s_axis_aclk_0 = 1'b0;
        m_axis_aclk_0 = 1'b0;
        s_axis_aresetn_0 = 1'b0;
        m_axis_aresetn_0 = 1'b0;
        S_AXIS_0_tvalid = 1'b0;
        M_AXIS_0_tready = 1'b0;
        S_AXIS_0_tuser = 1'b1;
        
        // Wait 100 ns for global reset to finish
        #101;
        
        s_axis_aresetn_0 = 1'b1;
        m_axis_aresetn_0 = 1'b1;
        
        #100;
        S_AXIS_0_tvalid = 1'b1;
        
        #400;
        M_AXIS_0_tready = 1'b1;
        
        #400
        S_AXIS_0_tuser = 1'b0;
    
    end
    
    always @(posedge m_axis_aclk_0) begin
        if(s_axis_aresetn_0 == 1'b0) begin
            S_AXIS_0_tdata <= 8'd0;
        end else begin
            S_AXIS_0_tdata <= S_AXIS_0_tdata + 8'd1;
        end
    end
    
    design_1_wrapper design_1_wrapper_i (
        .M_AXIS_0_tdata(M_AXIS_0_tdata),
        .M_AXIS_0_tready(M_AXIS_0_tready),
        .M_AXIS_0_tuser(M_AXIS_0_tuser),
        .M_AXIS_0_tvalid(M_AXIS_0_tvalid),
        .S_AXIS_0_tdata(S_AXIS_0_tdata),
        .S_AXIS_0_tready(S_AXIS_0_tready),
        .S_AXIS_0_tuser(S_AXIS_0_tuser),
        .S_AXIS_0_tvalid(S_AXIS_0_tvalid),
        .axis_data_count_0(axis_data_count_0),
        .axis_rd_data_count_0(axis_rd_data_count_0),
        .axis_wr_data_count_0(axis_wr_data_count_0),
        .m_axis_aclk_0(m_axis_aclk_0),
        .m_axis_aresetn_0(m_axis_aresetn_0),
        .s_axis_aclk_0(s_axis_aclk_0),
        .s_axis_aresetn_0(s_axis_aresetn_0)
    );

endmodule


これで、論理シミュレーションを行った。結果を示す。
OV5642_10_181205.png

OV5642_11_181205.png

タイミングチャートで、S_AXIS_0_tvalid が 1 になったときに、S_AXIS_0_tready が 1 になるのがだいぶ遅れるようだ。これでは今回の用途では使い物にならない。。。

次に、OV5642 の画像データを受け取るVivado HLS のIP も試しに作ってみた。まだデータはおかしいがC/RTL 強調シミュレーションをしてみた。
OV5642_13_181205.png

C/RTL 強調シミュレーションの波形を示す。
OV5642_14_181205.png

cam_sig_TREADY が 1 になった後で、0 に戻っている部分があるので、やはり、Vivado HLS 単体でも使用できない。

以上の結果より、”秋月電子カメラモジュールOV5642を使う3(OV5642インターフェースIPの検討)”のスキームは使えないことがわかった。
次回以降は、mt9d111_inf_axis IP を修正して、OV5642 対応としたいとおもう。つまり、HDL を書いてOV5642 の画像データをAXI4-Stream に変換する。
  1. 2018年12月05日 04:25 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う3(OV5642インターフェースIPの検討)

秋月電子カメラモジュールOV5642を使う2(OV5642の設定の検討)”の続き。

前回は、OV5642の設定レジスタの設定値を検討した。今回は、OV5642の信号を取り込むOV5642インターフェースIP を検討する。

OV5642の信号をVivado HLS で制作したインターフェースIP で受け取りたいが、Vivado HLS で作成したAXI4-Stream インターフェースのIP は for 文が始まることで初期化レイテンシがあることがある。処理化のレイテンシがあるとフリーランしているOV5642の画像データを取りこぼしてしまう。
例えば下の図は、AXI4-Stream インターフェースのMax Pooling層のシミュレーション波形だが、C Inputs -> ins(axis) -> ins_TREADY を見てみると、最初の方で 0 になっている部分があることが分かる。この 0 になっている部分はTDATA を受けられない期間なのだが、これがあるとプロトコル関係なくデータを出力するOV5642のデータを取りこぼしてしまう。
Max_Pooling_6_180225.png

そこで、最初にFIFO を置いてみればどうだろうか?そのFIFO がレイテンシなくデータを受け取れる必要はあるのだが、そうすれば、Vivado HLS で作ったOV5642インターフェースIP を接続できる。
OV5642_8_181204.png

Xilinx 社のIP として、AXI-Stream Data FIFO があるのでこれを使用できないか?と思う。 AXI-Stream Data FIFO は入力、出力に独立なクロックを選べるので、OV5642のPCLK のデータを受けて、AXI4-Stream のクロックのデータを出力することができる。HREF が 1 のときしか画像データは出ていないので、HREF 信号はTVALID に入れることにする。つまり、データが有効なときのみAXI-Stream Data FIFO にデータを取り込むことが出来る。
しかし、それでは画像フレームの先頭がわからない?そこで、VSYNC も一緒にTVALID に入れることにする。つまり、HREF とVSYNC のOR を取るわけだ。VSYNC はTUSER にも同時に入れておくと、VSYNC が 1 にアサートされたときのデータなのか?それともHREF が 1 になったきちんとしたデータなのか?が分かると思う。
もう1つ条件があってVSYNC が 1 のときはOV5642 の出力クロックのPCLK のデータレートでデータが入ってくるので、それを捌き切れるように AXI4-Stream の方のクロックをPCLK よりも周波数を高くしておこう。
HREF とVSYNC のタイミングは”秋月電子カメラモジュールOV5642を使う2(OV5642の設定の検討)”のタイミングチャート参照。
OV5642_9_181204.png

次は、AXI-Stream Data FIFO をHDLシミュレーションしてみて、レイテンシが無いかどうか?を確かめてみよう。
  1. 2018年12月04日 05:39 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

秋月電子カメラモジュールOV5642を使う2(OV5642の設定の検討)

秋月電子カメラモジュールOV5642を使う1”の続き。

Ultra96 用PMOD 拡張ボードの発注ができたので、OV5642 に戻ってUltra96 や ZYBO-Z7-20 で使えるようにしたい。MT9D111 がディスコンになってしまったので、容易に購入できる秋月電子で売っているOV5642 に乗り換えたいからだ。
問題は、今まで使っていた800 x 600 ピクセルの画像サイズはデフォルトではないので、大きな画像サイズを切り取るしか無いかな?ということだ。もしくは、VGAかXGA に乗り換えるか?大きな画像サイズを切り取るにしてもOV5642 のレジスタ設定で出来るようだ。

タイミングを示す。
秋月電子のOV5642 からダウンロードした。OV5642のPDFデータシートを引用する。
106、107ページの figure 6-9 と table 6-8 の一部を引用する。
OV5642_4_181203.png
OV5642_5_181203.png

figure 6-9 では、VSYNC、HREF はアクティブハイとして描かれているが、デフォルトでは、どちらもアクティブローだ。
OV5642のPDFデータシートの 105 ページの 0x4740 POLARITY CTRL 00 レジスタを引用する。
OV5642_6_181203.png

デフォルトでPCLK はネガティブ・エッジ・トリガ、VSYNC、HREF はアクティブローであることが分かる。VSYNC はアクティブローとして、 HREF はアクティブハイに設定変更しようと思う。ついでにPCLK はポジティブ・エッジ・トリガに変更しよう。つまり、0x4740 は 0x02 に設定変更しよう。figure 6-9 のタイミングチャートはVSYNC がインバートされる以外はそのままとする。(2018/12/05 : VSYNC の極性をアクティブローに変更した)

次にカメラ画像のフォーマットだが、これは、0x4300 FORMAT CONTROL 00 レジスタを設定するようだ。デフォルト値は 0xF8 で、Raw モードだが、MT9D111 と同様のRGB565 モードに設定変更する。
MT9D111 のRGB565 モードは、8ビット幅転送2回で{r[4:0],g[5:3]}, {g[2:0],b[4:0]} というようにパックされているので、0x4300 FORMAT CONTROL 00 レジスタは 0x61 に設定すれば良い。

SVGA 800 x 600 ピクセルの画像にすることを考える。
OV5642のPDFデータシートの 36 ページの figure 4-2 と table 4-2 を引用する。
OV5642_7_181203.png

インターフェースの 2014年11月号の57 〜 60 ページを参照してSVGA での設定値を求めた。

0x3800 TIMING CONTROL HS HIGH BYTE  0x00
0x3801 TIMING CONTROL HS LOW BYTE   0x50(80d)
0x3802 TIMING CONTROL VS HIGH BYTE  0x00
0x3803 TIMING CONTROL VS LOW BYTE   0x08(08d)
0x3804 TIMING HW HIGH BYTE          0x06
0x3805 TIMING HW LOW BYTE           0x40(1600d)
0x3806 TIMING VW HIGH BYTE          0x04
0x3807 TIMING VW LOW BYTE           0xB0(1200d)
0x3808 TIMING DVPHO HIGH BYTE       0x03
0x3809 TIMING DVPHO LOW BYTE        0x20(800d)
0x380A TIMING DVPVO HIGH BYTE       0x02
0x380B TIMING DVPVO LOW BYTE        0x58(600d)
0x380C TIMING HTS HIGH BYTE         0x09
0x380D TIMING HTS LOW BYTE          0x48(2376d, default)
0x380E TIMING VTS HIGH BYTE         0x06
0x380F TIMING VTS LOW BYTE          0x18(1560d, default)
0x3815                              0x2


また、0x3011 PLL CONTROL 02 はデフォルト値の 0x14 とする。
画像加算をするために 0x370D ANALOG CONTROL D は 0x06、0x3621 ANALOG CONTROL 01 は 0x09 とする。
  1. 2018年12月03日 05:10 |
  2. CMOSイメージセンサ
  3. | トラックバック:0
  4. | コメント:0

Ultra96用PMOD拡張ボード10(基板の改版3)

Ultra96用PMOD拡張ボード9(基板の改版2)”の続き。

前回は、Ultra96用PMOD拡張ボードの基板レイアウトが完成した。今回は、ガーバー・データとドリル・データを出力してFusion PCB に発注しよう。

Pcbnew のFile メニューから Plot... を選択した。
Plot ダイアログが開いた。下図の様にチェックを入れてPlot ボタンをクリックした。
Ultra96_ext_board2_16_181201.png

Generate Drill Files... ボタンをクリックして、Generate Drill Files ダイアログを表示させた。
下の図の様にセットして、Create Drill File ボタンをクリックしてドリル・ファイルを出力させた。
Ultra96_ext_board2_17_181201.png

これで、ガーバー・ファイルとドリル・ファイルが出力された。
KiCad のGerbView でガーバー・ファイルとドリル・ファイルを見てみよう。
GerbView を立ち上げてすべてのガーバー・ファイルとドリル・ファイルを入れた。
Ultra96_ext_board2_18_181201.png

裏面の配線を示す。
Ultra96_ext_board2_19_181201.png

表面の配線を示す。
Ultra96_ext_board2_20_181201.png

裏面のハンダ・マスクとシルクを示す。B7, B8 の文字のシルクの太さを変え忘れてしまったようだ。失敗。
Ultra96_ext_board2_21_181201.png

表面のハンダ・マスクとシルクを示す。
Ultra96_ext_board2_22_181201.png

ガーバー・ファイルとドリル・ファイルをZIP で固めた。
Ultra96_ext_board2_24_181202.png

SeeedStudio のPCB製作ページに行って、ガーバー・ファイルをアップロードした。1.2 mm の厚さで青の基板にした。
Ultra96_ext_board2_23_181201.png

値段は $4.9 だったが、DHL の配送料が $15.48 だったので、合計 $20.38 だった。
PayPal で支払った日本円は 2,401 円だった。
  1. 2018年12月02日 04:30 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0