#1. はじめに
1500円 ZYNQ 基板( EBAZ4205 )で、Digilent Zybo Z7-20 の Pcam 5C デモを動かしてみます。
このデモでは、CMOS カメラで撮影した映像を、HDMI 出力してモニタに映すことができます。
カメラは、手持ちの Raspberry Pi Camera Module V2 (SONY IMX219) を使用します。
記述が長くなりましたので、記事を前編と後編に分けています。
前編: Vivado での作業
後編: 接続ケーブルの作成と、Vitis での作業
後編の今回は、CSI-2 カメラ入力 + HDMI 出力ケーブルの作成と、Vitis での動作確認を行います。
#2. 使用環境
- Windows10 Pro (20H2)
- Vivado 2020.1 (Windows 版)
- Vitis 2020.1 (同上)
- EBAZ4205
- Raspberry Pi Camera Module V2 (SONY IMX219 搭載)
- HDMI Monitor (Leader LV5382)
#3. 参考資料
Zybo Z7 Pcam 5C Demo
OV5640 datasheet
IMX219 datasheet
XAPP894 D-PHY Solutions
#4. ハードウェアの準備
##4-1. HDMI 出力+CSI-2 入力ケーブルの作成
これを、
aitendo の HDMI コネクタ with 基板 と、
★2.0★2列ピンソケット [PS20DV] 2x10 を使って作成します。
完成したケーブルは下記のようになりました。
HDMI と CSI-2 の高速差動信号が通る線は、波形改善のためツイストしてあります。
Zybo HDMIデモでは、ツイストで顕著に性能向上したので、撚り数を更に増やしてみました。
( FFC ケーブルについて注意 )
Raspberry Pi Camera Module V2 に付属の FFC ケーブルは、端子が逆面タイプです。
FFCコネクタwith基板では、端子が同一面の FFC ケーブルを使用しないと、1-15 番ピンが、裏返しの 15-1 番ピンに接続されてしまいます。
そのため、FFCケーブル★1.0-15P★ [FFC1015P] 150S も一緒に調達してください。
##4-2. ダンピング抵抗の 22Ω → 0Ω交換
CSI-2 受信、HDMI 送信どちらも、PL の I/O ピンから直結する回路にする必要があります。
HDMIデモの時と同様に、22Ω のダンピング抵抗を、0Ω に交換します。
※HDMI デモで使った EBAZ4205 基板は、一部に 3.3V プルアップ抵抗を付けたので、また別の EBAZ4205 基板を使用しています。いっぱい買ってあるので全然 OK。
DATA1~DATA3 コネクタへの途中にある 22Ω のダンピング抵抗を、すべて 0Ωに交換します。
基板上のダンピング抵抗を、全て交換しました。
(写真は使いまわし)
あと、DATA1 コネクタから接続する HDMI OUT の +5V Power 端子に電源を出力するため、逆流防止ダイオード D21 にジャンパを追加します。
(EBAZ4205 の電源供給は +5V で行っているので、V IN に直結でよい)
同様に、DATA2 コネクタから +3.3V を出力するため、逆流防止ダイオード D22-K に、基板上の +3.3V 電源ラインからジャンパを追加します。
実基板の配線は、下記のようになりました。
+3.3V は C2321/C2319 から引き出し、+5V は D21 をバイパスしています。
#5. Vitis プロジェクトの作成
##5-1. プログラムの読み込み
設計ファイルから sdk_appsrc フォルダを展開して、適当なフォルダに置いておきます。
このフォルダに、前回の記事でエクスポートした system_wrapper.xsa をコピーします。
例では \デスクトップ\EBAZ です。
Vitis を起動したら、File - Switch Workspace... - Other... で \デスクトップ\EBAZ をワークスペースに指定して、Launch します。
Create Platform Project で、EBAZ-PiCam としてプロジェクトを作成し、system_wrapper.xsa を指定して Finish。
プラットフォームプロジェクトを、先にビルドしておきます。ビルドで Out-of-date が解消します。
次に File - New - Application Project... で EBAZ-PiCam を platform に選択し、EBAZ-PiCam_app という名前で Next。
standalone on ps7_cortexa9_0 で Next した後、Empty Applicaion(C++) を選び Finish。
EBAZ-PiCam_app の src フォルダで右クリックして、Inport Sources... を選びます。
From directory: に \sdk_appsrc を指定します。
Import Sources で、sdk_appsrc チェック、Overwrite existing resources without warning にチェックを入れて Finish。
##5-2. カメラ設定の変更
OV5640 用の設定ファイルを、IMX219 用に差し替えます。
OV5640.h を、下記のファイルで上書きします。
同ファイル名で、中身だけ IMX219 用に変更してあります。
namespace に digilent が残っていますが、ご愛敬ということで...
/*
* OV5640.h
*
* Created on: May 15, 2021
* Author: kan573
* Retarget : IMX219 (Raspberry Pi Camera Module V2.1)
*/
#ifndef OV5640_H_
#define OV5640_H_
#include <sstream>
#include <iostream>
#include <cstdio>
#include <climits>
#include "I2C_Client.h"
#include "GPIO_Client.h"
#include "../hdmi/VideoOutput.h"
#define SIZEOF_ARRAY(x) sizeof(x)/sizeof(x[0])
#define MAP_ENUM_TO_CFG(en, cfg) en, cfg, SIZEOF_ARRAY(cfg)
namespace digilent {
typedef enum {OK=0, ERR_LOGICAL, ERR_GENERAL} Errc;
namespace OV5640_cfg {
using config_word_t = struct { uint16_t addr; uint8_t data; } ;
using mode_t = enum { MODE_720P_1280_720_60fps = 0, MODE_1080P_1920_1080_15fps,
MODE_1080P_1920_1080_30fps, MODE_END } ;
using config_modes_t = struct { mode_t mode; config_word_t const* cfg; size_t cfg_size; };
using test_t = enum { TEST_DISABLED = 0, TEST_EIGHT_COLOR_BAR, TEST_END };
using awb_t = enum { AWB_DISABLED = 0, AWB_SIMPLE, AWB_ADVANCED, AWB_END };
using config_awb_t = struct { awb_t awb; config_word_t const* cfg; size_t cfg_size; };
using isp_format_t = enum { ISP_RAW = 0, ISP_RGB, ISP_END };
uint16_t const OV5640_REG_PRE_ISP_TEST_SET1 = 0x503D;
uint16_t const OV5640_FORMAT_MUX_CONTROL = 0x501f;
config_word_t const cfg_advanced_awb_[] =
{
{0x0100 ,0x01} // Start Stream
};
config_word_t const cfg_simple_awb_[] =
{ // No function assignment
};
config_word_t const cfg_disable_awb_[] =
{ // No function assignment
};
config_word_t const cfg_720p_60fps_[] =
{ //1280 x 720 binned, RAW10, MIPISCLK=456M, SCLK=91.2Mz, PCLK=91.2M, 2lane_mipi
{0x6620, 0x01},
{0x6621, 0x01},
{0x6622, 0x01},
{0x6623, 0x01},
{0x30EB, 0x05},
{0x30EB, 0x0C},
{0x300A, 0xFF},
{0x300B, 0xFF},
{0x30EB, 0x05},
{0x30EB, 0x09},
{0x0114, 0x01},
{0x0128, 0x00},
{0x012A, 0x18},
{0x012B, 0x00},
{0x0157, 0x50},
{0x0158, 0x01},
{0x0159, 0x00},
{0x015A, 0x03},
{0x015B, 0x68},
{0x0160, 0x03},
{0x0161, 0x6E},
{0x0162, 0x0D},
{0x0163, 0x80},
{0x0164, 0x01},
{0x0165, 0x68},
{0x0166, 0x0B},
{0x0167, 0x68},
{0x0168, 0x02},
{0x0169, 0x00},
{0x016A, 0x07},
{0x016B, 0xA0},
{0x016C, 0x05},
{0x016D, 0x00},
{0x016E, 0x02},
{0x016F, 0xD0},
{0x0170, 0x01},
{0x0171, 0x01},
{0x0172, 0x00},
{0x0174, 0x01},
{0x0175, 0x01},
{0x0176, 0x01},
{0x0177, 0x01},
{0x018C, 0x0A},
{0x018D, 0x0A},
{0xD1EA, 0x00},
{0xD1EB, 0x20},
{0x0301, 0x05},
{0x0303, 0x01},
{0x0304, 0x03},
{0x0305, 0x03},
{0x0306, 0x00},
{0x0307, 0x39},
{0x0309, 0x0A},
{0x030B, 0x01},
{0x030C, 0x00},
{0x030D, 0x72},
{0x455E, 0x00},
{0x471E, 0x4B},
{0x4767, 0x0F},
{0x4750, 0x14},
{0x4540, 0x00},
{0x47B4, 0x14},
{0x4713, 0x30},
{0x478B, 0x10},
{0x478F, 0x10},
{0x4793, 0x10},
{0x4797, 0x0E},
{0x479B, 0x0E},
{0x0601, 0x00},
{0x0620, 0x00},
{0x0621, 0x00},
{0x0621, 0x00},
{0x0623, 0x00},
{0x0624, 0x05},
{0x0625, 0x00},
{0x0626, 0x02},
{0x0627, 0xD0},
};
config_word_t const cfg_1080p_15fps_[] =
{ //1920 x 1080 @ 30 fps, RAW10, MIPISCLK=288, SCLK=57.6MHz, PCLK=57.6M, 2lane_mipi
{0x6620, 0x01},
{0x6621, 0x01},
{0x6622, 0x01},
{0x6623, 0x01},
{0x30EB, 0x05},
{0x30EB, 0x0C},
{0x300A, 0xFF},
{0x300B, 0xFF},
{0x30EB, 0x05},
{0x30EB, 0x09},
{0x0114, 0x01},
{0x0128, 0x00},
{0x012A, 0x18},
{0x012B, 0x00},
{0x0157, 0x80},
{0x0158, 0x01},
{0x0159, 0x00},
{0x015A, 0x04},
{0x015B, 0x52},
{0x0160, 0x04},
{0x0161, 0x58},
{0x0162, 0x0D},
{0x0163, 0x78},
{0x0164, 0x02},
{0x0165, 0xA8},
{0x0166, 0x0A},
{0x0167, 0x28},
{0x0168, 0x02},
{0x0169, 0xB4},
{0x016A, 0x06},
{0x016B, 0xEC},
{0x016C, 0x07},
{0x016D, 0x80},
{0x016E, 0x04},
{0x016F, 0x38},
{0x0170, 0x01},
{0x0171, 0x01},
{0x0172, 0x00},
{0x0174, 0x00},
{0x0175, 0x00},
{0x0176, 0x00},
{0x0177, 0x00},
{0x018C, 0x0A},
{0x018D, 0x0A},
{0xD1EA, 0x00},
{0xD1EB, 0x20},
{0x0301, 0x05},
{0x0303, 0x01},
{0x0304, 0x02},
{0x0305, 0x02},
{0x0306, 0x00},
{0x0307, 0x24},
{0x0309, 0x0A},
{0x030B, 0x01},
{0x030C, 0x00},
{0x030D, 0x48},
{0x455E, 0x00},
{0x471E, 0x4B},
{0x4767, 0x0F},
{0x4750, 0x14},
{0x4540, 0x00},
{0x47B4, 0x14},
{0x4713, 0x30},
{0x478B, 0x10},
{0x478F, 0x10},
{0x4793, 0x10},
{0x4797, 0x0E},
{0x479B, 0x0E},
{0x0601, 0x00},
{0x0620, 0x00},
{0x0621, 0x00},
{0x0621, 0x00},
{0x0623, 0x00},
{0x0624, 0x07},
{0x0625, 0x80},
{0x0626, 0x04},
{0x0627, 0x38},
};
config_word_t const cfg_1080p_30fps_[] =
{ //1920 x 1080 @ 60fps, RAW10, MIPISCLK=520, SCLK=130MHz, PCLK=130M, 2lane_mipi
{0x6620, 0x01},
{0x6621, 0x01},
{0x6622, 0x01},
{0x6623, 0x01},
{0x30EB, 0x05},
{0x30EB, 0x0C},
{0x300A, 0xFF},
{0x300B, 0xFF},
{0x30EB, 0x05},
{0x30EB, 0x09},
{0x0114, 0x01},
{0x0128, 0x00},
{0x012A, 0x18},
{0x012B, 0x00},
{0x0157, 0xB0},
{0x0158, 0x01},
{0x0159, 0x00},
{0x015A, 0x04},
{0x015B, 0xE0},
{0x0160, 0x04},
{0x0161, 0xE8},
{0x0162, 0x0D},
{0x0163, 0x78},
{0x0164, 0x02},
{0x0165, 0xA8},
{0x0166, 0x0A},
{0x0167, 0x28},
{0x0168, 0x02},
{0x0169, 0xB4},
{0x016A, 0x06},
{0x016B, 0xEC},
{0x016C, 0x07},
{0x016D, 0x80},
{0x016E, 0x04},
{0x016F, 0x38},
{0x0170, 0x01},
{0x0171, 0x01},
{0x0172, 0x00},
{0x0174, 0x00},
{0x0175, 0x00},
{0x0176, 0x00},
{0x0177, 0x00},
{0x018C, 0x0A},
{0x018D, 0x0A},
{0xD1EA, 0x00},
{0xD1EB, 0x20},
{0x0301, 0x04},
{0x0303, 0x01},
{0x0304, 0x02},
{0x0305, 0x02},
{0x0306, 0x00},
{0x0307, 0x41},
{0x0309, 0x0A},
{0x030B, 0x01},
{0x030C, 0x00},
{0x030D, 0x82},
{0x455E, 0x00},
{0x471E, 0x4B},
{0x4767, 0x0F},
{0x4750, 0x14},
{0x4540, 0x00},
{0x47B4, 0x14},
{0x4713, 0x30},
{0x478B, 0x10},
{0x478F, 0x10},
{0x4793, 0x10},
{0x4797, 0x0E},
{0x479B, 0x0E},
{0x0601, 0x00},
{0x0620, 0x00},
{0x0621, 0x00},
{0x0621, 0x00},
{0x0623, 0x00},
{0x0624, 0x07},
{0x0625, 0x80},
{0x0626, 0x04},
{0x0627, 0x38},
};
config_word_t const cfg_init_[] =
{
{0x0100, 0x00}, // Stream off
{0x0103, 0x01} // Software reset
};
config_modes_t const modes[] =
{
{ MAP_ENUM_TO_CFG(MODE_720P_1280_720_60fps, cfg_720p_60fps_) },
{ MAP_ENUM_TO_CFG(MODE_1080P_1920_1080_15fps, cfg_1080p_15fps_) },
{ MAP_ENUM_TO_CFG(MODE_1080P_1920_1080_30fps, cfg_1080p_30fps_), },
};
config_awb_t const awbs[] =
{
{ MAP_ENUM_TO_CFG(AWB_DISABLED, cfg_disable_awb_) },
{ MAP_ENUM_TO_CFG(AWB_SIMPLE, cfg_simple_awb_) },
{ MAP_ENUM_TO_CFG(AWB_ADVANCED, cfg_advanced_awb_) }
};
}
class OV5640 {
public:
class HardwareError;
OV5640(I2C_Client& iic, GPIO_Client& gpio) :
iic_(iic), gpio_(gpio)
{
reset();
init();
}
void init()
{
usleep(1000000);
size_t i;
for (i=0;i<sizeof(OV5640_cfg::cfg_init_)/sizeof(OV5640_cfg::cfg_init_[0]); ++i)
{
writeReg(OV5640_cfg::cfg_init_[i].addr, OV5640_cfg::cfg_init_[i].data);
}
usleep(2000000); // wait 24ms after reset
}
Errc reset()
{
//Power cycle
gpio_.clearBit(gpio_.Bits::CAM_GPIO0);
usleep(1000000);
gpio_.setBit(gpio_.Bits::CAM_GPIO0);
usleep(1000000);
return OK;
}
Errc set_mode(OV5640_cfg::mode_t mode)
{
if (mode >= OV5640_cfg::mode_t::MODE_END)
return ERR_LOGICAL;
auto cfg_mode = &OV5640_cfg::modes[mode];
writeConfig(cfg_mode->cfg, cfg_mode->cfg_size);
return OK;
}
Errc set_awb(OV5640_cfg::awb_t awb)
{
if (awb >= OV5640_cfg::awb_t::AWB_END)
return ERR_LOGICAL;
auto cfg_mode = &OV5640_cfg::awbs[awb];
writeConfig(cfg_mode->cfg, cfg_mode->cfg_size);
return OK;
}
Errc set_isp_format(OV5640_cfg::isp_format_t isp)
{
if (isp >= OV5640_cfg::isp_format_t::ISP_END)
return ERR_LOGICAL;
switch (isp)
{
case OV5640_cfg::isp_format_t::ISP_RGB:
// writeReg(OV5640_cfg::OV5640_FORMAT_MUX_CONTROL, 0x01);
break;
case OV5640_cfg::isp_format_t::ISP_RAW:
// writeReg(OV5640_cfg::OV5640_FORMAT_MUX_CONTROL, 0x03);
break;
default:
break;
}
return OK;
}
~OV5640() { }
void set_test(OV5640_cfg::test_t test)
{
switch(test)
{
case OV5640_cfg::test_t::TEST_DISABLED:
// writeReg(OV5640_cfg::OV5640_REG_PRE_ISP_TEST_SET1, 0x00);
break;
case OV5640_cfg::test_t::TEST_EIGHT_COLOR_BAR:
// writeReg(OV5640_cfg::OV5640_REG_PRE_ISP_TEST_SET1, 0x80);
break;
default:
break;
}
}
void readReg(uint16_t reg_addr, uint8_t& buf)
{
for(auto retry_count = retry_count_; retry_count > 0; --retry_count)
{
try
{
auto buf_addr = std::vector<uint8_t>{(uint8_t)(reg_addr>>8), (uint8_t)reg_addr};
iic_.write(dev_address_, buf_addr.data(), buf_addr.size());
iic_.read(dev_address_, &buf, 1);
break; //If no exceptions, no mo retries
}
catch (I2C_Client::TransmitError const& e)
{
if (retry_count > 0)
{
continue;
}
else
{
throw HardwareError(HardwareError::IIC_NACK, e.what());
}
}
}
}
void writeReg(uint16_t reg_addr, uint8_t const reg_data)
{
for(auto retry_count = retry_count_; retry_count > 0; --retry_count)
{
try
{
auto buf = std::vector<uint8_t>{(uint8_t)(reg_addr>>8), (uint8_t)reg_addr, reg_data};
iic_.write(dev_address_, buf.data(), buf.size());
break; //If no exceptions, no mo retries
}
catch (I2C_Client::TransmitError const& e)
{
if (retry_count > 0) continue;
else throw HardwareError(HardwareError::IIC_NACK, e.what());
}
}
}
void writeRegLiquid(uint8_t const reg_data)
{
for(auto retry_count = retry_count_; retry_count > 0; --retry_count)
{
try
{
auto buf = std::vector<uint8_t>{0x06, 0x01, reg_data}; // 0x0601 = test_pattern_mode
iic_.write(dev_address2_, buf.data(), buf.size());
break; //If no exceptions, no mo retries
}
catch (I2C_Client::TransmitError const& e)
{
if (retry_count > 0) continue;
else throw HardwareError(HardwareError::IIC_NACK, e.what());
}
}
}
class HardwareError : public std::runtime_error
{
public:
using Errc = enum {WRONG_ID = 1, IIC_NACK};
HardwareError(Errc errc, char const* msg) : std::runtime_error(msg), errc_(errc) {}
Errc errc() const { return errc_; }
private:
Errc errc_;
};
private:
void usleep(uint32_t time)
{//TODO couldn't think of anything better
for (uint32_t i=0; i<time; i++) ;
}
void writeConfig(OV5640_cfg::config_word_t const* cfg, size_t cfg_size)
{
for (size_t i=0; i<cfg_size; ++i)
{
writeReg(cfg[i].addr, cfg[i].data);
}
}
private:
I2C_Client& iic_;
GPIO_Client& gpio_;
uint8_t dev_address_ = (0x20 >> 1);
uint8_t dev_address2_ = (0x20 >> 1);
unsigned int const retry_count_ = 10;
};
} /* namespace digilent */
#endif /* OV5640_H_ */
##5-3. コンパイル
これで準備はできましたので、アプリケーションプロジェクトをビルドします。
ビルドが終わったら準備完了です。
#6. 動作確認
EBAZ4205 基板と HDMI出力/CSI-2 入力ケーブル、HDMI モニタ、他一式を接続しておきます。
EBAZ4205 基板と HDMI モニタの電源を入れ、Vitis から認識できるようにしておきます。
TeraTerm を起動して、設定で Local Echo にチェックを入れて OK します。
##6-1. プログラム起動
TeraTerm にアプリケーションの操作画面が表示され、HDMI モニタにカメラの映像が映ります。
##6-2. プログラムの操作方法
HDMI Demo の時とは、操作が違うので注意してください。
指定のアルファベットや数値を入力した後、ENTER する必要があります。
main.cc はそのまま流用していますので、操作内容が画面と合っていません。
使える操作は、下記の通りです。
a: カメラと HDMI 出力のモード切り替え
1, CAMERA: 1280x 720/60p, HDMI OUT: 1280x720/60p
2, CAMERA: 1920x1080/30p, HDMI OUT: 1920x1080/60p
3, CAMERA: 1920x1080/60p, HDMI OUT: 1920x1080/60pb: IMX219 内蔵テストパターン出力
00, テストオフ(通常出力)
01, 全黒
02, 100% カラーバー
03, グレーフェード付 100% カラーバー
04, PN9(9ビット疑似ノイズ)
05, 16分割カラーバー
06, 16分割逆カラーバー
07, カラムカウンタ
08, 逆カラムカウンタ
09, PN31(31ビット疑似ノイズ)d: 機能の割り当て無し
e: 指定レジスタに書き込み
f: 指定レジスタから読み出し
g: ガンマカーブ変更(Bayer2RGB IP)
1, Gamma Factor = 1
2, Gamma Factor = 1/1.2
3, Gamma Factor = 1/1.5
4, Gamma Factor = 1/1.8 (Default)
5, Gamma Factor = 1/2.2h: 機能の割り当て無し
メニューの場所により、アルファベットまたは数字 1 文字を入力して ENTER のところと、
2桁 or 4桁の HEX 値を入力して ENTER のところがあります。
メニューのアルファベット 1 文字を入力する所で返答がおかしくなったら、
aa とか bb というように 2 文字を入力して ENTER すると戻ります。
(コマンド解釈に癖が多い)
##6-3. テストパターンの表示
メニューの b で、IMX219 に内蔵されたテストパターンを表示することができます。
全部で 10 種類のテストパターンがあり、CSI-2 信号経路の評価に使えます。
パターンの詳細は、データシートを参照してください。
例は 03, グレーフェード付 100% カラーバー です。
00, テストオフ(通常出力) で、元のカメラ画像に戻ります。
##6-4. レジスタの Read/Write
メニューの e と f で、カメラのレジスタを直接読み書きできるのが、非常に便利です。
カメラの露出が、0x0157 で操作できますので、映像が明るすぎる/暗すぎるときは、値を変更してみてください。
大きい値を書くと露出量を増やす(明るく映る)、小さい値では露出量を減らす(暗く映る)
という操作ができます。
全てのレジスタを読み書きできますので、IMX219 データシートを見ながら触ってみてください。
#7. IMX219 の設定と、ケーブルの調整について
データシートで設定用レジスタの詳細を読めますが、パラメータ値を実際に書いてみると、いろいろと制約があることがわかりました。
raspivid でカメラをいろいろ操作して、I2C のデータを全ダンプして確認し、IMX219 の設定方法を理解しました。
今回の実習では、ケーブルと Zynq の実力値で調整した設定を ov5640.h に記載しています。
Zynq の LVDS_25 な I/O ピンで受信できる信号周波数は、スピードグレード -1 の場合、最大 950 Mb/s となっています(DS187)
1080/60p の設定では、1040 Mbps で受信している計算になりますので、受信エラーで画面にノイズが見えます。
03 グレーフェード付 100% カラーバーで、特定の明るさの所にノイズが見えやすいです。
FFC ケーブルや、CSI-2 - DATA2 ケーブルを指でつまむと、ノイズの見え方が変わります。
ピンセットで CSI-2 の信号線を触れて、良くなる(⇒ ディレイさせると受信状態が改善する)ところを探し、配線を適度に延長すると、ノイズを減らすことができます。
手元のケーブルでは、1080/60p でも、ほぼノイズレスが実現できています。
上にあるグレーフェード付 100% カラーバーの画像を拡大してみると、右側のブルーの帯とグレーの帯の中間あたりに、それぞれ少しノイズが出ているのが見えると思います。
#8. 全体のまとめ
EBAZ4205 で、Zybo Z7 Pcam 5C Demo を実行することができました。
RasPi にカメラを接続してHDMI出力するのと違い、スケーラが噛まない素のカメラ画像を確認することができます。
汎用の CSI-2 カメラテストベッドとして利用してもよさそうです。