📷

Ultra96 Linux で MIPI カメラから画像を取得する (セットアップ編)

に公開

最初に

こんにちは、フィックスターズ新規事業推進室の大澤です。
新規事業推進室では、Halide と呼ばれるドメイン固有言語のコンパイラに関する研究開発を行っています。FPGA 向けのバックエンドを独自に開発しており、Halide で記述した IP を Xilinx の FPGA 開発ボード上で動作させたりしています。
この度、Ultra96 と MIPI 拡張ボードを組み合わせ、イメージセンサで取得した画像を FPGA で処理してから CPU 側で取得することができるようになりましたので、ソースコードを公開し、セットアップ方法の説明、簡単な解説を行いたいと思います。特定ボード、特定カメラでの情報ではありますが、少しでも皆様のお役に立てれば幸いです。

まず、今回はセットアップ方法についての説明です。

必要なものは、

です。

後、AVNET の USB to JTAG/UART ボードもあると便利、というかないと不便だと思います。

1. ボードセットアップ

写真のようにカメラは J5 コネクタに差します。また、J13 ピンヘッダは写真と同じように 19 と 20, 21 と 22 をショートさせてください。同様に J15 ビンヘッダは 1 と 2 をショートさせてください。J14 ピンヘッダに関しては、写真と同じでなくても大丈夫と思います。

ちなみに、J13 ピンヘッダと J15 ピンヘッダのピン番号のアサインがどうなっているか、文書が見当たらないのですが、↓のようになっているようです。

2. debian Linux イメージ SD カードの作成

Linux カーネルおよびファイルシステムは ikwzm さんご作成のものを使わせていただいています。ikwzm さん、どうもありがとうございます。https://qiita.com/ikwzm/items/975ab6997905700dd2e0 の通りに実行して、SD カードを作成してください。

3. HW の作成

3.1 事前準備

作業は Vivado 上で行います。以下手順は全て Vivado 2018.2.2 Linux 版を使用して動作を確認しています。Windows 版でもいけると思いますが、試したことはありません。

ultra96 のボードファイルは https://github.com/Avnet/bdf から取得できます。取得したら /opt/Xilinx/Vivado/2018.2/data/boards/board_files/ に配置してください。

また、Xilinx が提供する MIPI IP を使用していますので、ライセンスをお持ちでない方は以下から評価ライセンスを取得し、インストールしてください。 https://japan.xilinx.com/products/intellectual-property/ef-di-mipi-csi-rx.html

3.2 ソースコード取得

以下の手順で github からソースコードを取得してください。

$ source 
$ git clone https://github.com/fixstars/ultra96_design.git
$ cd ultra96_design
$ git submodule init
$ git submodule update

3.3 プロジェクト作成およびビットストリーム作成

Vivado 2018.2 GUI を起動します。

$ source /opt/Xilinx/Vivado/2018.2/settings64.sh
$ vivado &

Vivado GUI の Tcl Console から

source ./script/create_project.tcl

を入力すると、プロジェクトが生成されます。プロジェクトが生成されたら、"Generate Bitstream" により bitstream を生成してください。まれに bitstream の生成が失敗する時があるようですが、もう一回 "Generate Bitstream" すると、たいていの場合は成功します。

3.4 bin ファイルの生成

生成された bitstream ファイルから bin ファイルを生成します。生成された bitstream は、ultra96_design/ultra96_design/ultra96_design.runs/impl_1/design_1_wrapper.bit です。

以下のような fpga.bif を用意して、

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

以下のコマンドを実行して fpga.bin を生成します。

$ bootgen -image fpga.bif -arch zynqmp -w -o fpga.bin

生成するファイル名は、fpga.bin としてください。 ultra96_design のトップディレクトリから以下を実行することによって fpba.bin を生成することもできます。

$ ./script/bit2bin.sh

4. V4L2 カーネルドライバおよびカメラ初期化 S/W のビルド

4.1 SDK による BSP 生成

Vivado 2018.2 GUI にて、File -> Export -> Export Hardware... を実行し、続いて File -> Launch SDK を実行します。 SDK GUI が開いたら、File -> New -> Board Support Package を選択します。"Xilinx Board Support Package Project" 画面ではデフォルトのまま何も変更せず、Finish を押下します。
次の "Board Support Package Settings" 画面でも、そのまま OK を押下してください。standalone_bsp_0 プロジェクトが生成されます。
この Board Support Package は、次のカーネルドライバのビルド時に使用されます。

4.2 カーネルドライバのビルド

以下の手順により、カーネルドライバ v4l2.ko を生成します。

$ cd ultra96_design/src/linux/driver
$ make

4.3 カメラ初期化 S/W のビルド

以下の手順により、カメラ初期化 S/W である caminit を生成します。

まず、必要に応じて修正を行います。
ultra96_design/src/linux/caminit/src/main.cc に caminit() 関数呼び出しがあります。この関数の第1引数で、Raspberry Pi カメラ v2 か Pcam-5C カメラかを指定できます。Raspberry Pi カメラ v2 を使う場合は SENSOR_IMX219 を、Pcam-5C カメラを使う場合は SENSOR_OV5640 を指定してください。

修正後、以下を実行します。

$ cd ultra96_design/src/linux/caminit/build/
$ make

5. 実機上でのカーネルドライバロードおよび初期化 S/W の実行

実機 Linux のユーザー名/パスワードは fpga/fpga, もしくは root/admin です。以下の手順は、基本的に root 権限が必要です。

実機 Linux 上に適当なディレクトリを作成してください。ultra96_design/overlay にある以下のファイルを作成したディレクトリにコピーしてください。

  • init_camera.sh
  • rm_camera.sh
  • fpga-load.dts
  • fclk0-zynqmp.dts
  • v4l2.dts

また、手順 4.3 で生成した

  • caminit

も同じディレクトリにコピーしてください。

/lib/modules/4.14.0-xlnx-v2018.2-zynqmp-fpga/kernel/drivers ディレクトリに v4l2 ディレクトリを作成し、手順 4.2 で作成した v4l2.ko を v4l2 ディレクトリにコピーしてください。その上で、以下を実行します。(任意のディレクトリ上で構いません。)

# depmod -a

最後に、3.4 で作成した fpga.bin を /lib/firmware ディレクトリにコピーします。

ここまできたら準備完了です。
./init_camera.sh を実行すると、FPGA コンフィギュレーション、V4L2 ドライバのロード、HW 初期化、カメラ初期化が行われます。

root@debian-fpga:~/fpga_manager# ./init_camera.sh
[ 8280.322752] fpga_manager fpga0: writing fpga.bin to Xilinx ZynqMP FPGA Manager
[ 8280.731570] fclkcfg: loading out-of-tree module taints kernel.
[ 8280.741059] fclkcfg amba:fclk0: driver installed.
[ 8280.745751] fclkcfg amba:fclk0: device name    : fclk0
[ 8280.750852] fclkcfg amba:fclk0: clock  name    : pl0_ref
[ 8280.756118] fclkcfg amba:fclk0: clock  rate    : 99999999
[ 8280.761516] fclkcfg amba:fclk0: clock  enabled : 1
[ 8280.766270] fclkcfg amba:fclk0: remove rate    : 1000000
[ 8280.771570] fclkcfg amba:fclk0: remove enable  : 0
[ 8280.799827] zynq_v4l2_init
[ 8280.802791] v4l2 amba_pl@0:v4l2: Device Tree Probing
[ 8280.807689] zynq_v4l2_probe
[ 8280.811046] zynq_v4l2_vdma_init
[ 8280.816000] zynq_v4l2_demosaic_init
[ 8280.819433] zynq_v4l2_mipicsi_init
ID = 0x2, 0x19
root@debian-fpga:~/fpga_manager#

6. 実機上でのカメラ画像取得テストの実行

6.1 事前準備

opencv-3.4.1 をソースコードからビルドしておきます。highgui を使うので、libgtk-3-dev パッケージと libgl1-mesa-dev パッケージを apt-get install でインストールしてから opencv-3.4.1 をビルドしてください。

6.2 テストのビルド

実機上に適当なディレクトリを作成し、ultra96_design/test にある以下のファイルをコピーします。

  • camera_umd ディレクトリ以下全部
  • makefile
  • uvc_camera_test.cc
  • yuvtest.cc
  • rgbtest.cc
  • rgbvideo.cc
  • cam.cc
  • cam.h

makefile 先頭の OPENCV_DIR を適当に修正し、make を実行してください。

6.3 テスト実行

OpenCV ライブラリを使用するので、LD_LIBRARY_PATH に OpenCV ライブラリがあるパスを追加してください。その上で rgbtest を実行します。実行すると、20 フレーム分の png 画像ファイルを生成します。

Pcam-5C カメラで取得すると自然な色合いですが↓ Raspberry Pi カメラ v2 で取得すると緑がかった色合いになります↓

7. display port 経由での外部ディスプレイ出力

test ディレクトリでビルドを行うと、他にもテストプログラムが生成されます。rgbvideo を実行すると、カメラ動画を表示させることができます。表示出力先として、X11 forwarding を利用して ssh 経由で作業 PC 上に X Window を表示させることができます。ただし、環境にもよると思いますが、1fps か 2fps くらいでしょうか、とても遅いです。

そこで、display port で繋いだ外部ディスプレイに直接出力しましょう。

以下の手順で、とりあえず外部ディスプレイに X window を出力することができます。

  • 実機の display port と外部ディスプレイを接続する
  • 実機上で apt-get install により xserver-xorg パッケージと lightdm パッケージと gnome-session パッケージをインストール
  • ultra96_design/etc/xorg.conf を実機上の /etc/X11/ にコピー
  • 実機再起動
  • 起動時に外部ディスプレイにログイン画面が表示されるので、実機の USB ポートに繋いだキーボードから root, admin でログイン
  • シリアル端末、もしくは ssh ログイン端末上で、export DISPLAY=:0.0 を実行
  • シリアル端末、もしくは ssh ログイン端末上で rgbvideo を実行すると、外部ディスプレイに表示される

ただし、これをやると、その後の shutdown 時に drm_vblank_cleanup で Exception が発生してしまいます。回避策は今のところ分かりません。

8. 解像度、カメラ出力フォーマットの変更

デフォルトでは、RGB24 640x480 画像を出力するような設定にしています。 一応、

  • RGB24 640x480
  • RGB24 1280x720
  • RGB24 1920x1080
  • YUYV 640x480
  • YUYV 1280x720
  • YUYV 1920x0180

を出せるように用意をしています。
ただ、V4L2 の VIDIOC_S_FMT コマンドを使って動的に切り替える、なんてことはできません、スミマセン。変更するには、bitstream の再作成、SW の再ビルドが必要になります。

8.1 bitstream の再作成

ultra96_design/ip/demosaic ディレクトリに、xilinx_com_hls_demosaic_root_1_0_[フォーマット][解像度].zip を置いています。
ultra96_design/ip/demosaic ディレクトリで必要な zip ファイルを unzip し、touch component.xml してください。
Vivado 2018.2 GUI から demosaic IP を upgrade した上で、"Generate Bitstream" により bitstream を再生成してください。bootgen を使って bit から bin に変換することを忘れずに。

8.2 V4L2 ドライバの修正

ultra96_design/src/linux/driver/zynq_v4l2.h と ultra96_design/src/linux/driver/main.c を修正する必要があります。
出力フォーマットを変更する場合は、zynq_v4l2.h を修正します。
zynq_v4l2.h の 15行目、YUYVOUT 定義を有効にすれば YUYV 出力、無効にすれば RGB24 出力です。
解像度を変更する場合は、main.c を修正します。
main.c の 15行目、16行目、vdma_h_res, vdma_v_res が横、高さを決定します。

8.3 caminit の修正

解像度の変更を行う場合のみ、修正が必要です。
ultra96_design/src/linux/caminit/src/main.cc に記述されている caminit の第2引数を変更します。

  • RESOLUTION_640_480
  • RESOLUTION_1280_720
  • RESOLUTION_1920_1080

8.4 テストプログラムの修正

rgbtest, yuvtest, uvc_camera_test, rgbvideo いずれにも先頭付近に WIDTH, HEIGHT の定義がありますので、これを変更します。

と、一応用意はしてみたものの、Raspberry Pi カメラ v2 だとあまりまともに動いてくれないです、スミマセン。

出力フォーマット 解像度 FPS
RGB24 640x480 30
RGB24 1280x720 15
RGB24 1920x1080 15
YUYV 640x480 30
YUYV 1280x720 正常動作せず
YUYV 1920x1080 正常動作せず

Pcam-5C カメラの場合は、どの組み合わせでも 30fps で動くと思います。

[解説編] に続きます。

Fixstars Tech Blog /proc/cpuinfo

Discussion