FPGA 学习笔记(十一) VGA驱动的实现

来源:互联网 发布:嘉兴学院客户端mac 编辑:程序博客网 时间:2024/05/16 11:31

VGA时序图

1)行扫描时序图

a:行同步时期,扫描地址的复位
b:行消隐后肩,扫描地址转移后的稳定等待准备期
c:行显示时期,数据有效区域
d:行消隐前肩,扫描地址转移的准备
e:行扫描总时间,一行扫描的总时间

2)场扫描时序图

o:场同步时期,扫描地址的复位
p:场消隐后肩,扫描地址转移后的稳定等待准备期
q:场显示时期,数据有效区域
r:场消隐前肩,扫描地址转移的准备
s:场扫描总时间,一场扫描的总时间

3)VGA显示器扫描轨迹

常见的刷新率时序表

由于FPGA擅长计数电路这里采用像素表示法来设计驱动

FPGA硬件 测试时要将sys_pll中的输出频率改为25MHZ。

驱动电路的verilog设计(lcd_driver)

由亍目前液晶显示器的普及,而高于 60Hz 的刷新率对于液晶来说,没有任何意义,所以我们以 640*480 在 60Hz 的刷新率下为例。

本次我们采用的是ADV7123视频转换芯片来实现。

1)为便于移植,根据640*480 60hz分辨率下的参数,宏定义相关数据

//---------------------------------//  640 * 480`define H_FRONT 11'd16`define H_SYNC  11'd96  `define H_BACK  11'd48  `define H_DISP  11'd640 `define H_TOTAL 11'd800     `define V_FRONT 11'd10  `define V_SYNC  11'd2   `define V_BACK  11'd33 `define V_DISP  11'd480   `define V_TOTAL 11'd525

2)行扫描单位hcnt计数

/*******************************************        SYNC--BACK--DISP--FRONT*******************************************///------------------------------------------//h_sync counter & generatorreg [10:0] hcnt; always @ (posedge clk or negedge rst_n)begin    if (!rst_n)        hcnt <= 11'd0;    else        begin        if(hcnt < `H_TOTAL - 1'b1)      //line over                     hcnt <= hcnt + 1'b1;        else            hcnt <= 11'd0;        endend assign  lcd_hs = (hcnt <= `H_SYNC - 1'b1) ? 1'b0 : 1'b1;//VGA行同步信号

3)列扫描单位vcnt计数
每扫描完一行,即hcnt完成H_TOTAL次计数后,vcnt进行自加。

//------------------------------------------//v_sync counter & generatorreg [10:0] vcnt;always@(posedge clk or negedge rst_n)begin    if (!rst_n)        vcnt <= 11'b0;    else if(hcnt == `H_TOTAL - 1'b1)        //line over        begin        if(vcnt < `V_TOTAL - 1'b1)      //frame over            vcnt <= vcnt + 1'b1;        else            vcnt <= 11'd0;        endendassign  lcd_vs = (vcnt <= `V_SYNC - 1'b1) ? 1'b0 : 1'b1;//VGA场同步信号

4)ADV7123控制信号输出
为了实现数据在lcd_dclk上升沿有效,我们将clk翻转输出,已实现上升沿采样
lcd_blank作为显示空白信号,低电平有效。
设计中不需要lcd_sync信息,可以直接接地。

//------------------------------------------//LCELL LCELL(.in(clk),.out(lcd_dclk));assign  lcd_dclk = ~clk;assign  lcd_blank = lcd_hs & lcd_vs;        assign  lcd_sync = 1'b0;

5)有效显示使能信号输出
当使能信号有效时,接收外部输入的RGB数据lcd_data.

//-----------------------------------------assign  lcd_en      =   (hcnt >= `H_SYNC + `H_BACK  && hcnt < `H_SYNC + `H_BACK + `H_DISP) &&                        (vcnt >= `V_SYNC + `V_BACK  && vcnt < `V_SYNC + `V_BACK + `V_DISP)                         ? 1'b1 : 1'b0;assign  lcd_rgb     =   lcd_en ? lcd_data : 24'h000000; //ffffff;

6)外部数据请求控制信号。
为了实现数据的稳定,lcd_request要提前一个时钟请求外部输入数据
同时,设计中实时显示下一时刻的扫描地址lcd_xpos、lcd_ypos,也要提前一个时钟输出,以保证外部数据输入的同步化。
lcd_xpos、lcd_ypos作为显示器有效显示区域的行列坐标计数值。

//------------------------------------------//ahead x clocklocalparam  H_AHEAD =   11'd1;assign  lcd_request =   (hcnt >= `H_SYNC + `H_BACK - H_AHEAD && hcnt < `H_SYNC + `H_BACK + `H_DISP - H_AHEAD) &&                        (vcnt >= `V_SYNC + `V_BACK && vcnt < `V_SYNC + `V_BACK + `V_DISP)                         ? 1'b1 : 1'b0;//lcd xpos & yposassign  lcd_xpos    =   lcd_request ? (hcnt - (`H_SYNC + `H_BACK - H_AHEAD)) : 11'd0;assign  lcd_ypos    =   lcd_request ? (vcnt - (`V_SYNC + `V_BACK)) : 11'd0;

模拟VGA图像数据的输入

1)宏定义三原色组合的颜色如下

//define colors RGB--8|8|8`define RED     24'hFF0000   /*11111111,00000000,00000000   */`define GREEN   24'h00FF00   /*00000000,11111111,00000000   */`define BLUE    24'h0000FF   /*00000000,00000000,11111111   */`define WHITE   24'hFFFFFF   /*11111111,11111111,11111111   */`define BLACK   24'h000000   /*00000000,00000000,00000000   */`define YELLOW  24'hFFFF00   /*11111111,11111111,00000000   */`define CYAN    24'hFF00FF   /*11111111,00000000,11111111   */`define ROYAL   24'h00FFFF   /*00000000,11111111,11111111   */ 

这里要注意你所用的VGA驱动电路是RGB888还是RGB565,若是RGB565,三原色要改成下面样式,并把其他程序中lcd_data的位数改为16位:
笔者曾在这里犯过错误。

//define colors RGB--5|6|5`define RED     16'hF800   /*11111111,00000000,00000000 */`define GREEN   16'h07E8  /*00000000,11111111,00000000  */`define BLUE    16'h0011   /*00000000,00000000,11111111 */`define WHITE   16'hFFFF   /*11111111,11111111,11111111 */`define BLACK   16'h0000   /*00000000,00000000,00000000 */`define YELLOW  16'hFFE0   /*11111111,11111111,00000000 */`define CYAN    16'hF81F   /*11111111,00000000,11111111 */`define ROYAL   16'h07FF   /*00000000,11111111,11111111 */ 

2)根据输入的行、列地址信号,输出三原色组合后得到的8条彩色。

//-------------------------------------------`ifdef VGA_HORIZONTAL_COLORalways@(posedge clk or negedge rst_n)begin    if(!rst_n)        lcd_data <= 24'h0;    else        begin        if  (lcd_ypos >= 0 && lcd_ypos < (`V_DISP/8)*1)            lcd_data <= `RED;        else if(lcd_ypos >= (`V_DISP/8)*1 && lcd_ypos < (`V_DISP/8)*2)            lcd_data <= `GREEN;        else if(lcd_ypos >= (`V_DISP/8)*2 && lcd_ypos < (`V_DISP/8)*3)            lcd_data <= `BLUE;        else if(lcd_ypos >= (`V_DISP/8)*3 && lcd_ypos < (`V_DISP/8)*4)            lcd_data <= `WHITE;        else if(lcd_ypos >= (`V_DISP/8)*4 && lcd_ypos < (`V_DISP/8)*5)            lcd_data <= `BLACK;        else if(lcd_ypos >= (`V_DISP/8)*5 && lcd_ypos < (`V_DISP/8)*6)            lcd_data <= `YELLOW;        else if(lcd_ypos >= (`V_DISP/8)*6 && lcd_ypos < (`V_DISP/8)*7)            lcd_data <= `CYAN;        else// if(lcd_ypos >= (`V_DISP/8)*7 && lcd_ypos < (`V_DISP/8)*8)            lcd_data <= `ROYAL;        endend`endif

不同分辨率的VGA驱动

lcd_para文件定义了四种VGA分辨率驱动,这里只需修改定义的注释就行,并把PLL锁相环中的频率改为相应的频率。

//`define   VGA_640_480_60FPS_25MHz//`define   VGA_800_600_72FPS_50MHz//`define   VGA_1024_768_60FPS_65MHz `define VGA_1280_1024_60FPS_105MHz

PLL修改方法为直接修改下面参数中的乘法除法因子:

        altpll_component.clk0_divide_by = 10,        altpll_component.clk0_duty_cycle = 50,        altpll_component.clk0_multiply_by = 21,        altpll_component.clk0_phase_shift = "0",        altpll_component.compensate_clock = "CLK0",        altpll_component.inclk0_input_frequency = 20000,
0 0
原创粉丝点击