显示模块_VGA控制器
一.功能:
①.基本功能:设计一个VGA控制器,输出data_request从外部读取RGB值,产生RGB,HS,VS五个信号,驱动VG视频输出模块(包含专用视频 DAC 芯片 GM7123)控制显示屏动态色彩输出。
说明:因为VGA是传输模拟信号,用模拟信号驱动显示屏显示,所以这里FPGA设计完VGA_CTL模块后,通过GN7123把数字信号转为模拟信号,再接到VGA接口去驱动。
对于数字信号驱动的接口,可能不需要GM7123。(留坑)
②.强化功能:
Ⅰ.实现快速改变显示器分辨率:条件编译语句(见下文)。
Ⅱ.实现RGB888与RGB565的变换:截位/补位思想。
Ⅲ.实现显示特定区域:在模块内部定义区域参数,区域内取1,区域外取0。接着利用区域参数界定是否输出像素值。
Ⅳ.输出当前扫描点的坐标。( assign axis = vis_sig ? (cnt - start ) : 0 )
二.设计:根据显示屏分辨率设置各节点参数,行,列计数器,而后利用参数限制范围约束行计数器和列计数器设计每个信号的输出。
三.框图:
四.过程:定义行和列计数器。进入显示区域时,发出data_request信号向外部请求要显示的像素值rgb_data,然后输出该值rgb。同时根据显示器分辨率设计hs和vs信号。不显示区域信号输出0。
在这里要注意,data_request信号是本模块内部定义的,适用于本模块的情况。之后做项目时从其他模块取数据,可能会慢几拍到达本模块,所以需要调整data_request信号的出现位置。
五.修改参数的方法:
1.使用变量(数组边界:array[ ( 变量名 ) + : x 位 ] )。
2.参数化设计(例化时修改参数)(如:①defparameter xx = m ; ②#(.参数名(新值)))
3.条件编译语法:写一个新的文件来存储参数,然后在主文件中include该参数文件(`incluede"xxx.v"),便可以实现不同分辨率的整套参数切换。如下:
//`define Resolution_480x272 1 //刷新率为60Hz其时钟频率为 9MHz //`define Resolution_640x480 1 //刷新率为60Hz其时钟频率为 25.2MHz //`define Resolution_800x480 1 //刷新率为60Hz其时钟频率为 33.264MHz //`define Resolution_800x600 1 //刷新率为60Hz其时钟频率为 40MHz //`define Resolution_1024x600 1 //刷新率为60Hz其时钟频率为 50.64MHz //`define Resolution_1024x768 1 //刷新率为60Hz其时钟频率为 65MHz `define Resolution_1280x720 1 //刷新率为60Hz其时钟频率为 74.25MHz //`define Resolution_1920x1080 1 //(1080p)刷新率为60Hz其时钟频率为 148.5MHz //时钟频率计算公式:f = 1 / (( 1 / 60 ) / ( H_Total_Time * V_Total_Time ) ) `ifdef Resolution_480x272 `define H_Right_Border 0 `define H_Front_Porch 2 `define H_Sync_Time 41 `define H_Back_Porch 2 `define H_Left_Border 0 `define H_Data_Time 480 `define H_Total_Time 525 `define V_Bottom_Border 0 `define V_Front_Porch 2 `define V_Sync_Time 10 `define V_Back_Porch 2 `define V_Top_Border 0 `define V_Data_Time 272 `define V_Total_Time 286 `elsif Resolution_640x480 `define H_Right_Border 8 `define H_Front_Porch 8 `define H_Sync_Time 96 `define H_Back_Porch 40 `define H_Left_Border 8 `define H_Data_Time 640 `define H_Total_Time 800 `define V_Bottom_Border 8 `define V_Front_Porch 2 `define V_Sync_Time 2 `define V_Back_Porch 25 `define V_Top_Border 8 `define V_Data_Time 480 `define V_Total_Time 525 `elsif Resolution_800x480 `define H_Right_Border 0 `define H_Front_Porch 40 `define H_Sync_Time 128 `define H_Back_Porch 88 `define H_Left_Border 0 `define H_Data_Time 800 `define H_Total_Time 1056 `define V_Bottom_Border 8 `define V_Front_Porch 2 `define V_Sync_Time 2 `define V_Back_Porch 25 `define V_Top_Border 8 `define V_Data_Time 480 `define V_Total_Time 525 `elsif Resolution_800x600 `define H_Right_Border 0 `define H_Front_Porch 40 `define H_Sync_Time 128 `define H_Back_Porch 88 `define H_Left_Border 0 `define H_Data_Time 800 `define H_Total_Time 1056 `define V_Bottom_Border 0 `define V_Front_Porch 1 `define V_Sync_Time 4 `define V_Back_Porch 23 `define V_Top_Border 0 `define V_Data_Time 600 `define V_Total_Time 628 `elsif Resolution_1024x600 `define H_Right_Border 0 `define H_Front_Porch 24 `define H_Sync_Time 136 `define H_Back_Porch 160 `define H_Left_Border 0 `define H_Data_Time 1024 `define H_Total_Time 1344 `define V_Bottom_Border 0 `define V_Front_Porch 1 `define V_Sync_Time 4 `define V_Back_Porch 23 `define V_Top_Border 0 `define V_Data_Time 600 `define V_Total_Time 628 `elsif Resolution_1024x768 `define H_Right_Border 0 `define H_Front_Porch 24 `define H_Sync_Time 136 `define H_Back_Porch 160 `define H_Left_Border 0 `define H_Data_Time 1024 `define H_Total_Time 1344 `define V_Bottom_Border 0 `define V_Front_Porch 3 `define V_Sync_Time 6 `define V_Back_Porch 29 `define V_Top_Border 0 `define V_Data_Time 768 `define V_Total_Time 806 `elsif Resolution_1280x720 `define H_Right_Border 0 `define H_Front_Porch 110 `define H_Sync_Time 40 `define H_Back_Porch 220 `define H_Left_Border 0 `define H_Data_Time 1280 `define H_Total_Time 1650 `define V_Bottom_Border 0 `define V_Front_Porch 5 `define V_Sync_Time 5 `define V_Back_Porch 20 `define V_Top_Border 0 `define V_Data_Time 720 `define V_Total_Time 750 `elsif Resolution_1960x1080 `define H_Right_Border 0 `define H_Front_Porch 88 `define H_Sync_Time 44 `define H_Back_Porch 148 `define H_Left_Border 0 `define H_Data_Time 1920 `define H_Total_Time 2200 `define V_Bottom_Border 0 `define V_Front_Porch 4 `define V_Sync_Time 5 `define V_Back_Porch 36 `define V_Top_Border 0 `define V_Data_Time 1080 `define V_Total_Time 1125 `endif
六.截位/补位思想:
Ⅰ.24位RGB[23:0]转16位RGB[15:0]是通过取高位来实现的。取RGB[23:19],RGB[15:10],RGB[7:3]作为RGB三原色的值。
Ⅱ.16位RGB[23:0]转24位RGB[15:0]是通过补位来实现的。使用位拼接的语法为RGB低位补0至8位即可。
七.程序设计
module VGA( clk, reset, content_data_request,//数据请求信号 horizontal_sig,//horizontal 水平的 vertical_sig, //vertical 垂直的 content_data,//要显示的内容数据 RGB_data,//输出的内容数据 vis_sig//内容显示同步信号(高电平时显示) ); input clk ; input reset ; output reg content_data_request ;//数据请求信号 output reg horizontal_sig ; output reg vertical_sig ; input [23:0]content_data ; output reg [23:0]RGB_data ; output reg vis_sig ;//内容显示同步信号 reg h_vis_sig ;//行内容显示同步信号 reg v_vis_sig ;//列内容显示同步信号 `include "VGA_resolution_parameter.v" //定义时间节点参数 //行参数 parameter h_pulse_start = 0 ; //行起始脉冲开始信号 parameter h_pulse_end = `H_Sync_Time ;// 行起始脉冲结束信号 parameter h_content_start = `H_Sync_Time + `H_Back_Porch + `H_Left_Border ;//行内容开始信号 parameter h_content_end = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time ;//行内容结束信号 parameter h_end = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time + `H_Right_Border + `H_Front_Porch;//行结束信号 //列参数 parameter v_pulse_start = 0 ; //列起始脉冲开始信号 parameter v_pulse_end = `V_Sync_Time ;//列起始脉冲结束信号 parameter content_start = `V_Sync_Time + `V_Back_Porch + `V_Top_Border ;//列内容开始信号 parameter content_end = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time ;//列内容结束信号 parameter v_end = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time + `V_Bottom_Border + `V_Front_Porch;//列结束信号 //行与列 计数器 reg [11:0]h_cnt ; reg [11:0]v_cnt ; always@(posedge clk or negedge reset)//行计数 if(!reset) h_cnt <= 0 ; else if ( h_end - 1 <= h_cnt )//0-799 h_cnt <= 0 ; else h_cnt <= h_cnt + 1 ; always@(posedge clk or negedge reset)//列计数 if(!reset) v_cnt <= 0 ; else if (( v_end - 1 <= v_cnt ) && ( h_end - 1 <= h_cnt ))//0-524 v_cnt <= 0 ; else if (( h_end - 1 <= h_cnt ) && ( v_end - 1 > v_cnt )) v_cnt <= v_cnt + 1 ; //产生行起始脉冲 always@(posedge clk or negedge reset)// if(!reset) horizontal_sig <= 1 ; else if( h_cnt == 0 ) horizontal_sig <= 0 ;//1-96 共96 else if ( h_cnt == h_pulse_end ) horizontal_sig <= 1 ; //产生列起始脉冲 always@(posedge clk or negedge reset)// if(!reset) vertical_sig <= 1 ; else if(( v_cnt == 0 )&& ( h_end - 1 <= h_cnt ) ) vertical_sig <= 0 ;//1-2 共2 else if (( v_cnt == v_pulse_end )&& ( h_end - 1 <= h_cnt ) ) vertical_sig <= 1 ; //产生行显示同步信号 always@(posedge clk or negedge reset)// if(!reset) h_vis_sig <= 0 ; else if (( h_content_start - 2 <= h_cnt ) && ( h_content_end - 1 - 2 >= h_cnt )) //提前两拍保证输出在第145拍开始 h_vis_sig <= 1 ;//146 - 785共 else h_vis_sig <= 0 ; //产生列显示同步信号 always@(posedge clk or negedge reset)// if(!reset) v_vis_sig <= 0 ; else if (( content_start <= v_cnt ) && ( content_end >= v_cnt ) && ( ( h_end - 1 <= h_cnt ) ) ) v_vis_sig <= 1 ; else if (( content_start > v_cnt ) || ( content_end < v_cnt ) ) v_vis_sig <= 0 ; //请求信号 always@(posedge clk or negedge reset) if(!reset) content_data_request <= 0 ;// else if ( ( v_vis_sig ) && ( h_vis_sig ) ) content_data_request <= 1 ; else content_data_request <= 0 ; //显示同步信号 always@(posedge clk or negedge reset)// if(!reset) vis_sig <= 0 ; else if ( content_data_request ) vis_sig <= 1 ; else vis_sig <= 0 ; //显示 always@(posedge clk or negedge reset)// if(!reset) RGB_data <= 0 ; else if ( content_data_request ) RGB_data <= content_data ; else RGB_data <= 0 ; endmodule
`timescale 1ns / 1ns module VGB_tb( ); reg clk ; reg reset ; wire horizontal_sig ; wire vertical_sig ; reg [23:0]content_data ; wire [23:0]RGB_data ; wire content_data_request ;//数据请求信号 ; wire vis_sig ; VGA VGA_sim( clk, reset, content_data_request,//数据请求信号 horizontal_sig,//horizontal 水平的 vertical_sig, //vertical 垂直的 content_data,//要显示的内容数据 RGB_data,//输出的内容数据 vis_sig //内容显示同步信号 ); initial clk = 1 ; always #20 clk = ! clk ;//25MHz initial begin reset = 0 ; content_data = 0 ; #201 reset = 1 ; #70000000; $stop; end always@(posedge clk or negedge reset)// if(!reset) content_data <= 0 ; else if (content_data_request ) content_data <= content_data + 1 ; endmodule
七.仿真结果: