アルテラCyclone III FPGA VGAアダプター

こんにちはHabr-この記事では、Altera Cyclone III FPGAの開発における成功を紹介します 。 ライトとゲームをカウンターで点滅させた後、もっと深刻なことをすることにしました。 最も単純なVGAアダプターを作成しました。 その主要部分について説明します。 この記事は初心者に焦点を当てています。経験豊富な人にとっては、このタスクは難しくありませんが、開発のために、私の意見では-良いトレーニングタスクです。 アルテラDE0デバッグボードで実験を行っています。 水曜日のVerilog -Quartus II v 12.0で回路を説明します。 だから-猫へようこそ:



VGAアダプターのブロック図

まず、VGAの構成要素とそれが何で食べられるかを把握します。

当初、VGAはブラウン管を備えたモニター用に作成されていたため、ここではLCDディスプレイのようなピクセルのマトリックスではなく、画面を走る電子ビームを制御し、適切なタイミングで増幅/弱化または完全にオフにする必要があります。 VGAを使い始めたとき、驚いたことに、この標準を説明する詳細な情報がほとんどないことを知りました-ついでに理解できる-それはすでに時代遅れであり、メーカーはそれを放棄しています。 私の記事が誰かが標準をマスターするのに役立つことを願っています。

VGAに関するWiki記事からの抜粋:

VGA(およびEGA)は、次のメインサブシステムで構成されています(一般的に、「シーケンサー」という語は、ビデオメモリプレーンへのアクセスを制御するためのレジスタセットを指します)。



シンクロナイザーの役割では、デバッグボードに50 MHzジェネレーターが存在します。

プロセッサとのビデオメモリおよびデータ交換はまだ実装しません。代わりに、属性コントローラ用のビットストリームを生成します。

そのため、タスクは次のブロックの実装に分割されます。



  1. シンクロナイザー -50メガヘルツの周波数は私たちにとってあまり便利ではないので、少し変更する必要があります
  2. VGA規格の要件に従って同期信号を発行するCRTコントローラー
  3. 画像ジェネレーター -デバッグに使用します-ブロックは単純な画像を描画し、CRTコントローラーに渡します


シンクロナイザー



まず、英語版のWikiにアクセスして、VGAの信号タイミングを確認します。ここから、クロック周波数は25.175 MHzであることがわかります。



ここに最初のタスクがあります-50 MHz-25.175 MHzから作成します。 この問題については、PLLまたはPLLが役立ちます。

Mega Wizardを使用して、必要な設定でPLLを作成します。 これを行うには、Tools / MegaWizard Plug-InManagerに移動します。 そこで、出力ファイルのタイプを選択し、Verilog HDL I / O ALTPLLを構成します。入力周波数を設定してから変換します。 25.175 MHzの周波数を取得する必要がありますが、乗算と整数による除算しかできません。つまり、数値0.5035を小数に変換する必要があります。 5035を掛けて10000で除算できますが、両方の数を5減らすことができることに注意してください。分数1007/2000が得られます。この場合、ウィザードは必要な係数を利用可能な分数に近づけます。 受信したモジュールをプロジェクトに含め、ボードからのシュレッドをその入力に接続し、出力のためにワイヤーを作成し、それからどこかで開始して、このアイテムの主な目標-25.175 MHzの周波数を取得します。

CRTコントローラー



クロックジェネレーター


先に進みます。 次に、水平および垂直同期タイミングを満たすクロック信号を発行するモジュールを作成する必要があります。つまり、これは水平同期用です。



つまり、データを発行する前に、時間Aの間同期ラインをハイ状態に保持し、次に時間Bの間地面に押し付け、それをハイ状態にして、時間Cだけ待機する必要があります。その後、データフローが発生します-レイは時間Dのラインを通り始めます各ラインの周波数が25.175メガヘルツなどのすべてのピクセルには、この時間を設定する時間が必要です。 垂直同期はほぼ同じように機能し、ピクセルを使用する代わりにラインを送信し、クロックの1周期でフレーム全体を描画します。

タスクは決定されました-おそらくリセット信号を追加する入力から、VGA_CLK周波数を入力として上記のシーケンスを実装するブロックを作成します。 このようなブロックの実装は単純ではありませんが、非常に単純です。

1 / VGA_CLK = 0.03972194637537239324726911618669マイクロ秒の周期では、Aで24サイクル、Bで95サイクル、Cで48サイクル、Dで640サイクルが必要です。また、水平同期信号の立ち上がりエッジでは、すべての遅延を線画の期間で考慮することができます。 さらに、画面上に「アイドル」領域があります。これは実際の画面です。画面は目盛りがわずかに大きく、可視領域にのみ描画する必要があります。したがって、モジュールが光線の現在の座標を通知し、各ピクセルを割り当てる場合でも、いくつかの色-あなたはビームの現在の位置を知らずにはできません。

同期モジュール
module VGA_SYNC( input CLK, input SYNC_RST_N, output reg H_SYNC_CLK, output reg V_SYNC_CLK, output wire [10:0]oCurrent_X, output wire [10:0]oCurrent_Y, output reg oSYNC_COLOR); parameter A_TIME_H = 24; parameter B_TIME_H = 95; parameter C_TIME_H = 48; parameter D_TIME_H = 640; parameter TOTAL_TIME_H = A_TIME_H + B_TIME_H + C_TIME_H + D_TIME_H; parameter BLANK_H = A_TIME_H + B_TIME_H + C_TIME_H; parameter A_TIME_V = 10; parameter B_TIME_V = 2; parameter C_TIME_V = 33; parameter D_TIME_V = 480; parameter TOTAL_TIME_V = A_TIME_V + B_TIME_V + C_TIME_V + D_TIME_V; parameter BLANK_V = A_TIME_V + B_TIME_V + C_TIME_V; reg [10:0]H_Counter; reg [10:0]V_Counter; assign oCurrent_X = (H_Counter >= BLANK_H) ? H_Counter-BLANK_H : 11'h0 ; assign oCurrent_Y = (V_Counter >= BLANK_V) ? V_Counter-BLANK_V : 11'h0 ; always@(posedge(CLK) or negedge(SYNC_RST_N)) begin if(!SYNC_RST_N) begin H_Counter <= 1'b0; H_SYNC_CLK <= 1'b1; end else begin if(H_Counter < (TOTAL_TIME_H-1)) H_Counter <= H_Counter + 1'b1; else begin H_Counter <= 1'b0; oSYNC_COLOR <= 1'b0; end if(H_Counter == A_TIME_H-1) H_SYNC_CLK <= 1'b0; if(H_Counter == A_TIME_H + B_TIME_H-1) H_SYNC_CLK <= 1'b1; if(H_Counter == BLANK_H) oSYNC_COLOR <= 1'b1; end end always@(posedge(H_SYNC_CLK) or negedge(SYNC_RST_N)) begin if(!SYNC_RST_N) begin V_Counter <= 1'b0; V_SYNC_CLK <= 1'b1; end else begin if(V_Counter < (TOTAL_TIME_V-1)) V_Counter <= V_Counter + 1'b1; else V_Counter <= 1'b0; if(V_Counter == A_TIME_V-1) V_SYNC_CLK <= 1'b0; if(V_Counter == A_TIME_V + B_TIME_V-1) V_SYNC_CLK <= 1'b1; end end endmodule
      
      





出力モジュール


実際には、パルスが生成され、ポイントの座標が既知であり、時間内に目的の色をオンにするだけで、光線はラインを通過します-このために、同期信号、周波数25.175 MHz、3つのカラーバスと座標を受信するモジュールを作成し、出力は4ビットR-2Rです各色のDAC、さらに-VGAコネクタ

出力モジュール
 module VGA_OUT(RESET, SYNC_COLOR, VGA_CLK, oVGA_R, oVGA_G, oVGA_B, iVGA_R, iVGA_G, iVGA_B, Current_X, Current_Y); input wire VGA_CLK; input wire RESET; input wire SYNC_COLOR; input wire [10:0]Current_X; input wire [10:0]Current_Y; input wire [3:0]iVGA_R; input wire [3:0]iVGA_G; input wire [3:0]iVGA_B; output reg [3:0]oVGA_R; output reg [3:0]oVGA_G; output reg [3:0]oVGA_B; always@(posedge VGA_CLK or negedge RESET) begin if(!RESET) begin oVGA_R <= 0; oVGA_G <= 0; oVGA_B <= 0; end else begin oVGA_R <= ((SYNC_COLOR == 1)&&(Current_X > 0)&&(Current_Y > 0)) ? iVGA_R : 0; oVGA_G <= ((SYNC_COLOR == 1)&&(Current_X > 0)&&(Current_Y > 0)) ? iVGA_G : 0; oVGA_B <= ((SYNC_COLOR == 1)&&(Current_X > 0)&&(Current_Y > 0)) ? iVGA_B : 0; end end endmodule
      
      





システムをテストするには-何らかの画像を生成します-このブロックは私には説明されていません。Alterのexterovsから取得しました。一般に、対処するものは何もありません-このモジュールの画像のみが必要です

ビストリム生成モジュール
 module VGA_BITSTREAM ( // Read Out Side oRed, oGreen, oBlue, iVGA_X, iVGA_Y, iVGA_CLK, // Control Signals iRST_n, iColor_SW ); // Read Out Side output reg [9:0] oRed; output reg [9:0] oGreen; output reg [9:0] oBlue; input [9:0] iVGA_X; input [9:0] iVGA_Y; input iVGA_CLK; // Control Signals input iRST_n; input iColor_SW; always@(posedge iVGA_CLK or negedge iRST_n) begin if(!iRST_n) begin oRed <= 0; oGreen <= 0; oBlue <= 0; end else begin if(iColor_SW == 1) begin if (iVGA_Y<120) begin oRed <= (iVGA_X<40) ? 0 : (iVGA_X>=40 && iVGA_X<80) ? 1 : (iVGA_X>=80 && iVGA_X<120) ? 2 : (iVGA_X>=120 && iVGA_X<160) ? 3 : (iVGA_X>=160 && iVGA_X<200) ? 4 : (iVGA_X>=200 && iVGA_X<240) ? 5 : (iVGA_X>=240 && iVGA_X<280) ? 6 : (iVGA_X>=280 && iVGA_X<320) ? 7 : (iVGA_X>=320 && iVGA_X<360) ? 8 : (iVGA_X>=360 && iVGA_X<400) ? 9 : (iVGA_X>=400 && iVGA_X<440) ? 10 : (iVGA_X>=440 && iVGA_X<480 ) ? 11 : (iVGA_X>=480 && iVGA_X<520 ) ? 12 : (iVGA_X>=520 && iVGA_X<560 ) ? 13 : (iVGA_X>=560 && iVGA_X<600 ) ? 14 : 15 ; oGreen <= 0; oBlue <= 0; end else if (iVGA_Y>=120 && iVGA_Y<240) begin oRed <= 0; oGreen <= (iVGA_X<40) ? 15 : (iVGA_X>=40 && iVGA_X<80) ? 14 : (iVGA_X>=80 && iVGA_X<120) ? 13 : (iVGA_X>=120 && iVGA_X<160) ? 12 : (iVGA_X>=160 && iVGA_X<200) ? 11 : (iVGA_X>=200 && iVGA_X<240) ? 10 : (iVGA_X>=240 && iVGA_X<280) ? 9 : (iVGA_X>=280 && iVGA_X<320) ? 8 : (iVGA_X>=320 && iVGA_X<360) ? 7 : (iVGA_X>=360 && iVGA_X<400) ? 6 : (iVGA_X>=400 && iVGA_X<440) ? 5 : (iVGA_X>=440 && iVGA_X<480 ) ? 4 : (iVGA_X>=480 && iVGA_X<520 ) ? 3 : (iVGA_X>=520 && iVGA_X<560 ) ? 2 : (iVGA_X>=560 && iVGA_X<600 ) ? 1 : 0 ; oBlue <= 0; end else if (iVGA_Y>=240 && iVGA_Y<360) begin oRed <= 0; oGreen <= 0; oBlue <= (iVGA_X<40) ? 0 : (iVGA_X>=40 && iVGA_X<80) ? 1 : (iVGA_X>=80 && iVGA_X<120) ? 2 : (iVGA_X>=120 && iVGA_X<160) ? 3 : (iVGA_X>=160 && iVGA_X<200) ? 4 : (iVGA_X>=200 && iVGA_X<240) ? 5 : (iVGA_X>=240 && iVGA_X<280) ? 6 : (iVGA_X>=280 && iVGA_X<320) ? 7 : (iVGA_X>=320 && iVGA_X<360) ? 8 : (iVGA_X>=360 && iVGA_X<400) ? 9 : (iVGA_X>=400 && iVGA_X<440) ? 10 : (iVGA_X>=440 && iVGA_X<480 ) ? 11 : (iVGA_X>=480 && iVGA_X<520 ) ? 12 : (iVGA_X>=520 && iVGA_X<560 ) ? 13 : (iVGA_X>=560 && iVGA_X<600 ) ? 14 : 15 ; end else begin oRed <= (iVGA_X<40) ? 15 : (iVGA_X>=40 && iVGA_X<80) ? 14 : (iVGA_X>=80 && iVGA_X<120) ? 13 : (iVGA_X>=120 && iVGA_X<160) ? 12 : (iVGA_X>=160 && iVGA_X<200) ? 11 : (iVGA_X>=200 && iVGA_X<240) ? 10 : (iVGA_X>=240 && iVGA_X<280) ? 9 : (iVGA_X>=280 && iVGA_X<320) ? 8 : (iVGA_X>=320 && iVGA_X<360) ? 7 : (iVGA_X>=360 && iVGA_X<400) ? 6 : (iVGA_X>=400 && iVGA_X<440) ? 5 : (iVGA_X>=440 && iVGA_X<480 ) ? 4 : (iVGA_X>=480 && iVGA_X<520 ) ? 3 : (iVGA_X>=520 && iVGA_X<560 ) ? 2 : (iVGA_X>=560 && iVGA_X<600 ) ? 1 : 0 ; oGreen <= (iVGA_X<40) ? 15 : (iVGA_X>=40 && iVGA_X<80) ? 14 : (iVGA_X>=80 && iVGA_X<120) ? 13 : (iVGA_X>=120 && iVGA_X<160) ? 12 : (iVGA_X>=160 && iVGA_X<200) ? 11 : (iVGA_X>=200 && iVGA_X<240) ? 10 : (iVGA_X>=240 && iVGA_X<280) ? 9 : (iVGA_X>=280 && iVGA_X<320) ? 8 : (iVGA_X>=320 && iVGA_X<360) ? 7 : (iVGA_X>=360 && iVGA_X<400) ? 6 : (iVGA_X>=400 && iVGA_X<440) ? 5 : (iVGA_X>=440 && iVGA_X<480 ) ? 4 : (iVGA_X>=480 && iVGA_X<520 ) ? 3 : (iVGA_X>=520 && iVGA_X<560 ) ? 2 : (iVGA_X>=560 && iVGA_X<600 ) ? 1 : 0 ; oBlue <= (iVGA_X<40) ? 15 : (iVGA_X>=40 && iVGA_X<80) ? 14 : (iVGA_X>=80 && iVGA_X<120) ? 13 : (iVGA_X>=120 && iVGA_X<160) ? 12 : (iVGA_X>=160 && iVGA_X<200) ? 11 : (iVGA_X>=200 && iVGA_X<240) ? 10 : (iVGA_X>=240 && iVGA_X<280) ? 9 : (iVGA_X>=280 && iVGA_X<320) ? 8 : (iVGA_X>=320 && iVGA_X<360) ? 7 : (iVGA_X>=360 && iVGA_X<400) ? 6 : (iVGA_X>=400 && iVGA_X<440) ? 5 : (iVGA_X>=440 && iVGA_X<480 ) ? 4 : (iVGA_X>=480 && iVGA_X<520 ) ? 3 : (iVGA_X>=520 && iVGA_X<560 ) ? 2 : (iVGA_X>=560 && iVGA_X<600 ) ? 1 : 0 ; end end else begin oRed <= (iVGA_Y<120) ? 3 : (iVGA_Y>=120 && iVGA_Y<240) ? 7 : (iVGA_Y>=240 && iVGA_Y<360) ? 11 : 15 ; oGreen <= (iVGA_X<80) ? 1 : (iVGA_X>=80 && iVGA_X<160) ? 3 : (iVGA_X>=160 && iVGA_X<240) ? 5 : (iVGA_X>=240 && iVGA_X<320) ? 7 : (iVGA_X>=320 && iVGA_X<400) ? 9 : (iVGA_X>=400 && iVGA_X<480) ? 11 : (iVGA_X>=480 && iVGA_X<560) ? 13 : 15 ; oBlue <= (iVGA_Y<60) ? 15 : (iVGA_Y>=60 && iVGA_Y<120) ? 13 : (iVGA_Y>=120 && iVGA_Y<180) ? 11 : (iVGA_Y>=180 && iVGA_Y<240) ? 9 : (iVGA_Y>=240 && iVGA_Y<300) ? 7 : (iVGA_Y>=300 && iVGA_Y<360) ? 5 : (iVGA_Y>=360 && iVGA_Y<420) ? 3 : 1 ; end end end endmodule
      
      





メインモジュール
 module VGA_MAIN(CLOCK_50, KEY, LEDG, VGA_HS, VGA_VS, VGA_R, VGA_G, VGA_B, SW ); input CLOCK_50; input [2:0]KEY; input [9:0]SW; output [9:0]LEDG; output VGA_HS; // VGA H_SYNC output VGA_VS; // VGA V_SYNC output [3:0] VGA_R; // VGA Red[3:0] output [3:0] VGA_G; // VGA Green[3:0] output [3:0] VGA_B; // VGA Blue[3:0] wire VGA_CLK; wire H_SYNC_CLK; wire V_SYNC_CLK; wire RESET; wire [10:0]Current_X; wire [10:0]Current_Y; wire SYNC_COLOR; reg [3:0] iVGA_R; reg [3:0] iVGA_G; reg [3:0] iVGA_B; wire [3:0] irVGA_R; wire [3:0] irVGA_G; wire [3:0] irVGA_B; assign irVGA_R[3:0] = iVGA_R[3:0]; assign irVGA_G[3:0] = iVGA_G[3:0]; assign irVGA_B[3:0] = iVGA_B[3:0]; assign RESET = KEY[0]; assign VGA_HS = H_SYNC_CLK; assign VGA_VS = V_SYNC_CLK; VGA_PLL u1 ( .inclk0(CLOCK_50), .c0(VGA_CLK) ); VGA_SYNC u2 ( .CLK(VGA_CLK), .H_SYNC_CLK(H_SYNC_CLK), .V_SYNC_CLK(V_SYNC_CLK), .SYNC_RST_N(KEY[0]), .oCurrent_X(Current_X), .oCurrent_Y(Current_Y), .oSYNC_COLOR(SYNC_COLOR)); VGA_OUT u3 ( .oVGA_R(VGA_R[3:0]), .oVGA_G(VGA_G[3:0]), .oVGA_B(VGA_B[3:0]), .iVGA_R(iVGA_R[3:0]), .iVGA_G(iVGA_G[3:0]), .iVGA_B(iVGA_B[3:0]), .VGA_CLK(VGA_CLK), .Current_X(Current_X), .Current_Y(Current_Y), .SYNC_COLOR(SYNC_COLOR), .RESET(RESET) ); VGA_BITSTREAM u4(.oRed(irVGA_R), .oGreen(irVGA_G), .oBlue(irVGA_B), .iVGA_X(Current_X), .iVGA_Y(Current_Y), .iVGA_CLK(VGA_CLK), .iRST_n(RESET), .iColor_SW(SW[0])); endmodule
      
      





ここにそのような構造図があります:





さて、ビデオは動作します:





一般に、ビデオカードを作成する最初の手順が完了しました。ビデオメモリを接続し、すべてを外部コントローラー(STM32など)に接続することが残ります。 将来的には、コントローラーでビデオストリームを生成し、それをビデオアダプターに送信して、画面に表示するようにします。 もちろん、このすべての実際的な意味について話す価値はありません-物事はすでに時代遅れでかなり原始的であり、すべてはトレーニングとスキルの強化を目的としてのみ行われました。ここで私は確かにそれに遭遇しましたので、質問、アドバイス、コメントがあればコメントを書いてください



All Articles