FC2カウンター FPGAの部屋 2013年01月

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

FPGAの部屋

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

ZedBoard Linux のフレームバッファにカメラ画像を表示3(ChipScopeで観察3)

前回はChipScope Pro を挿入してインプリメントすることが出来た。今回はChipScope Pro Analyzer を使用して、実際にAXI VDMA のAXIバスのアクセスの様子を見ていこう。

・最初に、Windows のスタートメニューからChipScope Pro Analyzer を単体で立ち上げた。
・左上端のアイコンOpen Cable/Search JTAG Chain をクリックして、ダウンロード・ケーブルを認識させる。
ZedBoard_Linux_27_130130.png

・ARMプロセッサとZynq XC7020 が認識される。
ZedBoard_Linux_28_130130.png

・ChipScope Pro Analyzer に信号が表示されたが、まだ信号名が入っていない。
ZedBoard_Linux_29_130130.png

・信号名を入力する。FileメニューからImport... を選択する。
ZedBoard_Linux_30_130130.png

・ZedBoard_OOB_Design\hw\xps_proj\implementation\chipscope_axi_monitor_0_wrapper フォルダの下に、chipscope_axi_monitor_0.cdc があるので、Select New File ボタンをクリックして選択する。下のリストボックスでDEV: 1 UNIT:0 (ILA) が表示されているのを確認する。
ZedBoard_Linux_31_130130.png

・AXIバスの信号名が入って、バスが自動的にまとまられた。
ZedBoard_Linux_32_130130.png

・次に、もう1つのChipScope Pro のチャネルも信号名を入力する。同様にFileメニューからImport... を選択し、ZedBoard_OOB_Design\hw\xps_proj\implementation\chipscope_ila_0_wrapper フォルダの下にchipscope_ila_0.cdc がSelect New File ボタンをクリックして選択する。下のリストボックスでDEV: 1 UNIT:1 (ILA) を選択する。
ZedBoard_Linux_33_130130.png

・こちらの信号名も入力された。
ZedBoard_Linux_34_130130.png

・AXIバスの信号をフリーランでキャプチャした。Readのトランザクションが並んでいることがわかる。(AXIバスの動作周波数は175MHz動作で、HD解像度のピクセルクロックと同じに設定されているようだ)
ZedBoard_Linux_35_130130.png

・1つのAXIバスのReadトランザクションを拡大してみた。
ZedBoard_Linux_36_130130.png

0x1A012F00 から8バイト単位で16個のピクセルデータをReadしているのがわかった。

・0x1A0XXXXX アドレスにアクセスが来ているようだったので、0x1A000000 & ARVALID & ARREADY でトリガを掛けた。
ZedBoard_Linux_37_130130.png

・トリガが掛かった。
ZedBoard_Linux_38_130130.png

・最初のAXIバスのReadトランザクションを拡大した。
ZedBoard_Linux_39_130130.png

・トリガを変更して、0x1BXXXXXX & ARVALID & ARREADY でトリガを掛けたら、トリガが掛からなかった。
これでスタートアドレスが、0x1A000000 であることがわかった

次にエンドアドレスを検証してみよう。すべてのピクセルデータは、1920ピクセル x 1080ライン x 4バイト = 8294400 = 0x7E9000 なので、エンドアドレス+1 は、0x1A7E9000 であるはずだ。

・0x1A7E8FXX & ARVALID & ARREADY でトリガを掛けた。
ZedBoard_Linux_40_130130.png

・計算通りに、トリガが掛かってからのアクセスは2つしか無い。
ZedBoard_Linux_41_130130.png

・最後のトランザクションを拡大した。
ZedBoard_Linux_42_130130.png

・0x1A7E9000 & ARVALID & ARREADY でトリガを掛けたところ、トリガは掛からなかった。
ZedBoard_Linux_43_130130.png

これで、アドレスは、0x1A000000 <= フレームバッファ・アドレス < 0x1A7E9000 で確定した。

フレームバッファのアドレスがわかったので、ここにカメラのデータを書き込もうと思うが、このペンギン画面はある一定時間の後に、(10分くらいだろうか?)消えてしまう。これはわざと消しているのか?それともバグで消えてしまうのか?今のところ分からない。ちなみに、アナログ・デバイセズ社のリファレンス・デザインは、1時間動作させているが、正常に動作している。
とりあえず、このアドレスを使用して、今のカメラ表示回路を載せようと思う。HDMIは既存のシステムが使用しているので、VGAポートだけに出力する。800 x 600 の現在の画像で出力するので、HDMI画面は表示されている時は乱れるが、それでOKとしよう。
  1. 2013年01月31日 05:08 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard Linux のフレームバッファにカメラ画像を表示2(ChipScopeで観察2)

これから、SDカードのLinuxブートイメージを作成する。手順は、ZedBoard_OOB_Design\doc\README.txt を参照した。

・SDK14.4をスタートメニューから立ち上げた。

・ワークスーペースにZedBoard_OOB_Design\sw フォルダを選択した。
ZedBoard_Linux_10_130130.png

・OKボタンをクリックして、SDK14.4を立ち上げると、Welcome画面だった。
ZedBoard_Linux_11_130130.png

・FileメニューからImport... を選択した。
ZedBoard_Linux_12_130130.png

・Import ダイアログが立ち上がった。General を展開して、Existing Projects into Workspace をクリックし、Next > ボタンをクリックした。
ZedBoard_Linux_13_130130.png

・Import Projects ダイアログで、Select root diectory ラジオボタンが選択してあるので、その右のBrowse... ボタンをクリックした。
・ZedBoard_OOB_Design\sw フォルダが選択されているので、OKボタンをクリックした。
ZedBoard_Linux_14_130130.png

・hw_platform とzynq_fsbl がProjects: に入った。
・Finish ボタンをクリックした。
ZedBoard_Linux_15_130130.png

・Welcome 画面を閉じるのを忘れていたので、"x" ボタンをクリックして、ウインドウを閉じた。
ZedBoard_Linux_16_130130.png

・一応、Project メニューからClean を選んで、リビルドしよう。
ZedBoard_Linux_17_130130.png

・Clean ダイアログで、Clean all projects がラジオボタンで選択されているので、OKボタンをクリックした。
ZedBoard_Linux_18_130130.png

・zynq_fsbl の下のBinaries にzynq_fsbl.elf が生成されている。
ZedBoard_Linux_19_130130.png

・Xilinx Tools メニューから Create Zynq Boot Image を選択した。
ZedBoard_Linux_20_130130.png

・Create Zynq Boot Image ダイアログが立ち上がった。まだ何も入力されていない。
ZedBoard_Linux_21_130130.png

・FSBL elf のBrowse ボタンをクリックして、SDKで作成したばかりのzynq_fsbl.elf を指定した。
・Add ボタンをクリックして、ZedBoard_OOB_Design\hw\xps_proj\implementation\system.bit を追加した。
・Add ボタンをクリックして、ZedBoard_OOB_Design\boot_image\u-boot.elf を指定した。
・Output folder を指定した。Browse ボタンをクリックして、ZedBoard_OOB_Design\boot_image フォルダを指定して、BOOT.BIN と入力し、ファイル名を指定した。
ZedBoard_Linux_22_130130.png

・Create Image ボタンをクリックして、BOOT.BIN を生成した。
・BOOT.BIN 生成後のSDKの画面。
ZedBoard_Linux_23_130130.png

・ZedBoard_OOB_Design\boot_image フォルダを見ると、BOOT.BIN フォルダが出来ていた。
・BOOT.BIN フォルダの下には、u-boot.bin ファイルが出来ていた。
ZedBoard_Linux_24_130130.png

・u-boot.bin をBOOT.BIN にリネームして、BOOT.BIN の生成が完了した。このBOOT.BIN をSDカードにすでに入っているBOOT.BIN と入れ替えた。

・SDカードをZedBoard に入れて電源ONしたら、無事にLinux が起動して、HDMI出力のペンギン画面も出力されていた。
  1. 2013年01月30日 05:03 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard Linux のフレームバッファにカメラ画像を表示1(ChipScopeで観察1)

Digilent 社のZedBoard 付属のLinuxはHDMI 出力に2頭のペンギンを表示している。
ZedBoard_Linux_8_130129.jpg

この画像は1920x1080のHD画像だが、そこに800x600のカメラ画像を表示しようと思う。カメラ画像は画面いっぱいに伸長するのではなく、そのままのスケールで小さく表示しようと思う。つまりHDMI の表示画面を乗っ取ってしまうということだ。たぶん、ペンギン画面は最初にDDR3 SDRAM のフレームバッファに1度書かれただけで、更新されてはいないと思うので、その場合はAXI_HP バスを介して、カメラ回路がフレームバッファに書けばHDMI に表示できると思う。HD画面に800x600のカメラ画像を表示するために、カメラ回路の多少の改造が必要となるが。。。
そのためには、VDMA がどのアドレスからペンギン画面を読んでいるかのアドレスが必要となる。そのために、ChipScope を入れて検証してみようと思う。
今回は、AXI VDMA のM_AXI_MM2S に、ChipScope AXI Monitor を入れ、AXI VDMA のmm2s_fsync やHDMI 出力は、ChipScope Integrated Analyzer (ILA) を入れて確かめることにした。
XPS上でのILAのプローブの配線方法については下の2つの記事を参照のこと。

XPSでChipScope Proコアを追加してデバック1
XPSでChipScope Proコアを追加してデバック2


ChipScope Integrated Controller, ChipScope AXI Monitor, ILA を入れた状態のBus Interface タブの表示画面を下に示す。
ZedBoard_Linux_6_130129.png

Ports タブの画面を下に示す。
ZedBoard_Linux_7_130129.png

これで、Generate BitStream を左端のウインドウから選択して、ビットストリームを生成した。
ZedBoard_Linux_9_130130.png

(追加)
ChipScope のMonitor Hardware Signals の画面を貼っておきます。
ZedBoard_Linux_25_130130.png

ZedBoard_Linux_26_130130.png
  1. 2013年01月29日 05:42 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard Linuxの勉強1

最終目的としては、専用機として、画像処理、画像認識をZedBoard にさせようと思っている。
そのためには、TCP/IPスタックや色々なツールがあるOSを載せたほうが便利だ。
それならば、Linuxを載せて、OpenCVなどもやってみたい。OpenCVもHLSを使って一部ハードウェア化してみたい。
OpenCVも目的達成の手段であって、目的ではない。OpenCVやってみたいと思っている。

上記の様な考えで、Linuxに手を出すことにした。ソフトウェアは得意じゃないので、進行が遅い、進まないことがあると思う。知っている方がいましたら教えて下さい。よろしくお願いします。

さて、最初にZedBoard のLinux から勉強していこうと思う。ZedBoard についてきたSDカードのLinux のソースがDilgilent 社のZedBoard のページに置いてある。それは、DSD-0000401(zipファイル注意)だ。DSD-0000401 をダウンロードして展開すると、ZedBoard_OOB_Design フォルダが出来る。
ZedBoard_Linux_1_130128.png

ZedBoard_OOB_Design フォルダの下には、boot_image, doc, hw, linux, sd_image, sw フォルダがある。

hw フォルダの下のxps_proj フォルダには、XPSのプロジェクトがある。これを起動してみた。バージョンは14.1だったが14.4に変換した。
ZedBoard_Linux_2_130128.png

Bus Interface タブをクリックした。
ZedBoard_Linux_3_130128.png

このXPSプロジェクトはどこかで見たことがある。そうだ、アナログ・デバイセズ社のZedBoardのリファレンス・デザインにそっくりだ。と言うことは、HDMIに表示されているペンギンも同様にソフトウェアで画像データを転送したのだと思う。そこのフレームバッファをカメラデータを表示するのに使えないものか?アドレスが分かれば良いのだが?

Portsタブをクリックした。
ZedBoard_Linux_4_130128.png

Addressタブをクリックした。
ZedBoard_Linux_5_130128.png

これで、各IPのアドレスが分かったので、VDMAのレジスタをXMDで読んでみれば、フレームバッファのアドレスが分かるだろうか?
  1. 2013年01月28日 05:36 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

カメラ回路をWebPACK14.4でインプリメントしてみた

完成したカメラ回路プロジェクトをWebPACK14.4でインプリメントできるかどうかやってみた。

プロジェクトをUSBメモリにコピーして、WebPACKをインストールしたパソコンにペーストする場合に、あまり階層が深い所にペーストするとパス名が長すぎると言われて怒られてしまった。PlanAheadプロジェクトは、プロジェクトのフォルダ名ににもプロジェクトの名前が負荷されるので、全体のパス名が長くなりやすいので、短い名前をつけるように気をつけたい。

・最初にWebPACK のPlanAhead14.4を立ちあげて、プロジェクトを開いた状態だ。
WebPACK_ZB_Cam_1_130126.png

・EDKプロジェクトのSystem をダブルクリックして立ち上げると、やはりエラーダイアログが出た。
WebPACK_ZB_Cam_2_130126.png

・ライセンス・マネージャのダイアログも出た。Closeする。
WebPACK_ZB_Cam_3_130126.png

・ライセンス・エラーは出ても、XPSが立ち上がる。
WebPACK_ZB_Cam_4_130126.png

・Bus Interface タブも正常に表示されている。
WebPACK_ZB_Cam_5_130126.png

・XPSプロジェクトで、Project メニューからClean All Generated Files を選択して、すべての生成ファイルを削除した。これで、WebPACKでインプリメントのプロセスを完了できるかがわかる。
WebPACK_ZB_Cam_6_130126.png

・PlanAheadに戻って、Synthesis の下のRun Synthesis をクリックして実行した。
・XPS script でエラーが出てしまった。やはり、WebPACKをインストールしてはダメなようだ。
WebPACK_ZB_Cam_7_130126.png

・WebPACKをアンインストールして、Logic Edition をインストールした。
・今度は、PlanAhead14.4のインプリメントは完了した。
WebPACK_ZB_Cam_8_130126.png

・SDKにハードウェアをエクスポートして、SDKを立ち上げたら、Board Support Package のコンパイルでエラーになってしまった。
WebPACK_ZB_Cam_9_130126.png

・このエラーは、ZedBoard_CamDisp_wHDMI.sdk フォルダを作りなおしても解消されなかった。

・Webの解決策を探っていると、Embedded Edition ではどうか?というのがヒットしたので、Logic Edition をアンインストールして、再度、Embedded Edition をインストールした。

・Embedded Edition でもやはりSDKで同じエラーだった。下にエラー全文を示す。

make -k all
libgen -hw ../system_hw_platform/system.xml\
\
-pe ps7_cortexa9_0 \
-log libgen.log \
system.mss
libgen
Xilinx EDK 14.4 Build EDK_P.49d
Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved.

Command Line: libgen -hw ../system_hw_platform/system.xml -pe ps7_cortexa9_0
-log libgen.log system.mss


Staging source files.
Running DRCs.
Running generate.
Running post_generate.
Running include - 'make -s include "COMPILER=arm-xilinx-eabi-gcc"
"ARCHIVER=arm-xilinx-eabi-ar" "COMPILER_FLAGS= -O2 -c"
"EXTRA_COMPILER_FLAGS=-g"'.

Running libs - 'make -s libs "COMPILER=arm-xilinx-eabi-gcc"
"ARCHIVER=arm-xilinx-eabi-ar" "COMPILER_FLAGS= -O2 -c"
"EXTRA_COMPILER_FLAGS=-g"'.
"Compiling common"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling xadc"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling standalone"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -march=armv7-a -mfloat-abi=soft -mfpu=neon -I./. -I../../../include _exit.c _open.c _sbrk.c abort.c close.c errno.c fcntl.c fstat.c getpid.c inbyte.c isatty.c kill.c lseek.c open.c outbyte.c print.c putnum.c read.c sbrk.c sleep.c smc.c uart.c unlink.c usleep.c vectors.c write.c xil_assert.c xil_cache.c xil_exception.c xil_io.c xil_mmu.c xil_printf.c xil_testcache.c xil_testio.c xil_testmem.c xl2cc_counter.c xpm_counter.c xtime_l.c asm_vectors.S boot.S cpu_init.S translation_table.s xil-crt0.S, ...) failed.
"Compiling gpio"
"Compiling iic"
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [standalone_libs] エラー 2
make[1]: ターゲット `libs' はエラーにより再 make できませんでした.
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling tmrctr"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling devcfg"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling dmaps"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling emacps"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling gpiops"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling qspips"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling scugic"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling scutimer"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling scuwdt"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling ttcps"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling uartps"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling usbps"
process_begin: CreateProcess(NULL, arm-xilinx-eabi-gcc -O2 -c -g -I./. -I../../../include *.c, ...) failed.
make (e=2): 指定されたファイルが見つかりません。

make[1]: *** [libs] エラー 2
"Compiling cpu_cortexa9"
ERROR:EDK:369 - make failed for target "libs"
ERROR:EDK:3418 - Error(s) while running make.
make: *** [ps7_cortexa9_0/lib/libxil.a] エラー 2
make: ターゲット `all' はエラーにより再 make できませんでした.


・色々格闘したがダメで、諦めかけた時、もしやと思いWindows を再起動してみたら、問題なくコンパイルすることが出来た。インストールして動かない時は再起動だと改めて思った。

・SDKでZedBoardにビットストリームをダウンロードして、Runさせたら、見事にカメラ画像がディスプレイに映った。

昨日は、ず~とこの対処に時間を費やしてしまった。再起動の指示が出てなかったので、再起動しなかったのが敗因だ。。。

#私の時間を返せ~。と言いたい。

(2013/01/28:追加)
Windowsを再起動したので、コンパイルができたわけではないようです。
PlanAheadからFile メニュー -> Export -> Export Hardware platform for SDK... でLaunch SDK をチェックして、SDKを立ち上げるとコンパイルがエラーになるようです。(プロジェクトをコピーして、USBメモリやDVD経由で、他のパソコンに貼り付けています)
Launch SDKをチェックせずにHardware だけExport して、また別にスタートメニューからSDKを立ち上げると、コンパイルすることができました。(WebPACKだけではなく、他の購入したエディションでも同じ状態のようです)。
  1. 2013年01月27日 04:33 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:4

ストロベリーナイト(映画)を見て来ました

ストロベリーナイト(映画)を見て来ました。小説で読んだことがあるので、楽しみにしていました。ドラマは見てないですが、映画を見に行きました。Yahoo映画ではスコアが悪かったですが、私は面白かったです。
  1. 2013年01月26日 22:53 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

カメラの表示回路及びソフトウェアをSDカードからブートする

カメラ回路と制御するソフトウェアをSDカードからブートして動作させたいと思ったのでやってみた。

まずは、”Zynq-7000 EPP ソフトウェア開発者向けガイド UG821 (v2.0) 2012 年 4 月 24 日”の”ブートおよびコンフィギュレーション”の”3.1 概要”(20ページ)によると、プロセッサシステムは2段階のプロセスでブートするそうだ。(LinuxだとU-BOOTがあるので3段階)

それは、内部BootROMとFSBL (First Stage Bootloader) だ。
・内部BootROMは、ステージ0ブートコードが入っていて、ARMプロセッサおよびペリフェラルをコンフィギュレーションする。そして、FSBLへ制御を渡す。BootROMには書き込みできない。
・FSBLブートコードは、BootROMコードでフラッシュメモリからオンチップメモリ (OCM) へコピーされてから、実行される。

・FSBLの役割
 ・XPSからのPSコンフィギュレーション・データで初期化(XPSのZynqタブで設定したMIOなどのコンフィギュレーションだと思う)
 ・ビットストリームでPLをプログラム。
 ・第2段階ブートローダーまたは、ベアメタル・アプリケーション・コードをメモリへロードする。
 ・第2段階ブートローダーまたは、ベアメタル・アプリケーション・コードの実行を開始する。

ということで、FSBLを作る必要がある。FSBLはSDKで生成することができる。そのやり方を見ていこう。

・SDKの Fileメニュー -> New -> Project を選択する。
Zynq_SDcard_1_130124.png

・New Project ダイアログで、Xilinx -> Application Project を選択して、Next > ボタンをクリックする。
Zynq_SDcard_2_130124.png

・Project Name にFSBL(これは任意の名前)と入力し、Target Software で、Board Support Package にUse existing のラジオボタンをクリックして、すでにあったBoard Support Package を指定した。Next > ボタンをクリックする。
Zynq_SDcard_3_130124.png

・Templates ダイアログが表示される。Available Templates から Zynq FSBL を選択する。
Zynq_SDcard_7_130124.png

・Finish ボタンをクリックすると、コンパイルされて、FSBL.elf が生成される。
Zynq_SDcard_4_130124.png

次に、BOOT.bin を生成する。

・ベアメタル・アプリケーション(この場合は cam_disp2 のプロジェクト)を選択しておいて、Xilinx Tools メニューから Create Zynq Boot Image を選択する。
Zynq_SDcard_5_130124.png

・先ほど作成したFSBL.elf とベアメタル・アプリケーション cam_disp2.elf はすでに入っていた。
・PL部のビットストリーム、system_stub.bit をAddボタンをクリックして追加する。
・cam_disp2.elf をクリックして、DOWNボタンをクリックし、system_stub.bit と順番を入れ替える。
Zynq_SDcard_6_130124.png

・Create Image ボタンをクリックして、イメージを作成する。
・ZedBoard_CamDisp_wHDMI_144_2\ZedBoard_CamDisp_wHDMI.sdk\SDK\SDK_Export\cam_disp2\bootimage を見ると、ファイルが3つ出来ている。
Zynq_SDcard_8_130124.png

・cam_disp2.bin を BOOT.bin にリネームする。
・BOOT.bin をSDカードにコピーする。
Zynq_SDcard_9_130124.png

・SDカードをパソコンから抜いて、ZedBoardのSDカードスロットに挿入する。
・ZedBoardの設定ピンを設定する。
 MIO2 GND
 MIO3 GND
 MIO4 3V3
 MIO5 3V3
 MIO6 GND

 JP2, JP6 ショート
 JTAG SELECT 1V8

・ZedBoardの電源SWをONにすると、DONE LEDが点灯して、カメラ画像が表示された。

これで、SDカードからブードして、PL部のビットストリームをダウンロードし、PS部のソフトウェアを動作させることが出来た。
  1. 2013年01月24日 04:59 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製13(カメラのテストパターンや特殊効果)

今回はカメラのテストパターンや特殊効果を試してみた。

R152(0x98):1から設定する。 このレジスタはビットの [5:3] を設定することで、テストパターンを発生することが出来る。0x00-off, 0x08-by column, 0x10-by row, 0x18-by frame となるそうだ。

・R152(0x98):1 = 0x08 としてみた。
下に、VGA出力の画面を示す。
ZedBoard_Cam_41_130122.jpg

下に、HDMIの画像を示す。
ZedBoard_Cam_42_130122.jpg

VGAとHDMIの画像を見ると一目瞭然に階調が違うことがわかる。

・R152(0x98):1 = 0x10 としてみた。
下にHDMIの画像を示す。
ZedBoard_Cam_43_130122.jpg

・R152(0x98):1 = 0x18 としてみた。
このテストパターンでは、画面が最初は暗くて、時間が経過するごとに、だんだんと明るくなっていく。
ZedBoard_Cam_44_130122.jpg

次に、R164(0xA4):1 の特殊効果をやってみた。[2:0] ビットを指定することで、モノクロームやセピアなどの特殊効果を掛ける事ができる。0x40-disabled, 0x41-monochrome, 0x42-sepia, 0x43-negative, 0x44-solarization with unmodified UV, 0x45-solarization with -UV となるそうだ。

・R164(0xA4):1 = 0x40, disabled(通常の画面)
下にVGAの画面を示す。
ZedBoard_Cam_45_130122.jpg

・R164(0xA4):1 = 0x41, monochrome
下にVGAの画面を示す。
ZedBoard_Cam_46_130122.jpg

・R164(0xA4):1 = 0x42, sepia
目で見るともっと黄色かったのですが、iPhone 4S で撮影した時にホワイトバランスを調整したようです。
ZedBoard_Cam_47_130122.jpg

・R164(0xA4):1 = 0x43, negative
ZedBoard_Cam_48_130122.jpg

・R164(0xA4):1 = 0x44, solarization with unmodified UV
・R164(0xA4):1 = 0x45, solarization with -UV
これらは、元画像とどこが違うのか分からなかったので、省略します。多分、室外で撮影すると違うんじゃないか?と思います。
  1. 2013年01月22日 05:52 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:4

「劇場版 HUNTER×HUNTER 緋色の幻影(ファントム・ルージュ)」を見てきました

今日は日曜日の代休だったので、「劇場版 HUNTER×HUNTER 緋色の幻影(ファントム・ルージュ)」(音注意)を見て来ました。HUNTER×HUNTER はコミック持っていて、好きな漫画なので、楽しみにして行きました。キャラクタに思いいれがあるので、楽しめましたが、HUNTER×HUNTERが好きな人が楽しめる映画なんじゃないかな?と思います。今まで、一番良かった日本のアニメは、クレヨンしんちゃん 嵐を呼ぶ モーレツ!オトナ帝国の逆襲が一番良かったと思います。クレヨンしんちゃんシリーズ面白いです。
  1. 2013年01月21日 21:15 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製12(ChipScopeで検証)

 前回、正常にカメラ画像をディスプレイに表示することが出来たが、AXIバスのデータ転送がシングル転送ということで、途中に入っている非同期FIFOが溢れていないかどうかをChipScopeを入れて確かめてみた。
非同期FIFOのrd_data_count (pfifo_rd_data_count) と overflow 信号をChipScope に入れて検証した。
取り敢えず、pfifo_rd_data_count の値を設定して、どの位、非同期FIFO(容量512深度、64ビット幅)の容量を使っているかを検証することにした。なお、pfifo_rd_data_count の値は、非同期FIFOにRead出来るピクセルデータがいくつ入っているかを表す。これが、511個つまり0x1ffを超えてしまうとオーバーフローになってしまう。(実際は付加回路が付いているので、もう少し大きい数でもオーバーフローとならないことがあります)
まずは、pfifo_rd_data_count の値を0x1に設定して、波形をキャプチャしてみた。下にChipScope Pro Analyzer で取得した波形を示す。pfifo_rd_data_count の値は、0x1 と 0x2 が見える。
ZedBoard_Cam_38_130121.png

次に、pfifo_rd_data_count の値を 0x8 に設定した。下に波形を示す。
ZedBoard_Cam_39_130121.png

pfifo_rd_data_count の値を 0xC に設定した。下に波形を示す。
ZedBoard_Cam_40_130121.png

上の波形を見るとわかるが、pfifo_rd_data_count の値が 0xC になった後、増えずに減ってきている。これは、多分 line_valid が0になって、当該ラインのピクセルデータの供給がなくなったためと考えられる。
pfifo_rd_data_count の値が 0xD にするとトリガが掛からない。
カメラ画像を上下反転するために、大きなアドレスからピクセルデータをDDR3 SDRAM上のフレームバッファに転送した。そのために、通常の方法ではバースト転送を行うことが出来ないので、シングル転送としたが非同期FIFOは overflow していないことがわかった。これで一安心だ。
  1. 2013年01月21日 05:49 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製11(正常に写った)

ZedBoard用CMOSカメラ回路の作製10(画像の上下を反転)で、正しい上下関係でCMOSカメラの画像を表示することが出来たが、ノイズが見えた。今回はその原因を探って、バグをフィックスし、正常に表示することが出来た。
どのようなバグかというと、前回の追加でも書いたが、フレームバッファにアドレスの大きい方から小さい方にアドレスを減算してWriteしていくので、データが溜まってバーストした際にアドレス加算バーストになってしまうことだった。このバグに対しての解決方法を2つ示したが、カメラの出てくるデータには、ブランク期間があるので、非同期FIFOが溢れないようにブランク期間にデータをDDR3 SDRAMにWriteすることが出来れば問題ないと考えた。つまり、上下反転モードの時は、バースト転送をせずにすべてシングル転送とした。この回路に変更したところ、正常にカメラ画像を表示することが出来た。
下にVGA画面のカメラ画像を示す。やはり、RGB565なので、擬似輪郭が見える。
ZedBoard_Cam_36_130120.jpg

次に、HDMIのカメラ画像を示す。こちらの方が、YCbCrで表示しているせいか?擬似輪郭が無く、綺麗に表示されている。データは同じRGB565なのだが、RGB-YCbCr変換の時にうまく出来ているのかもしれない?
ZedBoard_Cam_37_130120.jpg

ともかく、これで一応完成だが、バッファ用の非同期FIFOがオーバーフローしていないかどうかをChipScopeでチェックしてみよう。

(告知です)
2013年2月1日にTEDプログラマブル ソリューション 2013に行きます。その時に、現在のZedBoard用カメラボードを3枚、無料で配布しようと思います(TEDプログラマブル ソリューション 2013とは無関係です。個人的にお会いして、お渡ししようと思います)。プロジェクトをCD-ROMで付けます(プロジェクトは自分での使用に留めておいてください、配布する際は別途ご相談ください)。但し、基板は生板です。1608チップ部品をハンダ付けできる方用です。カメラボード(生板)以外に、下の部品が別途必要です。この部品はご自分で購入ください。
1.秋月電子のピンソケット(メス)2×10(20P)
2.秋月電子のピンヘッダ(オス)2×25(50P)
3.秋月電子の1608の0.1uF積層セラミックコンデンサ
4.秋月電子の47uF 16Vの積層セラミックコンデンサ
5.日昇テクノロジのMT9D111カメラモジュール

配布条件としましては、ZedBoardを持っているか、3ヶ月以内にZedBoardが届くことが決まっている方のみとします。自分のブログなどで動いたよ。動かなかったよという簡単なレポートを3ヶ月位以内にお願いします。
現在のカメラボードは、カメラの取り付けが上下逆で、フレームバッファに上位アドレスから先に書いて、アドレスを減算していくモードで動いています。非同期FIFOがオーバーフローしている可能性もありますが、画像は正常に表示されています。
条件に合致していてほしい方は、この記事のコメント欄に欲しい旨を書き込んでください。持っていく数を決めます。配布数の3枚を超えた場合は先着順とします申込期限は、2013年1月26日の午後5時までとします。(締めきりました。希望者は0でした。残念。。。)
なお、カメラボードは、すべてE-TEST済みなので動作すると思いますが、動作しない場合は、1枚ほど予備をとっておきますので、それをお送りします。1枚のみです。それ以上の責任はご容赦ください。
  1. 2013年01月20日 05:15 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:2

ZedBoard用CMOSカメラボードの作製6(カメラボード改)

 前回、カメラボードが完成したが、CMOSカメラを取り付けた時に上下逆さまというバグがあった。そのため、カメラボードを作りなおすことにした。CMOSカメラの取り付けを180度回して、取り付け、配線を修正した。KiCADで作成した基板を下に示す。
ZedBoard_Cam_Board_10_130119.png

以前のカメラボードの基板を下に示す。これは、まだベタを付けていない状態の基板だ。
ZedBoard_Cam_Board_2_121209.png 

早速、FusionPCBに発注した。カメラボードが出来上がってくるのが楽しみだ。

(2013/01/20:追加)
新しく作った基板のデータバスの参照面 (GND) が無いのが気になり、もう一度やり直して、FusionPCBに機能発注した。大した違いは無いかもしれないが、こっちは、50% E-TESTにしたので、$13.86、1300円くらいだった。
ZedBoard_Cam_Board_11_130120.png
  1. 2013年01月19日 04:41 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製10(画像の上下を反転)

 前回、CMOSカメラの取り付けをミスって、画像が上下反転してしまったので、カメラ回路の方で上下を反転することにした。
mt9d111_inf_axi_master IPをAdd IPする際に、C_UPSIDE_DOWN パラメータを追加して、TRUEだったら、カメラ画像の上下を反転することにした。
ZedBoard_Cam_34_130117.png

HDLコードも修正して、論理合成、インプリメントしてみたところ、正常に写っているんですが、エッジにゴミが見えます。
ZedBoard_Cam_35_130118.jpg 

上の写真では見づらいかもしれませんが、エッジの付近を見るとノイズが見えます。上下反転せずに、上下逆さまで表示するとノイズは見えません。シミュレーションでもう一度確認することにします。

(追加)
理由がわかった気がします。
カメラ回路はMT9D111から受け取ったピクセルデータを非同期FIFOを介して、100MHz動作のAXIバスでPSに送って、DDR3 SDRAMに書き込んでいます。その時に、AXIバスかバックエンドが遅く、2つ以上のピクセルデータをバーストで書き込む場合がありました。その時のAXIバスのM_AXI_AWBURST のモードは、INCR でアドレス・インクリメント・モードです。ですが、上下反転の場合は、後ろのアドレスから書き込んでいくので、アドレス・デクリメント・モードで書かないとバーストできません。そんなモードはAXIバスには無いですし、DDR3 SDRAMのバースト・モードの関係から言ってもできない相談です。というわけで、代替え案を考える必要がありそうです。考えられる代替え案としては、次に示す二つがあると思われます。

1.Last In First Out (つまりスタックですね!)を付ける。(結構面倒そう)
2.AXIバスの動作周波数を200MHz(アナデバのHDMIサンプルのAXIバスの動作周波数は 200MHz です)にして、シングル転送限定とする。


1.は面倒なので、2.をやってみたいと思います。その前に、1ドル = 90円を超えてしまったので、もっと高くなる前に、基板を改訂してFusionPCBに投げようと思います。
  1. 2013年01月18日 05:52 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:2

ZedBoard用CMOSカメラ回路の作製9(ともかく写った)

 前回、カメラ回路のバグをフィックスしたので、もう一度、論理合成、インプリメントしてやってみた。
最初は MT9D111 (CMOSカメラ)のレジスタ設定を全く行わずにディスプレイに表示させてみたところ、色が全くおかしかった。そこで、デフォルトのCMOSカメラのレジスタ設定を見ると、YUVになっていたので、RGB565に変更した。するとカメラ画像がディスプレイに表示されるようになった。
ZedBoard_Cam_33_130116.jpg

だが、残念ながら反対に表示されてしまう。どうやら、カメラの上下を間違ってしまったようだ。
日昇テクノロジのMT9D111メガピクセルカメラモジュール のページを見ると、ヘッダを下にした方向で後ろのシルクの文字が正常に読める。私は、今まで使ってきたOV7670, OV9655 の上下と同じと勘違いしてしまった。ヘッダを上にするのが正しいと思い込んでしまった。画像が表示されたが、上下が反対になってしまったので、喜びも半分といったところだ。ともかく、おるさん、ありがとうございました。おかげ様で、ともかくMT9D111 で画像表示することが出来るようになりました。
MT9D111 の機能で上下反転機能があったので、試してみたが、うまく上下を反転することができなかった。カメラ回路にオプションを設けて上下反転して表示するモードを付けようと思う。
それに、30fps で表示しているつもりなのだが、もっと表示フレーム数が小さい気がするので、PLLの設定も確かめてみたい。
  1. 2013年01月16日 04:25 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:2

ZedBoard用CMOSカメラ回路の作製8(バグ修正)

 前回見つかったバグを修正していた。まずは、バグを発生させるために、今のBus Function Model (BFM) では、バグが出ないので、修正を行った。どのように修正したかというと、M_AXI_BVALID をアサートする時刻をランダムに遅延できるようにBFMを変更した。そして、シミュレーションを行ったところバグが出たので、mt9d111_inf_axi_master.vhd のバグをフィックした。
下にシミュレーション波形を示す。
ZedBoard_Cam_31_130115.png 

カーソル間のWriteデータ転送を拡大して下の図に示す。
ZedBoard_Cam_32_130115.png 

M_AXI_AWVALID が 1 になった時に、M_AXI_AWLEN が 2 になっているので、Writeするデータ数は 3 個である。最初に2個バーストでWrite してから、少し間があって1個Write している。M_AXI_BVALID はかなりアサートが遅くなったが、16クロック目にアサートされている。
これで、今回のバグはフィックスできたと思うので、もう一度、カメラ回路をインプリメントし直して確かめてみよう。
  1. 2013年01月15日 05:34 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製7(バグ発見)

 前回、バグがあって、カメラのデータを表示しないという記事を書いたが、少なくとも1つのバグは見つけたので、記事に書いておく。
それは、M_AXI_AWLEN の保持タイミングが遅れているというバグだ。

AWLENはAWVALIDの立ち上がりで確定している必要がある。(下図参照)
AXI_Protcol_3_111209.png

これをミスってしまっていた。ChipScopeで測定した波形を下に示す。
ZedBoard_Cam_30_130114.png 

上のタイミングチャートでOカーソルが示す位置がバグがあるAXIバスアクセスの開始位置である。awvalid  が 1 になって、AXIバスアクセスが開始される。その時点での awlen は 0 だった。次にクロックで、awlen が 1 となり、本来の値になった。それでも、PSセクションの Processing_System_7 (PS) の S_AXI_HP0 に接続された、DDR3 SDRAMコントローラ(たぶん?)は、awlen が 0 と認知してしまって、Xカーソルの部分で、M_AXI_WREADY を 1 クロックだけ 1 にしてそれで終了してしまっている(たぶん?)。

次に、Verilog HDL ソースを見てみよう。

    -- write_count の処理 (pfifo_rd_data_count は当てにならない。使わないほうが良い)
    pfifo_rd_dcount_dec <= unsigned(pfifo_rd_data_count) - 1;
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_count <= (others => '0');
                awlen <= (others => '0');
            else
                if wrt_wv_cs=idle_wvalid then
                    if pfifo_rd_data_count/=std_logic_vector(to_unsigned(0, 9)) then
                        write_count <= std_logic_vector(pfifo_rd_dcount_dec(7 downto 0));
                        awlen <= std_logic_vector(pfifo_rd_dcount_dec(7 downto 0));
                    end if;
                elsif wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' and unsigned(write_count)/=0 then
                    write_count <= std_logic_vector(unsigned(write_count) - 1);
                end if;
            end if;
        end if;
    end process;

 if wrt_wv_cs=idle_wvalid then という行があるが、wrt_wv_cs は、Writeデータを扱うステートマシンなので、awlen のタイミングが遅延してしまう。これを awvalid と同期して変化するように Verilog HDL ソースを変更する。(ZedBoard用CMOSカメラ回路の作製2(HDLソースの公開1)を後ほど修正します)
  1. 2013年01月14日 12:35 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製6(実機で動作確認、動作しない)

 前回、インプリメントが終了した。次に、SDKにエクスポートし、ZynqのFPGA部分をコンフィギュレーションしてから、ソフトウェアを起動して動作させた。
しかし、カメラの画像は表示されなかった。残念。。。
ZedBoard_Cam_28_130113.jpg

カメラの信号をChipScopeで見てみた。line_valid_1d の立ち上がりでトリガを掛けている。
ZedBoard_Cam_26_130113.png 

前の景色を変えてみたところ、データが書き換わっている。
ZedBoard_Cam_27_130113.png 

line_valid_1d の幅は、予定通り、1600クロックだった。800ピクセル x 2バイトでピッタリだ。
ZedBoard_Cam_29_130113.png

これからAXIバス側をデバックする。
  1. 2013年01月13日 18:25 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

XPSで使用するIPのソースの情報

  XPSで使用するIPのソースは、Xilinx\バーション(14.2)\ISE_DS\EDK\hw\XilinxProcessorIPLib\pcores にある。
XPS_IP_Sources_1_130111.png

axi_vdma_v5_02_a を開くと、カスタムIPと同様に、data, doc, hdl フォルダがある。
XPS_IP_Sources_2_130111.png 

data フォルダの中には、 .mpd, .mui, .pao ファイルがあるが、.tcl ファイルが追加されている。
XPS_IP_Sources_3_130111.png 

doc フォルダには、マニュアルがあり、hdl フォルダの下には、Verilog フォルダと VHDL フォルダがあり、カスタムIP用のフォルダと同様の構成となっている。
  1. 2013年01月11日 10:19 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用カメラ回路のソフトウェアを書く上でのまとめ

ZedBoard用のカメラ回路のSDKのソフトウェアを書くのだが、今までのMT9D111のまとめ記事やAXI IICの使い方の勉強の記事を見やすいように、まとめておこうと思う。

MT9D111のお勉強1
 (特徴や3つのレジスタのページの話、変数)
MT9D111のお勉強2
 (Special Function Registers (SFR) and MCU SRAM、JPEG Indirect Registers)
MT9D111のお勉強3
 (Firmware Driver Variables(68ページ)、MCU Register List and Memory Map、Output Format and Timing(110ページ))
MT9D111のお勉強4
 (Sensor Core (116ページ)、ベイヤーパターン、ピクセルデータ出力タイミング)
MT9D111のお勉強5
 (RGBのゲインの設定、PLLの設定)
MT9D111のお勉強6
 (Start-Up and Usage、スタートアップ・シーケンスとモード遷移。プレビューモードとキャプチャモード)

AXI IIC のお勉強1
 (AXI IICのブロック図とレジスタ表、CR, SRレジスタ)
AXI IIC のお勉強2
 (TX_FIFO、RX_FIFO、TX_FIFO_OCY、RX_FIFO_OCY、MT9D111のレジスタ設定例)
  1. 2013年01月11日 05:40 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製5(制約、インプリメント)

前回では、XPSプロジェクトを作成して、PlanAheadプロジェクトでI/Oパッドの配置制約を追加した。今回は、PlanAheadプロジェクトでタイミング制約を作成してからインプリメントを行う。

・Flow Navigator のSynthesis -> Synthesized Design -> Edit Timing Constraints をクリックすると、Timing Constraints (UCF) タブが開いて、現在のタイミング制約を確認できる。Timespec period はAXI4バスの100MHzとSVGAのピクセルクロックの40MHzの制約がすでに設定されている。
ZedBoard_Cam_17_130109.png

・最初に、mt9d111_d のタイミング制約を行う。MT9D111のデータシートの176ページに”Electrical Specifications”がある。そこを見ると、tPD が 最小 -3nsec 最大 3nsec となっている。tPDは、Figure 50: I/O Timing Diagram より、PIXCLKがたち下がる時にDataの変化の遅延時間となる。Figure 50: I/O Timing Diagram を下に引用させたいただく。
ZedBoard_Cam_18_130109.png
        Figure 50: I/O Timing Diagram

mt9d111_d のセットアップ時間とVALID時間を算出してみよう。
・PIXCLKは36MHzとなっている。周期に直すと 27.7nsec となる。周期の半分は 13.8nsec でここから 3nsec 削られると 10.8nsec となる。これがセットアップ時間だ。VALID時間は、27.7 - 6 = 21.7 nsec となった。(小数点2位以下切り捨て)

PlanAhaedで OFFSET制約を生成する。
・Timing Constraints (UCF) タブで、Pad-clk offset の右クリックメニューからCreate Timing Constraint... を選択する。
ZedBoard_Cam_19_130109.png

・Create a New Timing Constraint ダイアログが開く。Input pad t clk offset を下の図のように設定した。
ZedBoard_Cam_20_130109.png

・OKボタンをクリックすると、mt9d111_d[0] の入力オフセット制約が出来上がった。
ZedBoard_Cam_21_130109.png

・次は、後7個残っているmt9d111_d の入力オフセット制約を追加するのだが、今入力した制約の右クリックメニューから Copy Constraint を選択し、制約をコピーする。
ZedBoard_Cam_22_130110.png

・コピーしておいて Pad net をmt9d111_d[1] に書き換えた。
ZedBoard_Cam_23_130110.png

(注:私の古いパソコンだとコピーするだけで、相当な負荷と時間がかかるので、1つ制約を作ったらUCFファイルのほうで増やすのが時間がかからないようだ)

・次に、mt9d111_href, mt9d111_vsync の入力オフセット制約を行う。入力オフセット制約の値は、データシートの値がmt9d111_d と同じなので、同じ制約を掛けた。
ZedBoard_Cam_24_130110.png

これで、CMOSカメラのタイミング制約は終わったので、セーブして、インプリメントとビットストリームの生成を行った。

・インプリメント、ビットストリームの生成が終了した。
ZedBoard_Cam_25_130110.png
  1. 2013年01月10日 05:34 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製4(XPSプロジェクトの作製)

ZedBoard用のカメラ回路IPが出来たので、XPSプロジェクトでプロジェクトに追加を行った。
次に、MT9D111のレジスタを設定するための AXI IIC IP を追加した。
ZedBoard_Cam_7_130107.png

Portタブでは、MT9D111 の外部ポートを追加した。
ZedBoard_Cam_8_130107.png

(2012/01/09:追加)
MT9D111はSVGAサイズの予定ですが、ビットマップ・ディスプレイ・コントローラはVGAサイズでした。ビットマップ・ディスプレイ・コントローラをSVGAサイズに変更した。disp_timing_parameters.vh のパラメータをSVGA解像度に変更した。

// SVGA 解像度 pixel clock = 40MHz
parameter H_ACTIVE_VIDEO= 800;
parameter H_FRONT_PORCH = 40;
parameter H_SYNC_PULSE = 128;
parameter H_BACK_PORCH = 88;
parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

parameter V_ACTIVE_VIDEO = 600;
parameter V_FRONT_PORCH = 1;
parameter V_SYNC_PULSE = 4;
parameter V_BACK_PORCH = 23;
parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;


その後で、XPSプロジェクトのZynqタブで、Clock Generation をクリックして、
ZedBoard_Cam_15_130107.png

FCLK_CLK1 を40MHzに変更した。MT9D111のピクセルクロックの動作周波数は 36MHz なので、FCLK_CLK2 を 36MHz に設定した。
ZedBoard_Cam_16_130107.png

(2012/01/09:追加ここまで)

次に、mt9d111_inf_axi_master のポートの接続を下に示す。(2012/01/09:変更:mt9d111_inf の pclk_from_pll の接続先をFCLK_CLK2 に変更)
ZedBoard_Cam_9_130107.png

MT9D111のI2C用のIP、axi_iic_mt9d111 のポートの接続を下に示す。
ZedBoard_Cam_10_130107.png

Addressタプの内容を下に示す。axi_iic_mt9d111 に64Kバイトのサイズを割り当てて、0x41700000 のアドレスを割り当てた。
ZedBoard_Cam_11_130107.png

これで、XPSプロジェクトの設定は終了した。
Project メニューから、Design Rule Check を選択して、デザインのルールチェックを行ったが、エラーはなかった。
XPSプロジェクトを閉じて、PlanAheadプロジェクトに戻った。
ZedBoard_Cam_12_130107.png

・Embedded Design Sources のSystem の右クリックメニューから Create Top HDL を選択して、トップファイルを再生成した。
・Synthesis を実行した。
・Synthesis -> Synthesized Desgin を開いた。
・Layout メニューからI/O Layout を選択して、I/Oのパッドを固定する。
・mt9d111_d のIOパッドを固定して、I/O Std を LVCMOS33に変更した。
ZedBoard_Cam_13_130107.png

・その他の MT9D111用の信号のIOパッドを固定した。
ZedBoard_Cam_14_130107.png
  1. 2013年01月08日 05:53 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

みやぎ蔵王えぼしスキー場に行って来ました

昨年の30日にハンターマウンテンスキー場に行こうと家を出たのですが、大雨で途中で戻って来ました。それじゃ、ということで、1月5日に娘を仙台に送って行くついでに、みやぎ蔵王えぼしスキー場に寄ることにしました。
みやぎ蔵王えぼしスキー場にアクセスする道路は、融雪道路完備ということで雪が溶けているかと思ってました。しかし、融雪道路は雪が溶けていたんですが、融雪道路の前が凍っていました。新品のスタッドレスタイヤだったんですが、上りがギリギリでした。車のATのDレンジでラフにアクセルを開けると、前輪が空転してしまいます(前輪駆動車です)。アクセルをゆっくりゆっくり踏みながら、空転しないギリギリのところでアクセルを踏みまして行きました。これでやっと上りました。久しぶりにヒヤヒヤしました。急な上りも、手前が完全に雪が溶けているところがあったので、勢いをつけていくことができました。殆どの車がスタッドレスタイヤなので、雪面が磨かれてしまうようでした。
久しぶりに雪道を登って、みやぎ蔵王えぼしスキー場に着きました。
zao_eboshi_1_130106.jpg

スキー場はゴンドラもあって、結構コースがありました。最長4.3Kmのロングランが出来ます。ロングランをするには、まずゴンドラで登って、かもしかリフトに乗って頂上まで行きます。そこからコースを左に左に行くとロングランコースが始まります。かもしかリフトに乗っている時の眺めです。右はコブ斜面です。
zao_eboshi_2_130106.jpg

かもしかリフトに乗って頂上についてから左に行くとロングランコースですが、最初に広い斜面に出た時がすごい眺めでした。遠くに海(太平洋)も見えている気がしました。
zao_eboshi_3_130106.jpg

zao_eboshi_4_130106.jpg

雪質も良くて最高の滑り心地でした。ロングランもとっても良いです。但し、体力が続けばですが。。。まだ、2日の筑波山登山の疲れも残っていました。1本で疲れたので、昼食にしました。私は朝食を食べ過ぎたので、たこ焼きでしたが、下の娘が頼んだ焼き鳥丼850円がリーズナブルで美味しかったです。メニューが安い気がします。
zao_eboshi_5_130106.jpg

昼食後に2本ロングランをやったら、へばってしまいました。私だけ休憩で他の3人は1本滑って来ました。
その後、スキーを終わりにして、無事に雪道も下ることができました。
仙台に行く前に温泉に寄って行こうということで、遠刈田温泉の神の湯に行きました。近くにゲート式の駐車場があって、60分無料で、その後は1時間100円(だったと思います)でした。男湯は温度がちょうどよかったですが、女湯は熱かったそうです。入った時はそこそこでしたが、出る頃には混んできました。
zao_eboshi_6_130106.jpg

足湯もありました。足湯は無料のようでした。出てから駐車場から見るとスキー場のナイターのライトが綺麗でした。
zao_eboshi_7_130106.jpg

その後、仙台に行って、夕食は仙台のショッピングモールの大戸屋へ。仙台のショッピングモールはライトアップが綺麗でした。
zao_eboshi_8_130106.jpg

昨日は仙台に泊まって、朝8時に仙台を出て、午後1時ころつくばに着きました。

多分ですが、みやぎ蔵王えぼしスキー場は普段は雪が少ないんじゃないでしょうか?今回は、前日まで強い冬型の気候で雪が降っていたんだと思います。よって、最高のコンディションでスキーができたんだと思います。とってもラッキーでした。
  1. 2013年01月06日 19:26 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

XPSでカスタムIPをAdd IPする時のダイアログに入出力ポートを表示する

XPSでカスタムIPをAdd IPする時のダイアログに項目を追加する”の最後の図でも、mt9d111_inf 信号がダイアログの中のシンボル領域に表示されていたと思う。
ZedBoard_Cam_3_130104.png

mt9d111_inf 信号の+記号をクリックすると、グループ化した信号が展開されて見える。
ZedBoard_Cam_4_130104.png

これをどのように表示しているかというと、最初に、IO_INTERFACE でmt9d111_inf を定義する(多分)

IO_INTERFACE IO_IF = mt9d111_inf



PORTをIO_IF = mt9d111_inf でグループ化して、IO_ISで名前をつけるようだ。mt9d111_inf_axi_master_v2_1_0.mpd の自分で定義したPROT定義を下に示す。

#Example IO port
PORT init_done = "", DIR = I, IO_IF = mt9d111_inf, IO_IS = init_done
PORT wr_error = "", DIR = O, IO_IF = mt9d111_inf, IO_IS = wr_error
PORT pclk_from_pll = "", DIR = I, SIGIS = CLK, IO_IF = mt9d111_inf, IO_IS = pclk_from_pll
PORT pclk = "", DIR = I, SIGIS = CLK, IO_IF = mt9d111_inf, IO_IS = pclk
PORT xck = "", DIR =O, SIGIS = CLK, IO_IF = mt9d111_inf, IO_IS = xck
PORT href = "", DIR = I, IO_IF = mt9d111_inf, IO_IS = href
PORT vsync = "", DIR = I, IO_IF = mt9d111_inf, IO_IS = vsync
PORT cam_data = "", DIR = I, VEC = [7:0], IO_IF = mt9d111_inf, IO_IS = cam_data
PORT standby = "", DIR = O, IO_IF = mt9d111_inf, IO_IS = standby
PORT pfifo_overflow, DIR = O, IO_IF = mt9d111_inf, IO_IS = pfifo_overflow
PORT pfifo_underflow, DIR = O, IO_IF = mt9d111_inf, IO_IS = pfifo_underflow


下に、t9d111_inf_axi_master_v2_1_0.mpd のIO_INTERFACEの位置を示す図を貼っておく。
ZedBoard_Cam_6_130104.png
  1. 2013年01月04日 20:48 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

XPSでカスタムIPをAdd IPする時のダイアログに項目を追加する

XPSでカスタムIPをAdd IPする時にダイアログが出るが、そこに自分で設定したパラメータをダイアログで設定したいということでやってみた。
使用するカスタムIPは、現在作っている mt9d111_inf_axi_master.vhd とした。mt9d111_inf_axi_master.vhd では、C_DISPLAY_START_ADDRESS をgeneric の最後に定義している。これをAdd IPのダイアログに表示して、設定できるようにする。なお、カスタムIPのテンプレートは ar37425.zip を参照している
参照するマニュアルは、”Platform Specification Format Reference ManualEmbedded Development Kit (EDK) 14.1 UG642 (v14.1) April 24, 2012”(PDFです)で、Parameter に関しては41ページ目から書いてある。

1.最初に、私のHDD上では、Zynq-7000\ZedBoard\ZedBoard_CamDisp_wHDMI_144\ZedBoard_BitMap_DispCont_142.srcs\sources_1\edk\system\pcores\mt9d111inf_axi_master_v1_00_a\data フォルダにある mt9d111_inf_axi_master_v2_1_0.mpd に DISPLAY_START_ADDRESS の PARAMETER を追加する。

PARAMETER C_DISPLAY_START_ADDRESS = 0x10000000, DT = std_logic_vector(31 downto 0)


mt9d111_inf_axi_master_v2_1_0.mpd の下の辺りに追加した。

# Number of address bits to test before wrapping
PARAMETER C_OFFSET_WIDTH = 9, DT = integer
PARAMETER C_DISPLAY_START_ADDRESS = 0x10000000, DT = std_logic_vector(31 downto 0)

## Ports
PORT ACLK = "", BUS = M_AXI, DIR = I, SIGIS = CLK
PORT ARESETN = ARESETN, BUS = M_AXI, DIR = I, SIGIS = RST


2.同じフォルダにある mt9d111_inf_axi_master_v2_1_0.mui に C_DISPLAY_START_ADDRESS の項目を追加する。

    <!ENTITY C_OFFSET_WIDTH '
    <widget id="C_OFFSET_WIDTH">
        <key>C_OFFSET_WIDTH</key>
        <label>C_OFFSET_WIDTH</label>
        <tip></tip>
    </widget>
    '>
    <!ENTITY C_DISPLAY_START_ADDRESS '
    <widget id="C_DISPLAY_START_ADDRESS">
        <key>C_DISPLAY_START_ADDRESS</key>
        <label>C_DISPLAY_START_ADDRESS</label>
        <tip></tip>
    </widget>
    '>
    
]>


次に、item にも C_DISPLAY_START_ADDRESS の項目を追加する。
ZedBoard_Cam_5_130104.png

これで、XPSでAdd IPすると、User タブに C_DISPLAY_START_ADDRESS の項目が追加された。
ZedBoard_Cam_3_130104.png
  1. 2013年01月04日 10:56 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製3(HDLソースの公開2)

ZedBoard用CMOSカメラ回路の作製2(HDLソースの公開1)”の続き。
今度は、テストベンチとMT9D111のモデルのVerilog ソースを貼っておく。勿論、無保証です。

最初にテストベンチ、mt9d111_inf_axi_master_tb.v から。

`default_nettype none

`timescale 100ps / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   09:51:18 12/31/2012
// Design Name:   mt9d111_inf_axi_master
// Module Name:   K:/HDL/FndtnISEWork/Zynq-7000/ZedBoard/ZedBoard_CamDisp_wHDMI_144/mt9d111_inf_axi_master/mt9d111_inf_axi_master_tb.v
// Project Name:  mt9d111_inf_axi_master
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: mt9d111_inf_axi_master
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module mt9d111_inf_axi_master_tb;

    // Inputs
    wire ACLK;
    wire ARESETN;
    wire M_AXI_AWREADY;
    wire M_AXI_WREADY;
    wire [0:0] M_AXI_BID;
    wire [1:0] M_AXI_BRESP;
    wire [0:0] M_AXI_BUSER;
    wire M_AXI_BVALID;
    wire M_AXI_ARREADY;
    wire [0:0] M_AXI_RID;
    wire [63:0] M_AXI_RDATA;
    wire [1:0] M_AXI_RRESP;
    wire M_AXI_RLAST;
    wire [0:0] M_AXI_RUSER;
    wire M_AXI_RVALID;
    wire init_done;
    wire pclk_from_pll;
    wire pclk;
    wire href;
    wire vsync;
    wire [7:0] cam_data;

    // Outputs
    wire [0:0] M_AXI_AWID;
    wire [31:0] M_AXI_AWADDR;
    wire [7:0] M_AXI_AWLEN;
    wire [2:0] M_AXI_AWSIZE;
    wire [1:0] M_AXI_AWBURST;
    wire M_AXI_AWLOCK;
    wire [3:0] M_AXI_AWCACHE;
    wire [2:0] M_AXI_AWPROT;
    wire [3:0] M_AXI_AWQOS;
    wire [0:0] M_AXI_AWUSER;
    wire M_AXI_AWVALID;
    wire [63:0] M_AXI_WDATA;
    wire [7:0] M_AXI_WSTRB;
    wire M_AXI_WLAST;
    wire [0:0] M_AXI_WUSER;
    wire M_AXI_WVALID;
    wire M_AXI_BREADY;
    wire [0:0] M_AXI_ARID;
    wire [31:0] M_AXI_ARADDR;
    wire [7:0] M_AXI_ARLEN;
    wire [2:0] M_AXI_ARSIZE;
    wire [1:0] M_AXI_ARBURST;
    wire [1:0] M_AXI_ARLOCK;
    wire [3:0] M_AXI_ARCACHE;
    wire [2:0] M_AXI_ARPROT;
    wire [3:0] M_AXI_ARQOS;
    wire [0:0] M_AXI_ARUSER;
    wire M_AXI_ARVALID;
    wire M_AXI_RREADY;
    wire wr_error;
    wire xck;
    wire standby;
    wire pfifo_overflow;
    wire pfifo_underflow;

    // Instantiate the Unit Under Test (UUT)
    mt9d111_inf_axi_master uut (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .M_AXI_AWID(M_AXI_AWID), 
        .M_AXI_AWADDR(M_AXI_AWADDR), 
        .M_AXI_AWLEN(M_AXI_AWLEN), 
        .M_AXI_AWSIZE(M_AXI_AWSIZE), 
        .M_AXI_AWBURST(M_AXI_AWBURST), 
        .M_AXI_AWLOCK(M_AXI_AWLOCK), 
        .M_AXI_AWCACHE(M_AXI_AWCACHE), 
        .M_AXI_AWPROT(M_AXI_AWPROT), 
        .M_AXI_AWQOS(M_AXI_AWQOS), 
        .M_AXI_AWUSER(M_AXI_AWUSER), 
        .M_AXI_AWVALID(M_AXI_AWVALID), 
        .M_AXI_AWREADY(M_AXI_AWREADY), 
        .M_AXI_WDATA(M_AXI_WDATA), 
        .M_AXI_WSTRB(M_AXI_WSTRB), 
        .M_AXI_WLAST(M_AXI_WLAST), 
        .M_AXI_WUSER(M_AXI_WUSER), 
        .M_AXI_WVALID(M_AXI_WVALID), 
        .M_AXI_WREADY(M_AXI_WREADY), 
        .M_AXI_BID(M_AXI_BID), 
        .M_AXI_BRESP(M_AXI_BRESP), 
        .M_AXI_BUSER(M_AXI_BUSER), 
        .M_AXI_BVALID(M_AXI_BVALID), 
        .M_AXI_BREADY(M_AXI_BREADY), 
        .M_AXI_ARID(M_AXI_ARID), 
        .M_AXI_ARADDR(M_AXI_ARADDR), 
        .M_AXI_ARLEN(M_AXI_ARLEN), 
        .M_AXI_ARSIZE(M_AXI_ARSIZE), 
        .M_AXI_ARBURST(M_AXI_ARBURST), 
        .M_AXI_ARLOCK(M_AXI_ARLOCK), 
        .M_AXI_ARCACHE(M_AXI_ARCACHE), 
        .M_AXI_ARPROT(M_AXI_ARPROT), 
        .M_AXI_ARQOS(M_AXI_ARQOS), 
        .M_AXI_ARUSER(M_AXI_ARUSER), 
        .M_AXI_ARVALID(M_AXI_ARVALID), 
        .M_AXI_ARREADY(M_AXI_ARREADY), 
        .M_AXI_RID(M_AXI_RID), 
        .M_AXI_RDATA(M_AXI_RDATA), 
        .M_AXI_RRESP(M_AXI_RRESP), 
        .M_AXI_RLAST(M_AXI_RLAST), 
        .M_AXI_RUSER(M_AXI_RUSER), 
        .M_AXI_RVALID(M_AXI_RVALID), 
        .M_AXI_RREADY(M_AXI_RREADY), 
        .init_done(init_done), 
        .wr_error(wr_error), 
        .pclk_from_pll(pclk_from_pll), 
        .pclk(pclk), 
        .xck(xck), 
        .href(href), 
        .vsync(vsync), 
        .cam_data(cam_data), 
        .standby(standby), 
        .pfifo_overflow(pfifo_overflow), 
        .pfifo_underflow(pfifo_underflow)
    );
    
    assign init_done = 1'b1;

    // ACLK のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    
    // pclk_from_pll のインスタンス
    clk_gen #(
        .CLK_PERIOD(278),    // 27.8nsec, 約36MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) pclk_from_pll_i (
        .clk_out(pclk_from_pll)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );
    
    // MT9D111 モデル
    mt9d111_model #(
        .HORIZONTAL_PIXELS(800),
        .VERTICAL_LINES(600),
        .HBLANK_REG(174),
        .VBLANK_REG(16),
        .PCLK_DELAY(1)
    ) mt9d111_model_i (
        .xck(xck),
        .pclk(pclk),
        .href(href),
        .vsync(vsync),
        .d(cam_data),
        .scl(1'b1),
        .sda(),
        .standby(standby)
    );

    // Instantiate the Unit Under Test (UUT_slave)
    axi_slave_bfm #(
        .C_M_AXI_DATA_WIDTH(64)
    ) uut_slave (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .M_AXI_AWID(M_AXI_AWID), 
        .M_AXI_AWADDR(M_AXI_AWADDR), 
        .M_AXI_AWLEN(M_AXI_AWLEN), 
        .M_AXI_AWSIZE(M_AXI_AWSIZE), 
        .M_AXI_AWBURST(M_AXI_AWBURST), 
        .M_AXI_AWLOCK(M_AXI_AWLOCK), 
        .M_AXI_AWCACHE(M_AXI_AWCACHE), 
        .M_AXI_AWPROT(M_AXI_AWPROT), 
        .M_AXI_AWQOS(M_AXI_AWQOS), 
        .M_AXI_AWUSER(M_AXI_AWUSER), 
        .M_AXI_AWVALID(M_AXI_AWVALID), 
        .M_AXI_AWREADY(M_AXI_AWREADY), 
        .M_AXI_WDATA(M_AXI_WDATA), 
        .M_AXI_WSTRB(M_AXI_WSTRB), 
        .M_AXI_WLAST(M_AXI_WLAST), 
        .M_AXI_WUSER(M_AXI_WUSER), 
        .M_AXI_WVALID(M_AXI_WVALID), 
        .M_AXI_WREADY(M_AXI_WREADY), 
        .M_AXI_BID(M_AXI_BID), 
        .M_AXI_BRESP(M_AXI_BRESP), 
        .M_AXI_BUSER(M_AXI_BUSER), 
        .M_AXI_BVALID(M_AXI_BVALID), 
        .M_AXI_BREADY(M_AXI_BREADY), 
        .M_AXI_ARID(M_AXI_ARID), 
        .M_AXI_ARADDR(M_AXI_ARADDR), 
        .M_AXI_ARLEN(M_AXI_ARLEN), 
        .M_AXI_ARSIZE(M_AXI_ARSIZE), 
        .M_AXI_ARBURST(M_AXI_ARBURST), 
        .M_AXI_ARLOCK(M_AXI_ARLOCK), 
        .M_AXI_ARCACHE(M_AXI_ARCACHE), 
        .M_AXI_ARPROT(M_AXI_ARPROT), 
        .M_AXI_ARQOS(M_AXI_ARQOS), 
        .M_AXI_ARUSER(M_AXI_ARUSER), 
        .M_AXI_ARVALID(M_AXI_ARVALID), 
        .M_AXI_ARREADY(M_AXI_ARREADY), 
        .M_AXI_RID(M_AXI_RID), 
        .M_AXI_RDATA(M_AXI_RDATA), 
        .M_AXI_RRESP(M_AXI_RRESP), 
        .M_AXI_RLAST(M_AXI_RLAST), 
        .M_AXI_RUSER(M_AXI_RUSER), 
        .M_AXI_RVALID(M_AXI_RVALID), 
        .M_AXI_RREADY(M_AXI_RREADY)
    );
      
endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


次に、mt9d111_model.v を貼っておく。RGBのデータにはM系列の疑似乱数を使用している。(2013/08/27:修正)

// mt9d111_model.v 
// mt9d111 の動作モデル
// RGB565 を出力

`default_nettype none
`timescale 1ns / 1ps

module mt9d111_model # (
    parameter    integer HORIZONTAL_PIXELS    = 800,
    parameter    integer    VERTICAL_LINES        = 600,
    parameter    integer    HBLANK_REG            = 174,     // pixels
    parameter    integer    VBLANK_REG            = 16,    // rows
    parameter    integer    PCLK_DELAY            = 1
)(
    input    wire    xck,
    output    reg        pclk = 1'b1,
    output    reg        href = 1'b0,
    output    reg        vsync = 1'b1,
    output    reg        [7:0]    d = 8'd0,
    input    wire    scl,
    inout    wire    sda,
    input    wire    standby
);

    parameter    [2:0]    FRAME_START_BLANKING =    3'b000,
                        ACTIVE_DATA_TIME =        3'b001,
                        HORIZONTAL_BLANKING =    3'b011,
                        FRAME_END_BLANKING =    3'b010,
                        VERTICAL_BLANKING =        3'b110;
                        
    reg        [2:0]    mt9d111_cs = FRAME_START_BLANKING;
    reg        [2:0]    fseb_count = 3'd5;
    reg        [15:0]    adt_count = (HORIZONTAL_PIXELS * 2) - 1;
    reg        [15:0]    hb_count = HBLANK_REG - 1;
    reg        [15:0]    fvt_count = VERTICAL_LINES - 1;
    reg        [31:0]    vb_count = VBLANK_REG * (HORIZONTAL_PIXELS + HBLANK_REG) - 1;
    reg        href_node = 1'b0;
    reg        vsync_node = 1'b1;
    reg        dout_is_even = 1'b0;

    // R, G, B 毎に違った生成多項式のM系列を用意した
    function [7:0] mseqf8_R (input [7:0] din);
        reg xor_result;
        begin
            xor_result = din[7] ^ din[3] ^ din[2] ^ din[1];
            mseqf8_R = {din[6:0], xor_result};
        end
    endfunction
    
    function [7:0] mseqf8_G (input [7:0] din);
        reg xor_result;
        begin
            xor_result = din[7] ^ din[4] ^ din[2] ^ din[0];
            mseqf8_G = {din[6:0], xor_result};
        end
    endfunction

    function [7:0] mseqf8_B (input [7:0] din);
        reg xor_result;
        begin
            xor_result = din[7] ^ din[5] ^ din[2] ^ din[1];
            mseqf8_B = {din[6:0], xor_result};
        end
    endfunction

    reg        [7:0]    mseq8r = 8'd1;
    reg        [7:0]    mseq8g = 8'd1;
    reg        [7:0]    mseq8b = 8'd1;
    
    // pclk の出力
    always @*
        pclk <= #PCLK_DELAY    xck;
        
    // MT9D111 のステート
    always @(posedge pclk) begin
        case (mt9d111_cs)
            FRAME_START_BLANKING : begin
                if (fseb_count==0) begin
                    mt9d111_cs <= ACTIVE_DATA_TIME;
                    href_node <= 1'b1;
                end
            end
            ACTIVE_DATA_TIME : begin
                if (adt_count==0) begin
                    if (fvt_count==0)    // frame end
                        mt9d111_cs <= FRAME_END_BLANKING;
                    else
                        mt9d111_cs <= HORIZONTAL_BLANKING;
                    href_node <= 1'b0;
                end
            end
            HORIZONTAL_BLANKING : begin
                if (hb_count==0) begin
                    mt9d111_cs <= ACTIVE_DATA_TIME;
                    href_node <= 1'b1;
                end
            end
            FRAME_END_BLANKING : begin
                if (fseb_count==0) begin
                    mt9d111_cs <= VERTICAL_BLANKING;
                    vsync_node <= 1'b0;
                end
            end
            VERTICAL_BLANKING : begin
                if (vb_count==0) begin
                    mt9d111_cs <= FRAME_START_BLANKING;
                    vsync_node <= 1'b1;
                end
            end
        endcase
    end
                
    // vsync, href 出力、レーシングを防ぐためにpclk よりも出力を遅らせる
    always @* begin
        vsync <= #1    vsync_node;
        href <= #1    href_node;
    end
    
    // Frame Start/End Blanking Counter (6 pixel clocks)
    always @(posedge pclk) begin
        if (mt9d111_cs==FRAME_START_BLANKING || mt9d111_cs==FRAME_END_BLANKING) begin
            if (fseb_count > 0)
                fseb_count <= fseb_count - 3'd1;
        end else
            fseb_count <= 3'd5;
    end
    
    // Active Data Time Counter
    always @(posedge pclk) begin
        if (mt9d111_cs==ACTIVE_DATA_TIME) begin
            if (adt_count > 0)
                adt_count <= adt_count - 16'd1;
        end else
            adt_count <= (HORIZONTAL_PIXELS * 2) - 1;
    end
    
    // Horizontal Blanking Counter
    always @(posedge pclk) begin
        if (mt9d111_cs==HORIZONTAL_BLANKING) begin
            if (hb_count > 0)
                hb_count <= hb_count - 16'd1;
        end else
            hb_count <= HBLANK_REG - 1;
    end
    
    // Frame Valid Time Counter
    always @(posedge pclk) begin
        if (mt9d111_cs==ACTIVE_DATA_TIME && adt_count==0) begin
            if (fvt_count > 0)
                fvt_count <= fvt_count - 16'd1;
        end if (mt9d111_cs == VERTICAL_BLANKING)
            fvt_count <= VERTICAL_LINES - 1;
    end
    
    // Vertical Blanking Counter
    always @(posedge pclk) begin
        if (mt9d111_cs==VERTICAL_BLANKING) begin
            if (vb_count > 0)
                vb_count <= vb_count - 32'd1;
        end else
            vb_count <= VBLANK_REG * (HORIZONTAL_PIXELS + HBLANK_REG) - 1;
    end
    
    // Red のM系列符号生成
    always @(posedge pclk) begin
        // if (mt9d111_cs==ACTIVE_DATA_TIME)
            mseq8r <= mseqf8_R(mseq8r);
    end
    
    // Green のM系列符号生成
    always @(posedge pclk) begin
        // if (mt9d111_cs==ACTIVE_DATA_TIME)
            mseq8g <= mseqf8_G(mseq8g);
    end
    
    // Blue のM系列符号生成
    always @(posedge pclk) begin
        // if (mt9d111_cs==ACTIVE_DATA_TIME)
            mseq8b <= mseqf8_B(mseq8b);
    end
    
    // d 出力のODD とEVEN を示す
    always @(posedge pclk) begin
        if (mt9d111_cs==ACTIVE_DATA_TIME)
            dout_is_even <= ~dout_is_even;
        else
            dout_is_even <= 1'b0;
    end
    
    // d 出力、レーシングを防ぐためにpclk よりも出力を遅らせる
    always @(posedge pclk) begin
        if (mt9d111_cs==ACTIVE_DATA_TIME) begin
            if (dout_is_even)
                d <= #1 {mseq8g[4:2], mseq8b[7:3]};
            else
                d <= #1 {mseq8r[7:3], mseq8g[7:5]};
        end
    end

endmodule

`default_nettype wire


AXI Master用 AXI Slave Bus Function Mode (BFM)も貼っておく。(2013/01/23:修正)

-----------------------------------------------------------------------------
--
-- AXI Master用 AXI Slave Bus Function Mode (BFM)
--
-----------------------------------------------------------------------------
-- 2012/02/25 : M_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/01/15 : BVALID が1になる間隔をランダム変更できるようにした。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;

package m_seq_bfm_pack is
    function M_SEQ16_BFM_F(mseq16in : std_logic_vector
        )return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
    function M_SEQ16_BFM_F(mseq16in : std_logic_vector
        )return std_logic_vector is
            variable mseq16 : std_logic_vector(15 downto 0);
            variable xor_result : std_logic;
    begin
        xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
        mseq16 := mseq16in(14 downto 0) & xor_result;
        return mseq16;
    end M_SEQ16_BFM_F;
end m_seq_bfm_pack;


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use IEEE.math_real.all;

library work;
use work.m_seq_bfm_pack.all;

--library unisim;
--use unisim.vcomponents.all;

entity axi_slave_bfm is
  generic (
    C_M_AXI_ID_WIDTH     : integer := 1;
    C_M_AXI_ADDR_WIDTH   : integer := 32;
    C_M_AXI_DATA_WIDTH   : integer := 32;
    C_M_AXI_AWUSER_WIDTH : integer := 1;
    C_M_AXI_ARUSER_WIDTH : integer := 1;
    C_M_AXI_WUSER_WIDTH  : integer := 1;
    C_M_AXI_RUSER_WIDTH  : integer := 1;
    C_M_AXI_BUSER_WIDTH  : integer := 1;
    
    C_M_AXI_TARGET        : integer := 0;
    C_OFFSET_WIDTH        : integer := 10; -- 割り当てるRAMのアドレスのビット幅
    C_M_AXI_BURST_LEN    : integer := 256;
    
    WRITE_RANDOM_WAIT    : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
    WR_BVALID_RANDOM_WAIT    : integer := 1; -- Write Transaction の時のM_AXI_BVALID をランダムにWaitする=1, Waitしない=0
    READ_RANDOM_WAIT    : integer := 0 -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
    );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Master Interface Write Address Ports
    M_AXI_AWID     : in  std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_AWADDR   : in  std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_AWLEN    : in  std_logic_vector(8-1 downto 0);
    M_AXI_AWSIZE   : in  std_logic_vector(3-1 downto 0);
    M_AXI_AWBURST  : in  std_logic_vector(2-1 downto 0);
    -- M_AXI_AWLOCK   : in  std_logic_vector(2-1 downto 0);
    M_AXI_AWLOCK   : in  std_logic;
    M_AXI_AWCACHE  : in  std_logic_vector(4-1 downto 0);
    M_AXI_AWPROT   : in  std_logic_vector(3-1 downto 0);
    M_AXI_AWQOS    : in  std_logic_vector(4-1 downto 0);
    M_AXI_AWUSER   : in  std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
    M_AXI_AWVALID  : in  std_logic;
    M_AXI_AWREADY  : out std_logic;

    -- Master Interface Write Data Ports
    M_AXI_WDATA  : in  std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_WSTRB  : in  std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
    M_AXI_WLAST  : in  std_logic;
    M_AXI_WUSER  : in  std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
    M_AXI_WVALID : in  std_logic;
    M_AXI_WREADY : out std_logic;

    -- Master Interface Write Response Ports
    M_AXI_BID    : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_BRESP  : out std_logic_vector(2-1 downto 0);
    M_AXI_BUSER  : out std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
    M_AXI_BVALID : out std_logic;
    M_AXI_BREADY : in  std_logic;

    -- Master Interface Read Address Ports
    M_AXI_ARID     : in  std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_ARADDR   : in  std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_ARLEN    : in  std_logic_vector(8-1 downto 0);
    M_AXI_ARSIZE   : in  std_logic_vector(3-1 downto 0);
    M_AXI_ARBURST  : in  std_logic_vector(2-1 downto 0);
    M_AXI_ARLOCK   : in  std_logic_vector(2-1 downto 0);
    M_AXI_ARCACHE  : in  std_logic_vector(4-1 downto 0);
    M_AXI_ARPROT   : in  std_logic_vector(3-1 downto 0);
    M_AXI_ARQOS    : in  std_logic_vector(4-1 downto 0);
    M_AXI_ARUSER   : in  std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
    M_AXI_ARVALID  : in  std_logic;
    M_AXI_ARREADY  : out std_logic;

    -- Master Interface Read Data Ports
    M_AXI_RID    : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
    M_AXI_RDATA  : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_RRESP  : out std_logic_vector(2-1 downto 0);
    M_AXI_RLAST  : out std_logic;
    M_AXI_RUSER  : out std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
    M_AXI_RVALID : out std_logic;
    M_AXI_RREADY : in  std_logic
    );

end axi_slave_bfm;

architecture implementation of axi_slave_bfm is

constant    AxBURST_FIXED    : std_logic_vector := "00";
constant    AxBURST_INCR    : std_logic_vector := "01";
constant    AxBURST_WRAP    : std_logic_vector := "10";

constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

constant    DATA_BUS_BYTES     : natural := C_M_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant    ADD_INC_OFFSET    : natural := natural(log(real(DATA_BUS_BYTES), 2.0));

-- RAMの生成
constant    SLAVE_ADDR_NUMBER    : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));

-- for write transaction
type write_transaction_state is (idle_wr, awr_wait, awr_accept, wr_burst, wr_bvalid_assert);
type write_response_state is (idle_wres, bvalid_assert);
type write_wready_state is (idle_wrdy, wready_assert);
signal wrt_cs : write_transaction_state;
signal wrres : write_response_state;
signal wrwr : write_wready_state;
signal addr_inc_step_wr : integer := 1;
signal awready         : std_logic;
signal wr_addr         : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bid         : std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp     : std_logic_vector(1 downto 0);
signal wr_bvalid     : std_logic;
signal m_seq16_wr    : std_logic_vector(15 downto 0);
signal wready        : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;

-- for read transaction
type read_transaction_state is (idle_rd, arr_wait, arr_accept, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdt_cs : read_transaction_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready         : std_logic;
signal rd_addr         : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count    : std_logic_vector(7 downto 0);
signal rvalid        : std_logic;
signal rlast        : std_logic;
signal m_seq16_rd    : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;

signal reset_1d, reset_2d, reset : std_logic := '1';
signal bvalid_cnt : std_logic_vector(3 downto 0);

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- AXI4バス Write Transaction State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wrt_cs <= idle_wr;
                awready <= '0';
            else
                case (wrt_cs) is
                    when idle_wr =>
                        if M_AXI_AWVALID='1' then -- M_AXI_AWVALID が1にアサートされた
                            if rdt_cs=idle_rd then -- Read Transaction が終了している(Writeの方が優先順位が高い)
                                wrt_cs <= awr_accept;
                                awready <= '1';
                            else -- Read Transaction が終了していないのでWait
                                wrt_cs <= awr_wait;
                            end if;
                        end if;
                    when awr_wait => -- Read Transaction の終了待ち
                        if rdt_cs=idle_rd or rdt_cs=arr_wait then -- Read Transaction が終了
                            wrt_cs <= awr_accept;
                            awready <= '1';
                        end if;
                    when awr_accept => -- M_AXI_AWREADY をアサート
                        wrt_cs <= wr_burst;
                        awready <= '0';
                    when wr_burst => -- Writeデータの転送
                        if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
                            wrt_cs <= wr_bvalid_assert;
                        end if;
                    when wr_bvalid_assert => -- M_AXI_BVALID アサート
                        if wr_bvalid='1' and M_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
                            wrt_cs <= idle_wr;
                        end if;
                end case;
            end if;
        end if;
    end process;
    M_AXI_AWREADY <= awready;
    
    -- m_seq_wr、16ビットのM系列を計算する
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                m_seq16_wr <= (0 => '1', others => '0');
            else
                if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
                    if wrt_cs=wr_burst and M_AXI_WVALID='1' then
                        m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
                    end if;
                else -- Wait無し
                    m_seq16_wr <= (others => '0');
                end if;
            end if;
        end if;
    end process;
                
    -- wready の処理、M系列を計算して128以上だったらWaitする。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                cs_wready <= idle_wready;
                wready <= '0';
            else
                case (cs_wready) is
                    when idle_wready =>
                        if wrt_cs=awr_accept then -- 次はwr_burst
                            if m_seq16_wr(7)='0' then -- wready='1'
                                cs_wready <= assert_wready;
                                wready <= '1';
                            else -- m_seq16_wr(7)='1' then -- wready='0'
                                cs_wready <= deassert_wready;
                                wready <= '0';
                            end if;
                        end if;
                    when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
                        if wrt_cs=wr_burst and M_AXI_WLAST='1' and M_AXI_WVALID='1' then -- 終了
                            cs_wready <= idle_wready;
                            wready <= '0';
                        elsif wrt_cs=wr_burst and M_AXI_WVALID='1' then -- 1つのトランザクション終了。
                            if m_seq16_wr(7)='1' then
                                cs_wready <= deassert_wready;
                                wready <= '0';
                            end if;
                        end if;
                    when deassert_wready =>
                        if m_seq16_wr(7)='0' then -- wready='1'
                            cs_wready <= assert_wready;
                            wready <= '1';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    M_AXI_WREADY <= wready;
    cdc_we <= '1' when wrt_cs=wr_burst and wready='1' and M_AXI_WVALID='1' else '0';
    
    -- addr_inc_step_wr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                addr_inc_step_wr <= 1;
            else
                if wrt_cs=awr_accept then
                    case (M_AXI_AWSIZE) is
                        when "000" => -- 8ビット転送
                            addr_inc_step_wr <= 1;
                        when "001" => -- 16ビット転送
                            addr_inc_step_wr <= 2;
                        when "010" => -- 32ビット転送
                            addr_inc_step_wr <= 4;
                        when "011" => -- 64ビット転送
                            addr_inc_step_wr <= 8;
                        when "100" => -- 128ビット転送
                            addr_inc_step_wr <= 16;
                        when "101" => -- 256ビット転送
                            addr_inc_step_wr <= 32;
                        when "110" => -- 512ビット転送
                            addr_inc_step_wr <= 64;
                        when others => --"111" => -- 1024ビット転送
                            addr_inc_step_wr <= 128;
                    end case;
                end if;
            end if;
        end if;
    end process;
    
    -- wr_addr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_addr <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    wr_addr <= M_AXI_AWADDR(C_OFFSET_WIDTH-1 downto 0);
                elsif wrt_cs=wr_burst and M_AXI_WVALID='1' and wready='1' then -- アドレスを進める
                    wr_addr <= wr_addr + addr_inc_step_wr;
                end if;
            end if;
        end if;
    end process;
    
    -- wr_bid の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_bid <= "0";
            else
                if wrt_cs=awr_accept then
                    wr_bid <= M_AXI_AWID;
                end if;
            end if;
        end if;
    end process;
    M_AXI_BID <= wr_bid;
    
    -- wr_bresp の処理
    -- M_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_bresp <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    if M_AXI_AWBURST=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
                        wr_bresp <= RESP_OKAY; -- Write Transaction は成功
                    else
                        wr_bresp <= RESP_SLVERR; -- エラー
                    end if;
                end if;
            end if;
        end if;
    end process;
    M_AXI_BRESP <= wr_bresp;
    
    -- wr_bvalid の処理
    -- WR_BVALID_RANDOM_WAIT が1の時にランダムにWait、0の時は1クロックWait
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                bvalid_cnt <= (others => '0');
            else
                if WR_BVALID_RANDOM_WAIT=1 then -- ランダムWait
                    if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
                        bvalid_cnt <= m_seq16_wr(3 downto 0); -- 0 ~ 15 wait
                    elsif bvalid_cnt /= 0 then
                        bvalid_cnt <= bvalid_cnt - 1;
                    end if;
                else
                    bvalid_cnt <= (others => '0');
                end if;
            end if;
        end if;
    end process;
        
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                wr_bvalid <= '0';
            else
                if wr_bvalid='1' and M_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
                    wr_bvalid <= '0';
                elsif wrt_cs=wr_bvalid_assert and bvalid_cnt=0 then -- Write Transaction 終了
                    wr_bvalid <= '1';
                end if;
            end if;
        end if;
    end process;
    M_AXI_BVALID <= wr_bvalid;
    M_AXI_BUSER <= (others => '0');
    
    
    -- AXI4バス Read Transaction State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rdt_cs <= idle_rd;
                arready <= '0';
            else
                case (rdt_cs) is
                    when idle_rd =>
                        if M_AXI_ARVALID='1' then -- Read Transaction 要求
                            if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
                                rdt_cs <= arr_accept;
                                arready <= '1';
                            else -- Write Transaction が終了していないのでWait
                                rdt_cs <= arr_wait;
                            end if;
                        end if;
                    when arr_wait => -- Write Transaction の終了待ち
                        if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
                            rdt_cs <= arr_accept;
                            arready <= '1';
                        end if;
                    when arr_accept => -- M_AXI_ARREADY をアサート
                        rdt_cs <= rd_burst;
                        arready <= '0';
                    when rd_burst => -- Readデータの転送
                        if rd_axi_count=0 and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了
                            rdt_cs <= idle_rd;
                        end if;
                end case;
            end if;
        end if;
    end process;
    M_AXI_ARREADY <= arready;

    -- m_seq_rd、16ビットのM系列を計算する
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
            else
                if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
                    if rdt_cs=rd_burst and M_AXI_RREADY='1' then
                        m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
                    end if;
                else -- Wati無し
                    m_seq16_rd <= (others => '0');
                end if;
            end if;
        end if;
    end process;
                
    -- rvalid の処理、M系列を計算して128以上だったらWaitする。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                cs_rvalid <= idle_rvalid;
                rvalid <= '0';
            else
                case (cs_rvalid) is
                    when idle_rvalid =>
                        if rdt_cs=arr_accept then -- 次はrd_burst
                            if m_seq16_rd(7)='0' then -- rvalid='1'
                                cs_rvalid <= assert_rvalid;
                                rvalid <= '1';
                            else -- m_seq16_rd(7)='1' then -- rvalid='0'
                                cs_rvalid <= deassert_rvalid;
                                rvalid <= '0';
                            end if;
                        end if;
                    when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
                        if rdt_cs=rd_burst and rlast='1' and M_AXI_RREADY='1' then -- 終了
                            cs_rvalid <= idle_rvalid;
                            rvalid <= '0';
                        elsif rdt_cs=rd_burst and M_AXI_RREADY='1' then -- 1つのトランザクション終了。
                            if m_seq16_rd(7)='1' then
                                cs_rvalid <= deassert_rvalid;
                                rvalid <= '0';
                            end if;
                        end if;
                    when deassert_rvalid =>
                        if m_seq16_rd(7)='0' then -- rvalid='1'
                            cs_rvalid <= assert_rvalid;
                            rvalid <= '1';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    M_AXI_RVALID <= rvalid;
    
    -- addr_inc_step_rd の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                addr_inc_step_rd <= 1;
            else
                if rdt_cs=arr_accept then
                    case (M_AXI_ARSIZE) is
                        when "000" => -- 8ビット転送
                            addr_inc_step_rd <= 1;
                        when "001" => -- 16ビット転送
                            addr_inc_step_rd <= 2;
                        when "010" => -- 32ビット転送
                            addr_inc_step_rd <= 4;
                        when "011" => -- 64ビット転送
                            addr_inc_step_rd <= 8;
                        when "100" => -- 128ビット転送
                            addr_inc_step_rd <= 16;
                        when "101" => -- 256ビット転送
                            addr_inc_step_rd <= 32;
                        when "110" => -- 512ビット転送
                            addr_inc_step_rd <= 64;
                        when others => -- "111" => -- 1024ビット転送
                            addr_inc_step_rd <= 128;
                    end case;
                end if;
            end if;
        end if;
    end process;
    
    -- rd_addr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rd_addr <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    rd_addr <= M_AXI_ARADDR(C_OFFSET_WIDTH-1 downto 0);
                elsif rdt_cs=rd_burst and M_AXI_RREADY='1' and rvalid='1' then
                    rd_addr <= rd_addr + addr_inc_step_rd;
                end if;
            end if;
        end if;
    end process;
    
    -- rd_axi_count の処理(AXIバス側のデータカウント)
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rd_axi_count <= (others => '0');
            else
                if rdt_cs=arr_accept then -- rd_axi_count のロード
                    rd_axi_count <= M_AXI_ARLEN;
                elsif rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
                    rd_axi_count <= rd_axi_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- rdlast State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                rdlast <= idle_rlast;
                rlast <= '0';
            else
                case (rdlast) is
                    when idle_rlast =>
                        if rd_axi_count=1 and rvalid='1' and M_AXI_RREADY='1' then -- バーストする場合
                            rdlast <= rlast_assert;
                            rlast <= '1';
                        elsif rdt_cs=arr_accept and M_AXI_ARLEN=0 then -- 転送数が1の場合
                            rdlast <= rlast_assert;
                            rlast <= '1';
                        end if;
                    when rlast_assert => 
                        if rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
                            rdlast <= idle_rlast;
                            rlast <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    M_AXI_RLAST <= rlast;
    
    -- M_AXI_RID, M_AXI_RUSER の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                M_AXI_RID <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    M_AXI_RID <= M_AXI_ARID;
                end if;
            end if;
        end if;
    end process;
    M_AXI_RUSER <= (others => '0');
    
    -- M_AXI_RRESP は、M_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset='1' then
                M_AXI_RRESP <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    if M_AXI_ARBURST=AxBURST_INCR then
                        M_AXI_RRESP <= RESP_OKAY;
                    else
                        M_AXI_RRESP <= RESP_SLVERR;
                    end if;
                end if;
            end if;
        end if;
    end process;
    
    -- RAM
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if cdc_we='1' then
                for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
                    if M_AXI_WSTRB(i)='1' then -- Byte Enable
                        ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= M_AXI_WDATA(i*8+7 downto i*8);
                    end if;
                end loop;
            end if;
        end if;
    end process;
    M_AXI_RDATA <= ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)));

end implementation;

  1. 2013年01月03日 17:18 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製2(HDLソースの公開1)

ZedBoard用CMOSカメラ回路の作製1(単体シミュレーション)”でシミュレーションを行ったHDLソースを公開します。バグなどで、予告なく修正する場合があります。なお、無保証です。

最初に、トップのmt9d111_inf_axi_master.vhd です。(2013/01/23:修正)(2013/02/10:修正)

-------------------------------------------------------------------------------
--
-- AXI Master
--
-- VHDL-Standard:   VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
--   mt9d111_inf_axi_master
--
----------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;

--library unisim;
--use unisim.vcomponents.all;

entity mt9d111_inf_axi_master is
  generic(
    C_M_AXI_SUPPORTS_THREADS            : integer := 0;
    C_M_AXI_THREAD_ID_WIDTH             : integer := 1;
    C_M_AXI_ADDR_WIDTH                     : integer := 32;
    C_M_AXI_DATA_WIDTH                     : integer := 64;
    C_INTERCONNECT_M_AXI_WRITE_ISSUING    : integer := 8;
    C_INTERCONNECT_M_AXI_READ_ISSUING    : integer := 8;
    C_M_AXI_SUPPORTS_READ                : integer := 0;
    C_M_AXI_SUPPORTS_WRITE                : integer := 1;
    C_M_AXI_SUPPORTS_USER_SIGNALS        : integer := 0;
    C_M_AXI_AWUSER_WIDTH                : integer := 1;
    C_M_AXI_ARUSER_WIDTH                : integer := 1;
    C_M_AXI_WUSER_WIDTH                 : integer := 1;
    C_M_AXI_RUSER_WIDTH                 : integer := 1;
    C_M_AXI_BUSER_WIDTH                 : integer := 1;
    C_M_AXI_SUPPORTS_NARROW_BURST        : integer := 0;
    C_M_AXI_TARGET                        : std_logic_vector(31 downto 0) := x"00000000";
    C_M_AXI_BURST_LEN                    : integer := 16;
    C_OFFSET_WIDTH                        : integer := 9;
    
    C_DISPLAY_START_ADDRESS                : std_logic_vector(31 downto 0) := x"10000000";
    C_UPSIDE_DOWN                        : integer := 0    -- 1 = 上下反転、0 = 正常
  );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Master Interface Write Address
    M_AXI_AWID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_AWADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_AWLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_AWSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_AWBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_AWLOCK  : out std_logic;
    M_AXI_AWCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_AWPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3    M_AXI_AWREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_AWQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_AWUSER  : out std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
    M_AXI_AWVALID : out std_logic;
    M_AXI_AWREADY : in  std_logic;

    -- Master Interface Write Data
    -- AXI3   M_AXI_WID(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_WDATA  : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_WSTRB  : out std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
    M_AXI_WLAST  : out std_logic;
    M_AXI_WUSER  : out std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
    M_AXI_WVALID : out std_logic;
    M_AXI_WREADY : in  std_logic;

    -- Master Interface Write Response
    M_AXI_BID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_BRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_BUSER  : in  std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
    M_AXI_BVALID : in  std_logic;
    M_AXI_BREADY : out std_logic;

    -- Master Interface Read Address
    M_AXI_ARID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_ARADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_ARLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_ARSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_ARBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_ARLOCK  : out std_logic_vector(2-1 downto 0);
    M_AXI_ARCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_ARPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3   M_AXI_ARREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_ARQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_ARUSER  : out std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
    M_AXI_ARVALID : out std_logic;
    M_AXI_ARREADY : in  std_logic;

    -- Master Interface Read Data 
    M_AXI_RID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_RDATA  : in  std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_RRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_RLAST  : in  std_logic;
    M_AXI_RUSER  : in  std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
    M_AXI_RVALID : in  std_logic;
    M_AXI_RREADY : out std_logic;

    init_done    : in std_logic;
    
    wr_error        : out std_logic;    -- AXI4 Write 時のエラー(M_AXI_BRESP/=RESP_OKAY)
    
    -- MT9D111 Camera Interface
    pclk_from_pll    : in    std_logic;    -- PLLからMT9D111のxck に出力するクロック
    pclk            : in     std_logic;    -- MT9D111からのピクセルクロック入力
    xck                : out    std_logic;    -- MT9D111へのピクセルクロック出力
    href            : in     std_logic;
    vsync            : in    std_logic;
    cam_data        : in    std_logic_vector(7 downto 0);
    standby            : out    std_logic;    -- STANDBY出力(ディスエーブル、0固定)
    pfifo_overflow    : out    std_logic;    -- pfifo overflow
    pfifo_underflow    : out    std_logic    -- pfifo underflow
);

end mt9d111_inf_axi_master;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of mt9d111_inf_axi_master is
constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

constant    DDR3_START_ADDR    : std_logic_vector := x"10000000";

constant    ROW_ALL_PIXELS : integer := 640;
constant    COULMN_ALL_PIXELS : integer := 480;

constant    SVGA_ADDR_LIMIT : integer := ROW_ALL_PIXELS*COULMN_ALL_PIXELS*4; -- SVGAのアドレスリミット(横ピクセル数 * 縦ピクセル数 * 1ピクセルを表すバイト数)

signal reset_1d, reset_2d, reset : std_logic;
type wr_main_transaction_state is (idle_wr_main, write_state);
signal wr_main_cs, wr_main_1d : wr_main_transaction_state;
type write_transaction_state is (idle_wr, awvalid_assert, data_write_hold, bready_assert, wr_tran_end);
signal wrt_cs : write_transaction_state;
type write_wvalid_state is (idle_wvalid, wvalid_assert, wvalid_hold);
signal wrt_wv_cs : write_wvalid_state;

signal awvalid, wvalid, bready : std_logic;
signal awlen, write_count : std_logic_vector(7 downto 0);
signal wlast : std_logic;
signal preset_1d, preset_2d, preset : std_logic;
signal pfifo_empty        : std_logic;
signal pfifo_almost_empty    : std_logic;
signal pfifo_rd_data_count    : std_logic_vector(9 downto 0);
signal pfifo_rd_dcount_dec : unsigned(9 downto 0);
signal pfifo_rd_en : std_logic;

component mt9d111_cam_cont generic (
        DISPLAY_START_ADDRESS : std_logic_vector(31 downto 0) := x"10000000";
        UPSIDE_DOWN : integer := 0
    );
    port(
        aclk            : in std_logic;
        areset            : in std_logic;
        pclk            : in std_logic;
        preset            : in std_logic;
        pclk_from_pll    : in std_logic;
        xclk            : out std_logic;
        line_valid        : in std_logic;
        frame_valid        : in std_logic;
        cam_data        : in std_logic_vector(7 downto 0);
        standby            : out std_logic;
        paddr            : out std_logic_vector(31 downto 0);
        pfifo_rd_en        : in std_logic;
        pfifo_dout        : out std_logic_vector(63 downto 0);
        pfifo_empty        : out std_logic;
        pfifo_almost_empty        : out std_logic;
        pfifo_rd_data_count    : out std_logic_vector(9 downto 0);
        pfifo_overflow        : out std_logic;
        pfifo_underflow        : out std_logic
    ); 
end component;

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN or not init_done;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- ARESETN をpclk で同期化
    process(pclk) begin
        if pclk'event and pclk='1' then
            preset_1d <= not ARESETN or not init_done;
            preset_2d <= preset_1d;
        end if;
    end process;
    preset <= preset_2d;
    
    -- Write Transaction State Machine
    -- ピクセルデータが存在する時(pfifo_empty=0)の時に、 Writeを行う。Readは無し
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_main_cs <= idle_wr_main;
            else
                case (wr_main_cs) is
                    when idle_wr_main =>
                        if pfifo_rd_data_count/=std_logic_vector(to_unsigned(0, pfifo_rd_data_count'length)) then
                            wr_main_cs <= write_state;
                        end if;
                    when write_state =>
                        if wrt_cs = wr_tran_end then -- pfifo のピクセルデータをAXI4バス経由で転送終了
                            wr_main_cs <= idle_wr_main;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    pfifo_rd_en <= M_AXI_WREADY and wvalid;
    mt9d111_cam_cont_i : mt9d111_cam_cont generic map(
        DISPLAY_START_ADDRESS    => C_DISPLAY_START_ADDRESS,
        UPSIDE_DOWN                => C_UPSIDE_DOWN
    )port map(
        aclk                => ACLK,
        areset                => reset,
        pclk                => pclk,
        preset                => preset,
        pclk_from_pll        => pclk_from_pll,
        xclk                => xck,
        line_valid            => href,
        frame_valid            => vsync,
        cam_data            => cam_data,
        standby                => standby,
        paddr                => M_AXI_AWADDR,
        pfifo_rd_en            => pfifo_rd_en,
        pfifo_dout            => M_AXI_WDATA,
        pfifo_empty            => pfifo_empty,
        pfifo_almost_empty    => pfifo_almost_empty,
        pfifo_rd_data_count    => pfifo_rd_data_count,
        pfifo_overflow        => pfifo_overflow,
        pfifo_underflow        => pfifo_underflow
    );
        
    -- Write
    M_AXI_AWID        <= "0";
    M_AXI_AWSIZE     <= "011";    -- 8 bytes fixed
    M_AXI_AWBURST    <= "01";    -- INCR
    M_AXI_AWLOCK    <= '0';    -- Normal Access
    M_AXI_AWCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    -- M_AXI_AWCACHE    <= "0011";    -- Normal Non-cacheable Bufferable, Zynq-7020ではBRESPが10でSLVERRになってしまい設定してはならない。
    M_AXI_AWPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_AWQOS        <= "0000";    -- default
    M_AXI_AWUSER    <= "0";
    M_AXI_WSTRB        <= (others => '1');
    M_AXI_WUSER        <= "0";
    M_AXI_AWLEN        <= awlen;
    
    -- AXI4バス Write Transaction State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_cs <= idle_wr;
                awvalid <= '0';
                bready <= '0';
            else 
                case(wrt_cs) is
                    when idle_wr =>
                        if wr_main_cs = write_state then
                            wrt_cs <= awvalid_assert;
                            awvalid <= '1';
                        end if;
                    when awvalid_assert =>
                        if M_AXI_AWREADY='1' then
                            if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and unsigned(write_count)=0 and M_AXI_WREADY='1') then
                                wrt_cs <= bready_assert;
                                bready <= '1';
                            else
                                wrt_cs <= data_write_hold;
                            end if;
                            awvalid <= '0';
                        end if;
                    when data_write_hold =>
                        if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and unsigned(write_count)=0 and M_AXI_WREADY='1') then
                            wrt_cs <= bready_assert;
                            bready <= '1';
                        end if;
                    when bready_assert =>
                        if M_AXI_BVALID='1' then
                            wrt_cs <= wr_tran_end;
                            bready <= '0';
                        end if;
                    when wr_tran_end =>
                        wrt_cs <= idle_wr;
                end case;
            end if;
        end if;
    end process;
    -- AXI4 バス Write Transaction WVALID State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_wv_cs <= idle_wvalid;
                wvalid <= '0';
            else 
                case(wrt_wv_cs) is
                    when idle_wvalid =>
                        if wrt_cs=awvalid_assert then
                            wrt_wv_cs <= wvalid_assert;
                            wvalid <= '1';
                        end if;
                    when wvalid_assert =>
                        if unsigned(write_count)=0 and M_AXI_WREADY='1' then -- 終了
                            wrt_wv_cs <= wvalid_hold;
                            wvalid <= '0';
                        end if;
                    when wvalid_hold =>
                        if wrt_cs=bready_assert then
                            wrt_wv_cs <= idle_wvalid;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    M_AXI_AWVALID    <= awvalid;
    M_AXI_WVALID    <= wvalid;
    M_AXI_BREADY    <= bready;
    
    -- write_count の処理
    pfifo_rd_dcount_dec <= unsigned(pfifo_rd_data_count) - 1;
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_count <= (others => '0');
                awlen <= (others => '0');
            else
                if wr_main_cs = write_state and wrt_cs=idle_wr then -- wr_main_cs がwrite_state になった最初の1クロック
                    if C_UPSIDE_DOWN = 0 then -- 正常表示の場合
                        write_count <= std_logic_vector(pfifo_rd_dcount_dec(7 downto 0));
                        awlen <= std_logic_vector(pfifo_rd_dcount_dec(7 downto 0));
                    else -- 上下反転する場合はシングル転送
                        write_count <= std_logic_vector(to_unsigned(0, write_count'length));
                        awlen <= std_logic_vector(to_unsigned(0, awlen'length));
                    end if;    
                elsif wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' and unsigned(write_count)/=0 then -- 1つデータ転送出来た
                    write_count <= std_logic_vector(unsigned(write_count) - 1);
                end if;
            end if;
        end if;
    end process;
    
    -- wlastの処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wlast <= '0';
            else
                if wr_main_cs = write_state and wrt_cs=idle_wr then -- Wrire Transaction を開始する際に、
                    if C_UPSIDE_DOWN = 0 then -- 正常表示の場合
                        if unsigned(pfifo_rd_data_count)=1 then -- pfifo_rd_data_count が1の時はデータ転送の最初からwlast をアサートする
                            wlast <= '1';
                        end if;
                    else -- 上下反転する場合はシングル転送
                        wlast <= '1';
                    end if;
                elsif wrt_wv_cs=wvalid_assert and unsigned(write_count)=1 and M_AXI_WREADY='1' then -- awlen が0で無い時はwrite_count が1でM_AXI_WREADY='1'の時、つまりwrite_count が0の時にwlastをアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and unsigned(write_count)=0 and M_AXI_WREADY='1' then -- データ転送が終了なのでwlast を0にする
                    wlast <= '0';
                end if;
            end if;
        end if;
    end process;
    M_AXI_WLAST <= wlast;
    
    -- wr_error の処理、M_AXI_BRESPがRESP_OKAY以外の時にwr_errorを点灯する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_error <= '0';
            else
                if wrt_cs=bready_assert and M_AXI_BVALID='1' and M_AXI_BRESP/=RESP_OKAY then
                    wr_error <= '1';
                end if;
            end if;
        end if;
    end process;
    
    -- Readは無し
    M_AXI_ARID        <= "0";
    M_AXI_ARLEN        <= (others => '0');
    M_AXI_ARSIZE    <= "010";    -- 4bytes
    M_AXI_ARBURST    <= "01";    -- INCR
    M_AXI_ARLOCK    <= "00";    -- Normal Access
    M_AXI_ARCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    M_AXI_ARPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_ARQOS        <= "0000";    -- default
    M_AXI_ARUSER    <= "0";
    M_AXI_ARADDR    <= (others => '0');
    M_AXI_ARVALID    <= '0';
    M_AXI_RREADY    <= '0';

end implementation;


次に、下位モジュールのmt9d111_cam_cont.v を貼っておきます。(2013/01/23:修正)

// MT9D111カメラコントローラ
// MT9D111_cam_cont.v
// 2012/12/26
// 

`default_nettype none

module mt9d111_cam_cont # (
    parameter    DISPLAY_START_ADDRESS = 32'h10000000,    // Frame Buffer Start Address
    parameter    integer    UPSIDE_DOWN = 0        // 1 = 上下反転、0 = 正常
)(
    input    wire    aclk,
    input    wire    areset,
    input    wire    pclk,
    input    wire    preset,
    input    wire    pclk_from_pll,
    output    wire    xclk,
    input    wire    line_valid,
    input    wire    frame_valid,
    input    wire    [7:0]    cam_data,
    output    wire    standby,
    output    wire    [31:0]    paddr,
    input    wire    pfifo_rd_en,
    output    wire    [63:0]    pfifo_dout,
    output    wire    pfifo_empty,
    output    wire    pfifo_almost_empty,
    output    wire    [9:0]    pfifo_rd_data_count,
    output    wire    pfifo_overflow,
    output    wire    pfifo_underflow
);
    `include "./disp_timing_parameters.vh"
    
    // Frame Buffer End Address
    localparam    DISPLAY_END_ADDRESS    = DISPLAY_START_ADDRESS + (H_ACTIVE_VIDEO * V_ACTIVE_VIDEO)*4 - 8; // 最後のピクセル、1ピクセル = 4バイトで、64ビットバス幅なので、8バイトごと
    
    reg        line_valid_1d;
    reg        frame_valid_1d;
    reg        [7:0]    cam_data_1d;
    reg        line_valid_1d_odd;
    reg        line_v_1d_odd_1d;
    reg        [63:0]    rgb565;
    wire    pfifo_full, pfifo_almost_full;
    reg        frame_valid_1d_aclk_1d, frame_valid_1d_aclk_2d;
    parameter    [1:0]    IDLE_ADDR_RST =    2'b00,
                        ADDR_RST =        2'b01,
                        ADDR_RST_HOLD =    2'b11;
    reg        [1:0]    addr_rst_cs;
    reg        [31:0]    paddr_reg;
    reg        rgb565_2nd;

    
    assign standby = 1'b0;
    
    // MT9D111 へのクロックを出力 (xclk)
    ODDR #(
        .DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
        .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
        .SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
    ) ODDR_inst (
        .Q(xclk), // 1-bit DDR output
        .C(pclk_from_pll), // 1-bit clock input
        .CE(1'b1), // 1-bit clock enable input
        .D1(1'b1), // 1-bit data input (positive edge)
        .D2(1'b0), // 1-bit data input (negative edge)
        .R(1'b0), // 1-bit reset
        .S(1'b0) // 1-bit set
    );
    
    // 入力信号を一旦ラッチする
    always @(posedge pclk) begin
        if (preset) begin
            line_valid_1d <=    1'b0;
            frame_valid_1d <=    1'b0;
            cam_data_1d <=        8'd0;
        end else begin
            line_valid_1d <=    line_valid;
            frame_valid_1d <=    frame_valid;
            cam_data_1d <=        cam_data;
        end
    end
    
    // frame_valid_1d をaclk でラッチする
    always @(posedge aclk) begin
        if (areset) begin
            frame_valid_1d_aclk_1d <= 1'b0;
            frame_valid_1d_aclk_2d <= 1'b0;
        end else begin
            frame_valid_1d_aclk_1d <= frame_valid_1d;
            frame_valid_1d_aclk_2d <= frame_valid_1d_aclk_1d;
        end
    end
    
    // line_valid_1d が偶数か奇数かをカウント
    always @(posedge pclk) begin
        if (preset)
            line_valid_1d_odd <= 1'b0;
        else begin
            if (line_valid_1d)
                line_valid_1d_odd <= ~line_valid_1d_odd;
            else
                line_valid_1d_odd <= 1'b0;
        end
    end
    
    // rgb565でラッチしているので、line_valid_1d_odd を1クロック遅延する
    always @(posedge pclk) begin
        if (preset)
            line_v_1d_odd_1d <= 1'b0;
        else
            line_v_1d_odd_1d <= line_valid_1d_odd;
    end
    
    // 2番めのRGB565を示す。64ビット長のFIFOに入れるのに2ピクセル集めてから非同期FIFOにWriteする
    always @(posedge pclk) begin
        if (preset)
            rgb565_2nd <= 1'b0;
        else begin
            if (line_valid_1d_odd)
                rgb565_2nd <= ~rgb565_2nd;
        end
    end
    
    // addressの生成
    always @(posedge aclk) begin
        if (areset) begin
            if (UPSIDE_DOWN==0) // 正常、それ以外は上下反転
                paddr_reg <= DISPLAY_START_ADDRESS;
            else // 上下反転
                paddr_reg <= DISPLAY_END_ADDRESS;
        end else begin
            if (pfifo_rd_en) begin
                if (UPSIDE_DOWN==0) // 正常
                    paddr_reg <= paddr_reg + 32'd8;
                else // 上下反転
                    paddr_reg <= paddr_reg - 32'd8;
            end else if (addr_rst_cs==ADDR_RST) begin    // frame_valid が0になって、pfifoにデータが無くなった時にアドレスをクリア
                if (UPSIDE_DOWN==0) // 正常、それ以外は上下反転
                    paddr_reg <= DISPLAY_START_ADDRESS;
                else // 上下反転
                    paddr_reg <= DISPLAY_END_ADDRESS;
            end
        end
    end
    assign paddr = paddr_reg;
    
    // address をリセットするためのステートマシン
    always @(posedge aclk) begin
        if (areset)
            addr_rst_cs <= IDLE_ADDR_RST;
        else begin
            case (addr_rst_cs)
                IDLE_ADDR_RST :
                    if (~frame_valid_1d_aclk_2d & pfifo_empty)
                        addr_rst_cs <= ADDR_RST;
                ADDR_RST :
                    addr_rst_cs <= ADDR_RST_HOLD;
                ADDR_RST_HOLD :
                    if (frame_valid_1d_aclk_2d)
                        addr_rst_cs <= IDLE_ADDR_RST;
            endcase
        end
    end
    
    // RGB565 のデータを保存する。正常と上下反転ではバイト配列が異なる
    always @(posedge pclk) begin
        if (preset)
            rgb565 <= 32'd0;
        else begin 
            if (UPSIDE_DOWN==0) begin // 正常、それ以外は上下反転
                case ({rgb565_2nd, line_valid_1d_odd})
                    2'b00 : // 1番目
                        rgb565[63:45] <= {8'd0, cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]};    // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
                    2'b01 : // 2番目
                        rgb565[44:32] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000};    // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
                    2'b10 : // 3番目
                        rgb565[31:13] <= {8'd0, cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]};    // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
                    2'b11 : // 4番目
                        rgb565[12:0] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000};    // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
                endcase
            end else begin // 上下反転
                case ({rgb565_2nd, line_valid_1d_odd})
                    2'b00 : // 1番目
                        rgb565[31:13] <= {8'd0, cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]};    // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
                    2'b01 : // 2番目
                        rgb565[12:0] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000};    // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
                    2'b10 : // 3番目
                        rgb565[63:45] <= {8'd0, cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]};    // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
                    2'b11 : // 4番目
                        rgb565[44:32] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000};    // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
                endcase
            end
        end
    end
            
    // pixel FIFO をインスタンスする
    pixel_fifo pfifo (
        .rst(areset), // input rst
        .wr_clk(pclk), // input wr_clk
        .rd_clk(aclk), // input rd_clk
        .din(rgb565), // input [63 : 0] din
        .wr_en(line_v_1d_odd_1d & ~rgb565_2nd), // input wr_en, 2つのピクセルが揃うには4クロック掛かる
        .rd_en(pfifo_rd_en), // input rd_en
        .dout(pfifo_dout), // output [63 : 0] dout
        .full(pfifo_full), // output full
        .almost_full(pfifo_almost_full), // output almost_full
        .overflow(pfifo_overflow), // output overflow
        .empty(pfifo_empty), // output empty
        .almost_empty(pfifo_almost_empty), // output almost_empty
        .underflow(pfifo_underflow), // output underflow
        .rd_data_count(pfifo_rd_data_count) // output [9 : 0] rd_data_count
    );
endmodule

`default_nettype wire


最後に、pixel_fifo.xco です。(2013/01/23:修正)

##############################################################
#
# Xilinx Core Generator version 14.4
# Date: Wed Jan 16 12:27:21 2013
#
##############################################################
#
# This file contains the customisation parameters for a
# Xilinx CORE Generator IP GUI. It is strongly recommended
# that you do not manually alter this file as it may cause
# unexpected and unsupported behavior.
#
##############################################################
#
# Generated from component: xilinx.com:ip:fifo_generator:9.3
#
##############################################################
#
# BEGIN Project Options
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = Verilog
SET device = xc7z020
SET devicefamily = zynq
SET flowvendor = Other
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = clg484
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -1
SET verilogsim = true
SET vhdlsim = false
# END Project Options
# BEGIN Select
SELECT FIFO_Generator xilinx.com:ip:fifo_generator:9.3
# END Select
# BEGIN Parameters
CSET add_ngc_constraint_axi=false
CSET almost_empty_flag=true
CSET almost_full_flag=true
CSET aruser_width=1
CSET awuser_width=1
CSET axi_address_width=32
CSET axi_data_width=64
CSET axi_type=AXI4_Stream
CSET axis_type=FIFO
CSET buser_width=1
CSET clock_enable_type=Slave_Interface_Clock_Enable
CSET clock_type_axi=Common_Clock
CSET component_name=pixel_fifo
CSET data_count=false
CSET data_count_width=9
CSET disable_timing_violations=false
CSET disable_timing_violations_axi=false
CSET dout_reset_value=0
CSET empty_threshold_assert_value=4
CSET empty_threshold_assert_value_axis=1022
CSET empty_threshold_assert_value_rach=1022
CSET empty_threshold_assert_value_rdch=1022
CSET empty_threshold_assert_value_wach=1022
CSET empty_threshold_assert_value_wdch=1022
CSET empty_threshold_assert_value_wrch=1022
CSET empty_threshold_negate_value=5
CSET enable_aruser=false
CSET enable_awuser=false
CSET enable_buser=false
CSET enable_common_overflow=false
CSET enable_common_underflow=false
CSET enable_data_counts_axis=false
CSET enable_data_counts_rach=false
CSET enable_data_counts_rdch=false
CSET enable_data_counts_wach=false
CSET enable_data_counts_wdch=false
CSET enable_data_counts_wrch=false
CSET enable_ecc=false
CSET enable_ecc_axis=false
CSET enable_ecc_rach=false
CSET enable_ecc_rdch=false
CSET enable_ecc_wach=false
CSET enable_ecc_wdch=false
CSET enable_ecc_wrch=false
CSET enable_read_channel=false
CSET enable_read_pointer_increment_by2=false
CSET enable_reset_synchronization=true
CSET enable_ruser=false
CSET enable_tdata=false
CSET enable_tdest=false
CSET enable_tid=false
CSET enable_tkeep=false
CSET enable_tlast=false
CSET enable_tready=true
CSET enable_tstrobe=false
CSET enable_tuser=false
CSET enable_write_channel=false
CSET enable_wuser=false
CSET fifo_application_type_axis=Data_FIFO
CSET fifo_application_type_rach=Data_FIFO
CSET fifo_application_type_rdch=Data_FIFO
CSET fifo_application_type_wach=Data_FIFO
CSET fifo_application_type_wdch=Data_FIFO
CSET fifo_application_type_wrch=Data_FIFO
CSET fifo_implementation=Independent_Clocks_Block_RAM
CSET fifo_implementation_axis=Common_Clock_Block_RAM
CSET fifo_implementation_rach=Common_Clock_Distributed_RAM
CSET fifo_implementation_rdch=Common_Clock_Block_RAM
CSET fifo_implementation_wach=Common_Clock_Distributed_RAM
CSET fifo_implementation_wdch=Common_Clock_Block_RAM
CSET fifo_implementation_wrch=Common_Clock_Distributed_RAM
CSET full_flags_reset_value=1
CSET full_threshold_assert_value=511
CSET full_threshold_assert_value_axis=1023
CSET full_threshold_assert_value_rach=1023
CSET full_threshold_assert_value_rdch=1023
CSET full_threshold_assert_value_wach=1023
CSET full_threshold_assert_value_wdch=1023
CSET full_threshold_assert_value_wrch=1023
CSET full_threshold_negate_value=510
CSET id_width=4
CSET inject_dbit_error=false
CSET inject_dbit_error_axis=false
CSET inject_dbit_error_rach=false
CSET inject_dbit_error_rdch=false
CSET inject_dbit_error_wach=false
CSET inject_dbit_error_wdch=false
CSET inject_dbit_error_wrch=false
CSET inject_sbit_error=false
CSET inject_sbit_error_axis=false
CSET inject_sbit_error_rach=false
CSET inject_sbit_error_rdch=false
CSET inject_sbit_error_wach=false
CSET inject_sbit_error_wdch=false
CSET inject_sbit_error_wrch=false
CSET input_data_width=64
CSET input_depth=512
CSET input_depth_axis=1024
CSET input_depth_rach=16
CSET input_depth_rdch=1024
CSET input_depth_wach=16
CSET input_depth_wdch=1024
CSET input_depth_wrch=16
CSET interface_type=Native
CSET output_data_width=64
CSET output_depth=512
CSET overflow_flag=true
CSET overflow_flag_axi=false
CSET overflow_sense=Active_High
CSET overflow_sense_axi=Active_High
CSET performance_options=First_Word_Fall_Through
CSET programmable_empty_type=No_Programmable_Empty_Threshold
CSET programmable_empty_type_axis=No_Programmable_Empty_Threshold
CSET programmable_empty_type_rach=No_Programmable_Empty_Threshold
CSET programmable_empty_type_rdch=No_Programmable_Empty_Threshold
CSET programmable_empty_type_wach=No_Programmable_Empty_Threshold
CSET programmable_empty_type_wdch=No_Programmable_Empty_Threshold
CSET programmable_empty_type_wrch=No_Programmable_Empty_Threshold
CSET programmable_full_type=No_Programmable_Full_Threshold
CSET programmable_full_type_axis=No_Programmable_Full_Threshold
CSET programmable_full_type_rach=No_Programmable_Full_Threshold
CSET programmable_full_type_rdch=No_Programmable_Full_Threshold
CSET programmable_full_type_wach=No_Programmable_Full_Threshold
CSET programmable_full_type_wdch=No_Programmable_Full_Threshold
CSET programmable_full_type_wrch=No_Programmable_Full_Threshold
CSET rach_type=FIFO
CSET rdch_type=FIFO
CSET read_clock_frequency=1
CSET read_data_count=true
CSET read_data_count_width=10
CSET register_slice_mode_axis=Fully_Registered
CSET register_slice_mode_rach=Fully_Registered
CSET register_slice_mode_rdch=Fully_Registered
CSET register_slice_mode_wach=Fully_Registered
CSET register_slice_mode_wdch=Fully_Registered
CSET register_slice_mode_wrch=Fully_Registered
CSET reset_pin=true
CSET reset_type=Asynchronous_Reset
CSET ruser_width=1
CSET synchronization_stages=2
CSET synchronization_stages_axi=2
CSET tdata_width=64
CSET tdest_width=4
CSET tid_width=8
CSET tkeep_width=4
CSET tstrb_width=4
CSET tuser_width=4
CSET underflow_flag=true
CSET underflow_flag_axi=false
CSET underflow_sense=Active_High
CSET underflow_sense_axi=Active_High
CSET use_clock_enable=false
CSET use_dout_reset=true
CSET use_embedded_registers=true
CSET use_extra_logic=true
CSET valid_flag=false
CSET valid_sense=Active_High
CSET wach_type=FIFO
CSET wdch_type=FIFO
CSET wrch_type=FIFO
CSET write_acknowledge_flag=false
CSET write_acknowledge_sense=Active_High
CSET write_clock_frequency=1
CSET write_data_count=false
CSET write_data_count_width=10
CSET wuser_width=1
# END Parameters
# BEGIN Extra information
MISC pkg_timestamp=2012-11-19T12:39:56Z
# END Extra information
GENERATE
# CRC: 73737d3d

  1. 2013年01月03日 05:23 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

筑波山に登って来ました

昨日、筑波山に登って来ました。麓の筑波総合体育館に車を置いて、つくば道を通って筑波山神社に行って、そこから登山道を登って、御幸ヶ原まで上りました。帰りはケーブルカーで筑波山神社まで降りて、そこからまた、つくば道を通って帰りました。行ったのは、私と奥さんと娘2人です。受験生の息子は家で勉強していました。

最初に筑波総合体育館に車を置いて、平沢官衙遺跡に方に歩いていきます。tukubasan_tozan_1_130103.jpg

更に、つくば道を歩いて行くと神郡の部落の中を歩いていきます。おいしいドーナツを売っているお菓子屋さんがあるんですが、正月で休みでした。残念。。。
tukubasan_tozan_2_130103.jpg

この辺まで来ると筑波山がとっても大きく見えるようになってきます。歩いていて熱くなってくるので、上着を脱いでいます。
tukubasan_tozan_3_130103.jpg

段々と上りになってきます。だいぶ歩くのが辛くなってきます。服を脱いで上りました。途中で鳥居をくぐります。
tukubasan_tozan_4_130103.jpg

鳥居の所のちょっとした公園で、コンビニで買ってきたお昼を食べました。おにぎりやパンです。

こんな風に民家の間を縫って登ってきます。車も来ますが、エンジンが焼ける匂いがします。
tukubasan_tozan_5_130103.jpg

後ろを振り返ると、こんな感じです。
tukubasan_tozan_6_130103.jpg

やっと筑波山神社に到着です。
tukubasan_tozan_7_130103.jpg

筑波山神社の奥の方の階段を登って行くとケーブルカーの発着所(宮脇駅)と登山口があります。ここから登山道に入ります。登山道は、木の間を歩いて上ります。木の階段もありますが、岩もあるので、スニーカーや登山靴が良いと思います。
tukubasan_tozan_8_130103.jpg

tukubasan_tozan_9_130103.jpg

手をついて登る必要が有るところもあります。岩ですね。かなりきつかったです。娘2人は若いので?、元気でした。奥さんもハーフマラソン出てるくらいなので、持久力がありましたね。私がへばってましたが、なんとか御幸ヶ原までたどり着きました。杖があったほうが楽でしたね。特に下りはスキーのストックのような杖を持っている人が多かったです。
tukubasan_tozan_10_130103.jpg

ここからはケーブルカーで宮脇駅まで降りてきました。その後、つくば道をもどりました。筑波山がとっても綺麗なスポットで写真を取りました。
tukubasan_tozan_11_130103.jpg

最後の頃に、私の去年の十月に痛めた左足が痛くなったので、奥さんが走って行って車取ってきてくれました。その後、マクドナルドでカフェラテを飲んで帰りました。とても疲れましたが、なかなか良かったです。
  1. 2013年01月03日 04:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ZedBoard用CMOSカメラ回路の作製1(単体シミュレーション)

MT9D111の勉強を下のように行った。
MT9D111のお勉強1MT9D111のお勉強2MT9D111のお勉強3MT9D111のお勉強4MT9D111のお勉強5MT9D111のお勉強6

ZedBoardのPMODに刺さるカメラボードが、ZedBoard用CMOSカメラボードの作製5(カメラボード完成)で完成した。
これで、CMOSカメラの画像をVGA端子やHDMI端子から出力する回路を作る準備が整ったので、この年末年始で、ZedBoard用CMOSカメラ回路を作っていた。大体できたので、AXI4 Slave BFMを使って単体テストをした。
CMOSカメラ回路の仕様だが、画像サイズは2Mピクセルの1スキップの 800x600 とする。更に36MHzのピクセルクロックを与えて、PLLバイパスでそのままPCLKに出力することにした。画像フォーマットはRGB565とし、これは、2バイトで1ピクセルなので、800ピクセルのデータを出力するために、1,600クロック掛かることになる。よって約 30fps で画像を出力する予定だ。AXI4バスのクロックは100MHzとする。

上の仕様で、トップモジュール mt9d111_inf_axi_master.vhd を作成し、その下にMT9D111の信号とのインターフェースを行う mt9d111_cam_cont.v がある。mt9d111_cam_cont.v には、非同期FIFOがインスタンスされている。非同期FIFOの入力は32ビット幅、出力は64ビット幅である。入力クロックがPCLKの36MHz、出力クロックがAXI4 の ACLK で100MHz である。

下に、AXI4バスのシミュレーション結果を示す。
ZedBoard_Cam_1_130102.png
あえて説明はしないが、36MHzクロックの2つで1個のピクセルが出力される。32ビットが1ピクセルに相当する。MSBから8ビットのダミー0、Redが8ビット、Greenが8ビット、Blueが8ビットで合計32ビットとなる。それが2ピクセル分集まって、64ビットのデータとして非同期FIFOから出力されている。
ここで、AXI4バスのトランザクションから次のトランザクションまでの間隔は110 nsec だった。これは、36MHzの周期、27.8 nsec x 2(クロックで1ピクセル) x 2ピクセル分のデータを非同期FIFOから出力 = 111.2 nsec と大体合っている。

下に、mt9d111_cam_cont.v のシミュレーション波形を示す。
ZedBoard_Cam_2_130102.png
黄色いカーソルは、AXI4バスのシミュレーション結果の図と同様の位置に置いてある。cam_dataからのAXI4のデータに変換する様子が見えると思う。
  1. 2013年01月02日 19:58 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

2012年のFPGAの部屋のアクセス数

あけましておめでとうございます。

2012年のFPGAの部屋のアクセス数は543,428アクセスでした。
皆さん見て頂いてありがとうございました。今年もよろしくお願いします。
fpgas_room_access_130101.png

今は、MT9D111(CMOSカメラモジュール)のシミュレーションモデルを作っています。これが出来たら、自作のAXI4 Slave BFMを使ってシミュレーションを行います。今年もZynqにフォーカスして行こうと思っています。それから、そろそろVivado も試してみたいです。Zynqがサポートされたら?と考えています。今のままではVivado で使えるボードが無いので、インプリメントまではやれても実機テストができません。
  1. 2013年01月01日 03:48 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0