FPGA数字电路板VGA模块原理及实现

某三本的数字逻辑课程已经进入了期末大作业阶段,所以这里为大家讲解一下如何在FPGA板上实现VGA的操控。


按照历史的发展, 屏幕显示分为了两种模式。较为简单的是文本模式,也就是平时命令行界面的样子,这种模式只能在屏幕上显示阵列字符,也就是横竖都是对齐的固定大小的字符。另一种,也是微软发家之路,就是图形模式。这种模式的显示单元为像素,每个像素都可以是不同的颜色。对于非程序猿来说,肯定是图形模式更加友好一些。不过,显而易见地,图形模式的实现要更复杂一些。


按照惯例,先上代码。

VGA(char mode).v

module VGA (
	input clk, //Clock cycle must be 25mhz.
	input rst, //VGA reset at positive edge of rst.
	input [31:0] d_in, //Values rrrr_gggg_bbbb_ascii, the color and ascii of the current character.
	
	output reg [3:0] r, //The VGA red channel.
	output reg [3:0] g, //The VGA green channel.
	output reg [3:0] b, //The VGA blue channel.
	output reg hs, //The VGA HSYNC bit.
	output reg vs, //The VGA VSYNC bit.
	output [12:0] addr //Current pixel position (x = addr[12:6], y = addr[5:0])
	);
	
	wire [9:0] row, col;
	wire [7:0] font_ascii;
	wire [3:0] font_line;
	wire [7:0] font_out;
	
	reg rdn;
	reg [9:0] h_count; // VGA horizontal counter (0-799): pixels
	reg [9:0] v_count; // VGA vertical counter (0-524): lines
	
	FONT FT(.ascii(font_ascii), .line(font_line), .out(font_out));
	
	always @ (posedge clk) begin
		if (rst) begin
			h_count <= 10'h0;
		end else if (h_count == 10'd799) begin
			h_count <= 10'h0;
		end else begin 
			h_count <= h_count + 10'h1;
		end
	end
	
	always @ (posedge clk or posedge rst) begin
		if (rst) begin
			v_count <= 10'h0;
		end else if (h_count == 10'd799) begin
			if (v_count == 10'd524) begin
				v_count <= 10'h0;
			end else begin
				v_count <= v_count + 10'h1;
			end
		end
	end
	
	assign row    =  v_count - 10'd35;     //pixel ram row addr 
	assign col    =  h_count - 10'd143;    //pixel ram col addr 
	wire h_sync = (h_count > 10'd95);    //96 -> 799
	wire v_sync = (v_count > 10'd1);     //2 -> 524
	wire read   = (h_count > 10'd142) &&
		(h_count < 10'd783) &&
		(v_count > 10'd34) &&
		(v_count < 10'd515);
    
	assign addr = rdn ? 13'h0 : {col[9:3], row[8:3]};
	assign font_ascii = rdn ? 8'b0 : d_in[7:0];
	assign font_line = {5'b0, row[2:0]};
	
	reg show_bit;
	always @ (posedge clk) begin
		rdn <= ~read;
		hs <= h_sync;
		vs <= v_sync;
		case(col[2:0])
		3'h0:show_bit <= font_out[7];
		3'h1:show_bit <= font_out[6];
		3'h2:show_bit <= font_out[5];
		3'h3:show_bit <= font_out[4];
		3'h4:show_bit <= font_out[3];
		3'h5:show_bit <= font_out[2];
		3'h6:show_bit <= font_out[1];
		3'h7:show_bit <= font_out[0];
		endcase
		
		r <= rdn ? 4'h0 : (show_bit ? d_in[31:28] : d_in[19:16]); // 4-bit red
		g <= rdn ? 4'h0 : (show_bit ? d_in[27:24] : d_in[15:12]); // 4-bit green
		b <= rdn ? 4'h0 : (show_bit ? d_in[23:20] : d_in[11:8]); // 4-bit blue
	end
endmodule


FONT.v

module FONT(
    input [7:0]ascii,
    input [3:0]line,
    output reg [7:0]out
    );


	wire [63:0] fontTable [0:127];
	
	assign fontTable[0] = 64'h0000_0000_0000_0000;
	assign fontTable[1] = 64'h7E81_A581_BD99_817E;
	assign fontTable[2] = 64'h7EFF_DBFF_C3E7_FF7E;
	assign fontTable[3] = 64'h6CFE_FEFE_7C38_1000;
	assign fontTable[4] = 64'h1038_7CFE_7C38_1000;
	assign fontTable[5] = 64'h386C_6CEE_C67C_387C;
	assign fontTable[6] = 64'h0010_387C_FE7C_387C;
	assign fontTable[7] = 64'h0000_183C_3C18_0000;
	assign fontTable[8] = 64'hFFFF_E7C3_C3E7_FFFF;
	assign fontTable[9] = 64'h003C_6642_4266_3C00;
	assign fontTable[10] = 64'hFFC3_99BD_BD99_C3FF;
	assign fontTable[11] = 64'h0F07_0D7C_CCCC_CC78;
	assign fontTable[12] = 64'h3C66_6666_3C18_7E18;
	assign fontTable[13] = 64'h3F30_3F30_3070_F0E0;
	assign fontTable[14] = 64'h7F63_7F63_6367_E6C0;
	assign fontTable[15] = 64'h995A_3CE7_E73C_5A99;
	assign fontTable[16] = 64'h80E0_F8FE_F8E0_8000;
	assign fontTable[17] = 64'h020E_3EFE_3E0E_0200;
	assign fontTable[18] = 64'h183C_7E18_7E3C_1800;
	assign fontTable[19] = 64'h6666_6666_6600_6600;
	assign fontTable[20] = 64'h7FDB_DB7B_1B1B_1B00;
	assign fontTable[21] = 64'h3E63_3C66_663C_C67C;
	assign fontTable[22] = 64'h0000_0000_7E7E_7E00;
	assign fontTable[23] = 64'h183C_7E18_7E3C_18FF;
	assign fontTable[24] = 64'h183C_7E18_1818_1800;
	assign fontTable[25] = 64'h1818_1818_7E3C_1800;
	assign fontTable[26] = 64'h0018_0CFE_0C18_0000;
	assign fontTable[27] = 64'h0030_60FE_6030_0000;
	assign fontTable[28] = 64'h0000_C0C0_C0FE_0000;
	assign fontTable[29] = 64'h0024_66FF_6624_0000;
	assign fontTable[30] = 64'h0018_3C7E_FFFF_0000;
	assign fontTable[31] = 64'h00FF_FF7E_3C18_0000;
	assign fontTable[32] = 64'h0000_0000_0000_0000;
	assign fontTable[33] = 64'h3078_7830_3000_3000;
	assign fontTable[34] = 64'h6C6C_6C00_0000_0000;
	assign fontTable[35] = 64'h6C6C_FE6C_FE6C_6C00;
	assign fontTable[36] = 64'h307C_C078_0CF8_3000;
	assign fontTable[37] = 64'h00C6_CC18_3066_C600;
	assign fontTable[38] = 64'h386C_3876_DCCC_7600;
	assign fontTable[39] = 64'h6060_C000_0000_0000;
	assign fontTable[40] = 64'h1830_6060_6030_1800;
	assign fontTable[41] = 64'h6030_1818_1830_6000;
	assign fontTable[42] = 64'h0066_3CFF_3C66_0000;
	assign fontTable[43] = 64'h0030_30FC_3030_0000;
	assign fontTable[44] = 64'h0000_0000_0030_3060;
	assign fontTable[45] = 64'h0000_00FC_0000_0000;
	assign fontTable[46] = 64'h0000_0000_0030_3000;
	assign fontTable[47] = 64'h060C_1830_60C0_8000;
	assign fontTable[48] = 64'h7CC6_C6D6_C6C6_7C00;
	assign fontTable[49] = 64'h3070_3030_3030_FC00;
	assign fontTable[50] = 64'h78CC_0C38_60CC_FC00;
	assign fontTable[51] = 64'h78CC_0C38_0CCC_7800;
	assign fontTable[52] = 64'h1C3C_6CCC_FE0C_1E00;
	assign fontTable[53] = 64'hFCC0_F80C_0CCC_7800;
	assign fontTable[54] = 64'h3860_C0F8_CCCC_7800;
	assign fontTable[55] = 64'hFCCC_0C18_3030_3000;
	assign fontTable[56] = 64'h78CC_CC78_CCCC_7800;
	assign fontTable[57] = 64'h78CC_CC7C_0C18_7000;
	assign fontTable[58] = 64'h0030_3000_3030_0000;
	assign fontTable[59] = 64'h0030_3000_3030_6000;
	assign fontTable[60] = 64'h1830_60C0_6030_1800;
	assign fontTable[61] = 64'h0000_FC00_00FC_0000;
	assign fontTable[62] = 64'h6030_180C_1830_6000;
	assign fontTable[63] = 64'h78CC_CC18_3000_3000;
	assign fontTable[64] = 64'h7CC6_DEDE_DEC0_7800;
	assign fontTable[65] = 64'h3078_CCCC_FCCC_CC00;
	assign fontTable[66] = 64'hFC66_667C_6666_FC00;
	assign fontTable[67] = 64'h3C66_C0C0_C066_3C00;
	assign fontTable[68] = 64'hF86C_6666_666C_F800;
	assign fontTable[69] = 64'hFE62_6878_6862_FE00;
	assign fontTable[70] = 64'hFE62_6878_6860_F000;
	assign fontTable[71] = 64'h3C66_C0C0_CE66_3E00;
	assign fontTable[72] = 64'hCCCC_CCFC_CCCC_CC00;
	assign fontTable[73] = 64'h7830_3030_3030_7800;
	assign fontTable[74] = 64'h1E0C_0C0C_CCCC_7800;
	assign fontTable[75] = 64'hC666_6C78_6C66_C600;
	assign fontTable[76] = 64'hF060_6060_6266_FE00;
	assign fontTable[77] = 64'hC6EE_FEFE_D6C6_C600;
	assign fontTable[78] = 64'hC6E6_F6DE_CEC6_C600;
	assign fontTable[79] = 64'h7CC6_C6C6_C6C6_7C00;
	assign fontTable[80] = 64'hFC66_667C_6060_F000;
	assign fontTable[81] = 64'h7CC6_C6C6_C6D6_7C06;
	assign fontTable[82] = 64'hFC66_667C_6C66_E600;
	assign fontTable[83] = 64'h7CC6_6038_0CC6_7C00;
	assign fontTable[84] = 64'hFF99_1818_1818_3C00;
	assign fontTable[85] = 64'hCCCC_CCCC_CCCC_7800;
	assign fontTable[86] = 64'hCCCC_CCCC_CC78_3000;
	assign fontTable[87] = 64'hC6C6_D6FE_FEEE_C600;
	assign fontTable[88] = 64'hC6C6_6C38_6CC6_C600;
	assign fontTable[89] = 64'hCCCC_CC78_3030_7800;
	assign fontTable[90] = 64'hFEC6_8C18_3266_FE00;
	assign fontTable[91] = 64'h7860_6060_6060_7800;
	assign fontTable[92] = 64'hC060_3018_0C06_0200;
	assign fontTable[93] = 64'h7818_1818_1818_7800;
	assign fontTable[94] = 64'h1038_6CC6_0000_0000;
	assign fontTable[95] = 64'h0000_0000_0000_00FF;
	assign fontTable[96] = 64'h3030_1800_0000_0000;
	assign fontTable[97] = 64'h0000_780C_7CCC_7600;
	assign fontTable[98] = 64'hE060_7C66_6666_DC00;
	assign fontTable[99] = 64'h0000_78CC_C0CC_7800;
	assign fontTable[100] = 64'h1C0C_7CCC_CCCC_7600;
	assign fontTable[101] = 64'h0000_78CC_FCC0_7800;
	assign fontTable[102] = 64'h386C_60F0_6060_F000;
	assign fontTable[103] = 64'h0000_76CC_CC7C_0CF8;
	assign fontTable[104] = 64'hE060_6C76_6666_E600;
	assign fontTable[105] = 64'h3000_7030_3030_7800;
	assign fontTable[106] = 64'h0C00_0C0C_0CCC_CC78;
	assign fontTable[107] = 64'hE060_666C_786C_6600;
	assign fontTable[108] = 64'h7030_3030_3030_7800;
	assign fontTable[109] = 64'h0000_CCFE_FED6_D600;
	assign fontTable[110] = 64'h0000_F8CC_CCCC_CC00;
	assign fontTable[111] = 64'h0000_78CC_CCCC_7800;
	assign fontTable[112] = 64'h0000_DC66_667C_60F0;
	assign fontTable[113] = 64'h0000_766C_6C7C_0C1E;
	assign fontTable[114] = 64'h0000_DC76_6060_F000;
	assign fontTable[115] = 64'h0000_7CC0_780C_F800;
	assign fontTable[116] = 64'h1030_7C30_3036_1C00;
	assign fontTable[117] = 64'h0000_CCCC_CCCC_7600;
	assign fontTable[118] = 64'h0000_CCCC_CC78_3000;
	assign fontTable[119] = 64'h0000_C6D6_FEFE_6C00;
	assign fontTable[120] = 64'h0000_C66C_386C_C600;
	assign fontTable[121] = 64'h0000_CCCC_CC7C_0CF8;
	assign fontTable[122] = 64'h0000_FC98_3064_FC00;
	assign fontTable[123] = 64'h1C30_30E0_3030_1C00;
	assign fontTable[124] = 64'h1818_1800_1818_1800;
	assign fontTable[125] = 64'hE030_301C_3030_E000;
	assign fontTable[126] = 64'h0000_72D6_9C00_0000;
	assign fontTable[127] = 64'h0010_386C_C6C6_FE00;


	always @(ascii)begin
		case(line)
		8'd0: out <= fontTable[ascii][63:56];
		8'd1: out <= fontTable[ascii][55:48];
		8'd2: out <= fontTable[ascii][47:40];
		8'd3: out <= fontTable[ascii][39:32];
		8'd4: out <= fontTable[ascii][31:24];
		8'd5: out <= fontTable[ascii][23:16];
		8'd6: out <= fontTable[ascii][15:8];
		8'd7: out <= fontTable[ascii][7:0];
		endcase
	end
	
endmodule


上面两个模块的关系是很明确的。VGA是用户代码和FPGA板子之间的关联辅助模块,FONT是点阵字库,用来将用户代码传入的ascii字符显示在屏幕上。使用VGA模块的时候,应该将它作为顶层模块的一个子模块。同时,在顶层模块中还应该有一个向VGA模块传输数据的文本显示模块。他们的层级关系应该是下面这样的:

顶层模块 包含

    文本显示模块  VGA模块


其中

VGA模块 包含

    FONT模块


文本显示模块的输出在顶层里连接到VGA模块的输入,VGA模块的输出一部分连接到顶层的输出,也就是FPGA板子,另一部分连回到文本显示模块。为了更好地理解这个结构,我们来模拟一下。现在假设整个系统刚刚启动,时钟信号开始翻转,VGA模块立即开始工作并产生输出。这个时候VGA输出部分的有效内容为所绘制的像素所在字符的坐标,然后这个坐标信号被传入文本显示模块,经过其内部的用户逻辑,输出这个像素所在字符的前景色背景色和ascii码。这三个信息组合而成的32位数据又被传入了VGA模块,然后经过VGA的计算,输出了当前绘制像素的rgb,传出到FPGA板子上。


所以,我们需要完成的就是文本显示模块的内部逻辑。这里给出一个范例,就是在(1, 1)的位置显示一个黑底白色的字符‘a'。

VGA vga(.d_in(ch), .addr(addr), others omitted);
if(addr[5:0]==6'b1 && addr[12:6]==7'b1)d_in<=20'b1111_1111_1111_0110_0001;

在这个范例中,因为逻辑过于简单,我直接将文本显示的逻辑写在了顶层中,与VGA并列。如果大家想要在屏幕上显示很多字符的话,逻辑会变得很复杂,这个时候据需要单独设立一个模块来完成这些逻辑了。


代码已经测试过了,仅仅在屏幕上(1, 1)显示一个‘a’的工程链接附上。emmm然后CSDN好像不允许设置资源免费下载了,,,那我就设置个最少的2分吧。

工程下载


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值