Verilog HDL那些事_建模篇筆記(實驗九:VGA驅動)


1.了解VGA協議

    VGA協議有5個輸入信號,列同步信號(HSYNC Signal),行同步信號(VSYNC Signal),紅--藍,顏色信號(RGB Signal)。

一幀屏幕的顯示是由行從上至下掃描,列從左至右填充。

    以800x600x60Hz為例:

    對於列填充信號:a是拉低的128個列像素,b是拉高的88個列像素,c是拉高的800個列像素,d是拉高的40個列像素。

    對於行掃描信號:o是拉低的4個行像素,p是拉高的23個行像素,q是拉高的600個行像素,r是拉高的1個行像素。

    其中,橘色為有效顯示區域

    一個行像素是以列像素為單位來定義的:

    1個行像素 = 1056個列像素 (即1行中有1056個像素需要填充)

    一個列像素是以時間單位來定義的:

    1個列像素 = 25ns

2.VGA驅動建模

     PLLFPGA的重要硬件資源,PLL主要功能是對源時鍾編程,翻頻,分頻。

     同步模塊實現對列填充信號與行掃描信號的控制,同時輸出當前的地址(Column_Addr_SigRow_Addr_Sig)和有效區域信號(Ready_Sig)。

 

    同步模塊的輸入只有CLKRSTn信號,不需要外部輸入其它信號,在模塊里面編寫一系列的驅動模型,並輸出驅動信號。

    首先,寫一個列計數器與一個行計數器:

    注意:時鍾頻率經過PLL倍頻后,時鍾周期達到了25ns,對比列計數器與行計數器的寫法,列計數器是每來一個時鍾上升沿,計數增加1,即每隔25ns,計數增加1。而行計數器,是當列填充完畢后(if(Count_H == 11d1056),計數增加1。這就解決了我剛才發現行掃描與列掃描不匹配的疑惑。

    有效區域信號的產生:

    根據有效區域產生有效區域信號(Ready_Sig

    首先定義了一個名為isRectangle的標志寄存器(有01兩種狀態),用來划定顯示區域,即(Column_Addr_Sig>11’d0  && Row_Addr_Sig < 11’d100)當掃描到以上區域時,顯示相應的顏色,其它區域則不顯示。

3.總體描述

    (1)整個系統由PLL模塊將外部時鍾倍頻,得到同步掃描與填充模塊與VGA顯示控制模塊所需要的時鍾。

    (2)同步掃描模塊接收經過倍頻后的時鍾信號后,通過內部編寫的行掃描計數器與列填充計數器來工作,通過編寫Ready_Sig狀態標志寄存器相關塊語句(掃描到有效區域后置1,不在有效區域則置0),同時結合isReady與行掃描計數器,列掃描計數器,計算出Column_Addr_Sig(列地址)Row_Addr_Sig(行地址)信號。

     (3VGA顯示控制模塊中,需要接收Ready_Sig(有效區域信號),列地址,行地址信號。然后在相應的位置填充顏色。同時,我們也可以在有效區域內,自己划定顯示區域(通過自定義狀態標志寄存器和划定行地址與列地址的范圍),並填充相應的顏色。

4.拓展一(向下兼容的概念)

    640x480x60Hz的顯示標准需要的時鍾頻率是25.175MHz,即填充1個列像素需要的時間是39.7ns。則可以用更高的源時鍾求得39.7ns的定時。引出向下兼容的處理方法:將外部20MHz時鍾源翻倍至100MHz,即1個時鍾周期為10ns,因此可以用4個時鍾周期40ns的時間來滿足填充1個列像素所需要的時間。

 

//40ns_Count,main_source = 10ns 
parameter T40NS = 3'd3;
reg [2:0]count1;
always@(posedge CLK or negedge RSTn)
    if(!RSTn)
        count1 <= 3'd0;
    else if(count1 == T40NS)
        count1 <= 3'd0;
    else
        count1 <= count1 + 1'b1;    
reg [10:0]count_H;    
always@(posedge CLK or negedge RSTn)
    if(!RSTn)
        count_H <= 11'd0;
    else if(count_H == 11'd800)
        count_H <= 11'd0;
    else if(count1 == T40NS)
        count_H <= count_H + 1'b1;
reg [10:0]count_V;
always@(posedge CLK or negedge RSTn)
    if(!RSTn)
        count_V <= 11'd0;
    else if(count_V == 11'd625)
        count_V <= 11'd0;
    else if(count_H == 11'd800)
        count_V <= count_V + 1'b1; 

    在寫代碼的過程中,需要注意的是寄存器的位寬要定義好,在使用數據的時候也需要帶上。計數器在進行加1操作的時候,加的是“1b1”,即二進制加法運算,因為起先我們定義的是 reg [10:0]count_V 位寬為11

    還有,並不是所有更高時鍾的頻率就能向下兼容。

5.拓展二(點陣顯示)

    點陣編碼的方式是:逐行顯示,高位在前。

    逐行顯示:表示圖像是逐行填充,完成完一行的填充后,再填充下一行。

    高位在前:列填充從左往右填充,但最左邊是列像素的最高位。即:

    以上為一個16個列像素,它的編碼為0xf738

    在點陣顯示模型中,需要有圖片ROM,存儲圖片(點陣)信息,VGA控制模塊需要給出點陣地址,並讀取點陣數據,點陣的數據是一行一行讀取的,因此,每次從圖片ROM模塊中取一行的數據。

    以下為部分VGA顯示控制的代碼,寄存器m存儲的是同步掃描模塊傳過來的行地址,n存儲的是同步掃描模塊傳過來的列地址。

    行地址直接傳給圖片ROM模塊,圖片ROM模塊接收到行地址后,給出相應行的像素信息ROM_DataVGA控制模塊根據傳來的行像素信息,填充相應的顏色。

解釋:

    Red_Sig = Ready_Sig ? Rom_Data[6d63 - n] : 1b0;

    VGA掃描控制模塊接收到列地址后,讀取Rom_Data中相應的列數據,即當n=0時,應該讀取第0列的數據,即Rom_Data[63] 為第0列數據,符合高位在前的原則。

    給出圖片ROM模塊的實例化代碼:

Wire [63:0] Rom_Data;
Rom_module U3
(
.clock(CLK_40MHz);
.address(Rom_Addr);
.q(Rom_Data)
);

6.拓展三(圖層顯示建模)

    關於圖層顯示的概論理解如下:

    黃色是由紅色圖層與綠色圖層疊加得到。

    黑色是由紅色圖層,綠色圖層和藍色圖層得到。

    如若顯示以下4個列像素的信息:

    此表應該豎着和橫着同時看,第1個列像素為紅色,則圖層顯示碼為:(第四位)紅色層:1,綠色層:0,藍色層:0;第2個列像素為黃色,則圖層顯示碼為:(第三位)紅色層:1,綠色層:1,藍色層:0

    紅色層:4’b1101

    綠色層:4’b0101

    藍色層:4’b0001

    在顯示控制模塊中,只需要將相同的行,相同的列,不同的層信息發送到相關的輸出信號。

    VGA控制模塊給出行信號Rom_Addr,圖片ROMred,圖片ROMgreen,圖片ROMblue)給出對應行的數據。

    體會:對於圖片ROM模塊,需要同步時鍾,不需要復位信號處理,里面應該事先存儲好圖片的數據信息,等待VGA顯示控制模塊來讀取。

    圖層的概念,就是通過使用不同顏色疊加,來產生我們需要的顏色。

7.拓展四(幀的概念)

    在VGA顯示標准中,如:800x600x60Hz,最后的“60Hz,表示顯示標准,意味着在1s內可以顯示60幀圖像。

    60Hz的來歷:1個行像素為1056個列像素,一個列像素需要25ns,1幀的圖像需要628*1056*25ns的時間,則1s內顯示(1/(628*1056*25ns) = 60)幀圖片。

    顯示動態圖片的時候,對於圖片ROM模塊怎樣存放圖片的點陣信息,我們需要做如下處理:

    假設每張圖片都是16x16x1Bit,共有6張圖片。則,一張圖片有16行,16列,保持這6張圖片列對齊,0~15行放置第一張圖片,16~31行放置第二張圖片.....以此類推。

    等待顯示完第一張圖片后,再顯示第二張圖片,怎樣判斷一幀圖片是否顯示完全呢?需要同步掃描填充模塊輸出一個顯示完成信號(Frame_Sig,)。

assign  Frame_Sig  =  (Count_V == 11d628)  ?  1b1  :  1b0;

    Frame_Sig並沒有在always塊語句中做處理,只是需要使用已經經過處理的信號,做出判斷就可以得出准確的Frame_Sig(也算是一種算法吧)

 

    在VGA顯示控制模塊中,定義了一個FRAME常量,和一個Count_Frame計數器,每當Frame_Sig高電平時,計數器加1,計數周期為60個,表明,每張圖片需要顯示60次。

   以上always塊語句的作用是一個圖片翻頁模塊,自帶狀態機與處理功能。初始化狀態為i = 0,rAddr = 0,表示顯示第一張圖片。

    對比以前實驗的寫法:狀態機與處理分開寫。

     不同點:狀態跳變條件與需要處理的動作條件相同,即狀態跳變時刻,應當有一個響應對應狀態的變化。本實驗的狀態變化不是一個完整的回路。分析本實驗case里面的語句,實質上還是一個查表的思想,當條件Count_Frame == FRAME;條件滿足時,狀態發生跳變,而沒有做出相應的響應。而rAddr <= 7d0,是當Count_Frame == FRAME;這一條件不滿足時,做出的響應。

    額外體會:本實驗中的case/endcase模塊中:

4’d0:

If( Count_Frame == FRAME ) i <= 4’d1;

else rAddr <= 7’d0;

    之所以兩條語句不分開寫(狀態機與響應分開的形式),還有一部分原因是里面是一個if/else條件判斷語句,兩條語句只執行其中的一條,並不是都會執行。

assign Rom_Addr = rAddr + m;

    rAddr表示為顯示第幾張圖片,即ROW的區域。

    m表示行偏移量,從同步掃描填充模塊獲得。

    總結:

    對於動態圖片的顯示(多張圖片)形成的動畫,在同步行掃描,列填充的模塊中,需要對一副圖畫掃描完成與否做出處理,最后提供一個掃描完成信號。

    在VGA顯示控制模塊中,首先要划定顯示區域,根據行與列掃描地址(確定一個顯示范圍)。如果對同一副圖片掃描次數有要求,則需要用到Frame_Sig掃描完成信號,設定一個計數器,記錄掃描完成信號產生的次數。在設定不同圖片行地址時,使用了case/endcase結構,集中包含了狀態機。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM