2013-01-23(水) DE0でFPGAによるVGA出力
■[fpga][de0][vga]DE0でFPGAによるVGA出力

DE0でVGA出力するのに、わざわざパソコンにつないでるディスプレイをつなぎかえたりするのも面倒なので、ディスプレイ欲しいなーと思ってた。
で、うっかりモバイル液晶ディスプレイを買ってしまったので、VGA出力してみた。
買ったのはこのディスプレイ。
外で開発するときに欲しいなーと前から思ってて、実物を見てから買おうと思ってたのだけど、そんなに高くないし今回はVGAでさえあればよかったので、ついうっかりポチってしまった。
- 出版社/メーカー: GeChic Corporation
- 発売日: 2012/04/13
- メディア: Personal Computers
- クリック: 45回
- この商品を含むブログ (7件) を見る
USB給電+VGA入力でドライバいらず。薄いし、いちおうスタンドもついていて、なかなかいい。縦置きにすると普通に開発で便利。
Mac用のケーブルがついてるのもある。
13.3インチ 液晶モバイルモニター ON-LAP1302 for Mac
VGA出力の話にもどると、基本的な出力回路は参考書に載っているものそのままなのだけど、せっかくだしDE0に出力できる4096色を表示できるようにして、あとスプライトっぽいものを動かしてみた。
動画はこれ。
ところで、DE0でVGA出力するときに落とし穴があって、vga_b0のピンになってるK22が、なんか別の目的に割り当てられてるということでエラーが出る。意味がわかんなくて、泣きそうなくらいハマった。
nCEOというのに割り当てられてるらしくて、メニューの「Assignments > Device」でデバイス設定を開いて「Device and Pin Options」ボタンを押すとピンオプション設定画面が開くので、「Dual-Purpose Pins」を選んで「nCEO」のところを「Use as programming pin」から「Use as regular I/O」に変更すれば、コンパイルできるようになった。
こうやって無事VGA出力ができたのだけど、小学生のときに初めて自分で考えて意図どおりに動いたプログラムもこんな感じでキャラクタが飛び跳ねるようなものだった。
まあ、小学生のときは、なんで移動量を1ずつ減らしていくとジャンプしてる動きになるのか理解せずに、なんとなくやってみて飛び跳ねるようになったので、なんか誤魔化されてるような気がして、実際にちゃんとやるなら小学生の自分にはわからないもっと複雑な式が必要なんだろうなーとか考えたのを覚えてる。
実のところは、ddy=1を積分すれば、dy=xとなって、さらにそれを積分すれば放物線y=x^2/2になるので、移動量を1ずつ減らしていけば放物線にちゃんとなるわけで、複雑な式は必要ないということに高校で微分積分を習ってから気づいたのだけど。
移動量を減らす1が重力加速度ということもできる。
小学生当時にすごく楽しかった記憶があって、今もやはり同様に楽しいので、人間やっぱ根っこのところは変わらんのだなーと思ったりした。
当時は用意されたハードウェアでスプライト表示して楽しんでたのが、まさかこうやって自分でスプライト機能をもったハードウェアを設計して動かすということができるとは夢にも思わなかったのだけど。
やはりFPGAすごいな。
ソースはこんな感じで。見事にコメントなしだけども・・・。
module colorbar( input clk, output [9:0]led, output [3:0] vga_r, output [3:0] vga_g, output [3:0] vga_b, output reg vga_hs, output reg vga_vs ); assign led = 10'h00; reg[9:0] hs_cnt = 10'd0; reg[9:0] vs_cnt = 10'd0; reg vga_clk; always @(posedge clk) begin vga_clk = ~vga_clk; end reg [26:0] ch_cnt; reg ch_clk; always @(posedge clk) begin if(ch_cnt == 27'd999999) ch_cnt = 27'd0; else begin if(ch_cnt == 0)begin ch_clk = 1'b1; end else begin ch_clk = 1'b0; end ch_cnt = ch_cnt + 1; end end reg [9:0] ch_x = 10'd300; reg [9:0] ch_y = 10'd300; reg [6:0] dy = 7'd1; always @(posedge ch_clk ) begin if(ch_x > 640 - 32) ch_x <= 0; else begin ch_x <= ch_x + 2; end if(dy == 7'd31) dy <= 7'd1; else begin dy <= dy + 7'd1; end ch_y <= ch_y + dy - 16; end reg [7:0] rg = 8'h00; reg [5:0] rg_cnt = 5'd0; always @(posedge vga_clk) begin if(hs_cnt == 10'd799) begin hs_cnt <= 10'd0; end else begin hs_cnt <= hs_cnt + 1; end if(hs_cnt >= 10'd148 && hs_cnt < 10'd788)begin if(rg_cnt >= 6'd24) begin rg_cnt <= rg_cnt -6'd24; rg <= rg + 8'd1; end else begin rg_cnt <= rg_cnt + 6'd16; end end end always @(posedge vga_clk) begin if(hs_cnt == 10'd0) vga_hs = 1'b0; else if(hs_cnt == 10'd96) vga_hs = 1'b1; end always @(posedge vga_clk) begin if(hs_cnt == 10'd144) i_hdisp = 1'b1; else if(hs_cnt == 10'd784) i_hdisp = 1'b0; end reg [3:0] b = 4'd0; reg [9:0] b_cnt = 10'd0; always @(posedge vga_hs) begin if(vs_cnt == 10'd520) vs_cnt = 10'd0; else vs_cnt = vs_cnt + 1; if(vs_cnt >= 10'd30 && vs_cnt < 10'd510) begin if(b_cnt >= 480 - 16)begin b_cnt = b_cnt + 16 - 480; b = b + 1; end else b_cnt = b_cnt + 16; end end always @(posedge vga_hs) begin if(vs_cnt == 10'd0) vga_vs = 1'b0; else if(vs_cnt == 10'd2) vga_vs = 1'b1; else vga_vs = vga_hs; end reg i_hdisp, i_vdisp; always @(posedge vga_hs) begin if(vs_cnt == 10'd31) i_vdisp = 1'b1; else if(hs_cnt == 10'd511) i_vdisp = 1'b0; end wire [9:0]disp_x = hs_cnt - 148; wire [9:0]disp_y = vs_cnt - 30; reg [31:0] line; wire [9:0] spr_y = disp_y - ch_y; always @(spr_y) begin case (spr_y) 10'd00: line = 32'b00000000000000111111000000000000; 10'd01: line = 32'b00000000000011111111110000000000; 10'd02: line = 32'b00000000000111111111111000000000; 10'd03: line = 32'b00000000001111111111111100000000; 10'd04: line = 32'b00000000001111111111111100000000; 10'd05: line = 32'b00000000001111111111001100111110; 10'd06: line = 32'b00000000001111111111001101111111; 10'd07: line = 32'b00000000001111111111111101111111; 10'd08: line = 32'b00000000001111111111111101111111; 10'd09: line = 32'b00000000001111111101111101111111; 10'd10: line = 32'b00000000000111111110000100111110; 10'd11: line = 32'b00000000000011111111111000111100; 10'd12: line = 32'b00000000000001111111110001111100; 10'd13: line = 32'b00000001111111111111111111111100; 10'd14: line = 32'b00000011111111111111111111111100; 10'd15: line = 32'b00001111111111111111111111111000; 10'd16: line = 32'b00011111111111111111111111100000; 10'd17: line = 32'b00011111111111111111111110000000; 10'd18: line = 32'b00011111111111111111111100000000; 10'd19: line = 32'b00011111000111111111111100000000; 10'd20: line = 32'b00111111100111111111111100000000; 10'd21: line = 32'b01111111100111111111111111111000; 10'd22: line = 32'b01111111100111111111111111111100; 10'd23: line = 32'b00111111000111111111111111111100; 10'd24: line = 32'b00000000000111111111111111111100; 10'd25: line = 32'b00000011100111111111110001111110; 10'd26: line = 32'b00000011111111111000000011111111; 10'd27: line = 32'b00000011111111111000000011111111; 10'd28: line = 32'b00000011111111110000000011111111; 10'd29: line = 32'b00000011111111100000000000000000; 10'd30: line = 32'b00000011111000000000000000000000; 10'd31: line = 32'b00000011110000000000000000000000; default: line = 32'b00000000000000000000000000000000; endcase end wire [11:0] rgb = (disp_x >= ch_x && disp_x < ch_x + 32 && disp_y >= ch_y && disp_y < ch_y + 32 && (line[31 - (disp_x - ch_x)]) ? 12'h00f : {b, rg}); assign vga_r = (i_hdisp && i_vdisp) ? rgb[11:8] : 4'd0; assign vga_g = (i_hdisp && i_vdisp) ? rgb[7:4] : 4'd0; assign vga_b = (i_hdisp && i_vdisp) ? rgb[3:0] : 4'd0; endmodule