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驅動建模
PLL是FPGA的重要硬件資源,PLL主要功能是對源時鍾編程,翻頻,分頻。
同步模塊實現對列填充信號與行掃描信號的控制,同時輸出當前的地址(Column_Addr_Sig,Row_Addr_Sig)和有效區域信號(Ready_Sig)。
同步模塊的輸入只有CLK和RSTn信號,不需要外部輸入其它信號,在模塊里面編寫一系列的驅動模型,並輸出驅動信號。
首先,寫一個列計數器與一個行計數器:
注意:時鍾頻率經過PLL倍頻后,時鍾周期達到了25ns,對比列計數器與行計數器的寫法,列計數器是每來一個時鍾上升沿,計數增加1,即每隔25ns,計數增加1。而行計數器,是當列填充完畢后(if(Count_H == 11’d1056)),計數增加1。這就解決了我剛才發現行掃描與列掃描不匹配的疑惑。
有效區域信號的產生:
根據有效區域產生有效區域信號(Ready_Sig)
首先定義了一個名為isRectangle的標志寄存器(有0和1兩種狀態),用來划定顯示區域,即(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(行地址)信號。
(3)VGA顯示控制模塊中,需要接收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操作的時候,加的是“1’b1”,即二進制加法運算,因為起先我們定義的是 reg [10:0]count_V 位寬為11。
還有,並不是所有更高時鍾的頻率就能向下兼容。
5.拓展二(點陣顯示)
點陣編碼的方式是:逐行顯示,高位在前。
逐行顯示:表示圖像是逐行填充,完成完一行的填充后,再填充下一行。
高位在前:列填充從左往右填充,但最左邊是列像素的最高位。即:
以上為一個16個列像素,它的編碼為0xf738。
在點陣顯示模型中,需要有圖片ROM,存儲圖片(點陣)信息,VGA控制模塊需要給出點陣地址,並讀取點陣數據,點陣的數據是一行一行讀取的,因此,每次從圖片ROM模塊中取一行的數據。
以下為部分VGA顯示控制的代碼,寄存器m存儲的是同步掃描模塊傳過來的行地址,n存儲的是同步掃描模塊傳過來的列地址。
行地址直接傳給圖片ROM模塊,圖片ROM模塊接收到行地址后,給出相應行的像素信息ROM_Data,VGA控制模塊根據傳來的行像素信息,填充相應的顏色。
解釋:
Red_Sig = Ready_Sig ? Rom_Data[6’d63 - n] : 1’b0;
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,圖片ROM(red),圖片ROM(green),圖片ROM(blue)給出對應行的數據。
體會:對於圖片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 == 11’d628) ? 1’b1 : 1’b0;
Frame_Sig並沒有在always塊語句中做處理,只是需要使用已經經過處理的信號,做出判斷就可以得出准確的Frame_Sig(也算是一種算法吧)。
在VGA顯示控制模塊中,定義了一個FRAME常量,和一個Count_Frame計數器,每當Frame_Sig高電平時,計數器加1,計數周期為60個,表明,每張圖片需要顯示60次。
以上always塊語句的作用是一個圖片翻頁模塊,自帶狀態機與處理功能。初始化狀態為i = 0,rAddr = 0,表示顯示第一張圖片。
對比以前實驗的寫法:狀態機與處理分開寫。
不同點:狀態跳變條件與需要處理的動作條件相同,即狀態跳變時刻,應當有一個響應對應狀態的變化。本實驗的狀態變化不是一個完整的回路。分析本實驗case里面的語句,實質上還是一個查表的思想,當條件Count_Frame == FRAME;條件滿足時,狀態發生跳變,而沒有做出相應的響應。而rAddr <= 7’d0,是當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結構,集中包含了狀態機。