2017年1月22日日曜日

ジャンクカメラ

近所のリサイクルショップで防犯カメラのジャンク品を見つけ、購入してみた。


で、分解してみた。



基板寸法はOV7670のカメラモジュールよりも小さいので、残念ながらこの筐体を流用してOV7670のモジュールを組み込むことは出来ない。レンズを外してOV7670のカメラモジュールに嵌めてみたところ適合した。ネジ部は互換性があるようだ。規格とかdefact standardがあるんだろうか?

OV7670のレンズでの撮影画像


レンズを交換して撮影した画像 ... このレンズは倍率が大きいようだ。









ZYBO34 (OV7670のパラメータ調整、左端の黒い領域を消すには)

今まではZYBOのHDMI出力もPCのHDMI出力もHDMI切替器を介して1台のLCDに表示させていたのだが、同時に両方の映像が見えないと作業がやり辛いのでモバイルモニターという8.9インチのdisplayを購入した。ZYBOのHDMI出力はこれに接続する。Dosparaで13,500だった。このdisplayの解像度は1920x1200だが、それ以下の解像度のHDMI信号を入力した場合は拡大せず以下のように中央に表示するようだ。画面が小さいせいか表示画像はとても綺麗に見える。


以前から気になっていたのだが、OV7670で撮影した画像は左側に太い黒い領域が入る。

出力画像をカラーバーにした場合は正常なので、 どうもイメージセンサからの画像の切り出し位置がズレているようだ。黒領域を無くし正常な画像を出力するにはどうしたらいいか? と設定を色々変えてみた結果、HSTARTとHSTOPを以下のように設定することで黒領域を無くすことができた。切り出し位置を右に16画素分ずらしている。データシートによればVGAでのブランキング期間も含めた総ピクセル数は784なのでhstopは次のように計算して求めた。

hstop = (hstart + 640) % 784
HSTOP = hstop / 8
HREF[5:3] = hstop % 8



画像も正常になったしffmpegで圧縮・録画やstreamingも出来ることが判ったので、防犯カメラ装置的なものを作ってみたくなった。TVなどでみる防犯カメラ装置はだいたいカメラが4台あってそれぞれのカメラの映像をモニタに表示&録画している。
イメージとしてはこんな感じ。

幸いなことにOV7670のカメラモジュールは4台購入してある。

まずは、4台のカメラをZYBOに接続する手段を検討しなければならない。


2017年1月9日月曜日

ZYBO33 (OV7670用IPの作成 3)

IPの動作確認ができたので、カメラの画像をffmpegとffserverでencode & streaming してみた。
その為には何とかしてカメラの画像をffmpegに入力する必要があるが、ffmpegはfile formatにfbdev (Linux framebuffer)が指定できるので、カメラ用のframebufferを作ることにした。と言ってもやることは単純で、devicetreeにカメラ用のsimple framebufferの定義を追加するだけだ。bufferは0x1F500000番地からの領域とした。

Linuxの起動ログ … fb1が認識されている。

OS起動後、以下のプログラムでIPを起動する。
このプログラムを一度実行すると、IPが動作状態になりカメラの画像がframebufferに記録される。

・ffserverとffmpegの起動


・ ffserver.conf
ffserverを使うためにはffserver.confに各種パラメータの値を書く必要があり、標準的にはそれを/etcに配置する。今回は以下のように書いた。

codecはflvを使った。swfも指定してみたのだが、client側のブラウザで画像表示出来なかった。また、カメラからは640x480 30fpsで取り込んでいるがstreamingは320x240のサイズに縮小した。

ffmpegが動作している様子 ...  一応 framerate は30fpsにはなっている。


母艦PC上のブラウザからzyboのサーバーにアクセスして画像を表示させてみた。(その様子をvokoscreenで録画した。)

singlebufferなので時折、画像が乱れるが被写体の動きは滑らかだ。

zybo側のcpu負荷やmemory消費の状態





ZYBO32 (OV7670用IPの作成 2)

・動作確認
IPの動作確認はベアメタル環境ではなくLinux環境で行うことにした。と言ってもデバイスドライバは作成せず、IPのレジスタ空間を/dev/memとmmapでユーザー空間にマッピングして読み書きする。また、バッファのページ数は1ページでフレームバッファに直接書き出すようにした。

プログラムのmain()関数


pCIF (st_cif)はcif ipのレジスタモデルの構造体で以下のように定義している。


OV7670への設定値
色々試行錯誤の結果、現状以下のパラメータを設定している。


SCCBアクセス用関数


動作させてみたところ、画は表示されたのだが90°回転していた。OV7670 camera boardは下の写真のように作成したのだが、cameraモジュールをよく見たら方向が90°違っていた。


このカメラモジュールはピンヘッダが垂直になるのが向きとしては正しいようだ。で、以下のように修正した。


以下は動作させている様子。フレームバッファの中央の領域に画像データを書かせている。YUV422とRGB565の設定で動作させてみたが表示された画像の質は殆ど同じだった。

YUV422の場合の画像


RGB565の場合の画像



ZYBO31 (OV7670用IPの作成 1)

OV7670用のIPが出来た。回路はverilogで記述した。

構成図


・cif_rx
OV7670からの信号を受けるモジュールで、色変換処理(YUV422➔RGB888やRGB565➔RGB888)も行う。OV7670からは一応VSYNC、HREF信号も受けているが使用していない。OV7670はCCIR656 formatをサポートしており、このformatに設定すると画像データのrowデータ列の前後に同期情報を含んだ4バイトのヘッダが付加される。

データシートにはSync Byteの詳細が記載されていないが、ITU656の規格を調べた結果以下の値であることが判った。

ロジアナでOV7670の実際の出力を確認したところ、OV7670はfield 2の値(SAV2,EAV2,SBV2,EBV2)のみが出力されているようだった。

SAV

EAV

SBV

EBV

RTLはfield1,2両方を検出するようにした。


色変換
OV7670のピクセルフォーマットはYUV422やRGB565に設定し、cif_rxでRGB888形式に変換するつもりだが、変換しないモードも選択できるようにした。

YUV➔RGB変換部は以前TCM8230MD用に作ったRTLを再利用した。
http://bravo-fpga.blogspot.jp/2010/12/yuv422.html


・cif_m_axi
 cif_m_axiはAXI MASTER moduleでcif_rxから来る画像データをDRAM上のバッファ領域に書き込む。

・cif_s_axi
cif_s_axiはAXI SLAVE moduleでソフトウェアはこのI/Fを介してこのIPを制御する。

cifのレジスタ構成
バッファは最大4ページまで管理することが可能で、PAGENレジスタにページ数を、そして、BASEnレジスタにバッファの先頭番地を設定する。PAGENに設定する値は0基準でありページ数から1を引いた値を設定する。各ページは環状に使用され1画面分書き込む度にページが更新される。現在どのページが書込対象になっているかはCPAGEレジスタで知ることができる。ページ番号と書込完了信号はf_CPAGEとf_FSYNCとしてmodule外部に出力されている。但し、f_CPAGEは現在の書込対象ページ番号ではなく、直近で書込が完了したページ番号が出力される。

・SCCB
OV7670の内部レジスタへのアクセスはSCCB I/Fを介して行う。 SCCBはI2Cと殆ど同じ仕様だがリードシーケンスがI2Cと異なる。具体的にはI2Cの場合はレジスタアドレスを指定するCycleとRead Cycleはシームレスに繋がっておりレジスタアドレスを指定するCycleのStop Conditionは無い。

(日立 I2C EEPROMのデータシートから引用)

これに対して、SCCBの場合は2-Phase Write Transmission Cycleに続いて2-Phase Read Transmission Cycleを実行することでリードを行うが、それぞれのCycleはStart Conditionで始まりStop Conditionで終わらなければならない。

レジスタの設定(書込)だけであれば自作のI2C IPをそのまま使用できるが、読出しもしたいのでステートマシンのリード部分を変更している。


・VivadoでIP化
RTLをVivadoでIP化してbase_design_systemのBlock Designに組み込んだ。同時にVGA用のdisplay controllerやVDMAは不要なので削除した。



合成は成功し、timingもmetした。




2017年1月1日日曜日

2017年

年が明けてしまった。
近所のお寺の除夜の鐘が聞こえている。

ここで一句。

 F・P・G
  Aが字余り
   なんでだろう

なんのこっちゃだな。
もう一句。

 IPを
    作れる幸せ
   ありがとう

これだな。
昨年はあんまりFPGAをいじれなかったから、今年はもっともっとFPGAをやりたいなっと思う、2017年1月1日 0:40:00




TE0720 No.4 (BNN-PYNQを動かしてみる 2)

TE0720でBNN-PYNQを動かすことが出来た。 以下は前回に続いてBNN-PYNQが動くまでの記録。 gdb (GNU debugger)で例外が出る原因を調べてみた。 例外が発生しているのはシェアードライブラリ(python_hw-cnv-pynq.so)の中であ...