FPGA-VGA显示

文章目录

  • 一、VGA介绍
  • 二、实验准备
  • 三、显示彩色条纹
  • 四、显示自定义汉字字符
  • 五、输出一幅彩色图像
  • 六、软件提取

实验器材
硬件:

  1. pc显示屏
  2. VGA线
  3. 开发板 (EP4CE6F17C8)
    软件:
  4. quartus
  5. BMP2MIf(位图转换)
  6. PCtoLCD2002(汉字取模)
    4、5 可通过链接获取

一、VGA介绍

VGA(Video Graphics Array)是IBM在1987年随PS/2机⼀起推出的⼀种视频,具有分辨率⾼、显⽰速率快、颜⾊丰富等优点,在彩 ⾊显⽰器领域得到了⼴泛的应⽤。不⽀持热插拔,不⽀持⾳频传输。对于⼀些嵌⼊式VGA显⽰系统,可以在不使⽤VGA显⽰卡和计算机的 情况下,实现VGA图像的显⽰和控制。VGA显⽰器具有成本低、结构简单、应⽤灵活的优点。对于⼀名FPGA⼯程师,尤其是视频图像的 ⽅向的学习者,VGA协议是必须要掌握的。

  1. 外部接口
    FPGA-VGA显示_第1张图片
    VGA并没有特殊的外部芯⽚,我们需要关注的其实只有5个信号:HS⾏同步信号,VS场同步信号,R红基⾊,G 绿基⾊,B蓝基⾊。

  2. 色彩原理
    设计RGB信号时,既可以R信号、G信号和B信号独⽴的赋值,最后连到端⼝上,也可以直接⽤RGB当做⼀个整体信号,RGB信号在使 ⽤时的位宽有三种常见格式,以你的VGA解码芯⽚的配置有关。
    1.RGB_8,R:G:B = 3: 3:2,即RGB332
    2.RGB_16,R:G:B = 5:6:5,即RGB565
    3.RGB_24,R:G:B = 8:8:8,即RGB888

  3. 扫描方式
    VGA显⽰器扫描⽅式分为逐⾏扫描和隔⾏扫描:逐⾏扫描是扫描从屏幕左上⾓⼀点开始,从左像右逐点扫描,每扫描完⼀⾏,电⼦束回 到屏幕的左边下⼀⾏的起始位置,在这期间,CRT对电⼦束进⾏消隐,每⾏结束时,⽤⾏同步信号进⾏同步;当扫描完所有的⾏,形成⼀ 帧,⽤场同步信号进⾏场同步,并使扫描回到屏幕左上⽅,同时进⾏场消隐,开始下⼀帧。隔⾏扫描是指电⼦束扫描时每隔⼀⾏扫⼀线,完成 ⼀屏后在返回来扫描剩下的线,隔⾏扫描的显⽰器闪烁的厉害,会让使⽤者的眼睛疲劳。因此我们⼀般都采⽤逐⾏扫描的⽅式。

FPGA-VGA显示_第2张图片
FPGA-VGA显示_第3张图片

  1. ⾏场信号
    FPGA-VGA显示_第4张图片
    SYNC是“信号同步”
    Back prochLeft border常常加在⼀起称为“显⽰后沿”,Addressable video为“显⽰区域”,
    Right porderFront porch常常加在⼀起称为“显⽰前沿”,
    ⼀个时序其实就是先拉⾼⼀段较短的“信号同 步”时间,然后拉低⼀段很长的时间,这就是⼀个回合。同时需要注意,其实也可以完全相反。即先拉低⼀段时间“信号同步”时间,然后 拉⾼⼀段很长的时间。
    FPGA-VGA显示_第5张图片

二、实验准备

  1. 任务要求
    1)屏幕上显示彩色条纹;
    2)显示自定义的汉字字符(姓名-学号);
    3)输出一幅彩色图像

  2. 查找对应分辨率相关数据
    FPGA-VGA显示_第6张图片
    像素时钟频率以640x480p/60hz为例
    total pixel=active video+front porch+sync pulse +back porch =800;
    total line=active video+front porch+sync pulse +back porc=525,
    filed rate=60Hz,
    那么:PCLK =80052560 = 25.175MHz;

  3. 查看对应开发板vga 原理图(我的:EP4CE6F17C8)
    FPGA-VGA显示_第7张图片
    可以知道该开发板是 RGB565,

同步信号 引脚 B 引脚 G 引脚 R 引脚
VGA_HSYNC C16 B[0] C15 G[0] B13 R[0] B10
VGA_VSYNC D15 B[1] B16 G[1] A13 R[1] A10
B[2] A15 G[2] B12 R[2] B9
B[3] B14 G[3] A12 R[3] A9
B[4] A14 G[4] B11 R[4] C8
G[5] A11
  1. 需要用到时钟的分频或倍频,调用ip核PLL实现
    以640*480 分辨率为例 像素时钟为25MHZ,开发板是50MKHZ,需要分频到25MHZ.如图:
    FPGA-VGA显示_第8张图片

  2. 模块设计
    FPGA-VGA显示_第9张图片

  3. VGA 相关参数

`define vga_640_480 //根据需要自行选择

`ifdef  vga_640_480
 
    `define H_Right_Border 8
    `define H_Front_Proch  8
    `define H_Sync_Time    96
    `define H_Back_Proch   40
    `define H_Left_Border  8
    `define H_Data_Time    640
    `define H_Total_Time   800

    `define V_Bottom_Border 8
    `define V_Front_Proch   2
    `define V_Sync_Time     2
    `define V_Back_Proch    25
    `define V_Top_Border    8
    `define V_Data_Time     480
    `define V_Total_Time    525
`elsif   vga_1024_768_75  //75MHz
	 `define H_Right_Border 0
    `define H_Front_Proch  16
    `define H_Sync_Time    96
    `define H_Back_Proch   176
    `define H_Left_Border  0
    `define H_Data_Time    1024
    `define H_Total_Time   1312

    `define V_Bottom_Border 0
    `define V_Front_Proch   1
    `define V_Sync_Time     3
    `define V_Back_Proch    28
    `define V_Top_Border    0
    `define V_Data_Time     768
    `define V_Total_Time    800
`elsif   vga_1024_768_60  //60MHz
	 `define H_Right_Border 0
    `define H_Front_Proch  24
    `define H_Sync_Time    136
    `define H_Back_Proch   160
    `define H_Left_Border  0
    `define H_Data_Time    1024
    `define H_Total_Time   1244

    `define V_Bottom_Border 0
    `define V_Front_Proch   3
    `define V_Sync_Time     6
    `define V_Back_Proch    29
    `define V_Top_Border    0
    `define V_Data_Time     768
    `define V_Total_Time    806
    
/**根据需要自行添加修改**/
`endif
  1. 顶层文件
module vga_top (
    input      clk    ,
    input      rst_n  ,

    output wire        VGA_HSYNC  ,
    output wire        VGA_VSYNC  ,
    output wire  [4:0] VGA_R   ,
    output wire  [5:0] VGA_G  ,
    output wire  [4:0] VGA_B  ,
    output wire       VGA_CLK 
);  
    wire [15:0] data_dis;
    wire [10:0] v_addr; 
    wire [10:0] h_addr;

    data_gen    data_gen(
        .vga_clk     (VGA_CLK     ),
        .rst_n   (rst_n   ),
        .h_addr (h_addr  ),
        .v_addr (v_addr  ),

        .data_dis(data_dis)
    );

    vga_ctrl    vga_ctrl(
        .clk     (clk     ),
        .rst_n   (rst_n   ),
		  
        .data_dis(data_dis),
        .h_addr (h_addr  ),
        .v_addr (v_addr  ),
        .vsync  (VGA_VSYNC ),
        .hsync  (VGA_HSYNC ),
        .vga_r   (VGA_R   ),
        .vga_g   (VGA_G   ),
        .vga_b   (VGA_B   ),
        .vga_clk (VGA_CLK )
    );
endmodule

  1. vga_ctrl

`include "vga_param.v"

module vga_ctrl(
	input 	clk,
	input 	rst_n,
	input    		[15:0] data_dis,
	
	output	reg	[10:0] h_addr,//数据有效显示区域行地址
	output	reg	[10:0] v_addr,
	output   reg          hsync,
	output   reg          vsync,
	output	reg 	[7:0]  vga_r,
	output	reg 	[7:0]  vga_g,
	output	reg	[7:0]  vga_b,
	output                vga_clk

);
reg [11:0] cnt_h_adder;//行地址计数器
wire       add_h_adder;
wire       end_h_adder;

reg [11:0] cnt_v_adder;//场地址计数器
wire       add_v_adder;
wire       end_v_adder;
reg        clk_25;
parameter 	H_SYNC_STA=`H_Sync_Time,
				H_SYNC_STO=`H_Total_Time,
				H_DATA_STA=`H_Sync_Time+`H_Back_Proch+`H_Left_Border,
				H_DATA_STO=`H_Sync_Time+`H_Back_Proch+`H_Left_Border+`H_Data_Time,
				
				V_SYNC_STA =`V_Sync_Time,
				V_SYNC_STO =`V_Total_Time,
				V_DATA_STA =`V_Sync_Time+`V_Back_Proch+`V_Top_Border,
				V_DATA_STO =`V_Sync_Time+`V_Back_Proch+`V_Top_Border+`V_Data_Time;

always@(posedge vga_clk,negedge rst_n)begin
	if(!rst_n)
		cnt_h_adder<=12'b0;
	else if(add_h_adder)
		if(end_h_adder)
			cnt_h_adder<=12'b0;
		else
			cnt_h_adder<=cnt_h_adder+12'b1;
	else
		cnt_h_adder<=cnt_h_adder;
end
assign add_h_adder=1'b1;
assign end_h_adder=add_h_adder&&cnt_h_adder>=`H_Total_Time-1;

always@(posedge vga_clk,negedge rst_n)begin
	if(!rst_n)
		cnt_v_adder<=12'b0;
	else if(add_v_adder)
		if(end_v_adder)
			cnt_v_adder<=12'b0;
		else
			cnt_v_adder<=cnt_v_adder+12'b1;
	else
		cnt_v_adder<=cnt_v_adder;
end
assign add_v_adder=end_h_adder;
assign end_v_adder=add_v_adder&&cnt_v_adder>=`V_Total_Time-1;


//行场同步信号
always@(posedge vga_clk, negedge rst_n)begin
	if(!rst_n)
		hsync<=1'b1;
	else if(cnt_h_adder==H_SYNC_STA-1)
		hsync<=1'b0;
	else if(cnt_h_adder==H_SYNC_STO-1)
		hsync<=1'b1;
	else
		hsync<=hsync;

end
always@(posedge vga_clk, negedge rst_n)begin
	if(!rst_n)
		vsync<=1'b1;
	else if(cnt_v_adder==V_SYNC_STA-1)
		vsync<=1'b0;
	else if(cnt_h_adder==V_SYNC_STO-1)
		vsync<=1'b1;
	else
		vsync<=vsync;

end

//数据有效显示区域定义
always@(posedge vga_clk, negedge rst_n)begin
	if(!rst_n)
		h_addr<=11'd0;
	else if(cnt_h_adder>=H_DATA_STO)
		h_addr<=11'd0;
	else if(cnt_h_adder>=H_DATA_STA)
		h_addr<=cnt_h_adder-H_DATA_STA;
	else 
		h_addr<=11'd0;
end

always@(posedge vga_clk, negedge rst_n)begin
	if(!rst_n)
		v_addr<=11'd0;
	else if(cnt_v_adder>=V_DATA_STO)
		v_addr<=11'd0;
	else if(cnt_v_adder>=V_DATA_STA)
		v_addr<=cnt_v_adder-V_DATA_STA;
	else 
		v_addr<=11'd0;
end

always@(posedge vga_clk,negedge rst_n)begin
	if(!rst_n)begin
		vga_r<=5'b0;
		vga_g<=6'b0;
		vga_b<=5'b0;
	end
	else if((cnt_h_adder>=H_DATA_STA-1)&&(cnt_h_adder<=H_DATA_STO-1)&&(cnt_v_adder>=V_DATA_STA-1)&&(cnt_v_adder<=V_DATA_STO-1))begin
		vga_r<=data_dis[15:11];
		vga_g<=data_dis[10:5];
		vga_b<=data_dis[4:0];
	end
	else begin
	   vga_r<=5'b0;
		vga_g<=6'b0;
		vga_b<=5'b0;
	end
end

wire c1_sig;
PLL	PLL_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 (  vga_clk  ),
	.c1 ( c1_sig )
	);
endmodule

  1. 我们的不同任务将会在data_gen.v 模块中进行修改,然后复用前面的模块完成
module data_gen(
	input  vga_clk,
	input  rst_n,
	
	input  [10:0] h_addr,
	input  [10:0] v_addr,
	
	output reg [15:0] data_dis

);

reg [14:0] address;
wire [15:0] q;
parameter	BLACK		=15'h0000,
				RED 		=15'hf800,
				GREEN		=15'h320,
				BLUE  	=15'hf7ff,
				YELLOW	=15'hffe0,
				SKY_BLUE	=15'h867d,
				PURPLE	=15'h939b,
				GRAY  	=15'h8410,
				WHITE    =15'hffff;

/*
 显示彩带块
*/	
 
/*
  显示汉字字符块
*/	

/*
  显示一张图片块
*/		
	
endmodule

三、显示彩色条纹

data_gen.v 模块

//显示彩带
always@(posedge vga_clk,negedge rst_n)begin
	if(!rst_n)
		data_dis<=BLACK;
	else
		case(h_addr)
			1  :data_dis<=WHITE		;
			80 :data_dis<=RED 		;
			160:data_dis<=GREEN		;
			240:data_dis<=BLUE  		;
			320:data_dis<=YELLOW		;
			400:data_dis<=SKY_BLUE	;
			480:data_dis<=PURPLE		;
			560:data_dis<=BLACK  		;
			default:data_dis<=data_dis;
		endcase

end		

效果展示

四、显示自定义汉字字符

  1. 汉字点阵提取
    FPGA-VGA显示_第10张图片
    点击保存为位图 320*32
    后再打开该图设置如下后,直接点击生成字模即可
    FPGA-VGA显示_第11张图片

FPGA-VGA显示_第12张图片

  1. data_gen.v 模块
//显示汉字字符块
 parameter  
			char_line00=320'h001E000000000078000001E000000000000000000000000000000000000000000000000000000000,
			char_line01=320'h007E00000F1FF87800001FF800000000000000000000000000000000000000000000000000000000,
			char_line02=320'h007800000F1FF87800001FF800000000000000000000000000000000000000000000000000000000,
			char_line03=320'h01F81F000FFFF87800FFFFF800000000000000000000000000000000000000000000000000000000,
			char_line04=320'h01E01F0003E0787800FFF80000000000000000000000000000000000000000000000000000000000,
			char_line05=320'h07E01FC003E0787800FFF8000000001F807FF003E01FE003F01FFF80FC007E007F03FFF80780FFFC,
			char_line06=320'h078003C003E0787800F000000000001F807FF003E01FE003F01FFF80FC007E007F03FFF80780FFFC,
			char_line07=320'h1FFFFFF0F3E0787800F000000000007FE1FFFC3FE07FF80FFC1FFF83FF03FF81FFC3FFF87F80FFFC,
			char_line08=320'h1FFFFFF0F000787800F0000000000079E1E03C3FE078780F3C1E0783CF03E781E3C3C0007F80F03C,
			char_line09=320'h1FFFFFF0FC1FF87800FFFFFE000003F9E1E03C3FE0787F3F3F1E1F9FCFCFE787E3F3C0007F80F0FC,
			char_line0a=320'h000000F03C1FF87800FFFFFE000003E001E03C03E0781F3C0F001E1F03CF000780F3C000078000F0,
			char_line0b=320'h000780F03C1FF87800FFFFFE000003E001E03C03E0781F3C0F001E1F03CF000780F3C000078000F0,
			char_line0c=320'h000780003C1E007800F01E00000003E000003C03E0781F3C0F001E1F03CF000780F3C000078000F0,
			char_line0d=320'h078780003FFE01F800F01E00000003FFE000FC03E0781F3C0F007E1F03CF7F8780F3FF00078003F0,
			char_line0e=320'h0787800003FE01E000F01E00000003FFE000F003E0781F3C0F00781F03CF7F8780F3FF00078003C0,
			char_line0f=320'h07FFFFF003FE01E000F01E0003FFF3FFF81FF003E0787F3C0F00781F03CFFFE780F3FFE0078003C0,
			char_line10=320'h07FFFFF003FE01E000F01E0003FFF3F8781FC003E0787F3C0F00781F03CFE1E780F3C3E0078003C0,
			char_line11=320'h1FFFFFF00FFFF9E000F01E0003FFF3F8781FF003E07FFF3C0F01F81F03CFE1E780F3C3F807800FC0,
			char_line12=320'h1E0780000F1FF9E000F01E00000003E07800F003E01FFF3C0F01E01F03CF01E780F0007807800F00,
			char_line13=320'h1E078000FF1FF9FF3FFFFFFFE00003E07800FC03E01FFF3C0F01E01F03CF01E780F0007807800F00,
			char_line14=320'h00078000FF0079FF3FFFFFFFE00003E078003C03E0001F3C0F01E01F03CF01E780F0007807800F00,
			char_line15=320'hFFFFFFFFFF007FFF3FFFFFFFE00003E079E03C03E0001F3C0F01E01F03CF01E780F3C07807800F00,
			char_line16=320'hFFFFFFFF0F007F9F00000000000003E079E03C03E0001F3C0F01E01F03CF01E780F3C07807800F00,
			char_line17=320'hFFFFFFFF0F007F9FC03C0780000003F879E03C03E01E7F3F3F01E01FCFCFE1E7E3F3C3F807800F00,
			char_line18=320'h000780000F007F83C03C07800000007879E03C03E01E780F3C01E003CF03E1E1E3C3C3E007800F00,
			char_line19=320'h000780000F007FFFC0FC07E00000007FF9FFFC3FFE1FF80FFC01E003FF03FFE1FFC3FFE07FF80F00,
			char_line1a=320'h000780000F007FFFC0F001E00000001FE07FF03FFE07E003F001E000FC007F807F00FF007FF80F00,
			char_line1b=320'h000780000F1FFFFFC3F001F80000001FE07FF03FFE07E003F001E000FC007F807F00FF007FF80F00,
			char_line1c=320'h000780000F1FE003C3C0007800000000000000000000000000000000000000000000000000000000,
			char_line1d=320'h000780000F1FE003CFC0007E00000000000000000000000000000000000000000000000000000000,
			char_line1e=320'h00078000000780000F00001E00000000000000000000000000000000000000000000000000000000,
			char_line1f=320'h00078000000780000F00001E00000000000000000000000000000000000000000000000000000000;

			
	  reg[8:0] char_bit;
    always@(posedge vga_clk)
        if(h_addr==10'd144)char_bit<=9'd320;   //当显示到144像素时准备开始输出图像数据
        else if(h_addr>10'd144&&h_addr<10'd464)     //左边距屏幕144像素到464像素时   464=144+320(图像宽度)
            char_bit<=char_bit-1'b1;       //倒着输出图像信息 
						
    always@(posedge vga_clk) 
        if(h_addr>10'd144&&h_addr<10'd464)    //X控制图像的横向显示边界:左边距屏幕左边144像素  右边界距屏幕左边界464像素
            begin case(v_addr)            //Y控制图像的纵向显示边界:从距离屏幕顶部160像素开始显示第一行数据
                10'd160:
                if(char_line00[char_bit])data_dis<=RED;  //如果该行有数据 则颜色为红色
                else data_dis<=BLUE;                      //否则为黑色
                10'd162:
                if(char_line01[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd163:
                if(char_line02[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd164:
                if(char_line03[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd165:
                if(char_line04[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd166:
                if(char_line05[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd167:
                if(char_line06[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd168:
                if(char_line07[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd169:
                if(char_line08[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd170:
                if(char_line09[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd171:
                if(char_line0a[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd172:
                if(char_line0b[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd173:
                if(char_line0c[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd174:
                if(char_line0d[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd175:
                if(char_line0e[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd176:
                if(char_line0f[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd177:
                if(char_line10[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd178:
                if(char_line11[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd179:
                if(char_line12[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd180:
                if(char_line13[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd181:
                if(char_line14[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd182:
                if(char_line15[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd183:
                if(char_line16[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd184:
                if(char_line17[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd185:
                if(char_line18[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd186:
                if(char_line19[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd187:
                if(char_line1a[char_bit])data_dis<=RED;
                else data_dis<=BLUE;
                10'd188:
                if(char_line1b[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd189:
                if(char_line1c[char_bit])data_dis<=RED;
                else data_dis<=BLUE;
                10'd190:
                if(char_line1d[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd191:
                if(char_line1e[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                10'd192:
                if(char_line1f[char_bit])data_dis<=RED;
                else  data_dis<=BLUE;
                default:data_dis<=BLUE;   //默认颜色蓝色
            endcase 
        end

	 else
			data_dis<=BLUE;		
  1. 效果展示:

五、输出一幅彩色图像

  1. 存储图片信息
    我们需要用到ROM,由于ROM 容量有限,我这选择了一张较小的100*100像素的位图
    转换位图生成对应文件
    FPGA-VGA显示_第13张图片

调用ROM的ip核。
RGB565 16位宽,所以选择16位宽,100*100像素所以是10000数据。
FPGA-VGA显示_第14张图片

将位图转换生成文件添加进去即可
FPGA-VGA显示_第15张图片

  1. data_gen.v 模块
显示图片
always@(posedge vga_clk, negedge rst_n)begin		
	if(!rst_n)begin
		data_dis=BLUE;
	end
	else if(add_cnt_address)
		data_dis=q;
   else
		data_dis=BLUE;
	

end

always@(posedge vga_clk,negedge rst_n)begin
	if(!rst_n)
		address<=1'b0;
	else if(add_cnt_address)
		if(end_cnt_address)
			address<=1'b0;
		else
			address<=address+1'b1;
   else	
		address<=address;

end
assign add_cnt_address=h_addr<200&&h_addr>=100&&v_addr<200&&v_addr>=100;
assign end_cnt_address=address==9999;

//例化ROM
ROM	ROM_inst (
	.address ( address),
	.clock ( vga_clk),
	.q ( q)
	);
		
  1. 效果展示:

六、软件提取

链接:https://pan.baidu.com/s/1ZZ8UFZILMjxfgNPAkM7Rgg
提取码:0614

你可能感兴趣的:(FPGA,fpga开发,图像处理,VGA)