このドキュメントは http://icrus.org/fpga_atlys_design/ 上にあります.
本日はATLYSでVGA信号を作り,ディスプレイに表示します.
これまでは,LEDを使って視覚的な出力をしていましたが今回はコンピュータ用のVGAディスプレイから画像を出力します.もちろんこれをUARTやAICと組み合わせたプログラムもできます.
Video Graphics Array の略でIBM社が同社のパソコンに組み込んだグラフィックシステム.それに使われた端子をVGA端子という.また元々のの解像度は640×480であった.
抵抗器とVGAケーブルをブレッドボードに挿して接続するでVGAドライバを作成しましょう.図7-1に回路図,図7-2に実体配線図を示します.
組上げると色信号のD/A変換器が完成する.
ATLYS,ブレッドボード,VGAディスプレイを図7-3に示すように接続して,リスト7-1,7-2をISEで合成しADEPTから転送しATLYSで実行すると,スライドSW2~SW0をON/OFFして,色を変化を確認できます.
001 `timescale 1ns / 1ps
002 //////////////////////////////////////////////////////////////////////////////////
003 // Create Date: 18:51:58 12/16/2013
004 // Module Name: RGB_color
005 //////////////////////////////////////////////////////////////////////////////////
006 module RGB_color(
007 input wire clk,
008 input wire reset,
009 input wire[2:0] ssw,
010 output reg[2:0] red, green, blue,
011 output reg HS, VS
012 );
013
014 parameter HTs = 800; // 実幅 (単位クロック)
015 parameter HTdisp = 640; // 表示幅
016 parameter HTfp =16; // フロントポーチ幅
017 parameter HTpw =96; // Hsync幅
018
019 parameter VTs =521; // 実高 (単位ライン)(1ライン=800クロック)
020 parameter VTdisp =480; // 表示高
021 parameter VTfp=10; // フロントポーチ高
022 parameter VTpw =2; // Vsync幅
023
024 reg[9:0] Hcnt=0, Vcnt=0;
025
026 reg[1:0] count=2'd0;
027 wire clk25MHz=count[1]; // クロックを1/4にする
028
029 always@( posedge clk)begin
030 count <= count+2'd1; // atlysのクロック100MHzをカウントする
031 end
032
033 // clk25MHzをカウントする(Hcnt),ラインをカウントする(Vcnt)
034 always@( posedge clk25MHz or posedge reset ) begin
035 if( reset==1'b1)
036 {Hcnt,Vcnt}<=0;
037 else if( Hcnt==HTs-1)
038 begin
039 Hcnt<=0;
040 if(Vcnt==VTs-1)
041 Vcnt<=0;
042 else
043 Vcnt <= Vcnt + 10'd1;
044 end
045 else
046 Hcnt <= Hcnt + 10'd1;
047 end
048
049 // 条件によりHsyncを出力する
050 always@( posedge clk25MHz or posedge reset )begin
051 if( reset==1'b1)
052 HS<=1'b1;
053 else if( Hcnt == HTdisp - 1 + HTfp )
054 HS<=1'b0;
055 else if( Hcnt == HTdisp - 1 + HTfp + HTpw )
056 HS<=1'b1;
057 end
058
059 // 条件によりVsyncを出力する
060 always@( posedge clk25MHz or posedge reset ) begin
061 if( reset == 1'b1 )
062 VS<=1'b1;
063 else if(Vcnt == VTdisp - 1 +VTfp )
064 VS <= 1'b0;
065 else if(Vcnt == VTdisp - 1 + VTfp + VTfp + VTpw )
066 VS <= 1'b1;
067 end
068
069 // Hcnt, Vcntを利用して,画像信号R,G,Bを作成する
070 always@(posedge clk25MHz ) begin
071 if( Hcnt < HTdisp && Vcnt <VTdisp)
072 begin
073 red <= ssw[2] ? 3'd7 : 3'd0;
074 green <= ssw[1] ? 3'd7 : 3'd0;
075 blue <= ssw[0] ? 3'd7 : 3'd0;
076 end
077 else
078 {red, green, blue } <= 0;
079 end
080
081 endmodule
001 // RGB_color.ucf
002 net "clk" loc=L15;
003 net "reset" loc=P3;
004
005 net "red(0)" loc=V15;
006 net "red(1)" loc=V13;
007 net "red(2)" loc=N11;
008
009 net "green(0)" loc=T11;
010 net "green(1)" loc=V12;
011 net "green(2)" loc=P11;
012
013 net "blue(0)" loc=N9;
014 net "blue(1)" loc=V11;
015 net "blue(2)" loc=T10;
016
017 net "HS" loc=V10;
018 net "VS" loc=T8;
019
020 net "ssw(0)" loc=A10;
021 net "ssw(1)" loc=D14;
022 net "ssw(2)" loc=C14;
023
リスト7-1の073~075行目をリスト7-3のように変更して,色のグラデーションを表示させ,R信号とHsync信号をオシロスコープで測定せよ.(注意:Hsyncの立ち下がりにトリガを掛けること)
073 red <= {ssw[2]?Hcnt/80:0}[2:0];
074 green <= {ssw[1]?Hcnt/80:0}[2:0];
075 blue <= {ssw[0]?Hcnt/80:0}[2:0];
VsyncとHsyncの関係をオシロスコープで観測せよ. (注意:Vsyncの周期とHsyncの周期,VsyncとHsyncのタイミング関係については必ず報告すること)
同期信号はCRTディスプレイ上を左から右へ,上から下へ走査(移動)した表示点を始点に素早く戻すためのきっかけになる信号である.水平同期信号(Hsync),垂直同期信号(Vsync)はそれぞれ,図7-7,7-8に示すようなタイミングをとる.実際に画面表示に利用される時間は水平方向では80%,垂直方向では92%であり,残りの時間は表示点が始点に帰るためだけに使われる.
VGA出力とUART通信,AIC制御を結合させよう.リスト7-4,7-5をISEで合成させると キーボードからの入力されたアスキーコードをVGAでディスプレイさせ,同時に音階を出力するプログラムを実行できる.
001 `timescale 1ns / 1ps
002 //////////////////////////////////////////////////////////////////////////////////
003 // Create Date: 23:08:53 12/30/2013
004 // Module Name: uart_vga
005 //////////////////////////////////////////////////////////////////////////////////
006 module uart_vga(
007 input wire clk, // 100MHz
008 input wire reset,
009 input wire[2:0] ssw, // slide switch
010 output reg[2:0] red, green, blue, // color signal
011 output reg HS, VS, // Hsync Vsync
012
013 input wire uart_r, // シリアル受信 comx→ATLYS
014 output wire uart_t, // シリアル送信 ATLYS→comx
015
016 input wire aud_bit_clk,
017 output reg aud_sdo,
018 output reg aud_sync,
019 output wire aud_reset,
020 input wire sw7,
021 output wire [7:0] led
022 );
023 parameter HTs = 800; // 実幅
024 parameter HTdisp = 640; // 表示幅
025 parameter HTfp = 16; // フロントポーチ幅
026 parameter HTpw = 96; // HT幅
027
028 parameter VTs = 521; // 実幅
029 parameter VTdisp = 480; // 表示幅
030 parameter VTfp = 10; // フロントポーチ幅
031 parameter VTpw = 2; // VT幅
032
033 reg[9:0] Hcnt=0, Vcnt=0; // 0~HTs-1, 0~VTs-1
034
035 reg[1:0] count=2'd0;
036 wire clk25MHz=count[1];
037
038 always@( posedge clk ) begin // make 25MHz clock
039 count <= count+2'd1;
040 end
041
042 always@( posedge clk25MHz or posedge reset ) begin // Hcnt, Vcnt
043 if( reset==1'b1 )
044 {Hcnt,Vcnt}<=0;
045 else if( Hcnt==HTs-1 )
046 begin
047 Hcnt<=0;
048 if( Vcnt==VTs-1 )
049 Vcnt<=0;
050 else
051 Vcnt <= Vcnt + 10'd1;
052 end
053 else
054 Hcnt <= Hcnt + 10'd1;
055 end
056
057 always@( posedge clk25MHz or posedge reset ) begin // make Hsync
058 if( reset==1'b1 )
059 HS <= 1'b1;
060 else if( Hcnt == HTdisp - 1 + HTfp )
061 HS <= 1'b0;
062 else if( Hcnt == HTdisp - 1 + HTfp + HTpw )
063 HS <= 1'b1;
064 end
065
066
067
068
069
070 always@( posedge clk25MHz or posedge reset ) begin // make Vsync
071 if( reset==1'b1 )
072 VS <= 1'b1;
073 else if( Vcnt == VTdisp - 1 + VTfp )
074 VS <= 1'b0;
075 else if( Vcnt == VTdisp - 1 + VTfp + VTpw )
076 VS <= 1'b1;
077 end
078
079 wire [7:0] data=8'haa;
080 always@( posedge clk25MHz ) begin // make image
081 if( Hcnt < HTdisp && Vcnt < VTdisp )
082 begin
083 if(7-Hcnt/80==ssw[2:0] && Vcnt/80==2)begin
084 {red,green,blue}<=0;
085 end
086 else if( data_r[7-Hcnt/80] && Vcnt/80==3)begin
087 {red,green,blue}<={3'd7,3'd0,3'd0};
088 end
089 else if(7-Hcnt/80==ssw[2:0] && Vcnt/80==4)begin
090 {red,green,blue}<=0;
091 end
092 else begin
093 {red,green,blue}<={3'd7,3'd7,3'd7};
094 end
095 end
096 else
097 { red, green, blue } <= 0;
098 end
099
100
101
102
103 // UART ///////////////////////
104 parameter MAX1=10416; // 9600bpsの1ビットのクロック数
105 parameter MAX2= 5208; // 9600bpsの0.5ビットのクロック数
106
107 assign uart_t = uart_r; // 受信したものをそのまま送信へスルーする
108
109 reg [12:0] cc=13'b0;
110 reg last_r=1'b1;
111 reg reciving=1'b0;
112 reg [4:0] bit_n=5'b0;
113 reg [7:0] data_r=10'b0;
114
115 always @(posedge clk)begin
116 if( reciving )begin
117 if(cc==MAX2-1)begin
118 if(bit_n==18)begin
119 bit_n<=1'b0;
120 reciving<=1'b0;
121 end
122 else begin
123 bit_n<=bit_n+1'b1;
124 if(bit_n>=2 && bit_n<=16 && bit_n[0]==0)begin
125 data_r[bit_n[4:1]-1]<=uart_r;
126 end
127 end
128 cc<=1'b0;
129 end
130 else begin
131 cc<=cc+1'b1;
132 end
133 end
134 else begin
135 if( {last_r,uart_r}==2'b10 )begin
136 reciving <= 1'b1;
137 cc<=1'b0;
138 bit_n<=1'b0;
139 end
140 end
141 last_r <= uart_r;
142 end
143
144
145
146 // 音出力 /////////////////////////
147 reg [7:0] key=1'b0;
148
149 reg [7:0] t=7'd0;
150 assign aud_reset=(!reset);
151 reg[7:0] a_count=8'd255;
152 assign led=c[23:16];
153 reg n_frame=1'b1;
154
155 reg[23:0] c=24'h0;
156 reg signed[19:0] wave=20'h0;
157
158 parameter tag=16'b_1111_1000_0000_0000;
159 parameter[19:0] control[0:3] ={
160 20'h_04_000, 20'h_18_000, 20'h_0000_0, 20'h_0808_0
161 };
162
163 // sine-wave generator (preparation)
164 reg signed[31:0] y0;
165 reg signed[15:0] y1=16'h_03af, y2=16'h_0000;
166 parameter signed[15:0] a1=16'h_7fc9, a2=16'h_c000;
167
168 always @( posedge aud_bit_clk ) begin
169 if( a_count==8'd255 || a_count<8'd14 )
170 aud_sync=1'b1;
171 else
172 aud_sync=1'b0;
173
174 if( a_count<=8'd15)
175 aud_sdo=tag[15-a_count];
176 else if( a_count<=8'd35 )
177 aud_sdo=control[n_frame][35-a_count];
178 else if( a_count <=8'd55 )
179 aud_sdo=control[n_frame][55-a_count];
180 else if(a_count <= 8'd75 )
181 aud_sdo=wave[75-a_count];
182 else if(a_count<=8'd95)
183 aud_sdo=wave[95-a_count];
184 else
185 aud_sdo=1'd0;
186
187 if( a_count==8'd255 )begin
188 // sine-wave ganerator
189 y0= y1*1*a1 + y2*a2;
190 y2 = y1;
191 y1 = { y0[31], y0[28:14]};
192 if(sw7==1'b1)
193 wave = y0[31:12];
194 else begin
195 case( data_r )
196 8'h61: key=8'd109;
197 8'h77: key=8'd102;
198 8'h73: key=8'd97;
199 8'h64: key=8'd91;
200 8'h72: key=8'd86;
201 8'h66: key=8'd81;
202 8'h74: key=8'd77;
203 8'h67: key=8'd72;
204 8'h68: key=8'd68;
205 8'h75: key=8'd64;
206
207 8'h6a: key=8'd61;
208 8'h69: key=8'd57;
209 8'h6b: key=8'd54;
210 8'h6f: key=8'd51;
211 8'h6c: key=8'd48;
212 8'h3b: key=8'd45;
213 8'h40: key=8'd43;
214 8'h3a: key=8'd40;
215 8'h5b: key=8'd38;
216 8'h5d: key=8'd36;
217 default: key=8'd0;
218 endcase
219
220 if(t<key )begin
221 wave = 20'h_f_f000;
222 t=t+1'b1;
223 end
224 else if(t<{key[6:0],1'b0})begin
225 wave = 20'h_0_0fff;
226 t=t+1'b1;
227 end
228 else if(t>={key[6:0],1'b0})begin
229 wave = 20'h_0_0fff;
230 t=0;
231 end
232 end
233
234 n_frame = n_frame+1'b1;
235 end
236
237 a_count = a_count+1'b1;
238 c = c+1'b1;
239 end
240
241
242 endmodule
243
001 // VGA色表示プログラム(*.ucf)
002 // RGB_color.ucf
003 NET clk LOC = L15;
004 NET reset LOC = P3;
005
006 NET red(0) LOC = V15;
007 NET red(1) LOC = V13;
008 NET red(2) LOC = N11;
009
010 NET green(0) LOC = T11;
011 NET green(1) LOC = V12;
012 NET green(2) LOC = P11;
013
014 NET blue(0) LOC = N9;
015 NET blue(1) LOC = V11;
016 NET blue(2) LOC = T10;
017
018 NET HS LOC = V10; // Hsync
019 NET VS LOC = T8; // Vsync
020
021 NET ssw(0) LOC = A10; // sw0
022 NET ssw(1) LOC = D14; // sw1
023 NET ssw(2) LOC = C14; // sw2
024
025 net uart_r loc=A16; // シリアル受信
026 net uart_t loc=B16; // シリアル送信
027
028 net aud_bit_clk loc=L13;
029 net aud_sdo loc=N16;
030 net aud_sync loc=U17;
031 net aud_reset loc=T17;
032
033 net sw7 loc=E4;
034
035 net led(7) loc=N12;
036 net led(6) loc=P16;
037 net led(5) loc=D4;
038 net led(4) loc=M13;
039 net led(3) loc=L14;
040 net led(2) loc=N14;
041 net led(1) loc=M14;
042 net led(0) loc=U18;
043
044
最後に動く画像を作成しよう.リスト7-6,7-7を実行すると字幕が動く電光掲示板を作成できる.文字は完全なビット情報のみで表示しているので,プログラムを解析・改変して,自分の好きな文字を表示させよう.
001 `timescale 1ns / 1ps
002 //////////////////////////////////////////////////////////////////////////////////
003 // Create Date: 18:51:58 12/16/2013
004 // Module Name: vga_denkou
005 module vga_denkou(
006 input wire clk,
007 input wire reset,
008 input wire[2:0] ssw,
009 output reg[2:0] red, green, blue,
010 output reg HS, VS
011 );
012
013 parameter HTs = 800;
014 parameter HTdisp = 640;
015 parameter HTfp =16;
016 parameter HTpw =96;
017
018 parameter VTs =512;
019 parameter VTdisp =480;
020 parameter VTfp=10;
021 parameter VTpw =2;
022
023 reg[9:0] Hcnt=0, Vcnt=0;
024
025 reg[1:0] count=2'd0;
026 wire clk25MHz=count[1];
027
028 always@( posedge clk)begin
029 count <= count+2'd1;
030 end
031
032 always@( posedge clk25MHz or posedge reset ) begin
033 if( reset==1'b1)
034 {Hcnt,Vcnt}<=0;
035 else if( Hcnt==HTs-1)
036 begin
037 Hcnt<=0;
038 if(Vcnt==VTs-1)
039 Vcnt<=0;
040 else
041 Vcnt <= Vcnt + 10'd1;
042 end
043 else
044 Hcnt <= Hcnt + 10'd1;
045 end
046
047 always@( posedge clk25MHz or posedge reset )begin
048 if( reset==1'b1)
049 HS<=1'b1;
050 else if( Hcnt == HTdisp - 1 + HTfp )
051 HS<=1'b0;
052 else if( Hcnt == HTdisp - 1 + HTfp + HTpw )
053 HS<=1'b1;
054 end
055
056
057
058
059
060 always@( posedge clk25MHz or posedge reset ) begin
061 if( reset == 1'b1 )
062 VS<=1'b1;
063 else if(Vcnt == VTdisp - 1 +VTfp )
064 VS <= 1'b0;
065 else if(Vcnt == VTdisp - 1 + VTfp + VTfp + VTpw )
066 VS <= 1'b1;
067 end
068
069 /*
070 always@(posedge clk25MHz ) begin
071 if( Hcnt < HTdisp && Vcnt <VTdisp)
072 begin
073 //red <= ssw[2] ? 3'd7 : 3'd0;
074 //green <= ssw[1] ? 3'd7 : 3'd0;
075 //blue <= ssw[0] ? 3'd7 : 3'd0;
076 red <= {ssw[2] ? Hcnt/80 : 0}[2:0];
077 green <= {ssw[1] ? Hcnt/80 : 0}[2:0];
078 blue <= {ssw[0] ? Hcnt/80 : 0}[2:0];
079 end
080 else
081 {red, green, blue } <= 0;
082 end
083 */
084
085 wire[6:0] xx=Hcnt[9:3];
086 wire[6:0] yy=Vcnt[9:3];
087 reg [7:0] cc=8'd0;
088 always@( posedge clk25MHz )begin
089 if( Hcnt < HTdisp && Vcnt<VTdisp)
090 if( yy>=10 && yy<26 && doro[yy-10][{xx+cc}[7:0]]==1'b1)
091 begin
092 red <= 0;
093 green <=3'b110;
094 blue <= 0;
095 end
096 else
097 begin
098 red <= ssw[2]?{3{!Hcnt[8]}}:3'd0;
099 green <= ssw[1]?{3{!Hcnt[7]}}:3'd0;
100 blue <= ssw[0]?{3{!Hcnt[6]}}:3'd0;
101 end
102 else
103 {red,green,blue}<=0;
104 if(Hcnt==639 && Vcnt==479)cc<=cc+1'b1;
105
106 end
107
108 /*
109 parameter [0:255] doro[0:15]={
110 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
111 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
112 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
113 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
114 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
115 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
116 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
117 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
118 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
119 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
120 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
121 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
122 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
123 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000,
124 256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
125 256'hffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000
126 };
127 */
128 parameter [0:255] doro[0:15]={
129 //256'h0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,
130 256'h00800200080000101040010000000440001808c0000000800000000000000000,
131 256'h0080020008000030304001000000044000f00860000000800000200020002000,
132 256'h008002000818006060fc0100000004403f8018207ffc00800000380038003800,
133 256'h3ffc3fe0780c00c0c48401fe00000446010013fe0060ffff00003e003e003e00,
134 256'h00800200080601806d8c01000000fc5c0100302000c5008000003f803f803f80,
135 256'h00800200180013001b58010000000470010020200185008000003fe03fe03fe0,
136 256'h3ffc3fe010200c0030303ffc00000440010060200100078000003ff83ff83ff8,
137 256'h00800400102018006478200400000440ffffa02003000cc000003ffc3ffc3ffc,
138 256'h0080040030200c00fccc200400000440010023fe0200084000003ff83ff83ff8,
139 256'h00800404202006001387200400000440010020200200084000003fe03fe03fe0,
140 256'h1f8004046020030010702004000004400100202002000c4000003fc03fc03fc0,
141 256'h20e0040403e0018054183ffc00001c4001002020030007c000003f003f003f00,
142 256'h20b8060c043800c05600000000007441010020200180008060003c003c003c00,
143 256'h218c0318046c0060d2e024440000c4630100202000e001809000380038003800,
144 256'h1f0001f003c00030903866660000043e010027ff003803009000200020002000,
145 256'h0000000000000010100cc223000004000100200000000e006000000000000000
146 };
147
148 endmodule
001 // vga_denkou.ucf
002 net "clk" loc=L15;
003 net "reset" loc=P3;
004
005 net "red(0)" loc=V15;
006 net "red(1)" loc=V13;
007 net "red(2)" loc=N11;
008
009 net "green(0)" loc=T11;
010 net "green(1)" loc=V12;
011 net "green(2)" loc=P11;
012
013 net "blue(0)" loc=N9;
014 net "blue(1)" loc=V11;
015 net "blue(2)" loc=T10;
016
017 net "HS" loc=V10;
018 net "VS" loc=T8;
019
020 net "ssw(0)" loc=A10;
021 net "ssw(1)" loc=D14;
022 net "ssw(2)" loc=C14;
023
以上,今回はVGA出力制御でした.
ここまでの知識をまとめて,課題作成・レポート作成に取り組んでください.
7回のFPGA_ATLYS_DESIGNの入門シリーズはこれで終了です.
ssatoh@
足立工科大学 工学部 情報通信工学科