1. 程式人生 > >【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗二十六:VGA模組

【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗二十六:VGA模組

實驗二十六:VGA模組

VGA這傢伙也算孽緣之一,從《建模篇》那時候開始便一路纏著筆者。《建模篇》之際,學習主要針對畫素,幀,顏色等VGA的簡單概念。《時序篇》之際,筆者便開始摸索VGA的時序。《整合篇》之際,筆者嘗試控制VGA的時序。如今《驅動篇I》的內容返回VGA的本題,也就是影象方面的故事。

此刻,澎湃之情不容怠慢,請怒筆者不再回憶往事,失憶者請複習《Verilog HDL那些事兒》,筆者雖然也想直奔主題 ... 可是在此之前,筆者必須補足那些不易注意的細節

。俗語有云,細節是關鍵的藏身之地,那些不起眼的小細節,往往都是左右大局的關鍵,學習也是如此。不過,實驗二十六究竟存在多少影響成敗的小細節呢?請豎起耳朵,讓筆者慢慢告訴讀者 ...

clip_image002

圖26.1 C1計數的理想時序。

圖26.1是一段計數時序,C1扮演計數器,而且時序理想。對此,這段時序一定按照“時間點”在表現。假設筆者想要建立判斷,那麼判斷基準會基於C1的過去值,例如:

if( C1 == 0 );

那麼if( C1 == 0 ) 必須在T1才能成立。再假設筆者想要拉長判斷的長度,例如T0~T8之間,那麼筆者可以這樣寫:

if( C1 == 0 || C1 == 1 || C1 == 2 || C1 == 3 || C1 == 4 || C1 == 5 || C1 == 6 || C1 == 7 );

如果長度像媽媽一樣長氣,例如T2~T99。當然,上述方法一定行不通,因為後果不僅累壞自己,而且模組的內容也會沉長臃腫。為此,筆者可以或者這樣寫:

if(C1 >= 0 && C1 <= 7);

其中,if( C1 >= 0 && C1 <= 7 ) 表示9個時鐘沿的長度。

clip_image004

圖26.2 長度有AB之別的計數時序。

假設某某長度是固定的傢伙,例如圖26.2,T0~T3組成4個時鐘沿的長度A,而

T3~T8組成5個時鐘沿的長度B。為了方便,筆者可以建立常量:

parameter A = 3, B = 5;

如果筆者想把長度A作為有效的判斷基準,那麼筆者可以這樣寫:

if( C1 >= 0 && C1 <= A -1 );

程式碼的用意非常明顯,C1 >= 0表示長度的起始,然而 C1 <= A -1 則是長度的結束。

如果長度B也作為判斷的基準,同樣的寫法也適用:

if( C1 >= 2 && C1 <= A + B -1 );

可是,不管怎麼看 ... 筆者覺得 C1 >= 2 非常彆扭,對此筆者可以這樣修改:

if( C1 >= A -1 && C1 < A + B -1 );

怎麼樣,讀者是不是稍微順眼一點?

clip_image006

圖26.3 長度有CDE之別的計數時序。

假設頑皮的長度作出手勢,然後分身成為3個,結果如圖26.3所示。T0~T1組成3個時鐘沿的長度C,T2~T6組成5個時鐘沿的長度D,T6~T8組成3個時鐘沿的長度E。為了方便,筆者先做常量宣告:

parameter C = 2, D = 4, E = 2。

如果筆者想把長度C作為判斷的基準,那麼筆者可以這樣寫:

if( C1 >= 0 && C1 <= C -1 );

如果筆者想把長度D作為判斷的基準,那麼筆者可以這樣寫:

if( C1 >= C -1 && C1 <= C + D -1 );

如果筆者想把長度E作為判斷的基準,那麼筆者可以這樣寫:

if( C1 >= C + D -1 && C1 <= C + D + E -1 );

理解完畢以後,筆者可以這樣總結 ... 由於C1從0開始計數,除非長度的起始地方是從0開始,否則長度的起始地方必須新增 -1 的處理。反之,不管結束地方怎麼歇斯底里抵抗,長度的結束地方都必須加上 -1 處理。

clip_image008

圖26.4 VGA時序。

圖26.4是典型的VGA時序,VGA有5條訊號,其中 HSYNC 與 VSYNC 控制顯示解析度還有顯示幀。本實驗的顯示標準選為 1024 × 768 @ 60Hz - 65Mhz,而表26.1就是該顯示標準的內容:

表26.1 顯示標準 1024 × 768 @ 60Hz - 65Mhz。

訊號

A

B

C

D

E

VGA_HSYNC

136

160

1024

24

1344

訊號

O

P

Q

R

S

VGA_VSYNC

6

29

768

3

806

如表26.1所示,A段與O段都是拉低的起始段,然後B段與P段是準備段,C段與Q段是資料段,D段與R段都是結束段,至於E段是ABCD段的總和,S段則是OPRQ段的總和。HSYNC有時候也稱為列畫素或者X,VSYNC則稱為行畫素或者Y。列畫素最小的週期時間(或稱畫素時鐘 Pixel Clock)是 1/65Mhz,行畫素最小的週期時間則是 E段 × 1/65Mhz。話題繼續之前,筆者再稍微補充一下細節內容。

clip_image010

圖26.5 計數例子。

我們先假設 HSYNC長度有8,前3個為拉低的起始段,後8個為拉高的資料段。如圖26.5所示,C1總共計數兩次,分別是T0~T8還有T8~T16。期間,第一次是無效的計數,所以HSYNC並沒有拉低起始段。換之,第二次開始才是有效的計數,因為HSYNC拉低起始段。為此,Verilog可以這樣描述:

if( C1 == 7 ) HSYNC <= 1’b0;

else if( C1 == 2 ) HSYNC <= 1’b1;

假設起始段宣告為A,而結束段宣告為D,E則是A與D的總和,那麼內容可以繼續修改:

parameter A = 3, D = 5, E = 8;

if( C1 == E -1 ) HSYNC <= 1’b0;

else if( C1 == A -1 ) HSYNC <= 1’b1;

明白以後,我們便可以用Verilog 描述表26.1的內容,結果如程式碼26.1所示:

1.         parameter SA = 11'd136, SE = 11'd1344;
2.         parameter SO = 11'd6, SS = 11'd806;
3.         
4.          reg [10:0]C1;
5.         reg [9:0]C2;
6.         reg rH,rV;
7.         
8.         always @ ( posedge CLOCK or negedge RESET )
9.             if( !RESET )
10.                  begin
11.                          C1 <= 11'd0;
12.                         C2 <= 10'd0;
13.                         rH <= 1'b1;
14.                         rV <= 1'b1;
15.                    end
16.              else 
17.                  begin
18.                        if( C1 == SE -1 ) rH <= 1'b0; 
19.                         else if( C1 == SA -1  ) rH <= 1'b1;
20.                         
21.                        if( C2 == SS -1 ) rV <= 1'b0;
22.                         else if( C2 == SO -1  ) rV <= 1'b1;
23.                         
24.                         if( C2 == SS -1 ) C2 <= 10'd0;
25.                         else if( C1 == SE -1 ) C2 <= C2 + 1'b1;
26.                         
27.                         if( C1 == SE -1 ) C1 <= 11'd0;
28.                         else C1 <= C1 + 1'b1; 
29.                    end

程式碼26.1

第1~2行是 A段與E段,O段還有S段的常量宣告。第4~6是相關的暫存器宣告,第10~14行則是這些暫存器的復位操作。請注意一下第8行的主時鐘是65Mhz。第27~28行是針對列畫素的計數器C1,計數範圍為0~1343。第24~25行是針對行畫素的計數器C2,計數範圍為0~805。第18~19行用來控制 HSYNC,第21~22行則是用來控制VSYNC。

理解完畢 HSYNC 與 VSYNC訊號以後,接下來我們便要學習 RGB 訊號。事實上,HSYNC與VSYNC的資料段,其實也是RGB有效的資料段。表26.1基於1024×768 @ 60Hz,所以HSYNC資料段的長度有1024,而VSYNC的資料段的長度則有768。如果VGA擁有顯示標準,那麼RGB訊號也有所謂的顏色標準。根據Photoshop ,常見的顏色如表26.2所示:

表26.2 常見的顏色。

顏色

位寬

黑白

1bit

灰度級

4bit,8bit

RGB

8bit,16bit,24bit,32bit

黑白可謂是最典型的顏色,不禁讓筆者想起懷念的小綠人。灰度級正如字面上的意思,意指失去顏色的影象,4bit有16灰度級,8bit則有256灰度級。RGB是電腦專用的顏色標準,從過去發展至今,RGB的顏色解析度也從4bit發展到32bit。雖說8位RGB是歷史悠久的前輩,不過至今它還未退休吔,例如街邊的LED招牌。8位RGB也稱為索引色。

16位RGB可是人眼比較接近的的顏色標準,也是本實驗的主題,其中RGB[15:11]是5位紅色,RGB[10:5]是6位綠色,RGB[4:0]則是5位藍色,16位RGB稱為高彩。24位RGB也是目前流行的顏色標準,其中位元組0為藍色,位元組1為綠色,位元組2為紅色,24位稱為真彩。32位RGB相較24位RGB則多了一個位元組3的通道位元組,通道也指透明效果,它稱為全綵。

為消除讀者對RGB的恐懼,筆者就解剖一下16位RGB:

clip_image012

圖26.6 4×1與16位RGB影象。

圖26.6是一幅寬為4高為1的16位RGB影象,如果從左至右開始數起,列0為飽和的紅色,列1為飽和的綠色,列2為飽和的藍色,列3為純黑。如果將其卸甲並且一字排開高位在前的內容,結果如表26.2所示:

表示26.3 4×1與16位RGB影象內容(高位在前)。

列0

列1

列2

列3

飽和紅

飽和綠

飽和藍

16’hF800

16’h07E0

16’h001F

16’h0000

16’b1111_1000_0000_0000

16’b0000_0111_1110_0000

16’b0000_0000_0001_1111

16’b0000_0000_0000_0000

如表26.3所示,我們可以看見列0的紅色佔據RGB[15:11]的位置,亦即紅色有25=32的解析度。列1的綠色則是佔據RGB[10:5]的位置,亦即26= 64的解析度。至於列2的藍色佔據RGB[4:0]的位置,結果它有25=32的解析度。

clip_image014

圖26.7 4×1與16位RGB影象(紅色漸變)。

圖26.7也是一幅寬有4高有1的16位RGB影象,不過是紅色漸變的影象。如果從左至右開始數起,列0為4/4飽和的紅色,列1為3/4飽和的紅色,列2為2/4飽和的紅色,列3為1/4飽和的紅色。筆者隨之伸出魔爪將其卸甲,然後一字排開高位在前的內容,結果如表26.4所示:

表示26.4 4×1與16位RGB影象內容(紅色漸變與高位在前)。

列0

列1

列2

列3

4/4飽和紅

3/4飽和紅

2/4飽和紅

1/4飽和紅

16’hF800

16’hC000

16’h8000

16’h4000

16’b1111_1000_0000_0000

16’b1100_0000_0000_0000

16’b1000_0000_0000_0000

16’b0100_0000_0000_0000

如表26.4所示,我們可以看見列0的紅色充斥整座RGB[15:11],列1的紅色則是佔據其中的14份內容而已。列2更慘,它佔據的份兒只有8份而已,而最慘的列3則是隻有麻雀眼淚般的4份內容而已。

clip_image016

圖26.8 實驗用的小可愛。

圖26.6是實驗二十六所用的影象資源,內容是一群可愛的比卡丘在玩耍。影象大小為128 × 96 × 16 bit,結果容量為:

128 × 96 × 16 bit = 196608 bit

如果儲存器的位寬有16位,那麼儲存器的地址位寬則是:

128 × 96 = 12208

因此,必須建立位寬為 214 的地址訊號:

214 = 16384

簡單而言,圖26.8的X為128還有Y為96,而Y也充當偏移量的角色。為此,正確的地址公式如下所示:

Address = X + ( Y × 128 )

= X + (Y << 7)

理解完畢這些準備知識以後,我們便可以開始建模了。

clip_image018

圖26.9 實驗二十六(VGA基礎模組)的建模圖。

圖26.9是實驗二十六的建模圖,其中PLL將50Mhz 的CLOCK增至 65Mhz。VGA儲存模組有 128 × 96 × 16 bit 的容量,裡邊暫存皮卡丘的影象資訊。VGA功能模組則是負責1024 × 768 @ 60Hz的顯示標準,還有將內部的計數資訊反饋給VGA控制模組。VGA控制模組位與中間,它藉助 iAddr然後轉換成為影象讀取的地址,最後再將反饋回來的影象資訊發至 VGAD頂層訊號。

vga_savemod.v

clip_image020

圖26.10 VGA儲存模組的建模圖。

圖26.10雖是VGA儲存模組的建模圖,不過內容卻是簡單ROM模組,具體內容讓我們來看程式碼吧。

1.    module vga_savemod
2.    (
3.         input CLOCK, RESET,
4.         input [13:0]iAddr,
5.         output [15:0]oData
6.    );
7.        (* ramstyle = "no_rw_check , m9k" , ram_init_file = "pikachu_128x96_16_msb.mif" *) 
8.         reg [15:0] RAM[12287:0];
9.         reg [15:0]D1;
10.         
11.         always @ ( posedge CLOCK or negedge RESET )
12.             if( !RESET )
13.                  D1 <= 16'd0;
14.              else 
15.                  D1 <= RAM[ iAddr ];
16.         
17.         assign oData = D1;
18.    
19.    endmodule

以上內容雖然簡單,不過還是注意一下第7行的建立宣告。其中 no_rw_check是用來告訴綜合器無視 read during write 的檢測,m9k則宣告片上記憶體用 m9k,至於ram

init file 則是RAM的初始化內容,亦即圖26.8。

vga_funcmod.v

clip_image022

圖26.11 VGA功能模組的建模圖。

圖26.11是VGA功能模組的建模圖,左邊是反饋給朋友的oAddr,其中[20:10]是X地址,[9:0]則是Y地址。右邊是驅動頂層的VGA_HSYNC與 VGA_VSYNC。

1.    module vga_funcmod 
2.    (
3.         input CLOCK, RESET,
4.         output VGA_HSYNC, VGA_VSYNC,
5.         output [20:0]oAddr
6.    );
7.         parameter SA = 11'd136, SE = 11'd1344;
8.         parameter SO = 11'd6, SS = 11'd806;
9.         

以上內容為相關的出入端宣告,還有A段,E段,O段還有S段的常量宣告。

10.         reg [10:0]C1;
11.         reg [9:0]C2;
12.         reg rH,rV;
13.         
14.         always @ ( posedge CLOCK or negedge RESET )
15.             if( !RESET )
16.                  begin
17.                         C1 <= 11'd0;
18.                         C2 <= 10'd0;
19.                         rH <= 1'b1;
20.                         rV <= 1'b1;
21.                    end
22.              else 

以上內容為相關的暫存器宣告,其中C1為HSYNC計數,C2則為VSYNC計數。

23.                  begin
24.                        
25.                         if( C1 == SE -1 ) rH <= 1'b0; 
26.                         else if( C1 == SA -1  ) rH <= 1'b1;
27.                         
28.                         if( C2 == SS -1 ) rV <= 1'b0;
29.                         else if( C2 == SO -1  ) rV <= 1'b1;
30.                         
31.                         if( C2 == SS -1 ) C2 <= 10'd0;
32.                         else if( C1 == SE -1 ) C2 <= C2 + 1'b1;
33.                         
34.                         if( C1 == SE -1 ) C1 <= 11'd0;
35.                         else C1 <= C1 + 1'b1;
36.                         
37.                    end
38.                    

以上內容為 HSYNC 與 VSYNC的驅動過程。第35~36行是計數HSYNC,第32~33行則是計數VYSNC,一個VSYNC為1344個HSYNC。第26~27行是 rH的控制,第29~30行則是 rV的控制。

39.        reg [1:0]B1,B2,B3;
40.         
41.        always @ ( posedge CLOCK or negedge RESET )
42.             if( !RESET )
43.                  {  B3, B2, B1 } <= 6'b11_11_11;
44.              else
45.                  begin
46.                         B1 <= { rH,rV };
47.                         B2 <= B1;
48.                         B3 <= B2;
49.                    end    
50.        

第40~51則是用來延遲 rH與rV的周邊操作,期間總共延遲3個時鐘。詳細內容往後再說。

51.         assign { VGA_HSYNC, VGA_VSYNC } = B3;
52.         assign oAddr = {C1,C2}
53.         
54.    endmodule

以上內容為相關的輸出驅動。

vga_ctrlmod.v

clip_image024

圖26.12 VGA控制模組的建模圖。

圖26.12是VGA控制模組的建模圖,而設計思路來源《整合篇》。左邊訊號連線儲存模組,右邊訊號連線功能模組,北邊訊號則驅動頂層。具體內容還是讓我們來看程式碼吧:

1.    module vga_ctrlmod
2.    (
3.         input CLOCK, RESET,
4.         output [15:0]VGAD,
5.         output [13:0]oAddr,
6.         input [15:0]iData,
7.         input [20:0]iAddr
8.    );

以上內容為相關的出入端宣告。

9.         parameter SA = 11'd136, SB = 11'd160, SC = 11'd1024, SD = 11'd24, SE = 11'd1344;
10.         parameter SO = 11'd6, SP = 11'd29, SQ = 11'd768, SR = 11'd3, SS = 11'd806;
11.         
12.         // Height , width, x-offset and y-offset
13.         parameter XSIZE = 8'd128, YSIZE = 8'd96, XOFF = 10'd0, YOFF = 10'd0; 
14.        
15.         wire isX = ( (iAddr[20:10] >= SA + SB + XOFF -1 ) && ( iAddr[20:10] <= SA + SB + XOFF + XSIZE -1) );
16.         wire isY = ( (iAddr[9:0] >= SO + SP + YOFF -1 ) && ( iAddr[9:0] <= SO + SP + YOFF + YSIZE -1) );
17.         wire isReady = isX & isY;
18.         
19.         wire [31:0] x = iAddr[20:10] - XOFF - SA - SB -1; 
20.         wire [31:0] y = iAddr[9:0] - YOFF - SO - SP -1;
21.         

以上內容為相關的常量宣告。第9~10行是針對 1024 × 768 @ 60Hz 顯示標準的常量宣告。第13行宣告影象資訊,如大小還有位置。第15行宣告有效的列畫素,第16行則宣告有效的Y畫素,至於第17行則是宣告影象的有效區域,注意它們都是即時事件。第19~20行用來是計算有效的X與Y,主要用來取得影象的讀取地址,注意它們也是即時事件。

22.         reg [31:0]D1;
23.         reg [15:0]rVGAD;
24.         
25.         always @ ( posedge CLOCK or negedge RESET )
26.             if( !RESET )
27.                  begin
28.                        D1 <= 18'd0;
29.                        rVGAD <= 16'd0;
30.                    end
31.                else

以上內容為相關的暫存器宣告還有復位操作。

32.                   begin
33.                    
34.                        // step 1 : compute data address and index-n
35.                         if( isReady )
36.                             D1 <= (y << 7) + x; 
37.                         else
38.                             D1 <= 14'd0;
39.                         
40.                         // step 2 : reading data from rom
41.                         // but do-nothing
42.                         
43.                         // step 3 : assign RGB_Sig
44.                         rVGAD <= isReady ? iData : 16'd0;
45.                         
46.                    end
47.                    

以上內容為VGA控制模組的核心操作。該控制模組採用流水操作,一邊不斷髮送讀取地址,一邊不斷等待影象資訊讀出,一邊不斷輸出影象資訊。

clip_image026

圖26.13 VGA功能模組的流水操作。

從某種程度來說,實驗二十六的VGA基礎模組可以看成如圖26.13所示。VGA功能模組輸出HSYNC與VSYNC的瞬間,它也傳送 Addr 給 VGA控制模組。VGA控制模組計算讀取地址以後再發送給 VGA儲存模組,VGA儲存模組隨意也將影象資訊返回傳送給VGA控制模組,最後VGA控制模組再將影象資訊驅動至 VGAD。

簡單來說,影象資訊一共慢HSYNC和VSYNC訊號3拍,因此VGA功能模組多了旁路的周邊操作,目的是為了同步 HSYNC,VSYNC還有 VGAD之間的延遲。返回話題,有效的讀取地址只有 isReady 拉高的時候,如程式碼行第36所示。同樣,有效的影象資訊也是 isReady 拉高的時候,如程式碼行第45所示。

48.        assign VGAD = rVGAD;
49.        assign oAddr = D1[13:0];
50.    
51.    endmodule

以上內容為相關的輸出驅動。

vga_basemod.v

該模組是VGA基礎模組,至於內部的連線部署請參考圖26.9。

1.    module vga_basemod
2.    (
3.         input CLOCK, RESET,
4.         output VGA_HSYNC, VGA_VSYNC,
5.         output [15:0]VGAD
6.    );
7.        wire CLOCK_65M;
8.         
9.        pll_module U1  
10.        (
11.            .inclk0 ( CLOCK ),
12.            .c0 ( CLOCK_65M ) // CLOCK 65Mhz
13.         );
14.         
15.         wire [20:0]AddrU2;
16.         
17.         vga_funcmod U2    // 1024 * 758 @ 60Hz
18.         (
19.           .CLOCK( CLOCK_65M ), 
20.           .RESET( RESET ),
21.           .VGA_HSYNC( VGA_HSYNC ), 
22.           .VGA_VSYNC( VGA_VSYNC ),
23.           .oAddr( AddrU2 ),
24.         );             
25.         
26.         wire [15:0]DataU3;
27.         
28.         vga_savemod U3
29.         (
30.            .CLOCK( CLOCK_65M ),
31.            .RESET( RESET ),
32.            .iAddr( AddrU4 ),
33.            .oData ( DataU3 )
34.        );
35.        
36.         wire [13:0]AddrU4;
37.         
38.         vga_ctrlmod U4  // 128 * 96 * 16bit, X0,Y0
39.         (
40.             .CLOCK( CLOCK_65M ),
41.              .RESET( RESET ),
42.              .VGAD( VGAD ),
43.             .iData( DataU3 ),
44.             .oAddr( AddrU4 ),
45.             .iAddr( AddrU2 ),
46.         );
47.         
48.    endmodule

詳細的內容請讀者自己看著辦吧。

clip_image028

圖26.14 實驗二十六的結果。

綜合完畢便下載程式,如果實驗成功,解析度為1024 * 768 的顯示器左上角便會出現一幅128 × 96 × 16 bit 的影象顯示在 X0與Y0的位置,結果如圖26.14所示。

細節一:完整的個體模組

實驗二十六的VGA基礎模組雖為就緒狀態,不過它是一隻能力有限的傢伙。原因很單純,因為儲存128 × 96 × 16 bit 的影象已經是EP4CE6F17C8 這塊FPGA的極限,這傢伙的度量很小,所以片上記憶體也不怎麼大。

細節二: 片上記憶體

筆者曾經說過,片上記憶體是資糧很棒的儲存資源,它不僅訪問時間短,自定義強,而且操作也簡單,但是肚量是它永遠的痛。EP4CE6F17C8 雖然有 476280 bit 的片上記憶體,不過實際可用的範圍只有其中的90%而已。

細節三: 緩衝影象的儲存模組

如果片上記憶體不行,那麼SDRAM當然是最好的替代。同樣,筆者也曾經說過,SDRAM的優點除了肚量大以外,無論是訪問速度還有操作程度也不及片上記憶體。一旦SDRAM謀朝散位成功,VGA控制模組,VGA儲存模組還有VGA功能模組之間就會失去同步性。此外,SDRAM也不能經過綜合器初始化內容。不管怎麼樣,實驗二十六已經完成任務,以後的問題以後再說吧。

相關推薦

黑金原創教程FPGA那些事兒-驅動I 實驗流水燈模組

實驗一:流水燈模組 對於發展商而言,動土儀式無疑是最重要的任務。為此,流水燈實驗作為低階建模II的動土儀式再適合不過了。廢話少說,我們還是開始實驗吧。 圖1.1 實驗一建模圖。 如圖1.1 所示,實驗一有名為 led_funcmod的功能模組。如果無視環境訊號(時鐘訊號還有復位訊號),該功能模組只有

黑金原創教程FPGA那些事兒-驅動I 連載導讀

前言: 無數晝夜的來回輪替以後,這本《驅動篇I》終於編輯完畢了,筆者真的感動到連鼻涕也流下來。所謂驅動就是認識硬體,還有前期建模。雖然《驅動篇I》的硬體都是我們熟悉的老友記,例如UART,VGA等,但是《驅動篇I》貴就貴在建模技巧的昇華,亦即低階建模II。 話說低階建模II,讀過《建模篇》的朋友多少也會面

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組② — 點選與長點選

實驗三:按鍵模組② — 點選與長點選 實驗二我們學過按鍵功能模組的基礎內容,其中我們知道按鍵功能模組有如下操作: l 電平變化檢測; l 過濾抖動; l 產生有效按鍵。 實驗三我們也會z執行同樣的事情,不過卻是產生不一樣的有效按鍵: l 按下有效(點選); l 長按下有效(長點選)。 圖3

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組

實驗二:按鍵模組① - 消抖 按鍵消抖實驗可謂是經典中的經典,按鍵消抖實驗雖曾在《建模篇》出現過,而且還惹來一堆麻煩。事實上,筆者這是在刁難各位同學,好讓對方的慣性思維短路一下,但是慘遭口水攻擊 ... 面對它,筆者宛如被甩的男人,對它又愛又恨。不管怎麼樣,如今 I’ll be back,筆者再也不會重複一

黑金原創教程FPGA那些事兒-驅動I 實驗數碼管模組

實驗六:數碼管模組 有關數碼管的驅動,想必讀者已經學爛了 ... 不過,作為學習的新儀式,再爛的東西也要溫故知新,不然學習就會不健全。黑金開發板上的數碼管資源,由始至終都沒有改變過,筆者因此由身懷念。為了點亮多位數碼管從而顯示數字,一般都會採用動態掃描,然而有關動態掃描的資訊請怒筆者不再重複。在此,同樣也是

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組③ — 單擊與雙擊

實驗四:按鍵模組③ — 單擊與雙擊 實驗三我們建立了“點選”還有“長點選”等有效按鍵的多功能按鍵模組。在此,實驗四同樣也是建立多功能按鍵模組,不過卻有不同的有效按鍵。實驗四的按鍵功能模組有以下兩項有效按鍵: l 單擊(按下有效); l 雙擊(連續按下兩下有效)。 圖4.1 單擊有效按鍵,時序示意圖

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組④ — 點選,長點選,雙擊

實驗五:按鍵模組④ — 點選,長點選,雙擊 實驗二至實驗四,我們一共完成如下有效按鍵: l 點選(按下有效) l 點選(釋放有效) l 長擊(長按下有效) l 雙擊(連續按下有效) 然而,不管哪個實驗都是隻有兩項“功能”的按鍵模組而已,如今我們要建立三項“功能”的按鍵模組,亦即點選(按下有效),長

黑金原創教程FPGA那些事兒-驅動I 原創教程連載導讀連載完成,共九章

前言: 無數晝夜的來回輪替以後,這本《驅動篇I》終於編輯完畢了,筆者真的感動到連鼻涕也流下來。所謂驅動就是認識硬體,還有前期建模。雖然《驅動篇I》的硬體都是我們熟悉的老友記,例如UART,VGA等,但是《驅動篇I》貴就貴在建模技巧的昇華,亦即低階建模II。 話說低階建模II,讀過《建模篇》的朋友多少也會面

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組④ — 頁讀寫 β

實驗二十一:SDRAM模組④ — 頁讀寫 β 未進入主題之前,讓我們先來談談一些重要的體外話。《整合篇》之際,筆者曾經比擬Verilog如何模仿for迴圈,我們知道for迴圈是順序語言的產物,如果Verilog要實現屬於自己的for迴圈,那麼它要考慮的東西除了步驟以外,還有非常關鍵的時鐘。 for(

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組④ — 普通滑鼠

實驗十:PS/2模組④ — 普通滑鼠 學習PS/2鍵盤以後,接下來就要學習 PS/2 滑鼠。PS/2滑鼠相較PS/2鍵盤,驅動難度稍微高了一點點,因為FPGA(從機)不僅僅是從PS/2滑鼠哪裡讀取資料,FPGA還要往滑鼠裡寫資料 ... 反之,FPGA只要對PS/2鍵盤讀取資料即可。然而,最傷腦筋的地方就在

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組① — 單字讀寫

實驗十八:SDRAM模組① — 單字讀寫 筆者與SDRAM有段不短的孽緣,它作為冤魂日夜不斷糾纏筆者。筆者嘗試過許多方法將其退散,不過屢試屢敗的筆者,最終心情像橘子一樣橙。《整合篇》之際,筆者曾經大戰幾回兒,不過內容都是點到即止。最近它破蠱而出,日夜不停:“好~痛苦!好~痛苦!”地呻吟著,嚇得筆者不敢半夜如

黑金原創教程FPGA那些事兒-驅動I 實驗TFT模組

實驗二十七:TFT模組 - 顯示 所謂TFT(Thin Film Transistor)就是眾多LCD當中,其中一種支援顏色的LCD,相較古老的點陣LCD(12864笑),它可謂高階了。黑金的TFT LCD除了320×240大小以外,內建SSD1289控制器,同時也是獨立模組。事實上,無論是驅動點陣LCD還

黑金原創教程FPGA那些事兒-驅動I 實驗十三串列埠模組② — 接收

實驗十三:串列埠模組② — 接收 我們在實驗十二實現了串列埠傳送,然而這章實驗則要實現串列埠接收 ... 在此,筆者也會使用其它思路實現串列埠接收。 圖13.1 模組之間的資料傳輸。 假設我們不考慮波特率,而且一幀資料之間的傳輸也只是發生在FPGA之間,即兩隻模組之間互轉,並且兩塊模組都使用相同的時

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組① — 鍵盤

實驗七:PS/2模組① — 鍵盤 實驗七依然也是熟爛的PS/2鍵盤。相較《建模篇》的PS/2鍵盤實驗,實驗七實除了實現基本的驅動以外,我們還要深入解PS/2時序,還有PS/2鍵盤的行為。不過,為了節省珍貴的頁數,怒筆者不再重複有關PS/2的基礎內容,那些不曉得的讀者請複習《建模篇》或者自行谷歌一下。 市場

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組③ — 鍵盤與多組合鍵

實驗九:PS/2模組③ — 鍵盤與多組合鍵 筆者曾經說過,通碼除了單位元組以外,也有雙位元組通碼,而且雙位元組通碼都是 8’hE0開頭,別名又是 E0按鍵。常見的的E0按鍵有,<↑>,<↓>,<←>,<→>,<HOME>,<PRTSC>

黑金原創教程FPGA那些事兒-驅動I 實驗SDHC模組

實驗二十五:SDHC模組 筆者曾經說過,SD卡發展至今已經衍生許多版本,實驗二十四就是針對版本SDV1.×的SD卡。實驗二十四也說過,CMD24還有CMD17會故意偏移地址29,讓原本範圍指向從原本的232 變成 223,原因是SD卡讀寫一次都有512個位元組。為此我們可以這樣計算: SDV1.x = 2

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組③ — 頁讀寫 α

實驗二十:SDRAM模組③ — 頁讀寫 α 完成單字讀寫與多字讀寫以後,接下來我們要實驗頁讀寫。醜話當前,實驗二十的頁讀寫只是實驗性質的東西,其中不存在任何實用價值,筆者希望讀者可以把它當成頁讀寫的熱身運動。 表示20.1 Mode Register的內容。 Mode Register

黑金原創教程FPGA那些事兒-驅動I 實驗TFT模組

實驗二十八:TFT模組 - 觸屏 讀者在上一個實驗所玩弄過的 TFT LCD模組,除了顯示大小為 320 × 240,顏色為16位RGB的影象資訊以外,它還支援觸屏。所謂觸屏就是滑鼠還有鍵盤以外的輸入手段,例如現在流行平板還有智慧手機,觸屏輸入對我們來說,已經成為日常的一部分。描述語言一門偏向硬體的語言

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組⑤ — FIFO讀寫

經過漫長的戰鬥以後,我們終於來到最後。對於普通人而言,頁讀寫就是一名戰士的墓碑(最終戰役) ... 然而,怕死的筆者想透過這個實驗告訴讀者,旅程的終點就是旅程的起點。一直以來,筆者都在煩惱“SDRAM是否應該成為儲存類?”SDRAM作為一介儲存資源(儲存器),它的好處就是大容量空間,壞處則就是麻煩的控制規

黑金原創教程FPGA那些事兒-驅動I 實驗儲存模組

實驗十四比起動手筆者更加註重原理,因為實驗十四要討論的東西,不是其它而是低階建模II之一的模組類,即儲存模組。接觸順序語言之際,“儲存”不禁讓人聯想到變數或者陣列,結果它們好比資料的暫存空間。 1. int main() 2. { 3. int VarA; 4.