”FPGAで遊んでみる”では、セミナー用に作成したサンプル回路などを整理して少しづつ紹介していきます。
セミナ開催します
手ぶらでOK!実習・Raspberry Pi PicoW×MicroPython I/Oデバイス「時短」開発入門
-- 133MHz ARM Cortex-M0マイコンをPythonでプログラミング
2024年12月6日(金)CQ出版社セミナルーム CQ出版社セミナ・ルーム
詳しくはこちらへ
ZYBOの本
FPGAパソコンZYBOで作るLinux I/Oミニコンピュータ CQ出版 発売中
Papilioの本
FPGA版Arduino!!Papilioで作るディジタル・ガジェット CQ出版 発売中
第9回 カメラモジュールから画像をFPGAへ取り込んでみる
今回は、カメラモジュールの出力をFPGAへ取り込み、FPGAからモニタへ出力する回路を紹介します。
なかなか綺麗な画像を取り出す設定が難しく時間がかかりましたがやっと紹介できます。
使用したカメラモジュールはOmniVision Technologies社製0V7670でaitendoさんから購入しました。
評価機器
上がSVGAモニタ(RGB)、
左からRS232C-USB変換器(FT2232D)、FPGAボード(MFPGA-SPAR3E)、簡易DAC(第4回で紹介)、
右下がカメラモジュール(OV7670)
カメラモジュール・インターフェースのソース(zip圧縮してあります)
camera_ap_files.zip
内容
camera_if.v カメラモジュールインターフェース回路
vram_ctrl.v 入力画像のメモリ保存、出力画像のメモリ読出し回路
ov7670_cmd_genv ov7670の設定情報の生成
i2c_ov7670_ctrl.v ov7670の設定情報からi2cモジュール制御情報生成
camera_ap.v 周辺回路も含めたFPGAの最上階層
svga_if.v SVGA画像出力回路(第4回で紹介)
layer_a.v 移動する箱のグラフィック生成(第4回で紹介)
layer_b.v カラーパタンのグラフィック生成(第4回で紹介)
msg_buf.v メッセージバッファ回路(第8回で紹介)
fifo.v メッセージ保持用FIFO(第8回で紹介)
ram.v メッセージ保持用FIFO用RAM(第8回で紹介)
rs232c_txrx.v RS232Cインターフェースモジュール(第3回で紹介)
vram_dumy.v チップスコープ使用時にメモリが足りないので、使用するvramのダミー記述
camera_ap_test.v camera_apのテストベンチ
camera_ap.ucf FPGAボードにMFPGA-SPAR3Eを使用した場合のPIN配置指定
ov7670_set_up.ttl OV7670設定用のteratermのマクロファイル
※この回路を使用する場合は、自己責任でお願いします。
仕様説明(camera_if.v)
動作概要
カメラモジュール(0V7670)からの画像データをメモリに保存して、第4回で紹介したSVGA画像出力回路へ画像データを出力します。
FPGAの容量の少ない内部メモリに画像保存しているので、扱う画像サイズは128×128ピクセルです。
出力では、256×256に拡大しています。
また、0V7670を設定するための制御情報をi2c通信モジュールへ出力する機能もあります。
ブロック図
入力信号
clk:クロック入力/今回使用してたボードは40MHzです。
rstb:リセット入力 0でリセット
rx_dara:re232c通信モジュールからの受信データ
rx_dara_en:re232c通信モジュールからの受信データイネーブル
出力信号
tx_fifo_data:送信メッセージデータ
tx_fifo_data_en:送信メッセージデータ・イネーブル
カメラモジュールからの入力信号
pclk:画像データ用クロック
c_vysnc:垂直同期信号
href:水平同期信号
in_data:画像データ
カメラモジュールへの出力信号
xclk:カメラモジュール用クロック出力、入力信号clkの2分周を出力します。
SVGA画像出力回路からの入力信号
h_c_en:座標指定のイネーブル
v_c[9:0]:出力画素データの水平座標指定
h_c[9:0]:出力画素データの垂直座標指定
SVGA画像出力回路へのの出力信号
gen_da_en:出力画像の座標(h_c,v_c)のデータイネーブル
gen_da_r[7:0]:出力画像の座標(h_c,v_c)の赤色データ
gen_da_g[7:0]:出力画像の座標(h_c,v_c)の緑色データ
gen_da_b[7:0]:出力画像の座標(h_c,v_c)の青色データ
i2c通信モジュールからの入力信号
rd_dara:i2c通信モジュールからの読出しデータ
rd_dara_en:i2c通信モジュールからの読出しデータイネーブル
i2c通信モジュールへの出力信号
adr[6:0]:接続するI2Cデバイスのスレーブアドレス指定
wr:I2Cで書込みアクセス,1クロック幅の1でアクセス開始、busy==1の時は通信中なのでwr=1にできない。
rd:I2Cで読出しアクセス,1クロック幅の1でアクセス開始、busy==1の時は通信中なのでrd=1にできない。
wr_data[31:0]:書き込みデータ、wr==1の時にデータを取り込み、wr_data[31:24]から送信
wr_bytes[2:0]:書き込みバイト数指定、wr==1の時に取り込み。1〜4の範囲で設定、1の場合はwr_data[31:24]を送信
2の場合はwr_data[31:16]を送信、3の場合はwr_data[31:8]を送信、4の場合はwr_data[31:0]を送信する
rd_bytes[2:0]:読み出しデータバイト数指定、rd==1の時に取り込み。1〜4の範囲で設定、1の場合はrd_data[31:24]に受信
2の場合はrd_data[31:16]に受信、3の場合はrd_data[31:8]に受信、4の場合はrd_data[31:0]に受信する
パラメータ(vram_ctrl内に設定)
vram_size_v :VRAM垂直方向サイズ 最大128
vram_size_h :VRAM水平方向サイズ 最大128
v_start:カメラ画像取り込み垂直方向開始位置
h_start :カメラ画像取り込み水平方向開始位置
out_size_v:出力画像サイズ vram_size_vの2倍に自動設定
out_size_h:出力画像サイズ vram_size_hの2倍に自動設定
out_start_v:出力画像 垂直方向開始位置
out_start_h:出力画像 水平方向開始位置
詳細動作
画像入力
OV7670(カメラモジュール)からRGB444モードで入力しています。
href==1で画素有効で、2clkで画素入力されます。データ入力順序は、先に入力される8bitの[3:0]がBデータ、
後に入力される8bitの[7:4]がGデータ、[3:0]がRデータになります。OV7670のデータシートと並び順が違うのですが
実際のデバイスからはこの順序で出力されます。OV7670からの出力の詳細はデータシートを参考にしてください。
i_h_cntは入力画素の水平方向のカウンタで、href==1の時にカウントアップします。2clkで1画素なので入力画素の2倍の
値になります。href==0になると次のラインに移行しますのでi_h_cntは0に戻します。
i_v_cntは入力画素の垂直方向のカウンタでhrefが1→0と変化するとカウントアップして、c_vsyncが1になると次の画面に
移るので、0に戻します。
画素データの入力、入力画像の垂直方向のカウンタ、水平方向のカウンタの動作
i_h_cnt、i_v_cntが画像の取り込み開始位置にくるとVRAMへの書込みを行います。
入力データの無効部分(先に入力される8bitデータの[7:4])を除いてRGB444の12bitのデータを書込みます。
VRAMへの書込み動作
画像出力
SVGA画像出力回路から、h_c_en==1のときに水平方向座標(h_c)、垂直方向座標(v_c)が指定されます。
指定された座標が出力範囲内の場合に指定座標に該当する画素データをVRAMから読み出して出力します。
画像表示を拡大するために1画素データを4画素へ出力しています。 出力範囲外の座標指定ではgen_da_en=0として
出力画素を無効にしてあります。
VRAMへの読出し、画素出力の動作
制御コマンド
s232c通信モジュールからの受信データを解釈してi2c通信モジュールへカメラモジュールへのリード/ライト情報を出力します。
入力データのフォーマットは、アスキーコードで
[W/R],アドレス[7:4],アドレス[3:0],データ[7:4],データ[3:0],CR,LFになます。
[W/R]はライト/リードの指定、アドレスはカメラモジュール内レジスタアドレス、データは書き込みデータになります。リード時も
コマンド処理を簡略化する都合でダミーのデータの入力が必要です。
rd_dataはアスキーコードなので、内部でバイナリーデータに変換しています。
rd_dataにLF(0x0a)が入力された時に過去に入力されたデータを調べてi2c通信モジュール(第6回で紹介)へコマンドを発行します。
制御コマンドの動作
rd_dataに"W09AF"+CR+LFと入力されたので,i2c通信モジュールからカメラモジュールに0x09AFの書込みが実行される
カメラモジュールでは、i2c経由の0x09AFの書込みにより、レジスタアドレス0x09へ0xAFの書込みが実行されます。
tx_fifo_dataはメッセージバッファへ送るデータです。i2cで書き込んだ情報を表示しています。
FPGAでの動作
FPGAトップモジュール(camera_ap.v)
camara_ifの周辺回路としてSVGA画像出力回路(svga_if),RS232C通信モジュール(rs232c_tx_rx)、
I2C通信モジュール(i2c_m_if)などを追加して、カメラモジュールからの入力入力をSVGAモニタへ表示します。
トップモジュール(camera_ap.v)のブロック図
vramは、ISEのBlockMemoryGeneratorから12bit×16384wordのSimpleDualPort
RAMを生成して使用します。
RAMの生成方法は第5回を参照してください。
カメラモジュールの設定
OV7670(カメラモジュール)はデフォルト状態のレジスタ設定では、残念ながら綺麗な画像は出力できませんでした。
初めにRGB444モードになる設定をしてみたのですが、結果は下の映像でした。
レジスタ設定前の画像
右上に表示されているのがカメラモジュールからの映像、レンズを回してピンとが合うと
画像らしきものは表示されます。
webで調べてみると多数のレジスタを設定しないと画像が綺麗にならいようで、linux用のデバイスドライバの設定を
参考にしてレジスタ設定することにしました。手での入力は、とても耐えられない量なので、
teratermのマクロ(ov670_set_up.ttl)を使って設定を行っています。
OV7670のレジスタ設定の詳細はデータシートを参考にしてください。
レジスタ設定後の画像
設定を調整するともう少し綺麗になりそうな気がします。
動作の様子
FPGAボードとカメラモジュール、FPGAボートとPCをUSB<->RS232C変換器(FT2232D)で接続して、
ターミナルソフト(TeraTeram)のマクロ機能を使ってOV7670を設定して動作確認しています。
マクロファイルはov670_set_up.ttlでcamera_ap_files.zipに入っています。
ov670_set_up.ttlの一部
; OV7670 set up macro ; ; delay set pause_ms =0 ; delay for debug ;pause_ms =2000 ; ; ADR=0x12 WDATA=0x04 sendln 'W1204' sendln mpause pause_ms ; ; ADR=0x40 WDATA=0xd0 sendln 'W40D0' sendln mpause pause_ms ; ; ADR=0x8c WDATA=0x02 sendln 'W8C02' sendln mpause pause_ms |
”;”が行頭にある場合はコメントです。
pasue_msコマンド間の遅延時間を設定しています。通常は0で、
設定のデバックでは2000(2秒)程度して画像へ影響を確認しています。
”sendln 'W1203'”はteratermからW1203+CR+LFの入力を行います。
teratermのOV7670設定時の通信ログ
表示は設定の最後の部分のみです。
マクロを実行するときは、メニューの”コントロール”の下の”マクロ”を
選択して、マクロファイルを指定します。
FPGAボードでの動作の様子
右上のカメラモジュールからの映像が表示されています。
初めにOV7670の設定を行っていますので、映像が消えたりしています。
設定が終了して映像が安定した後に、カメラを振っています。振り方に
応じて映像も揺れて表示されています。
今回使用したFPGAはメモリ容量が少なくて表示できる画像サイズが小さいので、
別のFPGAボードで外部RAMをVRAMとして使用して広い画像とRGB565で表示をする予定です。
完成しましたら、ここで紹介します。
紹介した回路を試す場合は、自己責任でお願いします。
次回は、”FPGAでステッピングモータを回してみる”を紹介する予定です。
リンクフリーです。
リンクされた場合はご連絡をいただけると嬉しいです。
メール:
変更履歴
(2010/11/17) 初版