ZYBOでOV7670カメラモジュールの画像を表示する
前回のポストでZYBOのZYNQ PS (ARMコア)を使ってOV7670カメラモジュールをI2C(SCCB)経由初期化できるようになりましたが、ようやく次のステップとしていた画像の取り込みとVGAモニターへの出力ができました。使ったカメラモジュールはaitendoさんから購入したOV7670です。
色々紆余曲折(最初の構想からの見直し)やFPGAを使った同期回路設計のスキル不足でかなり苦戦して、たかだか100行ちょっとのRTLコードを動かすのに1ヶ月近くかかってしまいました。まだまだ未熟ですが、(自己流ですが)少しノウハウがたまったので、顛末を書いてみます。
使用した開発環境は、最初はVivado 2016.2でしたが、最終的にVivado 2016.3にアップグレードしています。
当初の構想
最初は、既存のXILINX Video-OutとVTC IPを使って、画像の取り込み部分だけを作るのが近道かと思い(自分で記述する部分を最小にした方が確実に動かせると思っていた)この方向で情報収集を行いました。
Video Out IPに画像を流し込むためには、カメラ入力側にAXI4-Stream Masterインタフェースを作りこむ必要があります。今にして思うと、いきなりAIX4を作るというのも無謀な試みでした。You TubeにAXI-Stram Masterを作るチュートリアルビデオがあり、(英語ですが平易な語りなのでなんとか理解できますが、量は結構多い)これを参考にカメラデータの取り込みとAXI4-Stram出力のIPを作ってみました。単体のテストベンチではAIX4の制御信号を出力できているように見えていたのですが、Video OutやVTCと結合していきなり実機で動かそうとしても全く画像が表示されず。
当初、OV7670の解像度がVGA(640 x 480)なのでVGAモニターにスルーでデーターを流せると思っていたのですが、オシロで出力波形を観測すると垂直同期(リフレッシュ周期)が24Hz〜30Hz, 水平同期が12.5KHz位で、VGAのリフレッシュレート60Hz, 水平同期31KHzに対して速度が大きく異なるため、そもそもスルーで出力できないということが判明(考えてみれば、3000円以下のカメラモジュールで60Hzのリフレッシュレートを期待するのが間違っている)。Video OutやVTC IPもブラックボックスで中身が分からないため、問題の切り分けができず、表示部分も自分で作った方がよいと方針転換。
AXI4-Stramの実装は結局使い物にはなりませんでしたが、チュートリアルで学んだことはVivadoを使った開発フローを含めて結構有意義でした。
VGA画面表示も自分で作る
カメラモジュールとVGAの動作速度が異なるため、速度差を吸収するために、VRAM(Dual Port RAM)を間に入れて、カメラ入力に同期して画像データをVRAMに書き込み、VGAのPixelレートで画像データーを読み出せるようにする必要があります。
VGAのフル解像度を使うためには、必要なメモリー容量的にZYBOのDDR3-SDRAMを使う必要がありますが、いきなりDDR3-SDRAMを使うのはハードルが高いので、先ずはFPGA内に作れるBRAM(Block RAM)を使うことにしました。ZYBOに搭載されているZYNQ XC7Z010-1CLG400CのBRAM容量の制約から、VGAのフル解像度を使うのは諦めて、QVGA(320 x 240)で画像を取り込んで、VGA画面(640 x 480)の中央に320 x 240の画像を表示できるようにすることを目標に再設定。
このblogにあるVHDLの実装を参考に(というかほとんどパクっていますが…)Verilogに焼き直して、画像取り込みとVGA出力のIPを作成。参考にしたBlogはRGB444(12bitカラー)の画像データーをBRAMに取り込む際に、下位1bitを抜いた形でメモリーに格納していますが(BRAMの容量制約のために、19bit中の上位18bitをアドレスに使っている)、このようなデーターの間引きを行うとどういう形で画像データーが表示できるのかイメージができなかったのと、全部パクリでなく、多少オリジナルにしたかったため、RGB 565(16 bitカラー)のQVGAデーターを扱えるように改造しました。
再度カメラ画像取り込みとVGA表示のIPを作って単体でテストベンチを動かすと一応動いているように見えるので、BRAMやカメラモジュールと結合して実機で動かすとやはり画像が出力されず(画面が真っ暗)。オシロでVGA出力の信号を観測すると、VSYNCとHSYNCは正常に出力されているので、部分的には動作しているがどこが悪のか切り分けができず(後で、BRAMの読み出し側クロックを配線していなかったという、初歩的なチョンボだったことが分かるのですが..)。
モジュール単位のテストベンチだけでなく、全体を一気通貫で確認できるシミュレーション環境が必要と思い、以下のようにCPUブロックを除いた、カメラ画像取り込み→ BRAM → VGA出力のIPをつないだBlock Designを作ってシミュレーション環境にしました。
Test Benchを作る際は、Create HDL Wrapperが生成するBlock Designのインスタンスを雛形にして、試験信号生成の部分を追加記述しています。まず、以下の手順でWrapperファイルを生成。
生成されたWrapperファイルをベースに以下のテストベンチを記述
//Copyright 1986-2016 Xilinx, Inc. All Rights Reserved. //-------------------------------------------------------------------------------- //Tool Version: Vivado v.2016.3 (win64) Build 1682563 Mon Oct 10 19:07:27 MDT 2016 //Date : Tue Oct 18 21:28:14 2016 //Host : iMac2-Win running 64-bit major release (build 9200) //Command : generate_target ov7670_tb_wrapper.bd //Design : ov7670_tb_wrapper //Purpose : IP block netlist //-------------------------------------------------------------------------------- `timescale 1 ns / 1 ps module ov7670_tb_wrapper(); reg clka; reg clk25; reg href; reg vsync; reg pclk; reg resetN; wire [4:0]vo_b_data; wire [5:0]vo_g_data; wire [4:0]vo_r_data; wire vo_hsync; wire vo_vsync; reg [17:0] count; reg [7:0] test_data; reg [7:0] test_vector[307200:0]; // Instantiate device to be tested ov7670_tb ov7670_tb_i( // Instantiate ov7670_camera .pclk(pclk), .href(href), .data(test_data), // Instantiate VGA .clk25(clk25), .resetN(resetN), .vo_b_data(vo_b_data), .vo_g_data(vo_g_data), .vo_hsync(vo_hsync), .vo_r_data(vo_r_data), .vo_vsync(vo_vsync), .vsync(vsync) ); // Initialize test initial begin resetN <= 0; count <= 17'd0; vsync <= 0; href <= 0; #100; resetN <= 1; end // Generae vsync and href // 1t_LINE = (320 + 144) x pclk(84ns) initial begin $readmemh("testdata.txt", test_vector); #400; vsync <= 1; #400; vsync <= 0; #960; repeat (240) begin @(negedge pclk); href <= 1; #26880; // 320 pclk per line href <= 0; #1096; // 144 pclk end #2000; $display("Vsync"); #1000; vsync <= 1; #400; vsync <= 0; #960; repeat (240) begin @(negedge pclk); href <= 1; #26880; // 320 pclk per line href <= 0; #1096; // 144 pclk end #400; $finish; end // Generate clcok 12MHz camera pclk in => 84ns always begin pclk <= 1; if (href) begin test_data <= test_vector[count]; count <= count + 1; end #42; pclk <= 0; #42; end always begin clk25 <= 1; #20; clk25 <= 0; #20; // 25MHz VGA pixel clock end endmodule
試験用のダミーデータを読み込んで、2画面分の出力を行なっています。シミュレーション波形を見ると、hrefが有効になった後、2バイトのデーターを取り込んで、最初のweでBRAMのアドレス0x00000にデーターが書き込めています。タイミング的には動いている模様。
BRAMの設定は以下のように、Stand Alone/ Simple Dual Port RAMにしています。
BRAMのOperating ModeはWrite Firstを選択。BRAMへの書き込みと読み出しクロックは非同期ですが、書き込みと読み出しが競合する可能性がある場合は、Write Fisrtを推奨するとマニュアルに書いてあったのでそうしています。確かにテストベンチのシミュレーションでもcollisonの警告が出ていたりしますが、書き込みと読み出しの競合は避けられないので仕方ありません。
実機で動作させる
以下のようにPSコアとClock生成を組み込んだBlock Designを作成して実機で動作確認。OV7670の初期化はARMコアのソフト処理で行なっています。
またもや、画面が真っ黒、VSYNCとHSYNCは出ている、、
しばらく悩みましたが、VGA出力側のクロックをBRAMに配線し忘れていたという、超初歩的なミスが発覚。
配線を修正して動かしてみたら、やっと画像が表示されたが、こんな感じでえらく不鮮明。カメラの設定はちゃんとRGBにしているし(YUVとかになっているわけではない)。しばらく、カメラの設定が間違っていないかデーターシートとにらめっこをしながら確認しても、特におかしな箇所は見つからず。
しばらく悩んだのですが、カメラモジュールを壊したのではないかと結論づけて、2個目を購入。2個目が届いて入れ替えたら、やっと動きました!!
今回作ったVerilogコード
<カメラ画像取り込み>
/* This is a bit tricky href starts a pixel transfer that takes 3 cycles for first pixel then 2 cycles after 2nd pixcel Input | state after clock tick href | wr_hold data_in data_out we address address_next cycle -1 x | xx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx x xxxx xxx cycle 0 1 | 00 xxxxxxxxRRRRRGGG xxxxxxxxxxxxxxxx x xxxx addr cycle 1 1 | 01 RRRRRGGGGGBBBBB xxxxxxxxRRRRRGGG x addr addr cycle 2 1 | 10 GGGBBBBBxxxxxxxx RRRRRGGGGGGBBBBB 1 addr addr+1 */ module ov7670_camera( input wire pclk, input wire vsync, input wire href, input wire [7:0] data, output wire [16:0] bram_addr, output reg [15:0] data_out, output reg we ); reg [16:0] address; // address with one clcok cyle delayed reg [16:0] address_next; reg [15:0] data_in; reg [1:0] wr_hold; assign bram_addr = address; always @(posedge pclk) begin if (vsync) begin address <= 17'd0; address_next <= 17'd0; wr_hold <= 2'd0; end else begin data_out <= data_in; address <= address_next; we <= wr_hold[1]; wr_hold <= {wr_hold[0], (href & ~wr_hold[0])}; data_in <= {data_in[7:0], data}; if (wr_hold[1] == 1) begin address_next <= address_next + 1; end end end endmodule
<VGA画面表示>
module qvga_to_vga( input wire clk25, input wire resetN, output reg [4:0] vo_r_data, output reg [5:0] vo_g_data, output reg [4:0] vo_b_data, output wire vo_hsync, output wire vo_vsync, output reg [16:0] frame_addr, input wire [15:0] frame_pixel ); parameter hRez = 640, hStartSync = 640+16, hEndSync = 640+16+96, hMaxCount = 800; parameter vRez = 480, vStartSync = 480+10, vEndSync = 480+10+2, vMaxCount = 525; parameter hDispStart = 160, hDispEnd = 160+320; parameter vDispStart = 120, vDispEnd = 120+240; reg [9:0] hCounter; reg [9:0] vCounter; reg blank; assign vo_hsync = ((hCounter > hStartSync) && (hCounter <= hEndSync))? 0: 1; assign vo_vsync = ((vCounter >= vStartSync) && (vCounter < vEndSync))? 0: 1; always @(posedge clk25) begin if (resetN == 0) begin hCounter <= 10'd0; vCounter <= 10'd0; frame_addr <= 17'd0; blank <= 1; end else if (hCounter == (hMaxCount - 1) ) begin hCounter <= 10'd0; if (vCounter == (vMaxCount - 1)) begin vCounter <= 10'd0; end else begin vCounter <= vCounter + 1; end end else begin hCounter = hCounter + 1; end if (vCounter >= vDispEnd) begin frame_addr <= 0; end else if ( ((vCounter >= vDispStart) && (vCounter < vDispEnd)) && ((hCounter >= hDispStart) && (hCounter < hDispEnd)) ) begin blank <= 0; end else begin blank <= 1; end if (blank == 0) begin vo_r_data <= frame_pixel[15:11]; vo_g_data <= frame_pixel[10:5]; vo_b_data <= frame_pixel[4:0]; frame_addr <= frame_addr + 1; end else begin vo_r_data <= 5'd0; vo_g_data <= 6'd0; vo_b_data <= 5'd0; end end endmodule
2016/12/11追記:ピン配置の制約ファイルを追記します。
set_property PACKAGE_PIN V20 [get_ports iic_0_scl_io] set_property PACKAGE_PIN W19 [get_ports iic_0_sda_io] set_property PACKAGE_PIN W18 [get_ports xclk] set_property PACKAGE_PIN T20 [get_ports href] set_property PACKAGE_PIN U20 [get_ports pclk] set_property PACKAGE_PIN Y19 [get_ports vsync] set_property PACKAGE_PIN M14 [get_ports led0] set_property PACKAGE_PIN V15 [get_ports {data[0]}] set_property PACKAGE_PIN W15 [get_ports {data[2]}] set_property PACKAGE_PIN T11 [get_ports {data[4]}] set_property PACKAGE_PIN T10 [get_ports {data[6]}] set_property PACKAGE_PIN W14 [get_ports {data[1]}] set_property PACKAGE_PIN Y14 [get_ports {data[3]}] set_property PACKAGE_PIN T12 [get_ports {data[5]}] set_property PACKAGE_PIN U12 [get_ports {data[7]}] set_property PACKAGE_PIN M19 [get_ports {vo_r_data[0]}] set_property PACKAGE_PIN L20 [get_ports {vo_r_data[1]}] set_property PACKAGE_PIN J20 [get_ports {vo_r_data[2]}] set_property PACKAGE_PIN G20 [get_ports {vo_r_data[3]}] set_property PACKAGE_PIN F19 [get_ports {vo_r_data[4]}] set_property PACKAGE_PIN H18 [get_ports {vo_g_data[0]}] set_property PACKAGE_PIN N20 [get_ports {vo_g_data[1]}] set_property PACKAGE_PIN L19 [get_ports {vo_g_data[2]}] set_property PACKAGE_PIN J19 [get_ports {vo_g_data[3]}] set_property PACKAGE_PIN H20 [get_ports {vo_g_data[4]}] set_property PACKAGE_PIN F20 [get_ports {vo_g_data[5]}] set_property PACKAGE_PIN P20 [get_ports {vo_b_data[0]}] set_property PACKAGE_PIN M20 [get_ports {vo_b_data[1]}] set_property PACKAGE_PIN K19 [get_ports {vo_b_data[2]}] set_property PACKAGE_PIN J18 [get_ports {vo_b_data[3]}] set_property PACKAGE_PIN G19 [get_ports {vo_b_data[4]}] set_property PACKAGE_PIN P19 [get_ports vo_hsync] set_property PACKAGE_PIN R19 [get_ports vo_vsync] set_property IOSTANDARD LVCMOS33 [get_ports iic_0_scl_io] set_property IOSTANDARD LVCMOS33 [get_ports iic_0_sda_io] set_property IOSTANDARD LVCMOS33 [get_ports xclk] set_property IOSTANDARD LVCMOS33 [get_ports led0] set_property IOSTANDARD LVCMOS33 [get_ports vsync] set_property IOSTANDARD LVCMOS33 [get_ports href] set_property IOSTANDARD LVCMOS33 [get_ports pclk] set_property IOSTANDARD LVCMOS33 [get_ports {data[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {data[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_b_data[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_b_data[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_b_data[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_b_data[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_b_data[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_g_data[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_g_data[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_g_data[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_g_data[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_g_data[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_g_data[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_r_data[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_r_data[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_r_data[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_r_data[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {vo_r_data[0]}] set_property IOSTANDARD LVCMOS33 [get_ports vo_hsync] set_property IOSTANDARD LVCMOS33 [get_ports vo_vsync] set_property SLEW FAST [get_ports {vo_b_data[4]}] set_property SLEW FAST [get_ports {vo_b_data[3]}] set_property SLEW FAST [get_ports {vo_b_data[2]}] set_property SLEW FAST [get_ports {vo_b_data[1]}] set_property SLEW FAST [get_ports {vo_b_data[0]}] set_property SLEW FAST [get_ports {vo_g_data[5]}] set_property SLEW FAST [get_ports {vo_g_data[4]}] set_property SLEW FAST [get_ports {vo_g_data[3]}] set_property SLEW FAST [get_ports {vo_g_data[2]}] set_property SLEW FAST [get_ports {vo_g_data[1]}] set_property SLEW FAST [get_ports {vo_g_data[0]}] set_property SLEW FAST [get_ports {vo_r_data[4]}] set_property SLEW FAST [get_ports {vo_r_data[3]}] set_property SLEW FAST [get_ports {vo_r_data[2]}] set_property SLEW FAST [get_ports {vo_r_data[1]}] set_property SLEW FAST [get_ports {vo_r_data[0]}] set_property SLEW FAST [get_ports vo_hsync] set_property SLEW FAST [get_ports vo_vsync] set_property SLEW FAST [get_ports xclk] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF_BUFG]
ZYNQ PSを使ったカメラモジュールの初期化部分はコードが長いのでGitHubに置いておきました(初期化パラメーターはmbedの作例を流用)。
その他
実は、画像は表示できているのですが、画面が鏡に映った形で左右逆になるのと画面が倒立してしいます(aitendoのシルク印刷部分を上にすると画像が倒立する)。そのため、MVEPレジスタのMirror ImageをOn及びVFlipをOnにして反転を回避しています。この点はちょっと謎です。
カメラから読み出したデーターは、カメラのPCLK(Pixel Clock)をBRAMのクロックとして使っています。BRAMのWE信号もPCLKに同期して生成しているため、BRAMクロックの立ち上がりとWEの立ち上がりが同じタイミングになり、WEのSetup Timeマージンが取れていなのではないかと思い、BRAMのクロックを100MHzのFPGAクロックにしてみました(BRAMクロックの立ち上がりエッジでWEを確実に補足するため)。そうすると、逆に若干画像にノイズが乗るような現象が見えたので、BRAMの書き込み側はPCLKに戻しています。
Next Step
ZYBO + OV7670でI2Cを動かすのにもえらく時間がかかりましたが、最初AIX4で遠回りをしたことや、カメラモジュールの不調もありましたが、画像が出せるまで1ヶ月近くかかってしまいました。まだまだ、未熟で、先人の方には数週遅れで同じことをやっていますが、次はVGAのフル解像度データーをDDR3-SDRAMをVRAMとして取り込めるようにしたいと思っています。
その次は、HLSを使って画像処理などのフィルターを挿入できるようにしてみたいと思っています。
参考資料
« オシロ(RIGOL DS1054Z)を購入しました | トップページ | Vivado Integrated Logic Analyzer(ILA)の使い方 »
「FPGA」カテゴリの記事
- PYNQ-Z1のOverlay読み込みとPythonからのFPGA PLの制御(2)(2017.02.04)
- PYNQ-Z1のOverlay読み込みとPythonからのFPGA PLの制御(2017.01.28)
- Vivado Constraints Wizardによるクロック・入出力制約の作成(2016.12.11)
- ZYBOでOV7670カメラモジュールのVGA画像を表示する(2016.12.04)
- Vivado Integrated Logic Analyzer(ILA)の使い方(2016.11.12)
「ZYBO」カテゴリの記事
- Vivado Constraints Wizardによるクロック・入出力制約の作成(2016.12.11)
- ZYBOでOV7670カメラモジュールのVGA画像を表示する(2016.12.04)
- Vivado Integrated Logic Analyzer(ILA)の使い方(2016.11.12)
- ZYBOでOV7670カメラモジュールの画像を表示する(2016.10.22)
- ZYBOのPSでI2Cを動かしてみた(2016.09.24)
コメント
この記事へのコメントは終了しました。
« オシロ(RIGOL DS1054Z)を購入しました | トップページ | Vivado Integrated Logic Analyzer(ILA)の使い方 »
失礼します。
広島の大学院の学生です。
ひとつ質問があるのですが、このカメラから取ってきた画像をBRAMに保存し、表示するというのはPSがなくても動きますか?
投稿: | 2016年12月10日 (土) 19時59分
失礼します。
広島の大学院の学生です。
ひとつ質問があるのですが、このカメラからの画像をvga画像として表示する回路はPS部がなくても動きますか?(このページの一番上のブロック図のままでもうごくかどうかをお聞きしたいです)
今、PSなしでzyboに載せているのですがうまく表示されません。
いきなりすいません。
返信していただけたら幸いです。
投稿: 広島の学生 | 2016年12月10日 (土) 20時04分
todotaniです。
コメントありがとうございます。
OV7670カメラはSCCB(I2C相当)のプロトコルを使って初期化を行う必要があります。私の作例ではSCCBを使ったカメラモジュールの初期化はPS(ARMコア)のソフト処理で行なっているため、掲載したVerilogコードだけでは動きません。GitHubに上げているPSのソフトが必要です。
SCCBの処理をHDLで書くこともできますが、私はSCCBのステートマシンをVerilogで書く根性がなかったのでお手軽なソフト処理で済ましています。参照した"Lauri's blog | Piping OV7670 video to VGA output on ZYBO"ではVHDLですが、SCCBによるカメラの初期化もHDLで行なっているので、この辺りのコードを参考にされればPSなしでもカメラを動かせると思います。
Zynqの通常の使い方としては、ARM が最初に起動し、ARM から FPGA を Configuration します。そのため私はいつもPSのインスタンスも作成し、bitstremをSDKにexportしてARMからPLを立ち上げるやり方しか使ったことがないです。VivadoのFlow Navigatorからbitstreamを直接書き込んで、PSなしでPLのみを動かす方法もあるようですが、私はこの方法は試したことがありません。
PSなしで動かす方法についてはあまりお役に立てずすいません。
投稿: todotani | 2016年12月10日 (土) 21時03分
todotaniさん
広島の学生です。
早々に返信ありがとうございます。
初期化をがんばってやってみようと思います。
ひとつ気になったのですが、PSありのブロック図について、ov7670の入力クロックであるxclkのピンが見当たらないのですが、これがなくても動くのでしょうか。
投稿: 広島の学生 | 2016年12月11日 (日) 16時30分
こんにちは。
xclkはClock Wizard(clk_wiz_0)のclk_out_1で生成しています。xclkを供給しないとOV7670は起動してくれません。PSのソフトでOV7670を初期化する際のPSの設定は、別のポスト、「ZYBOのPSでI2Cを動かしてみた」(https://todotani.cocolog-nifty.com/blog/2016/09/zybopsi2c-615d.html)を参考にして下さい(OV7670でなくI2Cの温度センサーをつないでいますが、基本的な設定は同じです)。
あと、PSを使ったOV7670の初期化コードはGitHub(https://github.com/todotani/OV7670_ZYNQ)にあります。記事が細切れで分かりづらいですが、ご参考になれば。
このブログポストの末尾に、ピン割り当ての制約ファイルを追記しておきました。参考にして下さい。
投稿: todotani | 2016年12月11日 (日) 17時27分
todotaniさん
広島の学生です。
早々に返信ありがとうございます。
本当にご丁寧に答えてくださりありがとうございます。
とても助かります。
xclkについては、見落としていました。申し訳ありません。
Clock Wizard(clk_wiz_0)のclk_out_1とclk_out_2は二つとも25mhzですか?
投稿: 広島の学生 | 2016年12月11日 (日) 17時48分
OV7670カメラに供給しているxclk/clk_out_1は24MHzで、VGA用のclk_out_2は25MHzに設定しています。頑張って動かして下さい。
投稿: todotani | 2016年12月11日 (日) 18時52分
todotaniさん
広島の学生です。
返信ありがとうございます。
度重なる質問で申し訳ありません。
PSの載ったブロック図にはiic_0_scl_io、iic_0_sda_ioの信号線がなく、制約ファイルのなかにあるのですが、これはどのブロックからの出力でしょうか。
よろしくお願い致します。
投稿: 広島の学生 | 2016年12月11日 (日) 20時41分
PSでI2C_0ポートを有効にするとブロックデザインにIIC_0というポートができるので、それをMake Externalします。Implementation後にI/Oポートタブを開くと、iic_0_scl_io、iic_0_sda_ioの信号線が追加されています。「ZYBOのPSでI2Cを動かしてみた」に書いた通りです。
投稿: todotani | 2016年12月11日 (日) 21時06分
todotaniさん
広島の学生です。
返信ありがとうございます。
おかげさまでiic_0_scl_io、iic_0_sda_ioの信号線の問題は解決しました。
しかし、SDKを開いてHello worldのプログラムを選択するときに
this application requires a uart ip in the hardware
とエラーが出てしまい選択することができません。
PSの設定としてMIO configuration→uart1にチェックを付けMIO48...49としたのですが、未だ選択できずにいます。
この方法ではだめなのでしょうか。
よろしくお願いします。
投稿: 広島の学生 | 2016年12月11日 (日) 22時17分
まず、ZYBOを使っていらっしゃることを前提にしていますが、その場合、以下のURLにある手順でVivadoにZYBOのBoard Fileをインストールしていますか。
https://reference.digilentinc.com/reference/software/vivado/board-files?redirect=1
このURLの手順に従って、Boad FileをインストールしたVivadoで新規プロジェクトを作る際にBorad種別としてZYBOを選択すると、自動的にUART1が有効になって、電源スイッチ横のUSBコネクタにUSB-シリアル変換チップ(FT2232)を経由して接続されます(MIO48〜49に接続されます)。Windowsをお使いの場合は、このUSBコネクタにZYBOを接続するとCOMポートとして認識されます(場合によってはFT2232のデバイスドライバーをインストールする必要があるかもしれません)。
COMポートが認識されたら、SDKを起動して、Run→ Debug Configuration → STDIO Connectionタブを開き、Connect STDIOをチェックして、 ZYBOが接続されているCOMポートを選択、BAUD Rateを115200としてデバックを起動すると、FPGAのconfig情報(bitstream)とPSのプログラム(elfファイル)がZYNQに転送され、プログラムが起動して、SDKのデバックペインにprint文で出力した文字列が表示されます。
デバックの使い方の詳細が分からない場合は、Eclipse(SDKのベースになっているIDE)を使ったC/C++プログラムのデバック設定・デバッグ方法を調べて下さい。
基本的なZYBOを使った開発の流れは、以下のURLを参照して下さい。
"Getting Started with Zynq"
https://reference.digilentinc.com/learn/programmable-logic/tutorials/zybo-getting-started-with-zynq/start
投稿: todotani | 2016年12月11日 (日) 23時02分
todotaniさん
広島の学生です。
返信ありがとうございます。
おかげさまで,
this application requires a uart ip in the hardware
のエラーは, boad filesをインストールすることによって解決することができました。
ありがとうございます。
debugの際, portを設定する必要があると思うのですがこのときはzyboと繋がっているportを選べばよろしいのでしょうか。
teratermでそのportを設定すると port CPM11 is already in useとでてしまい, treaters上に実行したmain.cのprintf文がでてこない状況です。
この原因として, 調べたところ, program FPGA したことによってそのportがbusyになっているということが考えられるらしいです。
しかし, zyboにbitファイルを書き込まないことにはプログラムを実行できないと思うのですが, どうなんでしょうか...。
投稿: 広島の学生 | 2016年12月13日 (火) 03時50分
DebbugセッションでARMコアプログラム起動時のprintf出力を見たい場合は、SDKデバック画面下側のコンソール領域(当初、"this application requires a uart ip in the hardware"が出ていた場所)にprintfの出力が表示されるので、それを確認されてはいかがですか。
SDKを使ってプログラムを起動した場合は、SDKがCOMポートを占有してしまうため、Teratermなどでprintfの表示を行うことはできません。プログラムが完成してSDKなしでprint表示をしたい場合は、bitstreamとプログラムをブート可能な状態にパッケージ化してQSPI flashに書き込むなどして、SDKなしでFPGAを起動できるようにした状態でTeratermをつなぐ(Debugと同じCOMポートを使う)ことができますが、Debug目的のprint表示ならSDKのDebug画面への表示を使うのがよいです。
プログラムをQSPIブートできるようにする方法はご自分で調べて下さい(長いのでコメントバックで説明する気力はないです)。FSBLの作成やBoot Imageの作成など色々と手順が必要です。
投稿: todotani | 2016年12月13日 (火) 20時11分
todotaniさん
広島の学生です。
返信ありがとうございます。
printfをする理由としては、debugでプログラムが動いていることの確認がコンソールで確認ができれば十分です。しかし、現状ではコンソールに何も表示されません。
No souce available for ""と表示されており、そもそもプログラムが実行されていいないからコンソールに何も表示されないと考えています。
ちなみに、プログラムを実行/デバッグを行うとLED[0]がONになり、たしかにclock wizardの出力クロックは有効になっているのは確認できています。
ただディスプレイに何も表示されていないという状況です。
以下にスクリーンショットを載せさせていただきます。
時間があればでいいので、見ていただけると助かります。
http://or2.mobi/index.php?mode=image&file=140479.png
http://or2.mobi/index.php?mode=image&file=140477.png
投稿: 広島の学生 | 2016年12月13日 (火) 23時40分
Debugでprintfの出力が表示されない問題の対処ですが、思いつくのは、一度Debug configurationを削除して作り直す位です。
1)SDKのRun→ Debug ConfigurationsでDebug Configuration画面が表示されます。Xilinx C/C++ application (GDB)の下に"Camera Test.elf"等の名前がついたエントリがあるので、それを選択して右クリックでDeleteします。
2)一旦ClseボタンをクリックしてDebug Configuration画面を閉じます
3)再度、Run → Debug As → Launch on Hardware (GDB)でDebugを起動。 "this application requires a uart ip in the hardware"が表示されるので、一旦debugを終了
4)Run→ Debug configurationを開いて、STDIO Connectionを設定(いきなり、Debug Configurationを作ろうとするとプログラムが起動できないことがあるため、一度3)でまっさらなDebug Configurationを自動生成させて、その後でCOMポートを設定しています)
5)Debug Configuration画面のSource tabを開いて、"Project名" - Debug - Sourceが表示されていることを確認
それでもダメな場合は、申し訳ないですが、ちょっと対処を思いつきません。EclipseのDebug関連でググって調べてみて下さい。
画像が表示されない件ですが、地道にBlock Designの接続や、Pmodコネクターとカメラの配線が間違っていないかを調べるしかないですが、カメラが正しく起動していることを調べるには、オシロスコープを使ってカメラからのpclkやhrefが出力されているかを観測するのが一番早いです。大学の研究室かサークル関連でオシロスコープが使える場合は、そこに持ち込んで波形が出ているかを確認すると良いです。
VGA出力が出ているかは、ディスプレーでNo Signalになっていなければ(VGAの入力が来ていることが見えれば)VGAの信号は出ていると思われます。
投稿: todotani | 2016年12月14日 (水) 06時50分
todotaniさん
広島の学生です。
返信ありがとうございます。
お礼が遅くなってすいません。
いろいろやってみましたが画面に表示することができませんでした。
また色々調べて頑張ろうと思います。
本当に数々のアドバイスありがとうございました。
またtodotaniさんのサイトを参考にさせていただきたいと思います。
投稿: 広島の学生 | 2016年12月16日 (金) 19時02分
私もまだまだ、FPGA初心者で、このプロジェクトを動かすのに、1ヶ月以上かかりました。
めげずに、がんぱって続けて下さい。
一通りのコードや手順は書いたつもりなのですが、他の人がやった際の再現性がなかったのですね。
投稿: todotani | 2016年12月16日 (金) 20時42分