FPGA开发实验(9)- RGB_LCD显示实验

一、RGB_LCD简介与实验任务

1.1 RGB_LCD简介

TFT-LCD,即薄膜晶体管液晶显示屏。它显示的每个像素点都是由集成在液晶后面的薄膜晶体管独立驱动。使用LCD需要从使用的角度去关注 LCD 的几个重要点:
1.分辨率: LCD 显示器分辨率一般分为 720P、1080P、2K 或 4K等。RGB 灯由 R(红色)、G(绿色)和 B(蓝色)这三种颜色组成的。如:1080P 的意思就是一个 LCD 屏幕上的像素数量是 19201080 个,也就是这个屏幕一列 1080 个像素点,一共 1920 列。
2.像素格式:RGB888像素格式一个 R、G、B 这三部分分别使用8bit 的数据,一个像素点就是 8bit
3=24bit,一个像素点 3 个字节。像素点格式还有 RGB565,只需要两个字节,但在色彩鲜艳度上较差一些。本实验采用的LCD屏幕的像素格式为RGB888。
3.LCD 屏幕接口:LCD 屏幕或者说显示器有很多种接口,比如在显示器上常见的 VGA、HDMI、DP 等等,开发板支持RGB 接口的 LCD 和 HDMI 接口的显示器。本次实验采用的是 RGB LCD 接口:R[7:0]、G[7:0]和 B[7:0]是 24 位数据,DE、VSYNC、HSYNC 和PCLK 是四个控制信号。LCD_R7/G7/B7 则用来设置 LCD的 ID。本次实验采用ATK-7016 RGB LCD模块,LCD的 ID = 010 即可。
4.LCD 时间参数。一帧图像也是由一行一行组成的。HSYNC 是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了。VSYNC 信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了。假如一个 LCD 的分辨率为 1024600,那么其扫
描如图 28.1.6 所示:
在这里插入图片描述
5.RGB LCD 屏幕时序:
RGB LCD 的行显示时序如下图所示:
在这里插入图片描述
**HSYNC:**行同步信号,当此信号有效的时候就表示开始显示新的一行数据。
**HSPW:**行同步信号宽度,也就是 HSYNC 信号持续时间。
**HBP:**行显示后沿(或后肩)。
HOZVAL:行有效显示区域,即显示一行数据所需的时间,假如屏幕分辨率为 1024
600,那么HOZVAL 就是 1024,单位为 CLK。
HFP:行显示前沿(或前肩)。
所以
显示一行所需要的时间
:HSPW + HBP + HOZVAL + HFP。

RGB LCD 的帧显示时序如下图所示:
在这里插入图片描述
**VSYNC:**帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据
**VSPW:**帧同步信号宽度。
VBP:帧显示后沿(或后肩)。
LINE:帧有效显示区域,即显示一帧数据所需的时间。
VFP:帧显示前沿(或前肩)。
所以
显示一帧所需要的时间
:VSPW+VBP+LINE+VFP
最终的计算公式:T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)
两种数据同步方式,一种是
行场同步模式
(HV Mode),另一种是
数据使能同步模式
(DE Mode)。
当选择HV行场同步模式时,LCD 接口的时序与 VGA 接口的时序图非常相似,只是参数不同。行同步信号(HSYNC)和场同步信号(VSYNC)作为数据的同步信号,此时数据使能信号(DE)必须为低电平。
当选择 DE 同步模式时,LCD 的 DE 信号作为数据的有效信号。只有同时扫描到帧有效显示区域和行有效显示区域时,DE 信号才有效(高电平)。当选择 DE 同步模式时,此时行场同步信号 VS 和 HS 必须为高电平。
本实验采用 DE 同步的方式驱动 LCD 液晶屏。
6.像素时钟
本次实验显示一帧图像所需要的时钟数就是:N(CLK)= (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)= (3 + 20 + 600 + 12) * (20 + 140 + 1024 + 160) = 635 * 1344 = 853440
显示一帧图像需要 853440 个时钟数,那么显示 60 帧就是:853440 * 60 = 51206400≈51.2M,所以像素时钟就是 51.2MHz。不是必须严格采用51.2M,所以我们采用50MHZ。

1.2 实验任务

本节的实验任务是使用达芬奇开发板上的 RGB-LCD 接口,驱动 RGB-LCD 液晶屏(支持目前推出的所有 RGB-LCD 屏),并显示出彩条。

二、程序设计

2.1 总体模块设计

在这里插入图片描述
FPGA 部分包括五个模块,顶层模块(lcd_rgb_colorbar)、读取 ID 模块(rd_id)、时钟分频模块(clk_div)、LCD 显示模块(lcd_display)以及 LCD 驱动模块(lcd_driver),在顶层模块中完成对其余模块的例化。

RTL代码如下图所示:

module lcd_rgb_colorbar(
    input sys_clk,
    input sys_rst_n,
    output  reg          lcd_de,      //LCD 数据使能信号
    output               lcd_hs,      //LCD 行同步信号
    output               lcd_vs,      //LCD 场同步信号
    output               lcd_bl,      //LCD 背光控制信号
    output               lcd_clk,     //LCD 像素时钟
    output               lcd_rst,     //LCD复位
    inout        [23:0]  lcd_rgb
    );
    
    //wire define    
wire  [15:0]  lcd_id    ;    //LCD屏ID
wire          lcd_pclk  ;    //LCD像素时钟
              
wire  [10:0]  pixel_xpos;    //当前像素点横坐标
wire  [10:0]  pixel_ypos;    //当前像素点纵坐标
wire  [10:0]  h_disp    ;    //LCD屏水平分辨率
wire  [10:0]  v_disp    ;    //LCD屏垂直分辨率
wire  [23:0]  pixel_data;    //像素数据
wire  [23:0]  lcd_rgb_o ;    //输出的像素数据
wire  [23:0]  lcd_rgb_i ;    //输入的像素数据

//像素数据方向切换
assign lcd_rgb = lcd_de ?  lcd_rgb_o :  {24{1'bz}};
assign lcd_rgb_i = lcd_rgb;

//读LCD ID模块
rd_id u_rd_id(
    .clk          (sys_clk  ),
    .rst_n        (sys_rst_n),
    .lcd_rgb      (lcd_rgb_i),
    .lcd_id       (lcd_id   )
    );    

//时钟分频模块    
clk_div u_clk_div(
    .clk           (sys_clk  ),
    .rst_n         (sys_rst_n),
    .lcd_id        (lcd_id   ),
    .lcd_pclk      (lcd_pclk )
    );    

//LCD显示模块    
lcd_display u_lcd_display(
    .lcd_pclk       (lcd_pclk  ),
    .rst_n          (sys_rst_n ),
    .pixel_xpos     (pixel_xpos),
    .pixel_ypos     (pixel_ypos),
    .h_disp         (h_disp    ),
    .v_disp         (v_disp    ),
    .pixel_data     (pixel_data)
    );    

//LCD驱动模块
lcd_driver u_lcd_driver(
    .lcd_pclk      (lcd_pclk  ),
    .rst_n         (sys_rst_n ),
    .lcd_id        (lcd_id    ),
    .pixel_data    (pixel_data),
    .pixel_xpos    (pixel_xpos),
    .pixel_ypos    (pixel_ypos),
    .h_disp        (h_disp    ),
    .v_disp        (v_disp    ),
	.data_req	   (		  ),
	
    .lcd_de        (lcd_de    ),
    .lcd_hs        (lcd_hs    ),
    .lcd_vs        (lcd_vs    ),
    .lcd_bl        (lcd_bl    ),
    .lcd_clk       (lcd_clk   ),
    .lcd_rst       (lcd_rst   ),
    .lcd_rgb       (lcd_rgb_o )
    );

endmodule
    
endmodule
    

2.2 读 ID 模块设计

读ID模块框图如下所示:
在这里插入图片描述
波形图如下:
在这里插入图片描述

RTL代码如下:

module id_rd(
    input clk,
    input rst_n,
    input [23:0] lcd_rgb,
    output reg [15:0] lcd_id
);

reg rd_flag; //判断是否已读

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        lcd_id <= 16'd0;
        rd_flag <= 1'b0;
    end
    else begin
        if(rd_flag == 1'b0) begin
            rd_flag <= 1'b1;
            case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})
                3'b000 : lcd_id <= 16'h4342;
                3'b001 : lcd_id <= 16'h7084;
                3'b010 : lcd_id <= 16'h7016;
                3'b100 : lcd_id <= 16'h4384;
                3'b101 : lcd_id <= 16'h1018;
                default: lcd_id <= 16'h0;
            endcase
        end
        else
            lcd_id <= lcd_id;
    end
end

endmodule

2.3 时钟分频模块设计

分频模块根据输入的 LCD ID,来输出不同频率的像素时钟 lcd_pclk。时钟分频模块如下所示:
在这里插入图片描述
波形图如下:
在这里插入图片描述

RTL代码如下:

module clk_div(
    input clk,
    input rst_n,
    input [15:0] lcd_id,
    output reg lcd_pclk
    );

wire clk_25m;
wire clk_12_5m;

clk_wiz_0 instance_name
    (
    // Clock out ports
    .clk_25m(clk_25m),     // output clk_25m
    .clk_12_5m(clk_12_5m),     // output clk_12_5m
    // Status and control signals
    .reset(rst_n), // input reset
    .locked( ),       // output locked
   // Clock in ports
    .clk_in1(clk));      // input clk_in1
    
always @(*) begin
    case(lcd_id)
        16'h4342: lcd_pclk <= clk_12_5m;
        16'h7084: lcd_pclk <= clk_25m;
        16'h7016: lcd_pclk <= clk;
        16'h4384: lcd_pclk <= clk_25m;
        16'h1018: lcd_pclk <= clk;
end
    
endmodule
    

2.4 LCD 驱动模块设计

LCD 驱动模块设计:
在这里插入图片描述

RTL代码设计:

module lcd_driver(
    input lcd_pclk,
    input rst_n,
    input [15:0] lcd_id,
    input [23:0] pixel_data,
    
    output  reg  [10:0]  pixel_xpos,  
    output  reg  [10:0]  pixel_ypos,
    output  reg  [10:0]  h_disp,      
    output  reg  [10:0]  v_disp,
    output  reg  data_req, 
    //RGB LCD接口
    output  reg          lcd_de,      //LCD 数据使能信号
    output               lcd_hs,      //LCD 行同步信号
    output               lcd_vs,      //LCD 场同步信号
    output               lcd_bl,      //LCD 背光控制信号
    output               lcd_clk,     //LCD 像素时钟
    output               lcd_rst,     //LCD复位
    output       [23:0]  lcd_rgb
    );
    
//parameter define  
// 4.3' 480*272
parameter  H_SYNC_4342   =  11'd41;     //行同步
parameter  H_BACK_4342   =  11'd2;      //行显示后沿
parameter  H_DISP_4342   =  11'd480;    //行有效数据
parameter  H_FRONT_4342  =  11'd2;      //行显示前沿
parameter  H_TOTAL_4342  =  11'd525;    //行扫描周期
   
parameter  V_SYNC_4342   =  11'd10;     //场同步
parameter  V_BACK_4342   =  11'd2;      //场显示后沿
parameter  V_DISP_4342   =  11'd272;    //场有效数据
parameter  V_FRONT_4342  =  11'd2;      //场显示前沿
parameter  V_TOTAL_4342  =  11'd286;    //场扫描周期
   
// 7' 800*480   
parameter  H_SYNC_7084   =  11'd128;    //行同步
parameter  H_BACK_7084   =  11'd88;     //行显示后沿
parameter  H_DISP_7084   =  11'd800;    //行有效数据
parameter  H_FRONT_7084  =  11'd40;     //行显示前沿
parameter  H_TOTAL_7084  =  11'd1056;   //行扫描周期
   
parameter  V_SYNC_7084   =  11'd2;      //场同步
parameter  V_BACK_7084   =  11'd33;     //场显示后沿
parameter  V_DISP_7084   =  11'd480;    //场有效数据
parameter  V_FRONT_7084  =  11'd10;     //场显示前沿
parameter  V_TOTAL_7084  =  11'd525;    //场扫描周期       
   
// 7' 1024*600   
parameter  H_SYNC_7016   =  11'd20;     //行同步
parameter  H_BACK_7016   =  11'd140;    //行显示后沿
parameter  H_DISP_7016   =  11'd1024;   //行有效数据
parameter  H_FRONT_7016  =  11'd160;    //行显示前沿
parameter  H_TOTAL_7016  =  11'd1344;   //行扫描周期
   
parameter  V_SYNC_7016   =  11'd3;      //场同步
parameter  V_BACK_7016   =  11'd20;     //场显示后沿
parameter  V_DISP_7016   =  11'd600;    //场有效数据
parameter  V_FRONT_7016  =  11'd12;     //场显示前沿
parameter  V_TOTAL_7016  =  11'd635;    //场扫描周期
   
// 10.1' 1280*800   
parameter  H_SYNC_1018   =  11'd10;     //行同步
parameter  H_BACK_1018   =  11'd80;     //行显示后沿
parameter  H_DISP_1018   =  11'd1280;   //行有效数据
parameter  H_FRONT_1018  =  11'd70;     //行显示前沿
parameter  H_TOTAL_1018  =  11'd1440;   //行扫描周期
   
parameter  V_SYNC_1018   =  11'd3;      //场同步
parameter  V_BACK_1018   =  11'd10;     //场显示后沿
parameter  V_DISP_1018   =  11'd800;    //场有效数据
parameter  V_FRONT_1018  =  11'd10;     //场显示前沿
parameter  V_TOTAL_1018  =  11'd823;    //场扫描周期

// 4.3' 800*480   
parameter  H_SYNC_4384   =  11'd128;    //行同步
parameter  H_BACK_4384   =  11'd88;     //行显示后沿
parameter  H_DISP_4384   =  11'd800;    //行有效数据
parameter  H_FRONT_4384  =  11'd40;     //行显示前沿
parameter  H_TOTAL_4384  =  11'd1056;   //行扫描周期
   
parameter  V_SYNC_4384   =  11'd2;      //场同步
parameter  V_BACK_4384   =  11'd33;     //场显示后沿
parameter  V_DISP_4384   =  11'd480;    //场有效数据
parameter  V_FRONT_4384  =  11'd10;     //场显示前沿
parameter  V_TOTAL_4384  =  11'd525;    //场扫描周期    

//reg define
reg  [10:0] h_sync ;
reg  [10:0] h_back ;
reg  [10:0] h_total;
reg  [10:0] v_sync ;
reg  [10:0] v_back ;
reg  [10:0] v_total;
reg  [10:0] h_cnt  ;
reg  [10:0] v_cnt  ;

assign  lcd_hs = 1'b1;        //LCD行同步信号
assign  lcd_vs = 1'b1;        //LCD场同步信号
assign  lcd_bl = 1'b1;        //LCD背光控制信号  
assign  lcd_clk = lcd_pclk;   //LCD像素时钟
assign  lcd_rst= 1'b1;        //LCD复位

assign  lcd_rgb = lcd_de ? pixel_data : 24'd0;

always @(*) begin
    case(lcd_id)
        16'h4342 : begin
            h_sync  = H_SYNC_4342; 
            h_back  = H_BACK_4342; 
            h_disp  = H_DISP_4342; 
            h_total = H_TOTAL_4342;
            v_sync  = V_SYNC_4342; 
            v_back  = V_BACK_4342; 
            v_disp  = V_DISP_4342; 
            v_total = V_TOTAL_4342;            
        end
        16'h7084 : begin
            h_sync  = H_SYNC_7084; 
            h_back  = H_BACK_7084; 
            h_disp  = H_DISP_7084; 
            h_total = H_TOTAL_7084;
            v_sync  = V_SYNC_7084; 
            v_back  = V_BACK_7084; 
            v_disp  = V_DISP_7084; 
            v_total = V_TOTAL_7084;        
        end
        16'h7016 : begin
            h_sync  = H_SYNC_7016; 
            h_back  = H_BACK_7016; 
            h_disp  = H_DISP_7016; 
            h_total = H_TOTAL_7016;
            v_sync  = V_SYNC_7016; 
            v_back  = V_BACK_7016; 
            v_disp  = V_DISP_7016; 
            v_total = V_TOTAL_7016;            
        end
        16'h4384 : begin
            h_sync  = H_SYNC_4384; 
            h_back  = H_BACK_4384; 
            h_disp  = H_DISP_4384; 
            h_total = H_TOTAL_4384;
            v_sync  = V_SYNC_4384; 
            v_back  = V_BACK_4384; 
            v_disp  = V_DISP_4384; 
            v_total = V_TOTAL_4384;             
        end        
        16'h1018 : begin
            h_sync  = H_SYNC_1018; 
            h_back  = H_BACK_1018; 
            h_disp  = H_DISP_1018; 
            h_total = H_TOTAL_1018;
            v_sync  = V_SYNC_1018; 
            v_back  = V_BACK_1018; 
            v_disp  = V_DISP_1018; 
            v_total = V_TOTAL_1018;        
        end
        default : begin
            h_sync  = H_SYNC_4342; 
            h_back  = H_BACK_4342; 
            h_disp  = H_DISP_4342; 
            h_total = H_TOTAL_4342;
            v_sync  = V_SYNC_4342; 
            v_back  = V_BACK_4342; 
            v_disp  = V_DISP_4342; 
            v_total = V_TOTAL_4342;          
        end
    endcase
end

//X坐标
always@ (posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n)
        pixel_xpos <= 11'd0;
    else if(data_req)
        pixel_xpos <= h_cnt  + 2'd2 - h_sync - h_back;
    else
        pixel_xpos <= 11'd0;
end

//Y坐标
always@ (posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n)
        pixel_ypos <= 11'd0;
    else if(v_cnt >= (v_sync + v_back) && v_cnt < (v_sync + v_back + h_disp))
        pixel_ypos <= v_cnt  + 1'd1 - y_sync - y_back;
    else
        pixel_ypos <= 11'd0;
end

//数据使能信号		
always@ (posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n)	
		lcd_de <= 1'b0;
	else
		lcd_de <= data_req;
end
				  
//请求像素点颜色数据输入  
always@ (posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n)	
		data_req<=1'b0;
	else if((h_cnt >= h_sync + h_back - 2'd2) && (h_cnt < h_sync + h_back + h_disp - 2'd2)
             && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))
		data_req <= 1'b1;
	else
		data_req <= 1'b0;
end
				  
//行计数器对像素时钟计数
always@ (posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n) 
        h_cnt <= 11'd0;
    else begin
        if(h_cnt == h_total - 1'b1)
            h_cnt <= 11'd0;
        else
            h_cnt <= h_cnt + 1'b1;           
    end
end

//场计数器对行计数
always@ (posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n) 
        v_cnt <= 11'd0;
    else begin
        if(h_cnt == h_total - 1'b1) begin
            if(v_cnt == v_total - 1'b1)
                v_cnt <= 11'd0;
            else
                v_cnt <= v_cnt + 1'b1;    
        end
    end    
end

endmodule
    

2.5 LCD 显示模块设计

LCD 显示模块设计如下图所示:
在这里插入图片描述
RTL代码如下所示:

module lcd_display_colorbar(
    input lcd_pclk,
    input rst_n,
    input pixel_xpos,
    input pixel_ypos,
    input h_disp,
    input v_disp,
    output [23:0] pixel_data
);

parameter WHITE = 24'hFFFFFF; //白色
parameter BLACK = 24'h000000; //黑色
parameter RED = 24'hFF0000; //红色
parameter GREEN = 24'h00FF00; //绿色
parameter BLUE = 24'h0000FF; //蓝色

always @(posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n)
        pixel_data <= BLACK;
    else begin
        if((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1))
            pixel_data <= WHITE;
        else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2)) 
            pixel_data <= BLACK;
        else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3)) 
            pixel_data <= RED; 
        else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4)) 
            pixel_data <= GREEN; 
    else
        pixel_data <= BLUE; 
    end 
end

endmodule

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值