FPGA LCD显示彩条实验

LCD屏幕简介


LCD屏幕,即液晶显示屏(Liquid Crystal Display),是一种使用液晶材料来显示图像的屏幕技术。液晶本身并不发光,因此LCD屏幕通常需要背光源来照亮液晶以显示图像。

1.1 分辨率

分辨率是指屏幕上水平方向和垂直方向像素点的数量。分辨率通常以两个数字表示,例如1920x1080,其中第一个数字表示屏幕水平方向的像素点数,第二个数字表示垂直方向的像素点数。这个例子中的分辨率意味着屏幕有1920个像素宽和1080个像素高,也就是这个屏幕一列 1080 个像素点,一共 1920 列。

1.2 像素格式

屏幕的一个像素点就相当于一个 RGB小灯,通过控制 R、G、B 这三种颜色的亮度就可以显示出各种各样的色彩。
一般一个 R、G、B 这三部分分别使 用 8bit 的数据,那么一个像素点就是 8bit*3=24bit,也就是说一个像素点 3 个字节,这种像素格式称为 RGB888。当然常用的像素点格式还有 RGB565,只需要两个字节。
//RGB565转RGB888

assign rgb888_data[23:16] = {rom_rd_data[15:11], rom_rd_data[13:11]};  //red
assign rgb888_data[15:8] = {rom_rd_data[10:5], rom_rd_data[6:5]};  //green
assign rgb888_data[7:0] = {rom_rd_data[4:0], rom_rd_data[2:0]};  //blue

ab766b99c91f477b99cfb0d594e0fbae.png

一个像素点占用 3 个字节,其中 bit23~bit16 是 RED 通道,bit15~bit8 是 GREEN 通道,bit7~bit0 是 BLUE 通道。所以红色对应的值就是 24’hFF0000,绿色对应的值就是 24’h00FF00,蓝色对应的值为 24’h0000FF。
通过调节 R、G、B 的比例可以产生其它的颜色,比如 24’hFFFF00 就是黄色, 24’h000000 就是黑色,24’hFFFFFF 就是白色。

1.3 屏幕接口

本次实验用的是正点原子ATK-7084(7寸,800*480)RGB LCD 屏幕,RGB LCD 接口的信号线如下表所示:

e6bfb0a4ff554c06ab7a628578cc9783.png

行同步信号(HSYNC)

行同步信号用于同步显示器的水平扫描过程。在逐行扫描的显示器中,电子束从屏幕的左上角开始,逐行向右扫描,每扫描完一行后,电子束需要回到屏幕的左侧准备开始下一行的扫描。在这个过程中,行同步信号会在每行扫描结束时发出,指示电子束应该回到屏幕的左侧。这个信号通常是一个短暂的脉冲,其宽度和持续时间根据显示器的分辨率和刷新率而定。

场同步信号(VSYNC)

场同步信号则用于同步显示器的垂直扫描过程。在完成一整屏(即所有行)的扫描后,电子束需要回到屏幕的左上角开始新的一帧。场同步信号在这一过程中发出,指示电子束应该回到屏幕的顶部。这个信号通常在一帧结束时出现,标志着新的一帧即将开始。

1.4 像素时钟

LCD像素时钟是液晶显示器(LCD)中的一个关键参数,它定义了LCD面板能够更新显示多少像素的速率。像素时钟以赫兹(Hz)为单位,表示每秒钟可以传输的像素数量。

像素时钟的计算通常基于显示器的分辨率和刷新率。例如,一个分辨率为1920x1080的显示器,如果刷新率为60Hz,那么像素时钟的计算方法如下:
像素时钟=水平分辨率×垂直分辨率×刷新率
像素时钟=1920×1080×60
像素时钟=124,416,000Hz
这意味着该显示器每秒可以传输大约1.24亿个像素。

2 实验任务

使用正点原子 DFZU4EV MPSoC 开发板上的 RGB TFT-LCD 接口,驱动 RGB LCD 液晶屏,并显示出彩条。

3 实验设计

lcd_rgb_colorbar.v

`timescale 1ns / 1ps


module lcd_rgb_colorbar (
    input sys_clk_p,  //系统差分输入时钟
    input sys_clk_n,  //系统差分输入时钟
    input sys_rst_n,  //系统复位

    //RGB LCD接口
    output        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   //LCD RGB888颜色数据
);

  //wire define    

  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;  //像素数据


  //*****************************************************
  //**                    main code
  //*****************************************************


  //转换差分信号
  IBUFDS diff_clock (
      .I (sys_clk_p),  //系统差分输入时钟
      .IB(sys_clk_n),  //系统差分输入时钟
      .O (sys_clk)     //输出系统时钟
  );

  //时钟分频模块    
  clk_div u_clk_div (
      .clk  (sys_clk),
      .rst_n(sys_rst_n),
      .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),

      .pixel_data(pixel_data),
      .pixel_xpos(pixel_xpos),
      .pixel_ypos(pixel_ypos),
      .h_disp    (h_disp),
      .v_disp    (v_disp),

      .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)
  );

endmodule

clk_div.v

时钟分频模块,对系统时钟进行分频,生成驱动lcd屏幕的时钟。

`timescale 1ns / 1ps


module clk_div (
    input clk,   //100MHz
    input rst_n,

    output reg lcd_pclk
);


  reg clk_25m;
  reg div_4_cnt;


  //时钟4分频 输出25MHz时钟 
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      div_4_cnt <= 1'b0;
      clk_25m   <= 1'b0;
    end else begin
      div_4_cnt <= div_4_cnt + 1'b1;
      if (div_4_cnt == 1'b1) clk_25m <= ~clk_25m;
    end
  end


  always @(*) begin
    lcd_pclk = clk_25m;
  end

endmodule

lcd_driver.v

在像素时钟的驱动下输出数据使能信号用于数据同步,同时还输出像素点的纵横坐标,供 LCD 显示模块( lcd_display )调用。
`timescale 1ns / 1ps


module lcd_driver (
    input lcd_pclk,  //时钟
    input rst_n,     //复位,低电平有效

    input      [23:0] pixel_data,  //像素数据
    output     [10:0] pixel_xpos,  //当前像素点横坐标
    output     [10:0] pixel_ypos,  //当前像素点纵坐标   
    output reg [10:0] h_disp,      //LCD屏水平分辨率
    output reg [10:0] v_disp,      //LCD屏垂直分辨率   
    //RGB LCD接口
    output            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      //LCD RGB888颜色数据
);

  //parameter define  
  // 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;  //场扫描周期       


  //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;

  //wire define    
  wire        lcd_en;
  wire        data_req;

  //*****************************************************
  //**                    main code
  //*****************************************************

  //RGB LCD 采用DE模式时,行场同步信号需要拉高
  assign lcd_hs = 1'b1;  //LCD行同步信号
  assign lcd_vs = 1'b1;  //LCD场同步信号

  assign lcd_bl = 1'b1;  //LCD背光控制信号 
  assign lcd_rst = 1'b1;  //LCD 复位
  assign lcd_clk = lcd_pclk;  //LCD像素时钟
  assign lcd_de = lcd_en;  //LCD数据有效信号

  //使能RGB888数据输出
  assign  lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)
                  && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp)) 
                  ? 1'b1 : 1'b0;

  //请求像素点颜色数据输入  
  assign data_req = ((h_cnt >= h_sync + h_back - 1'b1) && (h_cnt < h_sync + h_back + h_disp - 1'b1)
                  && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp)) 
                  ? 1'b1 : 1'b0;

  //像素点坐标  
  assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'd0;
  assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;

  //RGB888数据输出
  assign lcd_rgb = lcd_en ? pixel_data : 24'd0;

  //行场时序参数
  always @(*) 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

  //行计数器对像素时钟计数
  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

lcd_display.v

lcd显示模块,主要是向该模块输入坐标信息,然后输出该坐标的像素信息。

`timescale 1ns / 1ps


module lcd_display (
    input             lcd_pclk,    //时钟
    input             rst_n,       //复位,低电平有效
    input      [10:0] pixel_xpos,  //当前像素点横坐标
    input      [10:0] pixel_ypos,  //当前像素点纵坐标  
    input      [10:0] h_disp,      //LCD屏水平分辨率
    input      [10:0] v_disp,      //LCD屏垂直分辨率       
    output reg [23:0] pixel_data   //像素数据
);

  //parameter define  
  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

pin.xdc

#IO管脚约束
#时钟周期约束
create_clock -name sys_clk_p -period 10.000 [get_ports sys_clk_p]
#时钟
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_n]
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
set_property PACKAGE_PIN AF5 [get_ports sys_clk_n]
#复位
set_property -dict {PACKAGE_PIN AH11 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
#LCD接口
set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[0]}]
set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[1]}]
set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[2]}]
set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[3]}]
set_property -dict {PACKAGE_PIN W12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[4]}]
set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[5]}]
set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[6]}]
set_property -dict {PACKAGE_PIN AA12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[7]}]
set_property -dict {PACKAGE_PIN AC14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[8]}]
set_property -dict {PACKAGE_PIN AD15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[9]}]
set_property -dict {PACKAGE_PIN AC13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[10]}]
set_property -dict {PACKAGE_PIN AD14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[11]}]
set_property -dict {PACKAGE_PIN AE15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[12]}]
set_property -dict {PACKAGE_PIN AA13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[13]}]
set_property -dict {PACKAGE_PIN AE14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[14]}]
set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[15]}]
set_property -dict {PACKAGE_PIN AG14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[16]}]
set_property -dict {PACKAGE_PIN AB15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[17]}]
set_property -dict {PACKAGE_PIN AH14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[18]}]
set_property -dict {PACKAGE_PIN AB14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[19]}]
set_property -dict {PACKAGE_PIN AG13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[20]}]
set_property -dict {PACKAGE_PIN AE13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[21]}]
set_property -dict {PACKAGE_PIN AH13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[22]}]
set_property -dict {PACKAGE_PIN AF13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[23]}]

set_property -dict {PACKAGE_PIN J11 IOSTANDARD LVCMOS33} [get_ports lcd_hs]
set_property -dict {PACKAGE_PIN K12 IOSTANDARD LVCMOS33} [get_ports lcd_vs]
set_property -dict {PACKAGE_PIN J10 IOSTANDARD LVCMOS33} [get_ports lcd_de]
set_property -dict {PACKAGE_PIN J12 IOSTANDARD LVCMOS33} [get_ports lcd_bl]
set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports lcd_clk]
set_property -dict {PACKAGE_PIN F10 IOSTANDARD LVCMOS33} [get_ports lcd_rst]

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的FPGA VGA显示彩条的代码示例: ```verilog module vga_color_bar( input clk, // 像素时钟 input rst_n, // 复位信号 output reg [7:0] r, // 红色分量 output reg [7:0] g, // 绿色分量 output reg [7:0] b, // 蓝色分量 output reg hsync, // 水平同步信号 output reg vsync // 垂直同步信号 ); parameter SCREEN_WIDTH = 640; parameter SCREEN_HEIGHT = 480; parameter H_SYNC_PULSE_WIDTH = 96; parameter H_BACK_PORCH = 48; parameter H_FRONT_PORCH = 16; parameter V_SYNC_PULSE_WIDTH = 2; parameter V_BACK_PORCH = 33; parameter V_FRONT_PORCH = 10; reg [9:0] h_count = 0; reg [8:0] v_count = 0; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin h_count <= 0; v_count <= 0; r <= 8'd0; g <= 8'd0; b <= 8'd0; hsync <= 1'b0; vsync <= 1'b0; end else begin if(h_count == SCREEN_WIDTH + H_SYNC_PULSE_WIDTH + H_BACK_PORCH + H_FRONT_PORCH - 1) begin h_count <= 0; if(v_count == SCREEN_HEIGHT + V_SYNC_PULSE_WIDTH + V_BACK_PORCH + V_FRONT_PORCH - 1) begin v_count <= 0; r <= 8'd0; g <= 8'd0; b <= 8'd0; hsync <= 1'b0; vsync <= 1'b0; end else begin v_count <= v_count + 1; hsync <= 1'b0; vsync <= (v_count >= SCREEN_HEIGHT + V_BACK_PORCH && v_count < SCREEN_HEIGHT + V_BACK_PORCH + V_SYNC_PULSE_WIDTH); end end else begin h_count <= h_count + 1; hsync <= (h_count >= SCREEN_WIDTH + H_BACK_PORCH && h_count < SCREEN_WIDTH + H_BACK_PORCH + H_SYNC_PULSE_WIDTH); if(v_count >= V_BACK_PORCH && v_count < V_BACK_PORCH + SCREEN_HEIGHT) begin r <= h_count[3:0] * 32; g <= h_count[3:0] * 8; b <= h_count[3:0] * 2; end else begin r <= 8'd0; g <= 8'd0; b <= 8'd0; end end end end endmodule ``` 该代码使用Verilog语言实现,使用了同步信号和计数器控制VGA信号的输出,通过改变红、绿、蓝三种颜色的分量实现彩条的渐变效果。注意:该代码只是一个简单的示例,实际使用时需要根据具体的FPGA开发板和显示器的参数进行调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值