【文章】FPGA驅(qū)動VGA顯示靜態(tài)圖片
摘自網(wǎng)絡班學員陳同學博客:
https://www.cnblogs.com/moluoqishi/p/9544146.html
一?、前言
本文設計思想采用明德?lián)P至簡設計法。VGA是最常見的視頻顯示接口,時序也較為簡單。本文從利用顯示屏通過VGA方式顯示測試圖案及靜態(tài)圖片著手帶大家接觸圖像顯示應用,算是為后續(xù)VGA顯示攝像頭采集圖像以及HDMI高清數(shù)字顯示方式打個基礎。
二、VGA顯示原理
關于VGA的詳細解釋可查看參考文獻1,這里主要講解下根據(jù)VGA的分辨率計算時鐘頻率的方式。以本文使用到的1024*768@60HZ為例。
一幀圖像顯示周期為Tv,在這段時間內(nèi)VGA需要掃描806行,每行1344個點。所以每個點的持續(xù)周期為:Ts=Tv/(n*m),故時鐘頻率:fs = n*m*fv=806*1344*60=65MHz。因此設計下來其實非常簡單,PLL產(chǎn)生65MHz工作時鐘信號,利用兩個計數(shù)器分別計數(shù)行列值,之后根據(jù)計數(shù)器數(shù)值產(chǎn)生行場同步信號以及相應的RGB圖像數(shù)據(jù)即可。有一點需要注意:VGA顯示標準規(guī)定行場同步脈沖均為負脈沖,意思是只有同步脈沖階段拉低,其他時刻為高電平。
三、靜態(tài)圖片顯示
VGA顯示基本原理和設計方式確定后,顯示圖片也不是什么難事??梢詫D片以.coe形式保存在FPGA內(nèi)部BRAM中,通過VGA接口模塊循環(huán)讀取RAM數(shù)據(jù)方式來顯示圖片。FPGA片內(nèi)BRAM的存儲容量一般在kbit量級,存儲640*480*24bit真彩色圖像捉襟見肘,因此這里僅顯示320*240*16bit圖像用于測試。把圖片格式設定為.coe文件的方法:一是可以利用些小的軟件工具,此處先用img2Lcd軟件將圖片調(diào)整為合適的分辨率,再用BMP2Mif軟件生成.coe文件初始化BMG IP核(見參考文獻2);第二就是自己寫一段軟件腳本來轉(zhuǎn)換。
測試需求:VGA接口以1024*768分辨率,60Hz幀頻,在顯示屏中央位置顯示一幅320*240圖片,其他位置左右各一半分別顯示白色和紅色。
BMG IP核配置:
第一頁選擇單口ROM模式,其他保持默認。主要第二頁的位寬和深度設置正確,另外取消掉輸出寄存器選擇匹配時序。
四、顯示硬件方案
大多數(shù)VGA顯示采用電阻網(wǎng)絡分壓代替DA過程,這種方案成本較低,能滿足大多數(shù)顯示需求。當對分辨率要求較高時,采用專用顯示芯片來完成R G B三路同步數(shù)模轉(zhuǎn)換,本文采用ADI公司的ADV7123芯片,內(nèi)含有三路10位DAC,最高支持1080p@60Hz圖像輸出。硬件中將每路低兩位拉低,僅提供高8位接口可滿足8*8*8 = 24bit真彩色顯示需求。上升沿采樣數(shù)據(jù),為方便處理和代碼規(guī)范,F(xiàn)PGA邏輯在PLL時鐘上升沿驅(qū)動,輸出顯示芯片工作采樣時鐘為PLL產(chǎn)生時鐘信號取反,如此可保證滿足顯示芯片建立保持時間需求。
五、邏輯代碼設計
??1?`timescale?1ns?/?1ps
??2
??3?module?vga_interface#(
??4?????parameter?DATA_W?=?8)
??5????(
??6?????input?????????????????????? clk,//65MHz
??7?????input?????????????????????? rst_n,
??8
??9?????output??????????????????????vga_clk,
?10?????output?reg??????????????????vga_en,
?11?????
?12?????//input?????? [DATA_W-1:0]????din_r,
?13?????//input?????? [DATA_W-1:0]????din_g,
?14?????//input?????? [DATA_W-1:0]????din_b,
?15?????output??????[DATA_W-1:0]????vga_r,
?16?????output??????[DATA_W-1:0]????vga_g,
?17?????output??????[DATA_W-1:0]????vga_b,
?18?????output?reg??????????????????vga_hs,
?19?????output?reg??????????????????vga_vs
?20?????);
?21
?22?/*********************************參數(shù)******************************************/
?23?????//VGA:1280*768@60HZ
?24?????//行參數(shù)
?25?????localparam?H_A?=?136,???//同步脈沖
?26????????????????H_B?=?160,???//顯示后沿
?27????????????????H_C?=?1024,??//顯示時段
?28????????????????H_D?=?24;????//顯示前沿
?29?????//場參數(shù)
?30?????localparam?V_A?=?6,?????//同步脈沖
?31????????????????V_B?=?29,????//顯示后沿
?32????????????????V_C?=?768,???//顯示時段
?33????????????????V_D?=?3;?????//顯示前沿
?34?????
?35?????//有效區(qū)域邊界??????????
?36?????localparam?X0?=?H_A+H_B,????????//136+160=296
?37????????????????X1?=?H_A+H_B+H_C,????//136+160+1024=1320
?38????????????????Y0?=?V_A+V_B,????????//6+29=35
?39????????????????Y1?=?V_A+V_B+V_C;????//6+29+768=803
?40?????
?41?????localparam?COL_NUM?=?H_A+H_B+H_C+H_D,//1344
?42????????????????ROW_NUM?=?V_A+V_B+V_C+V_D;//806
?43
?44?????//顯示中心位置??????????
?45?????localparam?X_CENTER?=?(X0+X1)/2,//808
?46????????????????Y_CENTER?=?(Y0+Y1)/2;//419
?47
?48?????//顯示圖片分辨率及位置
?49?????localparam?PIC_H?=?320,
?50????????????????PIC_V?=?240;
?51
?52?????localparam?PIC_H_LB?=?X_CENTER-PIC_H/2,
?53????????????????PIC_H_RB?=?X_CENTER+PIC_H/2,
?54????????????????PIC_V_UB?=?Y_CENTER-PIC_V/2,
?55????????????????PIC_V_DB?=?Y_CENTER+PIC_V/2;
?56?????
?57???/*********************************信號定義******************************************/????
?58?reg?[?(12-1):0]??cnt_hs?????;
?59?wire????????add_cnt_hs?;
?60?wire????????end_cnt_hs?;
?61?reg?[?(12-1):0]??cnt_vs?????;
?62?wire????????add_cnt_vs?;
?63?wire????????end_cnt_vs?;
?64?wire?valid_area;
?65?wire?left_half;
?66?wire?picture_area;
?67?reg?[DATA_W-1:0]?r_reg,g_reg,b_reg;
?68
?69?wire?ena;
?70?wire?[15:0]?douta;
?71?reg?[?(17-1):0]??cnt_addr?????;
?72?wire????????add_cnt_addr?;
?73?wire????????end_cnt_addr?;
?74?wire?[16:0]?addra;
?75?reg?ram_vld;
?76?/*********************************計數(shù)器******************************************/
?77?????
?78?always?@(posedge?clk?or?negedge?rst_n)?begin?
?79?????if?(rst_n==0)?begin
?80?????????cnt_hs?<=?0;?
?81?????end
?82?????else?if(add_cnt_hs)?begin
?83?????????if(end_cnt_hs)
?84?????????????cnt_hs?<=?0;?
?85?????????else
?86?????????????cnt_hs?<=?cnt_hs+1?;
?87????end
?88?end
?89
?90?assign?add_cnt_hs?=?1;
?91?assign?end_cnt_hs?=?add_cnt_hs??&&?cnt_hs?==?(COL_NUM)-1?;
?92
?93?always?@(posedge?clk?or?negedge?rst_n)?begin?
?94?????if?(rst_n==0)?begin
?95?????????cnt_vs?<=?0;?
?96?????end
?97?????else?if(add_cnt_vs)?begin
?98?????????if(end_cnt_vs)
?99?????????????cnt_vs?<=?0;?
100?????????else
101?????????????cnt_vs?<=?cnt_vs+1?;
102????end
103?end
104?assign?add_cnt_vs?=?(end_cnt_hs);
105?assign?end_cnt_vs?=?add_cnt_vs??&&?cnt_vs?==?(ROW_NUM)-1?;
106
107
108?/*********************************BRAM相關信號******************************************/
109?//BRAM讀取地址計數(shù)器
110?always?@(posedge?clk?or?negedge?rst_n)?begin?
111?????if?(rst_n==0)?begin
112?????????cnt_addr?<=?0;?
113?????end
114?????else?if(add_cnt_addr)?begin
115?????????if(end_cnt_addr)
116?????????????cnt_addr?<=?0;?
117?????????else
118?????????????cnt_addr?<=?cnt_addr+1?;
119????end
120?end
121
122?assign?add_cnt_addr?=?(ena);
123?assign?end_cnt_addr?=?add_cnt_addr??&&?cnt_addr?==?320*240?-1?;
124
125?assign?addra?=?cnt_addr;
126?assign?ena?=?picture_area;
127
128?//BRAM數(shù)據(jù)有效指示
129?always??@(posedge?clk?or?negedge?rst_n)begin
130?????if(rst_n==1'b0)begin
131?????????ram_vld?<=?0;
132?????end
133?????else?begin
134?????????ram_vld?<=?ena;
135?????end
136?end
137?/*********************************VGA輸出信號******************************************/
138?//行場同步信號
139?always??@(posedge?clk?or?negedge?rst_n)begin
140?????if(rst_n==1'b0)begin
141?????????vga_hs?<=?1;
142?????end
143?????else?if(add_cnt_hs?&&?cnt_hs?==?H_A-1)begin
144?????????vga_hs?<=?1;
145?????end
146?????else?if(end_cnt_hs)
147?????????vga_hs?<=?0;
148?end
149
150?always??@(posedge?clk?or?negedge?rst_n)begin
151?????if(rst_n==1'b0)begin
152?????????vga_vs?<=?1;
153?????end
154?????else?if(add_cnt_vs?&&?cnt_vs?==?V_A-1)begin
155?????????vga_vs?<=?1;
156?????end
157?????else?if(end_cnt_vs)
158?????????vga_vs?<=?0;
159?end
160
161?//R G B寄存器信號
162?always??@(posedge?clk?or?negedge?rst_n)begin
163?????if(rst_n==1'b0)begin
164?????????r_reg?<=?0;
165?????????g_reg?<=?0;
166?????????b_reg?<=?0;
167?????end
168?????else?if(valid_area?&&?!picture_area)begin??????
169????????if(left_half)begin???????//彩條測試??左半屏幕顯示白色
170?????????????r_reg?<=?8'b1111_1111;
171?????????????g_reg?<=?8'b1111_1111;
172?????????????b_reg?<=?8'b1111_1111;
173????????end
174????????else?begin???????????????//右半屏幕顯示紅色
175?????????????r_reg?<=?8'b1111_1111;
176?????????????g_reg?<=?0;
177?????????????b_reg?<=?0;
178????????end
179?????end
180?????else?begin//無效區(qū)域顯示黑色
181?????????r_reg?<=?0;
182?????????g_reg?<=?0;
183?????????b_reg?<=?0;
184?????end
185?end
186
187?assign?valid_area?=?cnt_hs?>=?X0?&&?cnt_hs?<?X1?&&?cnt_vs?>=?Y0?&&?cnt_vs?<?Y1;
188?assign?left_half?=??cnt_hs?>=?X0?&&?cnt_hs?<?X_CENTER;
189?assign?picture_area?=??cnt_hs?>=?PIC_H_LB?&&?cnt_hs?<?PIC_H_RB
190?????????????????????&&?cnt_vs?>=?PIC_V_UB?&&?cnt_vs?<?PIC_V_DB;
191
192?assign?vga_r?=?ram_vld???{douta[15:11],3'b0}?:?r_reg;//5bit
193?assign?vga_g?=?ram_vld???{douta[10:5],2'b0}??:?g_reg;//6bit
194?assign?vga_b?=?ram_vld???{douta[4:0],3'b0}???:?b_reg;//5bit
195
196?//輸出控制信號
197?assign?vga_clk?=?~clk;
198
199?always??@(posedge?clk?or?negedge?rst_n)begin
200?????if(rst_n==1'b0)begin
201?????????vga_en?<=?0;
202?????end
203?????else?if(valid_area)begin
204?????????vga_en?<=?1;
205?????end
206?????else
207?????????vga_en?<=?0;
208?end
209
210?/*********************************子模塊例化 BRAM******************************************/
211
212?blk_mem_gen_0 bram?(
213???.clka(clk),????// input wire clka
214???.ena(ena),??????// input wire ena
215???.addra(addra),??// input wire [16 : 0] addra
216???.douta(douta)??// output wire [15 : 0] douta
217?);
218
219?endmodule
220
221
222
這里VGA接口代碼包含了顯示內(nèi)容,在實際應用中要去掉顯示部分邏輯和BRAM的例化,添加用戶側(cè)接口及邏輯。測試工程頂層:
>??1?`timescale?1ns?/?1ps
?2
?3?module?vga_test_top(
?4?????input?sys_clk_p,
?5?????input?sys_clk_n,
?6?????input?rst_n,
?7
?8?????output?vga_hs,
?9?????output?vga_vs,
10?????output?vga_clk,
11?????output?vga_en,
12?????output?[8-1:0]?vga_r,
13?????output?[8-1:0]?vga_g,
14?????output?[8-1:0]?vga_b
15?????);
16
17?wire?clk;
18?wire?sys_clk_ibufg;
19?wire?locked;
20
21?IBUFGDS?#
22?(
23?.DIFF_TERM?("FALSE"),
24?.IBUF_LOW_PWR?("FALSE")
25?)
26?u_ibufg_sys_clk
27?(
28?.I?(sys_clk_p),
29?.IB?(sys_clk_n),
30?.O?(sys_clk_ibufg)
31?);
32
33??clk_wiz_0 pll
34?(
35??// Clock out ports
36??.clk_out1(clk),?????// output clk_out1
37??// Status and control signals
38??.resetn(rst_n),?// input resetn
39??.locked(locked),???????// output locked
40?// Clock in ports
41??.clk_in1(sys_clk_ibufg));??????// input clk_in1
42
43??
44??vga_interface#(.DATA_W(8))
45??vga_interface
46?(
47??.clk??????(clk)?,//65MHz
48??.rst_n????(rst_n)?,
49??.vga_clk??(vga_clk)?,
50??.vga_en???(vga_en)?,
51??.vga_r????(vga_r)?,
52??.vga_g????(vga_g)?,
53??.vga_b????(vga_b)?,
54??.vga_hs???(vga_hs)?,
55??.vga_vs???(vga_vs)?
56??);
57
58
59?endmodule
60
61?vga_test_top.v
62
六、仿真及板級測試
為了方便仿真,只將vga_interface作為uut。查看行為仿真波形:
可見行場計數(shù)器及同步脈沖按照預期工作,在顯示圖片區(qū)域地址計數(shù)器遞增。現(xiàn)在我們看看實際上板后的顯示效果:
和原始圖片對比下
由于原始圖片是24位真彩圖,且在VGA顯示接口模塊中進行了R G B低位填充導致些許失真,不過整體顯示正確。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
參考文獻:
1 [筆記]VGA時序及其原理?- LiangXuan -?博客園?https://www.cnblogs.com/spartan/archive/2011/08/16/2140546.html
2?【原創(chuàng)】bmp轉(zhuǎn)mif、coe或hex軟件發(fā)布及使用介紹-crazybird-電子技術應用-AET-北大中文核心期刊-最豐富的電子設計資源平臺?http://blog.chinaaet.com/crazybird/p/5100000224