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

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 & generator
reg [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;
        end
end 
assign  lcd_hs = (hcnt <= `H_SYNC - 1'b1) ? 1'b0 : 1'b1;
//VGA行同步信号

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

//------------------------------------------
//v_sync counter & generator
reg [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;
        end
end
assign  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 clock
localparam  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 & ypos
assign  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_COLOR
always@(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;
        end
end
`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,
  • 14
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值