Maker Faire Tokyo 2012 にアクリルサインを出展します。
FPGA-CAFEのレーザー加工機を使ってアクリルに彫刻して、そのアクリルにFusionPCBで作った自作基板を搭載して、7色に光ります。基板には、
ストロベリー・リナックス さんのArduino互換基板、
ダ・ヴィンチ32U with Arduino Bootloader が搭載されています。
自作基板には高輝度の赤、青、緑のLEDが5個ずつ15個搭載されています。それをダ・ヴィンチでPWM制御してじわ~っと明るくし、じわ~っと暗くしています。自作基板にはCdSも搭載されていて、暗くなったら明るさを落とすこともできますが、今は使っていません。
展示は、
1F, C12 のFabLab Japanの1角 でしていますので、MFTにお越しの際はお立ち寄りください。よろしくお願いします。
電子工作的には余り面白くはないですが、レーザー加工ではいろいろ試行錯誤しています。
2012年11月30日 05:23 |
Make出展
| トラックバック:0
| コメント:0
”
ZedBoardでHDMI出力13(HDMIに出力できた) ”でHDMIでキャラクタを出力することが出来た。
だが、よく見てみると特に青のキャラクタが汚い。下にHDMIで表示したキャラクタの拡大図を図1に示す。
図1 2つのCb, Crの平均を取る方式のHDMI出力画面
青のキャラクタが潰れて、ピンクのキャラクタの後ろに青が出ているのがわかるだろうか?
次にVGA端子から出力したキャラクタ拡大図を図2に示す。
図2 VGAコネクタ出力画面
2つ並べてみると違っているのがよく分かると思う。VGAの方はすっきり青のキャラクタも見えて、HDMIは青のキャラクタがぼけている。これは、YCbCr4:2:2 で色差信号を1/2に圧縮しているためだと思う。
私の色差信号の圧縮方式は、”
ZedBoardでHDMI出力10(ADV7511のピクセル入力レジスタ設定) ”で示したように、”1つ前のCb, Crの値を残しておいて、現在の値との平均を取る”という方法だった。リファレンス・デザインを見ると下の方式で色差信号を算出していた。
1.1つ前の色差信号 Z-1 の値を0.5倍する。 2.現在の色差信号の値を Z とする。 3.1つ後の色差信号の値 Z+1 を0.5倍する。 4.1.2.3.を合計して、それに 0.5 を掛ける。 4.つまり ((Z-1)*0.5 + Z + (Z+1)*0.5) * 0.5 を行う。
私もこの方式でやってみようと思う。
下にリファレンス・デザインでやってみた結果を示す。
図3 Cb, Crの値を ((Z-1)*0.5 + Z + (Z+1)*0.5) * 0.5 で求めたHDMI出力画面
最初のHDMI出力キャラクタとよーく見比べると、図1には、青の後ろに灰色で影みたいなのが出ているが、図3にはほとんど出ていない。更に図3の黄色のほうが、図1の黄色よりも白くなっている割合が少ないと思う。この様に僅かではあるが、リファレンス・デザインのYCbCr4:2:2 の算出方法のほうが良いようだ。しかし、色差信号を圧縮してないVGA信号には比べるべくもない。コンソール出力にはVGA出力を使ったほうが良さそうだ。HDMI写真やカメラ出力専用ということになると思う。
最後に、以前の方式のYCbCr4:2:2 算出方法を使ったconv_hdmi_out.v は、
”ZedBoardでHDMI出力11(ビットマップ・ディスプレイ・コントローラ単体テスト) ”に掲載している。リファレンス・デザインの方式でYCbCr4:2:2 を算出したconv_hdmi_out.v を下に載せておく。実際のVerilog HDLコードとしては、((Z-1) + Z * 2 + (Z+1)) / 4 となっている。* 2 は1ビット左シフトで、/ 4 は2ビット右シフトだ。
// BitMap Display Controller for HDMI // HDMI Interface // RGBをYCbCrに変換して出力する // HDMI出力はRGBよりも3クロック遅延する。 // フルHDだと3クロックでは足りない。conv_rgb2ycbcrの中でもう1つFFが必要。 // // 2012/11/21 // 2012/11/30 : Cb, Cr の算出方法を変更。(cb_d1 + cb_d2*2 + cb_d3)/4 // `default_nettype none module conv_hdmi_out ( input wire clk_disp, // ディスプレイ表示用クロック input wire reset_disp, // clk_disp 用リセット input wire [7:0] red, input wire [7:0] green, input wire [7:0] blue, input wire hsyncx, input wire vsyncx, input wire display_enable, output wire hdmi_clk, output wire hdmi_vsync, output wire hdmi_hsync, output reg hdmi_data_e, output reg [15:0] hdmi_data ); wire [7:0] y; wire [7:0] cb; wire [7:0] cr; reg [7:0] y_d1, y_d2; reg [7:0] cb_d1, cb_d2, cb_d3; reg [9:0] cb422; reg [7:0] cr_d1, cr_d2, cr_d3; reg [9:0] cr422; (*S="TRUE"*) reg hsyncx_d1, hsyncx_d2, hsyncx_d3; (*S="TRUE"*) reg vsyncx_d1, vsyncx_d2, vsyncx_d3; (*S="TRUE"*) reg de_d1, de_d2, de_d3; reg second_pixel; wire [2:0] de_stat; // hdmi_clk の出力 ODDR #( .DDR_CLK_EDGE("OPPOSITE_EDGE"), .INIT(1'b0), .SRTYPE("SYNC") ) hdmi_clk_ODDR ( .R (1'b0), .S (1'b0), .CE (1'b1), .D1 (1'b0), .D2 (1'b1), .C (clk_disp), .Q (hdmi_clk) ); // RGB - YCbCr 変換 conv_rgb2ycbcr conv_rgb2ycbcr_i ( .red(red), .green(green), .blue(blue), .y(y), .cb(cb), .cr(cr) ); // 同期信号、displya_enable を遅延 always @(posedge clk_disp) begin if (reset_disp) begin hsyncx_d1 <= 1'b1; hsyncx_d2 <= 1'b1; hsyncx_d3 <= 1'b1; vsyncx_d1 <= 1'b1; vsyncx_d2 <= 1'b1; vsyncx_d3 <= 1'b1; de_d1 <= 1'b0; de_d2 <= 1'b0; end else begin hsyncx_d1 <= hsyncx; hsyncx_d2 <= hsyncx_d1; hsyncx_d3 <= hsyncx_d2; vsyncx_d1 <= vsyncx; vsyncx_d2 <= vsyncx_d1; vsyncx_d3 <= vsyncx_d2; de_d1 <= display_enable; de_d2 <= de_d1; de_d3 <= de_d2; end end // YCbCr のラッチ always @(posedge clk_disp) begin if (reset_disp) begin y_d1 <= 8'd16; y_d2 <= 8'd16; cb_d1 <= 8'd128; cb_d2 <= 8'd128; cb_d3 <= 8'd128; cr_d1 <= 8'd128; cr_d2 <= 8'd128; cr_d3 <= 8'd128; end else begin y_d1 <= y; y_d2 <= y_d1; cb_d1 <= cb; cb_d2 <= cb_d1; cb_d3 <= cb_d2; cr_d1 <= cr; cr_d2 <= cr_d1; cr_d3 <= cr_d2; end end assign de_stat = {de_d1, de_d2, de_d3}; // Cb の値を算出する always @* begin case (de_stat) 3'b111 : // 通常の場合 cb422 <= {2'b00, cb_d1} + {1'b0, cb_d2, 1'b0} + {2'b00, cb_d3}; 3'b110 : // de が1になった時 cb422 <= {1'b0, cb_d2, 1'b0} + {1'b0, cb_d1, 1'b0}; 3'b011 : // deの終わりから2つ前 cb422 <= {1'b0, cb_d2, 1'b0} + {1'b0, cb_d3, 1'b0}; default : cb422 <= 10'd512; // 128*4 endcase end // Cr の平均を取る always @* begin case (de_stat) 3'b111 : // 通常の場合 cr422 <= {2'b00, cr_d1} + {1'b0, cr_d2, 1'b0} + {2'b00, cr_d3}; 3'b110 : // de が1になった時 cr422 <= {1'b0, cr_d2, 1'b0} + {1'b0, cr_d1, 1'b0}; 3'b011 : // deの終わりから2つ前 cr422 <= {1'b0, cr_d2, 1'b0} + {1'b0, cr_d3, 1'b0}; default : cr422 <= 10'd512; // 128*4 endcase end // hdmi_data の処理 always @(posedge clk_disp) begin if (reset_disp) hdmi_data <= 16'd0; else begin if (de_d2) begin if (~second_pixel) hdmi_data <= {y_d2, cb422[9:2]}; // cb422 / 4 else hdmi_data <= {y_d2, cr422[9:2]}; // cr422 / 4 end else hdmi_data <= 16'd0; end end // second_pixel の処理 always @(posedge clk_disp) begin if (reset_disp) second_pixel <= 1'b0; else begin if (de_d2) second_pixel<= ~second_pixel; else second_pixel <= 1'b0; end end // hdmi_data_e の処理 always @(posedge clk_disp) begin if (reset_disp) hdmi_data_e <= 1'b0; else hdmi_data_e <= de_d2; end; assign hdmi_hsync = hsyncx_d3; assign hdmi_vsync = vsyncx_d3; endmodule `default_nettype wire
2012年11月30日 05:06 |
ZedBoard
| トラックバック:0
| コメント:0
”ZedBoardでHDMI出力13(HDMIに出力できた) ”のプロジェクトをFPGA Editor でみたところ、hdmi_hsync, hdmi_vsync, vga_hsync, vga_vsync もデータもIOBのレジスタを使用していなかった。
全体像を説明するために、話をHSYNCやVSYNCに絞って、そのブロック図を図1 に示す。
図1 HSYNC, VSYNC出力ブロック図
bitmap_disp_cntrler_axi_master.v がビットマップ・ディスプレイ・コントローラのトップだ。その下に、bitmap_disp_engine.v とconv_hdmi_out.v がある。bitmap_disp_engine.v にはTiming Generatorがあって、HSYNCやVSYNCを生成している。それをFFを介してbitmap_disp_cntrler_axi_master.v に出力して、それをconv_hdmi_out.v に入力する。conv_hdmi_out.v では、YCbCr4:2:2 変換を行うために2クロック分遅延するので、その分をHSYNC, VSYNCも遅延させるために2段のFFを通している。bitmap_disp_engine.v のHSYNC, VSYNCは、conv_hdmi_out.v に渡しているので、このままではIOBレジスタを使用できない。その為、もう1段FFを介してFPGA外に出力している。
最初に、PlanAheadでFlow navigator のImplementation のImplementation Settings をクリックして、Mapのオプションを見た。none になっていたので、oに変更した。(グローバル・オプションで出力の最後のFFをIOBレジスタにマップするオプション)
これでインプリメントしてみたところ、HDMI関連はIOBレジスタを使用したが、vga_hsync, vga_vsync はIOBレジスタを使えていなかった。
次に、UCFファイルで、vga_hsync, vga_vsync, hdmi_hsync, hdmi_vsync にIOB = FORCE 制約を試してみたが、なぜか効かなかった?
そこで、Verilog HDLソースファイルのポート宣言に(* IOB = "FORCE" *)を追加した。
(* IOB = "FORCE" *) output reg vga_hsync, (* IOB = "FORCE" *) output reg vga_vsync, (* IOB = "FORCE" *) output wire hdmi_vsync, (* IOB = "FORCE" *) output wire hdmi_hsync,
これでやっと、vga_hsync, vga_vsyncがIOBレジスタに入らないとのエラーが出るようになった。どうやら、図1のFF2とFF3が統合されてしまっているようだ。これを防ぐためには、Synthhesis オプションの equivalent_register_removal をyes から no にすれば良いと思うのだが、全体にかかってしまうためやらない。
図1のFF3, FF4にS属性(S制約)を掛けてFFをキープした。
(*S="TRUE"*) reg hsyncx_d1, hsyncx_d2; (*S="TRUE"*) reg vsyncx_d1, vsyncx_d2;
これでも、やはり、vga_hsync, vga_vsyncがIOBレジスタに入らないとのエラーが出る。
FF2にS属性(S制約)を掛ければ良いのだが、すでにIOB = "FORCE"制約を掛けているので、2つ制約が書けるかどうか分からなかった。(1回、やってみるのに時間が掛かるんです)試しに、FF1にS属性(S制約)を掛けてみた。
(*S="TRUE"*) output reg hsyncx, (*S="TRUE"*) output reg vsyncx,
これでインプリメントしてみたところ、うまく、全部のポートでIOBレジスタを使うことができるようになった。
本当は出力ポートのvga_hsync, vga_vsync をreg で宣言してFFにするよりも、1つ前にノードをreg で宣言して、FF記述をして、そこをS属性(S制約)を掛ける。そして、そこから出力ポートに結んで、そこに、 IOB = "FORCE" 制約を掛けたほうが良いと思われる。
2012年11月29日 05:51 |
制約
| トラックバック:0
| コメント:0
前回、キャラクタは表示できても色がおかしかった 。その状況から、RGB - YCbCr変換がおかしいのか?と疑ったが、変換はおかしくないようだった。
その次に、YUV変換なのかな?と思っていたが、ツイッターでY, Cb,Crの値を教えていただいたので、現在のRGB - YCbCr変換はおかしくないようだということがわかった。
次に
ADV7511 Programming Guid Rev G のTable 18 YCbCr 4:2:2 Formats (24, 20, or 16 bits) Input Data Mapping: を見ると、現在はStyle 2, 16bit(赤の四角で囲った部分) で使用しているが、24bit, 20bit はCb, Crの方が先でYが後なのに、16bitだけYが先になっている。どうも怪しい。この図で行くと16bit の部分もCb, CrとYというフォーマットじゃないだろうか?と思った。つまり、Style 3(ピンクで囲った部分)にする必要があるのでは?と思った。下にTable 18を引用させていただく。
(こちらの回路では、YとCb, Crを連結してhdmi_data[15:0] に出力している)
そこで、Style 3に設定した。具体的にはADV7511のレジスタ設定の0x16番地を0xb5 から0xbd に変更した。”
ZedBoardでHDMI出力7(ADV7511のレジスタ設定1) ”を参照。
iic_write(0x39, 0x16, 0xbd); // [3:2] -> Input Style => 11 = style 3
その他の設定はリファレンス・デザインの通りにした。そうすると、ちゃんとした色で出力できた。マニュアルが間違っていたようだ。
良かった。嬉しいです。
リファレンス・デザインはどうやって出力しているか見るために、Verilog HDLコードを見てみたが、やはり、Cb, Crが上位ビットでYが下位ビットだった。本当に人騒がせなマニュアルだ。(怒怒怒)
リファレンス・デザインでは、cf_ss_444to422.v の123行目~134行目に、YCbCr422の出力部分がある。
次にDVIでも出力できるのか?を探るために、HDMIからDVIにモードを変更してみた。
iic_write(0x39, 0xaf, 0x04); // [1] -> HDMI/DVI Mode Select => 0 = DVI Mode // iic_write(0x39, 0xaf, 0x06); // [1] -> HDMI/DVI Mode Select => 1 = HDMI Mode
そうすると、また違ったように色がおかしくなってしまった。
ADV7511 Programming Guid Rev G の19ページ、4.2.2 HDMI DVI Selection を見ると、” DVI only supports the RGB color space”だそうだ。YCbCrはサポート無しとのことだった。もう一度、HDMIモードに変更した。
ZedBoardでVGAサイズの画像をHDMI出力することが出来た。
2012年11月27日 04:22 |
ZedBoard
| トラックバック:0
| コメント:2
11月23日の勤労感謝の日の金曜日に仙台に行って、松島観光に行って来ました。
仙台で娘を拾って、東北道の仙台宮城インターチェンジから北に向かい、富谷ジャンクションから仙台北部道路に、利府ジャンクションから三陸自動車道に乗り換えて、松島海岸インターチェンジで降りました。松島に向かい、町の中に入りましたが、結構道が混んでいたので、1日500円の駐車場に早々と入れて歩いて行きました。
11時30分発の松島湾一周の船 仁王丸に乗って50分間の松島湾一周の旅に出ました。値段は1人1,400円でしたが、2階席は暖房が入っていて、グリーンシートということで、1人あたり600円取られました。なんか、ぼられている気がしたんですが、仕方が無いですね。
船に乗るとかもめ?(ウミネコですか?)が寄って来ました。かもめの餌はかっぱえびせんでした。かっぱえびせんを手に腕を伸ばしていると勝手にかっぱらっていきます。(方言?泥棒していく)
かもめの数が半端じゃないです。怖いくらい。
かもめが凄かったですが、本当は島めぐりです。松島には260以上の島があるそうです。これが天然の防波堤となって、津波をだいぶ防いでくれたそうです。これは、仁王島です。(たぶん)
これは鐘島かな?4つの洞窟が見えます。
他にも小学校がある島がありました。去年の地震による津波は大丈夫だったんでしょうか?
降りてから、
海鮮を出す食堂の南部家 に入りました。私はカキ丼を頼みました。カキが小ぶりでした。
今年の牡蠣は出来が良くなかったという情報もあるんでそうなんでしょうか?奥さんは生牡蠣を食べたんですが、あまり美味しくなかったとのことです。那珂湊の巨大な牡蠣の方が美味しかったそうです。
食事の後は
五大堂 に行きました。ここも海につきだした島の様なところにありました。
赤い橋をわたって島に行って来ました。
島は公園になっていて、展望台から他の島が見えます。結構歩いて疲れました。
その後、ずんだ餅を食べてから瑞巌寺に行きました。
本堂は震災で壊れて工事中でしたが、伊達政宗の位牌があって見てきました。立派ですね。中は撮影禁止なので撮影していません。
宝物殿もあって、見応えがありました。この日は仙台の娘の所に泊まって来ました。
2012年11月25日 10:49 |
日記
| トラックバック:0
| コメント:0
”
ZedBoardでHDMI出力付き11(ビットマップ・ディスプレイ・コントローラ単体テスト) ”でHDMI出力付きビットマップ・ディスプレイ・コントローラ (BDC) の単体テストが終了した。
今回は、HDMI出力付きBDC のインプリメントを行う。使用しているバージョンはPlanAhead 14.3。
最初に、axi_iic を追加した。ProjectメニューからRescan Usre Repositories を行なって、BDC IPのリスキャンをして、HDMI関連のポートをXPSが認識できるようにした。
XPSのBus Interface タブの画面を下に示す。
Ports タブの画面を下に示す。HDMI出力関連のポートが増えている。
Address タブの画面を下に示す。
XPS を離れて、PlanAheadに戻って論理合成、インプリメントを行った。最後にエラーが出てしまった。
エラーは、Bit file generation で出ていて、Bad time stamp エラーということだった。検索すると、”
ISE 14.3 - 「ERROR:Bitstream:188 - Bad time stamp"」というエラー メッセージが表示される ”が見つかった。それによると、エラーは出るがビットストリームは生成されているそうだ。日本語設定になってるためにエラーが出るとのことだった。
このバグもあるけど、PlanAhead 14.3 は上図でわかるように、Hierarchyウインドウが頻繁にUpdating Hierarchy...になってしまって、階層が表示されない。他のウインドウ (Compile Order) などにすると問題ないので、Hierarchyウインドウの問題のようだ。
次に、ハードウェアをSDKにエクスポートしてSDKを立ち上げた。
リファレンス・デザインの ADV7511の設定をHDMIからDVIに変更してやってみたところ、HDMIから出力はされたのだが、色がおかしくなってしまった。VGAへの出力の色は問題ない。現在の解像度はVGA画像(640x480)で、ピクセルクロックは25MHzだ。
なぜそうなったのか?分からない。調査中。
2012年11月25日 05:30 |
ZedBoard
| トラックバック:0
| コメント:0
前回 までの調査で、ADV7511のことが大体わかったので、HDMI出力回路をビットマップ・ディスプレイ・コントローラに付けることにした。
bitmap_disp_cntrler_axi_master.v にconv_hdmi_out.v を追加した。bitmap_disp_cntrler_axi_master.v を下に示す。
// bitmap_disp_cntrler_axi_master.v // // Read Only IP, 64 bit bus // // 2012/06/28 // 2012/11/22 : HDMI出力を追加 `default_nettype none module bitmap_disp_cntrler_axi_master # ( parameter integer C_INTERCONNECT_M_AXI_WRITE_ISSUING = 8, parameter integer C_M_AXI_THREAD_ID_WIDTH = 1, parameter integer C_M_AXI_ADDR_WIDTH = 32, parameter integer C_M_AXI_DATA_WIDTH = 64, parameter integer C_M_AXI_AWUSER_WIDTH = 1, parameter integer C_M_AXI_ARUSER_WIDTH = 1, parameter integer C_M_AXI_WUSER_WIDTH = 1, parameter integer C_M_AXI_RUSER_WIDTH = 1, parameter integer C_M_AXI_BUSER_WIDTH = 1, parameter [31:0] C_M_AXI_TARGET = 32'h00000000, parameter integer C_M_AXI_BURST_LEN = 256, parameter integer C_OFFSET_WIDTH = 32, /* Disabling these parameters will remove any throttling. The resulting ERROR flag will not be useful */ parameter integer C_M_AXI_SUPPORTS_WRITE = 0, parameter integer C_M_AXI_SUPPORTS_READ = 1 ) ( // System Signals input wire ACLK, input wire ARESETN, // Master Interface Write Address output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_AWID, output wire [C_M_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR, output wire [8-1:0] M_AXI_AWLEN, output wire [3-1:0] M_AXI_AWSIZE, output wire [2-1:0] M_AXI_AWBURST, output wire M_AXI_AWLOCK, output wire [4-1:0] M_AXI_AWCACHE, output wire [3-1:0] M_AXI_AWPROT, // AXI3 output wire [4-1:0] M_AXI_AWREGION, output wire [4-1:0] M_AXI_AWQOS, output wire [C_M_AXI_AWUSER_WIDTH-1:0] M_AXI_AWUSER, output wire M_AXI_AWVALID, input wire M_AXI_AWREADY, // Master Interface Write Data // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_WID, output wire [C_M_AXI_DATA_WIDTH-1:0] M_AXI_WDATA, output wire [C_M_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB, output wire M_AXI_WLAST, output wire [C_M_AXI_WUSER_WIDTH-1:0] M_AXI_WUSER, output wire M_AXI_WVALID, input wire M_AXI_WREADY, // Master Interface Write Response input wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_BID, input wire [2-1:0] M_AXI_BRESP, input wire [C_M_AXI_BUSER_WIDTH-1:0] M_AXI_BUSER, input wire M_AXI_BVALID, output wire M_AXI_BREADY, // Master Interface Read Address output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_ARID, output wire [C_M_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR, output wire [8-1:0] M_AXI_ARLEN, output wire [3-1:0] M_AXI_ARSIZE, output wire [2-1:0] M_AXI_ARBURST, output wire [2-1:0] M_AXI_ARLOCK, output wire [4-1:0] M_AXI_ARCACHE, output wire [3-1:0] M_AXI_ARPROT, // AXI3 output wire [4-1:0] M_AXI_ARREGION, output wire [4-1:0] M_AXI_ARQOS, output wire [C_M_AXI_ARUSER_WIDTH-1:0] M_AXI_ARUSER, output wire M_AXI_ARVALID, input wire M_AXI_ARREADY, // Master Interface Read Data input wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_RID, input wire [C_M_AXI_DATA_WIDTH-1:0] M_AXI_RDATA, input wire [2-1:0] M_AXI_RRESP, input wire M_AXI_RLAST, input wire [C_M_AXI_RUSER_WIDTH-1:0] M_AXI_RUSER, input wire M_AXI_RVALID, output wire M_AXI_RREADY, // User Ports input wire pixclk, output wire [3:0] vga_red, output wire [3:0] vga_green, output wire [3:0] vga_blue, output wire vga_hsync, output wire vga_vsync, output wire hdmi_clk, output wire hdmi_vsync, output wire hdmi_hsync, output wire hdmi_data_e, output wire [15:0] hdmi_data, input wire init_done ); wire [7:0] red, green, blue; wire hsyncx, vsyncx; wire display_enable; wire bde_req, bde_ack; wire [7:0] bde_arlen; wire [31:0] bde_address; wire [63:0] bde_data; wire bde_data_valid; reg reset_disp_2b, reset_disp_1b; wire reset_disp; wire afifo_overflow, afifo_underflow; wire addr_is_zero, h_v_is_zero; axi_master_interface #( .C_M_AXI_THREAD_ID_WIDTH(C_M_AXI_THREAD_ID_WIDTH), .C_M_AXI_ADDR_WIDTH(C_M_AXI_ADDR_WIDTH), .C_M_AXI_DATA_WIDTH(C_M_AXI_DATA_WIDTH), .C_M_AXI_AWUSER_WIDTH(C_M_AXI_AWUSER_WIDTH), .C_M_AXI_ARUSER_WIDTH(C_M_AXI_ARUSER_WIDTH), .C_M_AXI_WUSER_WIDTH(C_M_AXI_WUSER_WIDTH), .C_M_AXI_RUSER_WIDTH(C_M_AXI_RUSER_WIDTH), .C_M_AXI_BUSER_WIDTH(C_M_AXI_BUSER_WIDTH), .C_M_AXI_SUPPORTS_WRITE(C_M_AXI_SUPPORTS_WRITE), .C_M_AXI_SUPPORTS_READ(C_M_AXI_SUPPORTS_READ) ) axi_master_inf_inst ( .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), .bde_req(bde_req), .bde_ack(bde_ack), .bde_arlen(bde_arlen), .bde_address(bde_address), .bde_data_out(bde_data), .bde_data_valid(bde_data_valid) ); bitmap_disp_engine bitmap_disp_eng_inst ( .clk_disp(pixclk), .clk_axi(ACLK), .reset_disp(reset_disp), .reset_axi(~ARESETN), .req(bde_req), .ack(bde_ack), .ARLEN(bde_arlen), .address(bde_address), .data_in(bde_data), .data_valid(bde_data_valid), .red_out(red), .green_out(green), .blue_out(blue), .hsyncx(hsyncx), .vsyncx(vsyncx), .display_enable(display_enable), .ddr_cont_init_done(init_done), .afifo_overflow(afifo_overflow), .afifo_underflow(afifo_underflow), .addr_is_zero(addr_is_zero), .h_v_is_zero(h_v_is_zero) ); assign vga_red = red[7:4]; assign vga_green = green[7:4]; assign vga_blue = blue[7:4]; assign vga_hsync = hsyncx; assign vga_vsync = vsyncx; always @(posedge pixclk) begin reset_disp_2b <= ~ARESETN; reset_disp_1b <= reset_disp_2b; end assign reset_disp = reset_disp_1b; conv_hdmi_out conv_hdmi_out_inst ( .clk_disp(pixclk), .reset_disp(reset_disp), .red(red), .green(green), .blue(blue), .hsyncx(hsyncx), .vsyncx(vsyncx), .display_enable(display_enable), .hdmi_clk(hdmi_clk), .hdmi_vsync(hdmi_vsync), .hdmi_hsync(hdmi_hsync), .hdmi_data_e(hdmi_data_e), .hdmi_data(hdmi_data) ); endmodule `default_nettype wire
次に、conv_hdmi_out.v を下に示す。単体テストではOKになったが、まだバグがあるかも知れない?
Cb とCr の4:2:2への変換方法は、
前回書いた 様に前のピクセルの値との平均値を取っている。
(2012/11/26: second_pixel の処理が抜けていたので、修正しました) // BitMap Display Controller for HDMI // HDMI Interface // RGBをYCbCrに変換して出力する // HDMI出力はRGBよりも3クロック遅延する。 // フルHDだと3クロックでは足りない。conv_rgb2ycbcrの中でもう1つFFが必要。 // // 2012/11/21 // `default_nettype none module conv_hdmi_out ( input wire clk_disp, // ディスプレイ表示用クロック input wire reset_disp, // clk_disp 用リセット input wire [7:0] red, input wire [7:0] green, input wire [7:0] blue, input wire hsyncx, input wire vsyncx, input wire display_enable, output wire hdmi_clk, output wire hdmi_vsync, output wire hdmi_hsync, output wire hdmi_data_e, output reg [15:0] hdmi_data ); wire [7:0] y; wire [7:0] cb; wire [7:0] cr; reg [7:0] y_d1; reg [7:0] cb_d1, cb_d2; reg [8:0] cb422; reg [7:0] cr_d1, cr_d2; reg [8:0] cr422; reg hsyncx_d1, hsyncx_d2; reg vsyncx_d1, vsyncx_d2; reg de_d1, de_d2; reg second_pixel; // hdmi_clk の出力 ODDR #( .DDR_CLK_EDGE("OPPOSITE_EDGE"), .INIT(1'b0), .SRTYPE("SYNC") ) hdmi_clk_ODDR ( .R (1'b0), .S (1'b0), .CE (1'b1), .D1 (1'b0), .D2 (1'b1), .C (clk_disp), .Q (hdmi_clk) ); // RGB - YCbCr 変換 conv_rgb2ycbcr conv_rgb2ycbcr_i ( .red(red), .green(green), .blue(blue), .y(y), .cb(cb), .cr(cr) ); // 同期信号、displya_enable を遅延 always @(posedge clk_disp) begin if (reset_disp) begin hsyncx_d1 <= 1'b1; hsyncx_d2 <= 1'b1; vsyncx_d1 <= 1'b1; vsyncx_d2 <= 1'b1; de_d1 <= 1'b0; de_d2 <= 1'b0; end else begin hsyncx_d1 <= hsyncx; hsyncx_d2 <= hsyncx_d1; vsyncx_d1 <= vsyncx; vsyncx_d2 <= vsyncx_d1; de_d1 <= display_enable; de_d2 <= de_d1; end end // YCbCr のラッチ always @(posedge clk_disp) begin if (reset_disp) begin y_d1 <= 8'd16; cb_d1 <= 8'd128; cb_d2 <= 8'd128; cr_d1 <= 8'd128; cr_d2 <= 8'd128; end else begin y_d1 <= y; cb_d1 <= cb; cb_d2 <= cb_d1; cr_d1 <= cr; cr_d2 <= cr_d1; end end // Cb の平均を取る always @* begin if (de_d1) begin if (de_d1==1'b1 && de_d2==1'b0) // ラインの最初の画素 cb422 <= {1'b0, cb_d1} + {1'b0, cb_d1}; // 最初のCbの値はそのまま平均値とする else cb422 <= {1'b0, cb_d1} + {1'b0, cb_d2}; end else cb422 <= 9'd256; // 128*2 end // Cr の平均を取る always @* begin if (de_d1) begin if (de_d1==1'b1 && de_d2==1'b0) // ラインの最初の画素 cr422 <= {1'b0, cr_d1} + {1'b0, cr_d1}; // 最初のCrの値はそのまま平均値とする else cr422 <= {1'b0, cr_d1} + {1'b0, cr_d2}; end else cr422 <= 9'd256; // 128*2 end // hdmi_data の処理 always @(posedge clk_disp) begin if (reset_disp) hdmi_data <= 16'd0; else begin if (de_d1) begin if (~second_pixel) hdmi_data <= {y_d1, cb422[8:1]}; else hdmi_data <= {y_d1, cr422[8:1]}; end else hdmi_data <= 16'd0; end end // second_pixel の処理 always @(posedge clk_disp) begin if (reset_disp) second_pixel <= 1'b0; else begin if (de_d1) second_pixel<= ~second_pixel; else second_pixel <= 1'b0; end end assign hdmi_data_e = de_d2; assign hdmi_hsync = hsyncx_d2; assign hdmi_vsync = vsyncx_d2; endmodule `default_nettype wire
conv_rgb2ycbcr.v は”
RGB―YCbCr変換の検討3(切り捨てと0捨1入) ”で決定したように、0捨1入の RGB - YCbCr変換を使用している。
これで、bitmap_disp_cntrler_axi_master.v をトップとして、テストベンチ・ファイルのbitmap_disp_cntrler_axi_master_tb.v を追加したProject Navigator のプロジェクトを作製した。
下にテストベンチのシミュレーション波形を示す。これは時刻 0ns からのスタートだ。
M_AXI_ARVALIDにM_AXI_ARREADYが応答して、M_AXI_RVALIDが1になったら、M_AXI_RREADYを1にしてデータを受け取っている。
次に、RGB - YCbCr変換のconv_rgb2ycbcr.v を見てみよう。red, green, blue に対して、hdmi_data が2クロック遅れて出力されている。
2012年11月22日 05:42 |
ZedBoard
| トラックバック:0
| コメント:0
”
ZedBoardでHDMI出力7(ADV7511のレジスタ設定1) ”、
”ZedBoardでHDMI出力8(ADV7511のレジスタ設定2) ”、”
ZedBoardでHDMI出力9(ADV7511のレジスタ設定3) ”で、
ANALOG DEVICESのリファレンス・デザイン における画像の主要なADV7511のレジスタ設定を見た。
今回は自分でADV7511を使うという視点からADV7511にピクセルデータを入力する信号についてまとめていきたいと思う。
・16ビット長のYCbCr4:2:2を入力する。
・
設定レジスタの0x16番地 [7] Output Format 1= 4:2:2
・
設定レジスタの0x16番地 [5:4] Color Depth 11 = 8bit(これでADV7511のデータ幅が16ビット決定)
・
設定レジスタの0x16番地 [3:2] Input Style 01 = style 2
・
設定レジスタの0x16番地 [0] Output Colorspace for Black Image 1 = YCbCr
・YCbCrの入力方法は”ADV7511 Low-Power HDMI 1.4 Compatible Transmitter with Audio Return Channel PROGRAMMING GUIDE - Revision G– March 2012 ”(このマニュアルは、
ADV7511 Design Support Files からダウンロードできる)の”Table 18 YCbCr 4:2:2 Formats (24, 20, or 16 bits) Input Data Mapping: 0x48[4:3] = ‘01’ (right justified) Input ID = 1 or 2”から調べることができる。
Table 18の一部を下に引用する。
上の表でピンクで囲ったYCbCr4:2:2 16ビットデータ幅となる。つまり、最初の16ビットはY, Cb、次の16ビットはY, Crと出力する。
・ここで問題となるのは、YはRGB - YCbCr変換のY出力をそのまま使用するが、Cb, Cr はどうするか?ということになる。解決策としては、2つあると思う。
1.1つ前のCb, Crの値を残しておいて、現在の値との平均を取る。
2.気にせずに、現在のRGB - YCbCr変換のCbかCrの値を使う。
・色差信号はそんなに急激に変化しないと思うので、どちらでも大丈夫だと思うが、よりなだらかに色が変化するはずの1.の平均を取ることにしようと思う。通常のRGB4:4:4 - YCbCr4:2:2変換はどうやっているのだろうか?
つまりこれって画像圧縮の一種で色差信号の帯域を圧縮しているということになるんだろう?平均を取るとローパスフィルタを通しているのと同じことになると思う。
2012年11月20日 05:32 |
ZedBoard
| トラックバック:1
| コメント:0
”
RGB―YCbCr変換の検討2(Verilog HDLで実装) ”の続き。(タイトルを四捨五入から0捨1入に変更しました)
今回、今までやってきたのは計算時に256を掛け算して(つまり2進数で言うと8ビット左論理シフト)して、計算してから、結果として15ビット目から8ビット目までを取り出していた(256で割り算する。つまり2進数で言うと8ビット右論理シフト)。これはつまり7ビット目から0ビット目の小数部を切り捨てていたわけだ。
0捨1入も行うことができる。7ビット目を見て、1だったら15ビット目から8ビット目に+1を行えば、0捨1入となる。実は0捨1入は演算が1つ増えるため(+1の演算器が1つ増える)採用していないで切り捨てていた。切り捨てによる誤差は、0≦x<-1に収まり、0捨1入による誤差は、-0.5≦x<0.5に収まる。この様に切り捨ては四捨五入に比べて平均で0.5だけ値が低くなるといえると思う。今回は切り捨てと0捨1入によるリソース使用量の違いと動作周波数について、Zynq-7020デバイスについて見ていこうと思う。(実際の型番は、xc7z020-1clg484)
今回、0捨1入のRGB-YCbCr変換のVerilog HDLを下に示す。
(2012/11/26:Y の変域が16から235だったためVerilog HDLソースファイルを修正しました。下のインプリメント後の結果と合わなくなる場合があります) // RGB - YCbCr変換 // Y = 0.257R + 0.504G + 0.098B + 16 // Cb = -0.148R - 0.291G + 0.439B + 128 // Cr = 0.439R - 0.368G - 0.071B + 128 // 但し、Yは255以上だったら飽和演算をして255に丸める。Cb, Crは16以下だったら16に、240以上だったら240に飽和演算を行う。 // 0捨1入バージョン `default_nettype none module conv_rgb2ycbcr ( input wire [7:0] red, input wire [7:0] green, input wire [7:0] blue, output reg [7:0] y, output reg [7:0] cb, output reg [7:0] cr ); wire [18:0] y_lshift8; wire [18:0] cb_lshift8; wire [18:0] cr_lshift8; assign y_lshift8 = ({5'd0, red, 6'd0} + {10'd0, red, 1'd0}) + ({4'd0, green, 7'd0} + {11'd0, green}) + ({7'd0, blue, 4'd0} + {8'd0, blue, 3'd0} + {11'd0, blue}) + 19'd4096; assign cb_lshift8 = 19'd0 - ({6'd0, red, 5'd0} + {9'd0, red, 2'd0} + {10'd0, red, 1'd0}) - ({5'd0, green, 6'd0} + {8'd0, green, 3'd0} + {10'd0, green, 1'd0}) + ({5'd0, blue, 6'd0} + {6'd0, blue, 5'd0} + {7'd0, blue, 4'd0}) + 19'd32768; assign cr_lshift8 = ({5'd0, red, 6'd0} + {6'd0, red, 5'd0} + {7'd0, red, 4'd0}) - ({5'd0, green, 6'd0} + {7'd0, green, 4'd0} + {8'd0, green, 3'd0} + {9'd0, green, 2'd0} + {10'd0, green, 1'd0}) - ({7'd0, blue, 4'd0} + {10'd0, blue , 1'd0}) + 19'd32768; always @* begin if (y_lshift8[18]==1'b1 || y_lshift8[17:8]<16) // マイナスまたは16以下なので16に丸める y <= 8'd16; else if (y_lshift8[17:8] > 235) // 235より大きければ235に丸める y <= 8'd235; else begin if (y_lshift8[7] == 1'b1) begin if (y_lshift8[15:8] == 8'd235) y <= 8'd235; else y <= y_lshift8[15:8] + 8'd1; end else y <= y_lshift8[15:8]; end end always @* begin if (cb_lshift8[18]==1'b1 || cb_lshift8[17:8]<16) // マイナスまたは16以下なので16に丸める cb <= 8'd16; else if (cb_lshift8[17:8] > 240) // 240より大きければ240に丸める cb <= 8'd240; else begin if (cb_lshift8[7] == 1'b1) begin if (cb_lshift8[15:8] == 8'd240) cb <= 8'd240; else cb <= cb_lshift8[15:8] + 8'd1; end else cb <= cb_lshift8[15:8]; end end always @* begin if (cr_lshift8[18]==1'b1 || cr_lshift8[17:8]<16) // マイナスまたは16以下なので16に丸める cr <= 8'd16; else if (cr_lshift8[17:8] > 240) // 240より大きければ240に丸める cr <= 8'd240; else begin if (cr_lshift8[7] == 1'b1) begin if (cr_lshift8[15:8] == 8'd240) cr <= 8'd240; else cr <= cr_lshift8[15:8] + 8'd1; end else cr <= cr_lshift8[15:8]; end end endmodule `default_nettype wire
切り捨てと四捨五入の違いを示す。前回の切り捨てのタイミングを下図に示す。
次に四捨五入のタイミングを下図に示す。
両方の図は同じ、red = 120, green = 212, blue = 76 の位置にカーソルを置いてある。切り捨てに比べて、0捨1入はカーソルの前から cb の値が 82 になっているのがわかると思う。これは、カーソルの前でcb_lshif8 が 0x051b8 となって、7ビット目が1になって、cb の値が0捨1入で繰り上がっているからである。
切り捨てと0捨1入の違いがわかったところで、使用リソースを比較してみる。
前回の最後に示した切り捨ての時の使用リソースはSlice Registersを41個、Slice LUTsを240個使用していた。
今回の四捨五入は、Slice Registersを43個、Slice LUTsを262個使用していた。なお、どちらも、Slice Registersは、AND/OR logicsとしての使用だった。FPGA Editorを見ると、Slice Registersは6入力2出力あるLUTの出力を2つ出すためにスルーロジックとして使われているようだ。
2つを比較すると、0捨1入(43 + 262) / 切り捨て(41 + 240) x 100 = 108.5% となり、0捨1入の方が切り捨てより 8.5% のリソースを余計に使用していた。
次に、動作周波数を検証してみよう。
切り捨てのRGB-YCbCr変換回路をconv_rgb2ycbcr_round_down.v、0捨1入のRGB-YCbCr変換回路をconv_rgb2ycbcr_round_off.v として、それぞれに入力、出力両方にFFを入れたトップファイルを作製した。(conv_rgb2ycbcr_rd_top.v, conv_rgb2ycbcr_ro_top.v)
conv_rgb2ycbcr_rd_top.v を下に示す。
// conv_rgb2ycbcr_top.v `default_nettype none module conv_rgb2ycbcr_rd_top ( input wire clk, input wire reset, input wire [7:0] red, input wire [7:0] green, input wire [7:0] blue, output reg [7:0] y, output reg [7:0] cb, output reg [7:0] cr ); reg [7:0] red_ff, green_ff, blue_ff; wire [7:0] y_node, cb_node, cr_node; always @(posedge clk) begin if (reset) begin red_ff <= 0; green_ff <= 0; blue_ff <= 0; end else begin red_ff <= red; green_ff <= green; blue_ff <= blue; end end conv_rgb2ycbcr_round_down conv_rgb2ycbcr_rd_inst ( .red(red_ff), .green(green_ff), .blue(blue_ff), .y(y_node), .cb(cb_node), .cr(cr_node) ); always @(posedge clk) begin if (reset) begin y <= 0; cb <= 0; cr <= 0; end else begin y <= y_node; cb <= cb_node; cr <= cr_node; end end endmodule `default_nettype wire
これで制約に、クロック周波数を148.5MHzにして、インプリメントを行った。
切り捨ての方のタイミング制約は満たされずに、クリティカル・パスは 10.237ns となった。最大の動作周波数は、97.684MHzということになる。
0捨1入の方のタイミング制約も満たされずに、クリティカル・パスは 10.565ns となった。最大の動作周波数は94.652MHz ということになる。
案外、切り捨てと0捨1入の遅延時間の差が少ない。クリティカル・パスの経路を調べてみることにした。
上のProject Navigator の右側のウインドウのConstraint の "clk" 148.5MHz HIGH 50% のリンクをクリックする。
クリティカル・パスにカーソルを持って行って、右クリックメニューからshow in Technology Viewer を選択する。
Technology Viewer が見えて、切り捨てでは9個のブロックがFFからFFまでで使用されていることがわかる。
同様に、四捨五入も見てみると、0捨1入でも9個のブロックが使用されていることがわかった。
1つ加算器が増えても、クリティカル・パスで使用するスライス数は同じなので、使用リソースは多少増えるが、値が確からしい0捨1入を使用することにした。
今回はLUTがどのようにコンフィグされているかまで、踏み込んで調べなかったが、+1の演算器だと足される数?が定数なので、簡単化されているのだと思う。
2012年11月19日 05:31 |
画像処理
| トラックバック:0
| コメント:0
”RGB―YCbCr変換の検討1(変換式) ”の続き。
前回は変換式をVerilog HDLで記述できる形に変換した。今回は、実際にVerilog-HDLでRGB-YCbCr変換を記述した。
まず、RGB-YCbCr変換を行うconv_rgb2ycbcr.v を下に示す。
(2012/11/27:conv_rgb2ycbcr.v を修正しました。以下のインプリメントの回路規模とかが違っている場合があります) // RGB - YCbCr変換 // Y = 0.257R + 0.504G + 0.098B + 16 // Cb = -0.148R - 0.291G + 0.439B + 128 // Cr = 0.439R - 0.368G - 0.071B + 128 // 但し、Yは255以上だったら飽和演算をして255に丸める。Cb, Crは16以下だったら16に、240以上だったら240に飽和演算を行う。 // 切り捨てバージョン `default_nettype none module conv_rgb2ycbcr_round_down ( input wire [7:0] red, input wire [7:0] green, input wire [7:0] blue, output reg [7:0] y, output reg [7:0] cb, output reg [7:0] cr ); wire [18:0] y_lshift8; wire [18:0] cb_lshift8; wire [18:0] cr_lshift8; assign y_lshift8 = ({5'd0, red, 6'd0} + {10'd0, red, 1'd0}) + ({4'd0, green, 7'd0} + {11'd0, green}) + ({7'd0, blue, 4'd0} + {8'd0, blue, 3'd0} + {11'd0, blue}) + 19'd4096; assign cb_lshift8 = 19'd0 - ({6'd0, red, 5'd0} + {9'd0, red, 2'd0} + {10'd0, red, 1'd0}) - ({5'd0, green, 6'd0} + {8'd0, green, 3'd0} + {10'd0, green, 1'd0}) + ({5'd0, blue, 6'd0} + {6'd0, blue, 5'd0} + {7'd0, blue, 4'd0}) + 19'd32768; assign cr_lshift8 = ({5'd0, red, 6'd0} + {6'd0, red, 5'd0} + {7'd0, red, 4'd0}) - ({5'd0, green, 6'd0} + {7'd0, green, 4'd0} + {8'd0, green, 3'd0} + {9'd0, green, 2'd0} + {10'd0, green, 1'd0}) - ({7'd0, blue, 4'd0} + {10'd0, blue , 1'd0}) + 19'd32768; always @* begin if (y_lshift8[18] == 1'b1 || y_lshift8[17:8]<16) // マイナスまたは16より小さいので16に丸める y <= 8'd16; else if (y_lshift8[17:8] > 235) // 235より大きければ235に丸める y <= 8'd235; else y <= y_lshift8[15:8]; end always @* begin if (cb_lshift8[18] == 1'b1 || cb_lshift8[17:8]<16) // マイナスまたは16より小さいので16に丸める cb <= 8'd16; else if (cb_lshift8[17:8] > 240) // 240より大きければ240に丸める cb <= 8'd240; else cb <= cb_lshift8[15:8]; end always @* begin if (cr_lshift8[18] == 1'b1 || cr_lshift8[17:8]<16) // マイナスまたは16より小さいので16に丸める cr <= 8'd16; else if (cr_lshift8[17:8] > 240) // 240より大きければ240に丸める cr <= 8'd240; else cr <= cr_lshift8[15:8]; end endmodule `default_nettype wire
次に、ISEのプロジェクトを作成して、conv_rgb2ycbcr.v をテストするテストベンチファイルconb_rgb2ycbcr.v を作製した。conb_rgb2ycbcr.v を下に示す。
`timescale 1ns / 1ps //////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 04:57:17 11/18/2012 // Design Name: conv_rgb2ycbcr // Module Name: K:/HDL/FndtnISEWork/Zynq-7000/ZedBoard/test/conv_rgb2ycbcr/conv_rgb2ycbcr_tb.v // Project Name: conv_rgb2ycbcr // Target Device: // Tool versions: // Description: // // Verilog Test Fixture created by ISE for module: conv_rgb2ycbcr // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // //////////////////////////////////////////////////////////////////////////////// module conv_rgb2ycbcr_tb; // Inputs reg [7:0] red; reg [7:0] green; reg [7:0] blue; // Outputs wire [7:0] y; wire [7:0] cb; wire [7:0] cr; integer i = 0; integer j = 0; integer k = 0; // Instantiate the Unit Under Test (UUT) conv_rgb2ycbcr uut ( .red(red), .green(green), .blue(blue), .y(y), .cb(cb), .cr(cr) ); initial begin // Initialize Inputs red = 0; green = 0; blue = 0; // Wait 100 ns for global reset to finish #100; // Add stimulus here for (i=0; i < 100; i = i + 10) begin red = i; green = i; blue = i; // 色は白 #10; end for (i=0; i<256; i=i+1) begin for (j=0; j<256; j=j+1) begin for (k=0; k<256; k=k+1) begin red = i; green = j; blue = k; #10; end end end $finish; end endmodule
最初は、RGBとも同じ値をシミュレーションしている。つまり白色をシミュレーションしているわけだ。
白色の場合はYの値は変わるが、Cb, Crの値は128で固定されている。なお、RGBがオール0の場合はYは16となる。下に白色の場合のシミュレーション結果を示す。
シミュレーション結果の一部を下に示す。
(追加)試しにインプリメントしてみました。MAPのリポートの一部を下に示します。
Release 14.3 Map P.40xd (nt) Xilinx Mapping Report File for Design 'conv_rgb2ycbcr' Design Information ------------------ Command Line : map -intstyle ise -p xc7z020-clg484-1 -w -logic_opt off -ol high -t 1 -xt 0 -register_duplication off -r 4 -mt off -ir off -pr off -lc off -power off -o conv_rgb2ycbcr_map.ncd conv_rgb2ycbcr.ngd conv_rgb2ycbcr.pcf Target Device : xc7z020 Target Package : clg484 Target Speed : -1 Mapper Version : zynq -- $Revision: 1.55 $ Mapped Date : SUN 18 NOV 6:1:11 2012 Design Summary -------------- Number of errors: 0 Number of warnings: 50 Slice Logic Utilization: Number of Slice Registers: 41 out of 106,400 1% Number used as Flip Flops: 0 Number used as Latches: 0 Number used as Latch-thrus: 0 Number used as AND/OR logics: 41 Number of Slice LUTs: 240 out of 53,200 1% Number used as logic: 238 out of 53,200 1% Number using O6 output only: 117 Number using O5 output only: 8 Number using O5 and O6: 113 Number used as ROM: 0 Number used as Memory: 0 out of 17,400 0% Number used exclusively as route-thrus: 2 Number with same-slice register load: 0 Number with same-slice carry load: 2 Number with other load: 0 Slice Logic Distribution: Number of occupied Slices: 93 out of 13,300 1% Number of LUT Flip Flop pairs used: 240 Number with an unused Flip Flop: 199 out of 240 82% Number with an unused LUT: 0 out of 240 0% Number of fully used LUT-FF pairs: 41 out of 240 17% Number of slice register sites lost to control set restrictions: 0 out of 106,400 0%
2012年11月18日 05:57 |
画像処理
| トラックバック:0
| コメント:0
RGBで表されたピクセルをADV7511に表示させるためにはYCbCrに返還する必要がある。その変換回路を実現するためにRGB-YCbCr変換回路を設計することにした。先ずは変換式を検討してみた。
”
YUV-RGB変換1(方式の検討) ”を式変換の参考にしながら、
”YUVフォーマット及び YUV<->RGB変換”ページの”ITU-R BT.601 規定YCbCrと8bitフルスケールRGBの相互変換” を参考にさせて頂いた。
そのページによるとのRGB-YCbCrの変換式は下のようになる。
Y = 0.257R + 0.504G + 0.098B + 16 Cb = -0.148R - 0.291G + 0.439B + 128 Cr = 0.439R - 0.368G - 0.071B + 128 但し、Yは255以上だったら飽和演算をして255に丸める。Cb, Crは16以下だったら16に、240以上だったら240に飽和演算を行う。
これを式1とする。
式1の右辺に256を掛けて256で割ることにする。256は8ビットのシフト演算で行うことができる。
電卓の関係上10進数で計算する。最初のRの係数0.257に256を掛けると65.792になった。小数点以下を四捨五入すると、66になる。この様に係数に256を掛けて四捨五入を行うと式2が導けた。
Y = (66R + 129G + 25B + 4096) >> 8 Cb = (-38R - 74G + 112B + 32768) >> 8 Cr = (112R - 94G - 18B + 32768) >> 8
これを式2とする。>>8は8ビット右シフトするということで、これは256で割ったのと等価になる。
32768は0x8000_0000で、16ビット長で、最大値になる項は、129Gだから、最大値はGを255とした時で、129x255 = 32895 = 0x807F でやはり16ビットになる。演算器のビット幅は、16bit + (log2(項の数 = 4)の小数点以下切り上げ) + 符号ビット1bit = 19bit とする。
式2を更に2進数に変換する。
Y = (0100_0010R + 1000_0001G + 0001_1001B + 19'd4096) >> 8 Cb = (-0010_0110R - 0100_1010G + 0111_0000B + 19'd32768) >> 8 Cr = (0111_0000R - 0101_1110G - 0001_0010B + 19'd32768) >> 8
これを式3とする。
これで、Verilog HDL の式にできる形になった。これからVerilogでRGB-YCbCr変換回路を作る予定だ。
2012年11月17日 05:39 |
画像処理
| トラックバック:0
| コメント:0
昨日は
ET2012 に行って来ました。主にFPGA関連の展示やカンファレンスを聞いてきて、TwitterのTLの方に4人ほどお会いできました。充実した1日でした。お会いできました皆様、説明していただいた皆様有難うございました。会場は混んでいてとっても活気がありました。日本の組み込み、まだまだ元気だと思います。。。
セミナは、展示を見るのが忙しかったので、
”FPGAを凌駕するハイパフォーマンス3PLDデバイスと応用例の紹介”と”これからのマルチコア・プロセッサ・システム~ ARMプロセッサ、Nios II そしてOpenCL~” FPGAトラックの2つの講演を聞いてきました。
最初のは、Tabula社の3D-PLDの話でした。IntelをFabとして使って、22nmプロセスでFPGAを作っていると話題になったあの会社です。基本のクロックは166MHzなんですが、それを12倍して2GHzで動かして、基本クロックの間に12個の違った回路を2GHzクロックごとにコンフィグして12倍の回路として動作させるというものです。ホントだったら凄いですね。後でブースにも言って説明を聞いてきたんですが、LUTの後にFF(FPGAではお決まりの回路です。普通のFPGAだったらここのFFは使わないこともありますが)
Spacetimeアーキテクチャ では必須で使うとのことです。2GHzで動くのは凄いなと思いましたが、LUT1個当たり2GHzのようでした。少なくとも長い配線を通しては2GHzで動かない様です。そうなるとツールの重要性が普通のFPGAより増すだろうと思いました。ツールのでき次第で評価がかわるんじゃないか?と思います。
2つ目のこれからのマルチコア・プロセッサ・システムはAltera社の講演でした。28nm FPGAの説明やAltera のSoC FPGA、そしてOpenCLの説明でした。SoC FPGAではZynqとの違いを説明していました。
・128ビット幅でARMとFPGAがやり取りできるようです。(Xilinxは64ビット幅)
・DDRメモリのハードマクロのコントローラがFPGA側にも付くようです。
・FPGA単体でもコンフィグROMでコンフィグできるようです。(Xilinxはプロセッサ経由コンフィギュレーションのみ)
OpenCL はPCIe経由でパソコンとFPGAボード間をやり取りするみたいです。ブースに行って確認したところ動いていましたが、アルファバージョンの様な感じでした。
ブースには、
アキュベリノス の
HARCA がありました。なんかどこかで見たようなボードです。これは、ブレッドボードに挿して周辺を作ってもらう学生実験にぴったりなボードだと思います。この基板を使って、
aitendoのOV9655 を付けたカメラボードも展示してありました。エネループ乾電池2本で動いていました。
XilinxのブースではZynqがいっぱい展示されていました。TEDの4K2Kテレビ用のHDビデオを入れて、4K2Kにするスケーラーを展示していました。構成は、
TEDのKintex7のボード に
HDMIの入力ボード、出力ボード X2を付けて実現していました。ディスプレイは4K2Kを表示するのに、HDディスプレイを4枚使って表示していました(マウンタ使用)。4k2Kディスプレイは高いので、お安く済ますのにはとっても良いと思いました。
特電のブースにも行って、なひたふさんに
スマートフォンからJTAGを使う デモを見せて頂きました。端子の情報が見えるだけでなく、スマートフォンの画面に表示されたICチップの端子を触ると遠隔で端子のレベルを変更することが出来ます。
ETフェスタまでいて、Twitterでお世話になっている方にお会いして来ました。Aさん、おいしいパンをありがとうございました。Gさん、マドレーヌ(ですよね?)美味しかったです。ありがとうございました。
1日会場にいて疲れましたが、色々見られて楽しかったです。
追加です。大学のブースで面白いものを見ました。Spartan-6のちっちゃなボードが壮観につながっていました
。A Scalable Many-core Processor Simulator だそうです。コネクタでFPGAボードが平面につながっていて、メニイコアをシミュレーションできるシステムみたいですね。面白そうでした。
東工大の吉瀬先生 のところのプロジェクトのようです。
2012年11月16日 05:29 |
その他のFPGAの話題
| トラックバック:0
| コメント:0
何か、飽きてきたのですが、途中でやめられないので続けます。
0xd0番地 -> 0x3c [7] ->
Enable DDR Negative Edge CLK Delay =>
0 = Disable DDR Negative Edge CLK Delay , 1 = Enable DDR Negative Edge CLK Delay
[6:4] ->
DDR Negative Edge CLK Delay => 000 = -1200 ps , 001 = -800 ps , 010 = -400 ps ,
011 = no delay , 100 = 400 ps , 101 = 800 ps , 110 = 1200 ps , 111 = Invert CLK
[3:2] ->
Sync Pulse Select 00 = DE , 01 = Hsync , 10 = Vsync ,
11 = no sync pulse [1] ->
Timing Generation Sequence =>
0 = sync adjustment then DE generation , 1 = DE generation then sync adjustment
[0] ->
Fixed => Must be set to Default Value
0xd1番地 -> 0xff [7:0] ->
Fixed => Must be set to Default Value
0xde番地 -> 0x9c [7:4] ->
Fixed => Must be set to Default Value (
1001 )
[3] ->
TMDS Clock Inversion 0 = Normal TMDS Clock ,
1 = Inverted TMDS Clock [2:0] ->
Fixed => Must be set to Default Value (
100 )
0xe0番地 -> 0xd0 [7:0] ->
Fixed => Must be set to 0xD0 for proper operation
0xe4番地 -> 0x60 [7:0] ->
Fixed => Must be set to Default Value
0xf9番地 -> 0x00 [7:0] ->
Fixed I2C Address => This should be set to a non-conflicting I2C address (
0x00 )
0xfa番地 -> 0x00 [7:5] ->
Hsync Placement MSB (Embedded Sync Decoding) =>
000 [4:2] ->
Hsync Placement MSB (Sync Adjustment) => (
000 )
0x17番地 -> 0x02 [7] ->
Fixed => Must be set to Default Value (
0 )
[6] ->
Vsync Polarity => (Case 2:Sync Adjustment Register (0x41[1]) = 0)
0 = sync polarity pass through, High polarity , 1 = sync polarity invert, Low polarity
[5] ->
Hsync Polarity => (Case 2:Sync Adjustment Register (0x41[1]) = 0)
0 = sync polarity pass through, High polarity , 1 = sync polarity invert, Low polarity
[4:3] ->
Reserved @ 00b => Must be set to Default Value
[2] ->
4:2:2 to 4:4:4 Interpolation Style =>
0 = use zero order interpolation , 1 = use first order interpolation
[1] ->
Aspect Ratio => 0 = 4:3 Aspect Ratio ,
1 = 16:9 Aspect Ratio [0] ->
DE Generator Enable =>
0 = Disabled , 1 = Enabled
2012年11月15日 04:43 |
ZedBoard
| トラックバック:0
| コメント:0
0x55番地 -> 0x20 [7] ->
AVI Byte 1 bit 7 => Reserved per HDMI spec. -
set to 0 [6:5] ->
Y1Y0 (AVI InfoFrame) => 00 = RGB ,
01 = YCbCr 4:2:2 , 10 = YCbCr 4:4:4 , 11 = reserved
[4] ->
Active Format Information Status (AVI InfoFrame) =>
0 = no data , 1 = Active format Information valid
[3:2] ->
Bar Information (AVI InfoFrame) =>
00 = invalid bar , 01 = vertical , 10 = horizontal , 11 = Both
[1:0] ->
Scan Information (AVI InfoFrame) =>
00 = no data , 01 = TV , 10 = PC , 11 = None
0x56番地 -> 0x08 [7:6] ->
Colorimetry (AVI InfoFrame) =>
00 = no data , 01 = ITU601 , 10 = ITU709 , 11 = Extended Colorimetry Information Valid (Indicated in register 0x57[6:4])
[5:4] ->
Picture Aspect Ratio (AVI InfoFrame) =>
00 = no data , 01 = 4:3 , 10 = 16:9 , 11 = None
[3:0] ->
Active Format Aspect Ratio (AVI InfoFrame) =>
1000 = Same as Aspect Ratio , 1001 = 4:3 (center) , 1010 = 16:9 (center) , 1011 = 14:9 (center)
0x96番地 -> -0x20 [7] ->
HPD Interrupt =>
0 = no interrupt detected , 1 = interrupt detected
[6] ->
Monitor Sense Interrupt => =>
0 = no interrupt detected , 1 = interrupt detected
[5] ->
Vsync Interrupt => 0 = no interrupt detected ,
1 = interrupt detected [4] ->
Audio FIFO Full Interrupt => =>
0 = no interrupt detected , 1 = interrupt detected
[3] ->
Fixed =>
0 [2] ->
EDID Ready Interrupt => =>
0 = no interrupt detected , 1 = interrupt detected
[1] ->
HDCP Authenticated => =>
0 = no interrupt detected , 1 = interrupt detected
[0] ->
Fixed @ 0b => Reserved
0x98番地 -> 0x03 [7:0] ->
Fixed => Must be set to 0x03 for proper operation
0x99番地 -> 0x02 [7:0] ->
Fixed => Must be set to Default Value (0x02)
0x9a番地 -> 0xe0 [7:0] ->
Fixed => Must be set to 0b1110000 for proper operation
0x9c番地 -> 0x30 [7:0] ->
Fixed => Must be set to 0x30 for proper operation
0x9d番地 -> 0x61 [7:4] ->
Fixed => Must be set to Default Value (0110)
[3:2] ->
Input Pixel Clock Divide =>
00 = Input Clock not Divided , 01 = Input Clock Divided by 2 , 10 = Input Clock Divided by 4 , 11 = Invalid Setting
[1:0] ->
Fixed => Must be set to 0b01 for proper operation
0xa2番地 -> 0xa4 [7:0] ->
Fixed => Must be set to 0xA4 for proper operation
0xa3番地 -> 0xa4 [7:0] ->
Fixed => Must be set to 0xA4 for proper operation
0xa5番地 -> 0x44 [7:1] ->
Fixed => Must be set to Default Value (Default Value = 0000 010*) レジスタの説明と矛盾している、なぜだろうか?
0xab番地 -> 0x40 [7:3] ->
Fixed => Must be set to Default Value (01000***)
0xaf番地 -> 0x06 [7] ->
HDCP Enable =>
0 = HDCP Disabled , 1 = HDCP Encryption Enabled
[6:5] ->
Fixed => Must be set to Default Value
[4] ->
Enable HDCP Frame Encryption =>
0 = Current Frame NOT HDCP Encrypted , 1 = Current Frame HDCP Encrypted
[3:2] ->
Fixed => Must be set to Default Value (
01 )
[1] ->
HDMI/DVI Mode Select => 0 = DVI Mode ,
1 = HDMI Mode [0] ->
Fixed => Must be set to Default Value (
0 )
0xba番地 -> 0x00 [7:5] ->
Clock Delay =>
000 = -1.2ns , 001 = -0.8ns , 010 = -0.4ns , 011 = no delay , 100 = 0.4ns , 101 = 0.8ns , 110 = 1.2ns , 111 = 1.6ns
[4] ->
Internal/External HDCP EEPROM =>
0 = external EEPROM , 1 = internal EEPROM
[3] ->
Fixed => Must be set to Default Value
[2] ->
Display AKSV =>
0 = Don't Show AKSV , 1 = Show AKSV in 0xB0 - 0xB4
[1] ->
Ri Two Point Check =>
0 = HDCP Ri standard , 1 = enable HDCP Ri two point check
2012年11月14日 05:35 |
ZedBoard
| トラックバック:0
| コメント:0
ANALOG DEVICES の
リファレンス・デザイン における画像の主要なADV7511のレジスタ設定を見ていきます。
レジスタの設定1(リファレンス・デザインでの設定) 0x15番地 -> 0x01 [3:0] ->
Input ID => 0000 = 24 bit RGB 4:4:4 or YCbCr 4:4:4 (separate syncs) ,
0001 = 16, 20, 24 bit YCbCr 4:2:2 (separate syncs) ...
0x16番地 -> 0xb5 [7] ->
Output Format => 0 = 4:4:4 ,
1 = 4:2:2 [5:4] ->
Color Depth => 00 = invalid , 10 = 12bit , 01 = 10bit ,
11 = 8bit [3:2] ->
Input Style => 00 = Not Valid , 01 = style 2 , 10 = style 1 ,
11 = style 3 (”
ZedBoardでHDMI出力13(HDMIに出力できた) ”参照)
[1] ->
DDR Input Edge =>
0 = falling edge , 1 = rising edge
[0] ->
Output Colorspace for Black Image => 0 = RGB ,
1 = YCbCr 0x18番地 -> 0x46 [7] ->
CSC Enable =>
0 = CSC Disabled , 1 = CSC Enabled
[6:5] ->
CSC Scaling Factor => 00 = +/- 1.0, -4096 - 4095 , 01 = +/- 2.0, -8192 - 8190 ,
10 = +/- 4.0, -16384 - 16380 , 11 = +/- 4.0, -16384 - 16380
0x40番地 -> 0x80 [7] ->
GC Packet Enable => 0 = GC Packet Disabled ,
1 = GC Packet Enabled [6] ->
SPD Packet Enabled =>
0 = Disabled , 1 = Enabled
[5] ->
MPEG Packet Enabled =>
0 = Disabled , 1 = Enabled
[4] ->
ACP Packet Enable =>
0 = Disabled , 1 = Enabled
[3] ->
ISRC Packet Enable =>
0 = Disabled , 1 = Enabled
[2] ->
GM Packet Enable =>
0 = Disabled , 1 = Enabled
[1] ->
Spare Packet 2 Enable =>
0 = Disabled , 1 = Enabled
[0] ->
Spare Packet 1 Enable =>
0 = Disabled , 1 = Enabled
0x41番地 -> 0x10 [6] ->
POWER DOWN =>
0 = Normal Operation , 1 = ADV7511 Powered Down
[5] ->
Fixed =>
0 [4] ->
Reserved @ 1b =>
1 [3:2] ->
Fixed =>
00 [1] ->
Sync Adjustment Enable =>
0 = Disabled , 1 = Enabled
[0] ->
Fixed =>
0 0x48番地 -> 0x08 [7] ->
Reserved =>
0 [6] ->
Video Input Bus Reverse =>
0 = Normal Bus Order , 1 = LSB .... MSB Reverse Bus Order
[5] ->
DDR Alignment =>
0 = DDR input is D[17:0] , 1 = DDR input is D[35:18]
[4:3] ->
Bit Justfication for YCbCr 4:2:2 modes => 00 = evenly distributed ,
01 = right justified , 10 = left justified , 11 = Invalid
0x49番地 -> 0xa8 [7:2] ->
Bit Trimming Mode => 000000 = Active Dither ,
101010 = Truncate 0x4C番地 -> 0x00 (Read Only) [7:4] ->
Pixel Packing (GC Packet) [3:0] ->
Color Depth (GC Packet) => 0000 = Color Depth Not Indicated, 0100 = 24 Bits/Pixel , 0101 = 30 Bits/Pixel , 0110 = 36 Bits/Pixel
2012年11月13日 05:56 |
ZedBoard
| トラックバック:0
| コメント:2
ADV7511の機能について探っていく覚書 ・Display Data Channel は、I2C Master が載っていて、EDIDをダウンロードしてバッファリングするそうだ。
・サポートフォーマット
・Color Space YCbCr or RGB
・Bits per Color 8, 10, or 12
・Format 4:2:2 or 4:4:4
・Sync Type Speparate or Embedded
・Clocks 1x, 2x or DDR
・Video Data input は8, 10, 12, 16, 20, 24, 30, 36ビット幅があるが、ZedBoardはD23~D8の16ビット幅
・ADV7511のSDA/SCLのメイン・レジスタ・マップのプログラム・アドレスは0x72と0x7Aで、PD/AD端子を10KΩでプルアップした時が0x7A、プルダウンまたGNDに接続した時が0x72
・ZedBoardではPD/AD端子が、GNDに接続されているので、アドレスは
0x72 となる。
・I2Cの動作周波数は up to 400KHzだそうだ。
・ZedBoardでのVido Input Table はID=1 Bits per Color 8bit, Maximum Input Clock 165.0MHz, Format Name YCbCr 4:2:2, Sync Type Separate Syncs (ADV7511 Programming Guide Rev. G 27ページ)
・Table 18 YCbCr 4:2:2 Formats (24, 20, or 16 bits) Input Data Mapping:
0x48[4:3] = ‘01’ (right justified) Input ID = 1 の16bit(Input ID = 1: An input with YCbCr 4:2:2 with separate syncs)( Input ID (0x15[3:0]) to 0b0001)
> 16bit 1st Y[7:0], Cb[7:0], 2nd Y[7:0], Cr[7:0]
2012年11月12日 04:47 |
ZedBoard
| トラックバック:0
| コメント:0
HDMI出力とVGA出力を同時に出来るBitmap Display Controller (BDC) を作ることにした。
今までのBDC は、VGA出力だけだった が、それにHDMI出力を追加する。
当初は、VDMAやIICコントローラなどの既存のIPを使おうと思ったが、IPのマニュアルを読んだり、構造を勉強したりするのが、結構大変なので、自分のビットマップ・ディスプレイ・コントローラを修正することにした。
HDMI出力を行うためにBDC の内部構造を変更する。そのブロック図を図1に示す。
図1 Bitmap Display Controller (BDC) ブロック図
Zynq PS HP0ポートからAXI3バスでAXI Interconnect に送られたPixelデータは、AXI4バスでBDC に送られる。そのPixelデータはPixel DMA Controller がMaster としてAXI Interconnect にリクエストを送って取得する。Pixel DMA Controller から出力されたRGB のPixel Data はDisplay Timing Controller に送られる。ここでPixel Dataの取得タイミングとHSYNC, VSYNCなどの表示タイミングを出力する。表示タイミングに揃えたRGBのPixel Data をVGA Controller とHDMI Controller に送る。VGA Controller は従来通りに各4ビットのRGBデータをDACに送る。HDMI Controller はADV7511 (Low-Power HDMI® Transmitter) にYCrCbデータを送る。
HDMI Controller のブロック図を図2に示す。
図2 HDMI Controlle (HDMIC) ブロック図
I2C Controller を置いて初期化の時に、ADV7511のレジスタに設置値をセットする。Register Configuration File にADV7511 のレジスタの設定値を保存しおく。RGB Pixel DataはRGB to YCbCr Converter でRGBからYCbCr4:2:2 に変換される。変換されたYCbCr4:2:2 データはADV 7511 Display Controller で制御されてADV75111 に送られる。
とりあえずは、この様な回路を構成することにした。なお、ADV7511のデータシートは完全なデータシートが見つからなかったが、ツイッターで教えて頂いた。その他、Programming Guide なども見つけたので、下にURLを示す。
ADV7511 Design Support Files (
2012/11/12 修正 :以前の上のリンクはADV7511Wという別のHDMI Trasmitter でした。ADV7511のファイルのリンクに修正しました。しかし、何でこんなにわかりにくいところにあるんでしょうか?探すのにとっても苦労しました。)
2012年11月11日 05:55 |
ZedBoard
| トラックバック:0
| コメント:0
Linuxでのフレームバッファの使い方、デバイスドライバについて 、昨日ツイッターで色々教えてもらったことをtogetter でまとめました。
たぶん、フレームバッファのドライバを使うところまでは必要ないと思うんですが、勉強しておきたいと思います。
2012年11月09日 03:48 |
Linux
| トラックバック:0
| コメント:0
”
ZedBoardでHDMI出力3(ChipScope AXI Monitor でAXIバスを観察2) ”の続き。
前回はHPポートのVDMAに接続されたAXIバスの様子をChipScopeで見てみたが、今回はVDMAからaxi_hdmi_tx_16b_0 につながっているAXI-streamバスのトランザクションを見ていこう。
Xilinx社のFPGAにおけるAXI-Streamバスの信号は
AXIリファレンスガイド に書いてある。このマニュアルの50ページの表 3-2 : AXI4-Stream の信号 を引用させていただく。
これによると、AXI-StreamはTVALIDだけ必須で後はオプションとのことだ。TKEEPは未使用と書いてあるが、ChipScopeの信号には入っていた。TDATAは必ず8ビットの倍数にするそうだ。
さて、AXI-Streamバスの信号をChipScpeで見てみよう。
TVALIDはいつも1で、時々TREADYをaxi_hdmi_tx_16b_0 が1にアサートしてデータを受け取っている。TLASTもVDMAによって、たまに1にアサートされている。
TLASTが1になった時には、どういう意味があるかを調べてみた。
LogiCORE IP AXI Video Direct Memory Access v5.02.a Product Guide PG020 July 25, 2012 によると、TLASTはそれぞれのラインの終了を表すそうだ。Example MM2S Timing、111ページ参照。
Example MM2S Timing、111ページの Figure 3-10: Example MM2S Interface Timing を下に引用させていただく。
このExample Timing とChipScope のタイミングを見ると違っているところがある。Example Timing では、TREADYが常時1にアサートされているが、ChipScopeではTVALIDが常時1にアサートされていて、TREADYが時々1になってデータを受け取っている。
AXI-Stream はデータ・ストリームをやり取りするだけなので、簡単なバス構造になっているようだ。
2012年11月08日 05:21 |
ZedBoard
| トラックバック:0
| コメント:0
”
ZedBoardでHDMI出力2(ChipScope AXI Monitor でAXIバスを観察1) ”の続き。
前回は、ChipScope Integrated Controller を1つ、ChipScope AXI Monitor をHPバス用と、VDMAのAXI Stream 用に2つ追加追加して、XPSでインプリメントが終了し、SDKでコンパイルが終了した。
cf_adv_7511_zedの右クリックメニューでRun as -> Run Configurations... を選択し、cf_adv_7511_zed Debugコンフィグレーションを作成して、Runしたら、”
ZedBoardでHDMI出力1(アナデバのリファレンス・デザイン) ”同様のサンプル画像と音が出てきた。
更に、今回はXPSプロジェクトなので、スタートメニューから、ISE14.1のChipScope Pro Analyzer を単独で起動した。
・Open Cabel/Sreach JTAG Chain ボタンをクリックして、Zynqを認識させた。
・信号名が入っていないDataportが表示されたので、ProjectウインドウのUNIT:0 の右クリックメニューからimport... を選択した。こうすると、各UNIT毎に.cdc ファイルを適用できる。
・cf_adv7511_zed\cf_adv7511_zed\implementation\chipscope_axi_monitor_0_wrapper フォルダにあるchipscope_axi_monitor_0.cdc を指定した。
・ProjectウインドウのUNIT:1 の右クリックメニューからimport... を選択した。
・cf_adv7511_zed\cf_adv7511_zed\implementation\chipscope_axi_monitor_stream_wrapper フォルダにあるchipscope_axi_monitor_stream.cdc を指定した。
これで、ChipScopeの設定が終了した。Triger Immediate ボタンをクリックすると波形が現れた。
VDMAのHP0ポートの波形を示す。
最初のトランザクションの塊を引き伸ばして、タイミングを見た。RDATAは64ビット幅になっている。
データを連続バースト転送している幅は84クロックだった。ARVALIDが1になるよりも前にRVALIDとRREADYが同時に1になっているのがわかるだろうか?これは以前のトランザクションが遅延して残っているようだ。84クロックはHP0ポートのバッファ量を示しているのではないか?と思う。それにしても、1クロックの遅延もなくデータのバースト転送が続くのは見事だと思う。スループットが最大になっている。processing_system_7_0::FCLK_CLK1 は200MHzだったので、64ビットデータ幅=8バイト、8バイト x 200MHz = 1.6GB/sec の転送スピードとなる。ビットに直せば12.8Gbit/sec だ。しかしどうして、連続アドレスにアクセスしていると思うのだが、バースト長を長くしないのだろう?
1番目と2番めにARVALIDが1になっているところを拡大してみた。
最初のARVALIDが1のアドレスが 021E2500 で、次のアドレスが、021E2580 になっている。つまり0x80分のアドレスの差があることになる。つまり、1つのトランザクションで、128バイト転送していることになる。バースト数は128バイト / 8バイト(64ビットバス幅) = 16バーストとなる。
次に、ARVALIDが1になる時の各制御信号を見ていこう。信号の意味は、”
AXI4バスのパラメータの意味 ”を参照のこと。
ARLEN = 0F : 16バースト転送 ARSIZE = 3 : 1回に転送するバイト数は8バイト ARBURST = 1 : INCR(アドレスをインクリメント) ARCACHE = 3 : Normal Non-cacheable Bufferable
”
ZedBoardにビットマップ・ディスプレイ・コントローラを追加する13(char_wirte_axi_master IPを追加4) ”でchar_write_axi_master IP、つまりAXIバスのWrite マスタを追加した時には、ARCACHE = 3、つまりBufferableにすると、BRESPに”10”、SLVERR (Slave error) が帰ってきた。Writeではダメだが、ReadではARCACHEを 3 Bufferable にしても良いようだ。
(2013/10/21:追記) ISE14.6を使用して、AWCACHE、ARCACHEの値を 3 にして、AXIバスのデータ転送を行ってみました。Write もRead もBRESP、RRESPの返り値が 0 で問題ないことが分かりました。”AXI4バスでのAWCACHE、ARCACHEの値 ”を参照下さい。
VDMAのRead Transaction Issuance Limit はAuto になっていたが、たぶんデフォルトでは8だと思うので、8個のアドレスまで発行できる。つまり今のデータ転送はどこのアドレスなのか、この部分を切り取っただけでは分からない。
VDMAは性能が良いと思った。これならば、使わせてもらって、自分の回路を修正しても良いかな?
最後にHP0ポート、最大性能1.6GB/sec の帯域のどのくらいを使用しているか?だが、この時点では、84 / 226 x 100 = 37% 使用している。
表示空間はこのくらいのデータ帯域を使用していると思う。ブランク期間はデータ帯域を使用していないはずだ。
(追記:AXIマスタとしてReadしているVDMAがHP0ポートを待たせている(RREADY = 0)。これで問題ないのだろうか?PCI-Xの仕様ではRead要求したデータはWaitせずに受けること、となっていたと思う。AXIはバスとは言ってもクロスバーになので、他のデバイスのスループットやレイテンシに問題はないのだと思う)
2012年11月07日 05:08 |
ZedBoard
| トラックバック:0
| コメント:0
”
ZedBoardでHDMI出力1(アナデバのリファレンス・デザイン) ”の続き。
前回はリファレンス・デザインをそのままやってみたが、HDMI経由で画像と音を出力することが出来た。音はまだしも、HDMI経由で画像を出したい。リファレンス・デザインそのままというのも良いかもしれないが、同時にVGAポートにも出力したい。そのために、axi_hdmi_tx_16b (HDMI IP) のHDLファイルを使わせて頂いて、独自IPに埋め込むということは、ADV7511のデータシートが全く無く、動作がわからない点から言ってもダメそうだ。その場合には、アナログ・デバイスのHDMI IPにVGA出力を組み込むことになる。また、AXI Stream Busがどのように動いているかを勉強してみたい。よって、XPSプロジェクト上の axi_vdma_0 のHP0バスと、axi_hdmi_tx_16b_0 とaxi_vdma_0 間のAXI Stream バスにChipScope AXI Monitor をつないで信号を観測してみることにした。
(
注 :ISE14.3 に変換するとSDKでエラーになってしまったので、ISE14.1で動作チェックをおこなった)
前回、”
ChipScope AXI Monitor を試してみた ”では、ChipScope AXI Monitor をAdd IPせずに、DebugメニューからDebug Configuration を選択して、ChipScope AXI Monitor を追加した。今回はAdd IPしてChipScope AXI Monitor IPコアを追加した。更に、ChipScope AXI Monitor を追加する際には、ChipScope Integrated Controller も必須だった。今回は、ChipScope Integrated Controller を1つ、ChipScope AXI Monitor をHPバス用と、VDMAのAXI Stream 用に2つ追加した。
下に追加したXPSプロジェクトの Bus Interfaces タブを示す。
Ports タブでは、2つのChipScope AXI Monitor のMON_AXI_ACLK をprocessing_system_7_0::FCLK_CLK1に接続した。chipscope_icon_0 (controllerを2つに増やした)の2つのcontrol を2つのChipScope AXI Monitor に接続した。(processing_system_7_0::FCLK_CLK1 は200MHz)
これで、Generate BitStream を行った。終了後、Export Design をSDKを立ち上げるようにボタンをクリックして、SDKにハードウェアをエクスポートした。
SDKが立ちあげったら、Xilinx C Project (cf_adv7511_zed) を新規作成して、リファレンス・デザインのcf_adv7511_zed\cf_adv7511_zed\sw フォルダにあるcf_adv7511_zed.h と cf_adv7511_zed.c をcf_adv7511_zed/src にドラッグアンドドロップした。
11行目の”#include "platform.h"”、151行目の”init_platform();”、249行目の”cleanup_platform();”はエラーが出るので、コメントアウトした。
これで、コンパイルが通った。
2012年11月06日 05:49 |
ZedBoard
| トラックバック:0
| コメント:0
アクリルサインの試作第1号が完成しました。
横から見るとこんな感じです。5mm アクリル+10mm アクリル + 5mm アクリルのサンドイッチで20mm厚です。
LEDを点灯するとこんな感じです。上にFPGA-CAFEのアクリルサインを載せてあります。
写真やビデオでは、目で見ている色は出ません。MFT2012の会場で御覧ください。と言っても、明るすぎるとあまり派手じゃないかもしれません。
表板のUSBミニBコネクタへの切り込みが浅かったので、よく挿入できません。やっとはまっている感じです。後、LEDは目隠しをする予定なのを忘れていました。表板を掘り込んで白いアクリルをはめ込みます。
来週、表板、裏板を作りなおして修正します。
2012年11月05日 05:31 |
Make出展
| トラックバック:0
| コメント:0
FusionPCBから基板が届いた ので、部品を実装しました。実装に失敗してしまいましたが、電気的にはつながっているので、良しとしました。動作は問題なかったです。PWMでぼわーと点灯、ぼわーと消灯。7色に変化します。明るいですよ。
今日、アクリルを加工して、1台完成させようと思っています。
2012年11月04日 04:16 |
Make出展
| トラックバック:0
| コメント:0
”
ZedBoardにビットマップ・ディスプレイ・コントローラを追加する17(ARMのソフトからキャラクタを書けた2) ”の続き。
またまたツイッターでACPポートの使用方法がTRMに書いてあると教えてもらったで、やってみることにした。
マニュアルは
”Zynq-7000 All Programmable SoC テクニカル リファレンス マニュアル UG585 (v1.6.1) 2013 年 9 月 10 日 ”の96ページに、ACP の要求として、
コヒーレントな ACP 読み出し要求 : ARVALID と一緒に ARUSER[0] = 1 および ARCACHE[1] = 1 が送信された場合、ACP 読み出し要求はコヒーレントです。
コヒーレントな ACP 書き込み要求 : AWVALID と共に AWUSER[0] = 1 および AWCACHE[1] = 1 が送信 された場合、ACP 書き込み要求はコヒーレントです。
ということで、
assign M_AXI_ARCACHE = 4'b0010; // Normal Non-cacheable Non-bufferable assign M_AXI_ARUSER = 1'b1; // コヒーレントな ACP 読み出し要求
にして、もう一度、”
ZedBoardにビットマップ・ディスプレイ・コントローラを追加する8(ACPを使用) ”を見ながら、ビットマップ・ディスプレイ・コントローラで使用するAXIバスのポートをACPポートに変更しました。そうすると、やはりキャラクタの表示波形が乱れた。その様子を図1に示す。
(ACPポートはキャッシュのコヒーレンシを維持できるAXIバスのポートだ。キャッシュのコヒーレンシを維持できれば、AXIバス経由でDDR3 SDRAMにReadする時に、キャシュにReadするアドレスの更新されたデータがあれば、AXIバスのReadをWaitさせて、キャッシュからDDR3 SDRAMにcast outし、その後にプロセッサで更新された正しい値をAXIバス経由でDMAできるはずだ。)
図1 ACPポートを使用したキャラクタ表示(C_M_AXI_SUPPORTS_USER_SIGNALSにチェックなし)
もう一度、XPSプロジェクトを見なおしてみると、bitmap_disp_cntrler_axi_master_0 IPコアのプロパティで、C_M_AXI_SUPPORTS_USER_SIGNALSにチェックが入っていなかったので、チェックを入れた。これは、ユーザー信号をサポートするかどうかを決めるチェックだった。チェックを入れると、下の5つのユーザー信号がハイドから回復した。(図2参照)
図2 bitmap_disp_cntrler_axi_master_0 IPコアのプロパティ
これで、論理合成、インプリメントを行なって、キャラクタを表示させたところ、だいぶましになったのだが、最初の行がおかしくなってしまった。何度、ソフトウェアを実行しても、おかしいパターンは変わるが、最初の行がいつもおかしい。その様子を図3に示す。
図3 ACPポートを使用したキャラクタ表示(C_M_AXI_SUPPORTS_USER_SIGNALSにチェック入り)
実行しているソフトウェアは、キャッシュのフラッシュをコメントアウトしてあるが、このコメントアウトを外してキャッシュをソフトウェアでフラッシュすると、キャラクタがきちんと表示される。図1、図3を表示したソフトウェアを下に示す。
リスト1 キャッシュのフラッシュを全く行わないビットマップ・ディスプレイ・コントローラ用キャラクタ表示ソフトウェア
#include "xparameters.h" #include "xgpio.h" #define VIDEO_BUFFER_START_ADDRESS 0x10000000 void Xil_DCacheFlush(void );void Xil_DCacheFlushLine(unsigned int adr);unsigned int *char_draw(unsigned int *addr, unsigned char char_code, unsigned int char_color){ int i,j; unsigned int char_pattern; unsigned int char_code_int; unsigned int *cal_char_addr; unsigned int *return_addr; char_code_int = (unsigned int )(char_code); return_addr = addr + 8 ; cal_char_addr = (unsigned int *)(XPAR_CHAR_ROM_AXI_LITE_0_S_AXI_RNG00_BASEADDR+((char_code_int<<3 )<<2 )); for (i=0 ; i<8 ; i++){ char_pattern = *(volatile unsigned int *)(cal_char_addr); for (j=0 ; j<8 ; j++){ if (char_pattern & 0x1 ) *(volatile unsigned int *)((unsigned int )addr ^ 4 ) = char_color; else *(volatile unsigned int *)((unsigned int )addr ^ 4 ) = 0 ; addr++; char_pattern >>= 1 ; } addr -= 8 ; addr += 640 ; cal_char_addr++; } return return_addr; }int main() { static XGpio GPIOInstance_Ptr; int xStatus; unsigned char char_code; unsigned int * ddr2_addr; unsigned int coler_code; unsigned int char_cnt; int i, j; xStatus = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID); if (XST_SUCCESS != xStatus) print("GPIO INIT FAILED\n\r" ); XGpio_SetDataDirection(&GPIOInstance_Ptr, 1 , 0 ); XGpio_DiscreteWrite(&GPIOInstance_Ptr, 1 , 1 ); for (ddr2_addr=(unsigned int *)VIDEO_BUFFER_START_ADDRESS; ddr2_addr<(unsigned int *)((unsigned int )VIDEO_BUFFER_START_ADDRESS + (unsigned int )0x12 C000); ddr2_addr++){ *(volatile unsigned int *)((unsigned int )ddr2_addr ^ 4 ) = 0 ; } ddr2_addr = (unsigned int *)VIDEO_BUFFER_START_ADDRESS; char_cnt = 0 ; for (j=0 ; j<8 ; j++){ for (i=1 ; i<8 ; i++){ switch (i){ case 1 : coler_code = 0xf f; break ; case 2 : coler_code = 0xf f00; break ; case 3 : coler_code = 0xf fff; break ; case 4 : coler_code = 0xf f0000; break ; case 5 : coler_code = 0xf f00ff; break ; case 6 : coler_code = 0xf fff00; break ; case 7 : coler_code = 0xf fffff; } for (char_code=0x21 ; char_code<0x80 ; char_code++){ if (char_code >= 0x80 ) char_code = 0x21 ; if (char_cnt!=0 && char_cnt%80 ==0 ) ddr2_addr = (unsigned int *)((unsigned int )ddr2_addr + 640 *4 *7 ); ddr2_addr = char_draw(ddr2_addr, char_code, coler_code); char_cnt++; } } } return 0 ; }
リスト1で、if行と共に、Xil_DCacheFlushLine((unsigned int)ddr2_addr); をコメントアウトから回復させると、正常にキャラクタが表示された。
ACPポートを使用すると、なんとも微妙な結果になってしまった。
(2013/10/12:追記) やっとACPポートがおかしい理由がわかりました。
XPSを立ちあげて、Zynqタブの 64b AXI ACP Slave Port をクリックします。
ダイアログの Accelerator Coherency Port (ACP) Slave AXI Interface の Use slave driven AxUSER values にチェックを入れます。
これで、キャッシュのフラッシュのないソフトウェアを走らせると、うまくキャラクタが表示できました。これを忘れていたようです。
ツイッターで、Dyrell6502さんに教えていただきました。本当にありがとうございました。長年の課題が解消出来ました。
(もう一度、追記) その後、Accelerator Coherency Port (ACP) Slave AXI Interface の Use slave driven AxUSER values のチェックを外しても完全に動作しました。PlanAhead14.2からPlanAhead14.6に移行したのが良かったのかもしれません?
ですが、やはりチェックを入れたほうが良いと思うので、入れておきたいと思います。
2012年11月03日 05:41 |
ZedBoard
| トラックバック:0
| コメント:0
今日、FusionPCBから基板が届きました。10月15日に注文したので、18日くらいで届きました。3回頼んだ中で一番早かったです。
基板は板厚1mm、50mm x 100mm、レジスト色は赤です。やはり基板は結構薄いです。明日から基板に部品を載せて、早く光らせてみたいです。楽しみです。
2012年11月02日 21:34 |
Make出展
| トラックバック:0
| コメント:1
”
ZedBoardにビットマップ・ディスプレイ・コントローラを追加する16(ARMのソフトからキャラクタを書けた )”の続き。
前回、ZynqのARMプロセッサのソフトウェアからビットマップ・ディスプレイ・コントローラに文字を書くことが出来た。その際使用した関数はXil_DCacheFlush(); だった。これはソースを読んでみるとL1, L2キャッシュをすべてフラッシュするようだ。これでは、画像フレームバッファをキャッシュするキャッシュラインだけでなく他のキャッシュラインもフラッシュされてしまう。これでは無駄が大きい。その内に、Xil_DCacheFlushLine((unsigned int)addr); という関数をツイッターで教えて頂いた。これだったら、当該キャッシュラインだけをフラッシュすることができるはずだ。
なお、Xil_DCacheFlushLine() のソースコードは、ISE14.2を使用している場合は、Xilinx\14.2\ISE_DS\EDK\sw\lib\bsp\standalone_v3_07_a\src\cortexa9\xil_cache.c にある。ツイッターで教えて頂いた。ありがとうございました。
ARMのキャッシュラインの幅は32バイトの様なので、文字をラスタ毎に書き込んでいる時のアドレスの下5ビットが0x1Cになったら、Xil_DCacheFlushLine() を行うこととする。この変更を加えて、drawn_disp.elf をSDKから実行したところ問題なく文字が表示された。やはり文字を表示するのが速い。
下に、drawn_disp.c を示す。
#include "xparameters.h" #include "xgpio.h" #define VIDEO_BUFFER_START_ADDRESS 0x10000000 void Xil_DCacheFlush(void );void Xil_DCacheFlushLine(unsigned int adr);unsigned int *char_draw(unsigned int *addr, unsigned char char_code, unsigned int char_color){ int i,j; unsigned int char_pattern; unsigned int char_code_int; unsigned int *cal_char_addr; unsigned int *return_addr; char_code_int = (unsigned int )(char_code); return_addr = addr + 8 ; cal_char_addr = (unsigned int *)(XPAR_CHAR_ROM_AXI_LITE_0_S_AXI_RNG00_BASEADDR+((char_code_int<<3 )<<2 )); for (i=0 ; i<8 ; i++){ char_pattern = *(volatile unsigned int *)(cal_char_addr); for (j=0 ; j<8 ; j++){ if (char_pattern & 0x1 ) *(volatile unsigned int *)((unsigned int )addr ^ 4 ) = char_color; else *(volatile unsigned int *)((unsigned int )addr ^ 4 ) = 0 ; if (((unsigned int )addr & 0x1f ) == 0x1 c) Xil_DCacheFlushLine((unsigned int )addr); addr++; char_pattern >>= 1 ; } addr -= 8 ; addr += 640 ; cal_char_addr++; } return return_addr; }int main() { static XGpio GPIOInstance_Ptr; int xStatus; unsigned char char_code; unsigned int * ddr2_addr; unsigned int coler_code; unsigned int char_cnt; int i, j; xStatus = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID); if (XST_SUCCESS != xStatus) print("GPIO INIT FAILED\n\r" ); XGpio_SetDataDirection(&GPIOInstance_Ptr, 1 , 0 ); XGpio_DiscreteWrite(&GPIOInstance_Ptr, 1 , 1 ); for (ddr2_addr=(unsigned int *)VIDEO_BUFFER_START_ADDRESS; ddr2_addr<(unsigned int *)((unsigned int )VIDEO_BUFFER_START_ADDRESS + (unsigned int )0x12 C000); ddr2_addr++){ *(volatile unsigned int *)((unsigned int )ddr2_addr ^ 4 ) = 0 ; if (((unsigned int )ddr2_addr & 0x1f ) == 0x1 c) Xil_DCacheFlushLine((unsigned int )ddr2_addr); } ddr2_addr = (unsigned int *)VIDEO_BUFFER_START_ADDRESS; char_cnt = 0 ; for (j=0 ; j<8 ; j++){ for (i=1 ; i<8 ; i++){ switch (i){ case 1 : coler_code = 0xf f; break ; case 2 : coler_code = 0xf f00; break ; case 3 : coler_code = 0xf fff; break ; case 4 : coler_code = 0xf f0000; break ; case 5 : coler_code = 0xf f00ff; break ; case 6 : coler_code = 0xf fff00; break ; case 7 : coler_code = 0xf fffff; } for (char_code=0x21 ; char_code<0x80 ; char_code++){ if (char_code >= 0x80 ) char_code = 0x21 ; if (char_cnt!=0 && char_cnt%80 ==0 ) ddr2_addr = (unsigned int *)((unsigned int )ddr2_addr + 640 *4 *7 ); ddr2_addr = char_draw(ddr2_addr, char_code, coler_code); char_cnt++; } } } return 0 ; }
これで、Zynq-7000シリーズのARMプロセッサを使用して、ビットマップ・ディスプレイ・コントローラに文字を描画するソフトウェアは完成だ。
2012年11月02日 05:02 |
ZedBoard
| トラックバック:0
| コメント:0