首页 > 其他分享 >FPGA驱动RGB888屏幕——基于正点原子达芬奇FPGA开发板

FPGA驱动RGB888屏幕——基于正点原子达芬奇FPGA开发板

时间:2023-12-11 12:00:58浏览次数:32  
标签:10 FPGA PIC 开发板 lcd RGB888 信号 output pixel

RGB888简介

重要提示:由于我没有RGB888屏幕,所以代码未经验证,但是我将其在HDMI中使用了,证明代码还是有一定的正确性

一个像素点由三种颜色控制,每个颜色8bit,共24bit,三个字节,这就是RGB888。同样的还有RGB565等。
RGB888 数据格式

LCD屏幕介绍

LCD时间参数
1、HSYNC(水平同步信号、行同步信号):产生此信号,说明开始显示新的一行。
2、VSYNC(垂直同步信号、帧同步信号):当产生此信号的话就表示开始显示新的一帧图像。
3、LCD 屏幕中继续存在HBP、 HFP、 VPB 和 VFP 这四个参数的主要目的是为了锁定有效的像素数据。 (白色区域为显示区域)

LCD屏幕时序

LCD 行显示时序
重要参数:

  1. HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据, 图中低电平有效。
  2. HSPW:行同步信号宽度,也就是 HSYNC 信号持续时间。 HSYNC 信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为 CLK。
  3. HBP:行显示后沿(或后肩), 单位是 CLK。
  4. HOZVAL:行有效显示区域,即显示一行数据所需的时间,假如屏幕分辨率为 1024*600,那么 HOZVAL就是 1024,单位为 CLK。
  5. HFP:行显示前沿(或前肩),单位是 CLK。

当 HSYNC 信号发出以后,需要等待 HSPW+HBP 个 CLK 时间才会接收到真正有效的像素数据。当显示完一行数据以后需要等待 HFP 个 CLK 时间才能发出下一个 HSYNC 信号,所以显示一行所需要的时间就是: HSPW + HBP + HOZVAL + HFP。
LCD 帧显示时序
重要参数:

  1. VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据。
  2. VSPW:帧同步信号宽度,也就是 VSYNC 信号持续时间,单位为 1 行的时间 。
  3. VBP:帧显示后沿(或后肩),单位为 1 行的时间。
  4. LINE:帧有效显示区域,即显示一帧数据所需的时间,假如屏幕分辨率为 1024*600,那么 LINE 就是600 行的时间。
  5. VFP:帧显示前沿(或前肩),单位为 1 行的时间。

显示一帧所需要的时间就是 T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP) 。

LCD数据同步模式

**行场同步模式(HV Mode) **

**数据使能同步模式(DE Mode) **
LCD 的 DE 信号作为数据的有效信号。只有同时扫描到帧有效显示区域和行有效显示区域时, DE 信号才有效(高电平)。当选择 DE 同步模式时,此时行场同步信号 VS 和 HS 必须为高电平。

像素时钟

像素时钟就是 RGB-LCD 的时钟信号 ,以 ATK7016 这款屏幕为例,显示一帧图像所需要的时钟数就是: 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。

不同分辨率的LCD时序参数
接口图

FPGA实现

系统框图

LCD驱动模块(1024*600分辨率)

名称 类型 解释
lcd_clk input lcd驱动时钟信号
sys_rst_n input 复位信号
[23:0]pixel_data input 像素数据
[10:0]pixel_xpos output 当前点横坐标
[10:0]pixel_ypos output 当前点纵坐标
lcd_bl output 背光
lcd_de output 数据使能
lcd_vs output 场同步信号
lcd_hs output 行同步信号
lcd_clk output LCD时钟
lcd_rgb output 颜色数据


module lcd_drive(
	  input           lcd_clk ,       //lcd驱动时钟信号
    input           sys_rst_n,
    input   [23:0]  pixel_data,     //像素数据

    output  [10:0]  pixel_xpos,     //当前点横坐标
    output  [10:0]  pixel_ypos,     //当前点纵坐标

//rgb接口
    output          lcd_bl,         //背光
    output          lcd_de,         //数据使能
    output          lcd_vs,         //场同步信号
    output          lcd_hs,         //行同步信号
    output          lcd_clk,        //LCD时钟
    output  [23:0]  lcd_rgb         //颜色数据
);

//parameter define

//reg define
    reg [10:0] h_disp  = 11'd1024;  //水平分辨率
    reg [10:0] v_disp  = 11'd600;   //垂直分辨率
    reg [10:0] h_cnt;               //行计数器计数
    reg [10:0] h_total = 11'd1344;  //行显示周期
    reg [10:0] v_cnt;               //帧计数器计数
    reg [10:0] v_total = 11'd635;   //帧显示周期
    reg [10:0] h_sync  = 11'd;      //行同步信号宽度
    reg [10:0] h_back;              //行显示后沿
    reg [10:0] v_sync;              //帧同步信号宽度
    reg [10:0] v_back;              //帧显示后沿



    assign lcd_bl = 1'b1;
    assign lcd_de = lcd_en;
    assign lcd_vs = 1'b1; //选择 DE 同步模式时,此时行场同步信号 VS 和 HS 必须为高电平。 
    assign lcd_hs = 1'b1;
    assign lcd_clk = lcd_clk;
    assign lcd_rgb = lcd_en ? pixel_data : 24'd0;

//h_cnt 行计数器计数
    always @(posedge lcd_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            h_cnt <= 1'b0;
        else if(h_cnt == h_total - 1'd1)
            h_cnt <= 1'b0;
        else    
            h_cnt <= h_cnt + 1'b1;
    end

//v_hnt 帧计数器计数
    always @(posedge lcd_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            v_cnt <= 1'b0;
        else begin
            if(h_cnt == h_total - 1'd1)begin
                if(v_cnt == v_total - 1'd1)
                    v_cnt <= 1'b0;
                else    
                    v_cnt <= v_cnt + 1'b1;
                end
        end
    end

//使能数据输入
    assign lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_cnt + 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_cnt + h_back + h_disp)
                 && (v_cnt >= v_sync + v_back - 1'b1) && (v_cnt < v_sync + v_back + v_disp))
                 ? 1'b1 : 1'b0;

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


endmodule

ROM显示
ROM 是通过例化 IP 核来实现的只读存储器,它使用 FPGA 的片上存储资源,即BRAM。(达芬奇开发板使用的FPGA 芯片的 BRAM 存储容量为 1.8Mbit)
OM 作为只读存储器,在调用 IP 核时需要指定初始化文件,在这里就是写入存储器中的图片数据,各种格式的图片(bmp、 jpg 等)在 Xilinx 开发软件中都是以 COE 文件或者 HEX 文件的形式导入到 ROM中的
image.png
COE 文件格式
使用matlab将图片转化成COE文件

clear %清理命令行窗口
clc %清理工作区
% 使用 imread 函数读取图片,并转化为三维矩阵
image_array = imread('logo.bmp');
% 使用 size 函数计算图片矩阵三个维度的大小
% 第一维为图片的高度,第二维为图片的宽度,第三维为图片维度
[height,width,z]=size(image_array); % 100*100*3
 red = image_array(:,:,1); % 提取红色分量,数据类型为 uint8
 green = image_array(:,:,2); % 提取绿色分量,数据类型为 uint8
 blue = image_array(:,:,3); % 提取蓝色分量,数据类型为 uint8

 % 使用 reshape 函数将各个分量重组成一个一维矩阵
 %为了避免溢出,将 uint8 类型的数据扩大为 uint32 类型
 r = uint32(reshape(red' , 1 ,height*width));
 g = uint32(reshape(green' , 1 ,height*width));
 b = uint32(reshape(blue' , 1 ,height*width));

 % 初始化要写入.COE 文件中的 RGB 颜色矩阵
 rgb=zeros(1,height*width);

 % 导入的图片为 24bit 真彩色图片,每个像素占用 24bit,RGB888
 % 将 RGB888 转换为 RGB565
 % 红色分量右移 3 位取出高 5 位,左移 11 位作为 ROM 中 RGB 数据的第 15bit 到第 11bit
 % 绿色分量右移 2 位取出高 6 位,左移 5 位作为 ROM 中 RGB 数据的第 10bit 到第 5bit
 % 蓝色分量右移 3 位取出高 5 位,左移 0 位作为 ROM 中 RGB 数据的第 4bit 到第 0bit
 for i = 1:height*width
 rgb(i) = bitshift(bitshift(r(i),-3),11)
 + bitshift(bitshift(g(i),-2),5)
 + bitshift(bitshift(b(i),-3),0);
 end

 fid = fopen( 'image.coe', 'w+' );

 % .mif 文件字符串打印
 fprintf( fid, 'MEMORY_INITIALIZATION_RADIX=16;\n');
 fprintf( fid, 'MEMORY_INITIALIZATION_VECTOR=\n',height*width);

 % 写入图片数据
 for i = 1:height*width
 if i == height*width
 fprintf(fid,'%x;\n',rgb(i)); %最后一个数据后面加分号
 else
 fprintf(fid,'%x,\n',rgb(i));
 end
 end

 fclose( fid ); % 关闭文件指针

LCD显示模块

module lcd_display (
    input               lcd_clk,
    input               sys_rst_n,
    input       [10:0]  pixel_xpos,
    input       [10:0]  pixel_ypos,  

    output reg  [23:0]  pixel_data
);
//parameter define
    localparam PIC_X_START = 11'd1; //图片起始点横坐标
    localparam PIC_Y_START = 11'd1; //图片起始点纵坐标
    localparam PIC_WIDTH   = 11'd100; //图片宽度
    localparam PIC_HEIGHT  = 11'd100; //图片高度
    localparam BACK_COLOR  = 24'hE0FFFF; //背景色,浅蓝色
//reg define
    reg [13:0] rom_addr ; //ROM 地址


    wire [10:0] x_cnt; //横坐标计数器
    wire [10:0] y_cnt; //纵坐标计数器
    wire rom_rd_en ; //ROM 读使能信号
    wire [23:0] rom_rd_data ;//ROM 数据
    


    assign x_cnt = pixel_xpos - PIC_X_START; //像素点相对于图像区域起始点水平坐标
    assign y_cnt = pixel_ypos - PIC_Y_START; //像素点相对于图像区域起始点垂直坐标
    assign rom_rd_en = 1'b1; //读使能拉高,即一直读 ROM 数据

//为 LCD 不同显示区域绘制图片、字符和背景色
    always @(posedge lcd_pclk or negedge rst_n) begin
        if (!sys_rst_n)
            pixel_data <= BACK_COLOR;
        else if( (pixel_xpos >= PIC_X_START) && (pixel_xpos < PIC_X_START + PIC_WIDTH)
                && (pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT) )
            pixel_data <= rom_rd_data ; //显示图片
        else
            pixel_data <= BACK_COLOR; //屏幕背景色
    end

//根据当前扫描点的横纵坐标为 ROM 地址赋值
     always @(posedge lcd_pclk or negedge rst_n) begin
        if (!sys_rst_n)
            rom_addr <= 14'd0;
        else if( (pixel_xpos >= PIC_X_START) && (pixel_xpos < PIC_X_START + PIC_WIDTH)
                && (pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT) )
            rom_addr <= rom_addr + 1'b1;
        else if((pixel_ypos >= PIC_Y_START + PIC_HEIGHT))
            rom_addr <= 14'd0;
     end

//ROM:存储图片
     blk_mem_gen_0 blk_mem_gen_0 (
        .clka (lcd_pclk), // input wire clka
        .ena (rom_rd_en), // input wire ena
        .addra (rom_addr), // input wire [13 : 0] addra
        .douta (rom_rd_data) // output wire [23 : 0] douta
     );
endmodule

顶层模块

module lcd_display_top (
    input sys_clk, //系统时钟
    input sys_rst_n, //系统复位
    output lcd_de, //LCD 数据使能信号
    output lcd_hs, //LCD 行同步信号
    output lcd_vs, //LCD 场同步信号
    output lcd_bl, //LCD 背光控制信号
    output lcd_clk, //LCD 像素时钟
    inout [23:0] lcd_rgb //LCD RGB888 颜色数据
);
    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_display u_lcd_display(
        .lcd_clk    (sys_clk),
        .sys_rst_n  (sys_rst_n),
        .pixel_xpos (pixel_xpos),
        .pixel_ypos (pixel_ypos),
        .pixel_data (pixel_data)
    );
    lcd_driver u_lcd_driver(
        .lcd_clk    (sys_clk),
        .sys_rst_n  (sys_rst_n),
        .pixel_data (pixel_data),
        .pixel_xpos (pixel_xpos),
        .pixel_ypos (pixel_ypos),
        .lcd_de     (lcd_de ),
        .lcd_hs     (lcd_hs ),
        .lcd_vs     (lcd_vs ),
        .lcd_bl     (lcd_bl ),
        .lcd_clk    (lcd_clk ),
        .lcd_rgb    (lcd_rgb_o)
    );
endmodule

标签:10,FPGA,PIC,开发板,lcd,RGB888,信号,output,pixel
From: https://www.cnblogs.com/fangrunze/p/17894081.html

相关文章

  • 飞凌OK113i-C全志T113-i开发板 rtl8723du WIFI 功能测试及蓝牙驱动移植
    飞凌OK113i-C全志T113-i开发板板载一个RTL8723duwifi/蓝牙二合一模块,板子出厂已经移植好了WIFI驱动但是蓝牙驱动没有,所以这篇文章我们主要做蓝牙驱动的移植和功能验证。./build.shmenuconfig在DeviceDrivers>Networkdevicesupport>WirelessLAN下找到Realtek8723DU......
  • 基于FPGA的图像缩小算法实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览   将FPGA的处理结果导出到matlab中显示图像效果:   2.算法运行软件版本vivado2019.2 matlab2022a 3.算法理论概述      图像放小算法主要通过抽取算法实现,常见的抽取算法最大值抽取,和均值抽取。其示意图如下所示:    ......
  • 开发板设置成静态ip的方式
    1开发板每次重新上电都要手动去分配ip地址才能与ubuntu通信,设置成静态ip的方式就不需要每次开发板重启后去设置一次ip地址。2在网上找了很多帖子,照着做都没有效果,直到看到一个帖子说vi/etc/profile在最后一行添加:ifconfigeth0192.168.1.100,重启开发板就可以了。关于/etc/p......
  • m基于FPGA的OFDM系统verilog实现,包括IFFT,FFT,成型滤波以及加CP去CP,包含testbench
    1.算法仿真效果vivado2019.2仿真结果如下:CP加入,删除效果:系统RTL结构图:2.算法涉及理论知识概要正交频分复用(OrthogonalFrequencyDivisionMultiplexing,OFDM)是一种高效的无线通信技术,已经被广泛应用于无线通信领域。OFDM技术的主要优势在于其可以有效地抵抗多径效应和频率......
  • m基于FPGA的OFDM系统verilog实现,包括IFFT,FFT,成型滤波以及加CP去CP,包含testbench
    1.算法仿真效果vivado2019.2仿真结果如下:   CP加入,删除效果:   系统RTL结构图:   2.算法涉及理论知识概要          正交频分复用(OrthogonalFrequencyDivisionMultiplexing,OFDM)是一种高效的无线通信技术,已经被广泛应用于无线通信领域。OFDM......
  • HNU FPGA毕设项目上手指南
    1.介绍本文章旨在帮助HNU的同学更优雅的完成数电的FPGA毕设(使用DE2-115),文章将涉及完成FPGA项目需要掌握的知识,资源分享以及一些关于完成项目的经验指导。大家快快搬好小板凳,准备发车吧(doge)。2.基础知识学习指导Verilog想要完成FPGA的项目,那必不可少的就是Verilog这个硬件描......
  • m基于FPGA的8PSK调制解调系统verilog实现,包含testbench测试文件
    1.算法仿真效果vivado仿真结果如下:   借助matlab看8PSK的星座图:   2.算法涉及理论知识概要        随着通信技术的不断发展,相位调制技术因其高频谱效率和抗干扰能力而广泛应用于无线通信系统中。其中,8PSK(8相位相移键控)作为一种高阶调制方式,具有更高的频......
  • Xlinx FPGA for DSP CORDIC 算法
    https://wenku.baidu.com/view/6c623aa8910ef12d2bf9e732.html?_wkts_=1701401816748&needWelcomeRecommand=1           ......
  • 系统性能提升2 倍以上【FPGA】XCKU5P-L2SFVB784E、XCKU5P-2SFVB784I
    Kintex™UltraScale+™器件在FinFET节点中提供最佳每瓦价格性能比,为需要高端功能(包括33Gb/s收发器和100G连接内核)的应用提供了经济高效的解决方案。最新的中端产品系列同时支持数据包处理和DSP密集型功能,是无线MIMO技术、Nx100G有线网络、以及数据中心网络和存储加速......
  • 迅为RK3588开发板定制Ubuntu和Debian系统-系统定制(无法联网)
    在上一个小节中讲解了ubuntu和debian文件系统的定制,但那是在可以运行脚本正常构建系统的前提下,而本小节则是针对部分特殊用户无法联网的情况。在source目录下存放了已经构建完成的压缩包,如下图所示然后使用以下命令将该压缩包解压到build目录下,解压完成如下图所示:tar-vxf......