首页 > 其他分享 >基于ROM的HDMI显示

基于ROM的HDMI显示

时间:2024-01-25 11:45:13浏览次数:31  
标签:11 基于 ROM HDMI clk PIC video data pixel

前言

  如何实现FPGA驱动HDMI显示在之前的文章已经实现了,其参考的代码主要是基于野火FPGA的教程,在正点原子的达芬奇FPGA开发板上实现。

系统框架

image.png
  这里简单介绍一下各个框架。
    1、clk_wiz_0
       调用的vivado的PLL生成了两种时钟频率:1280720@60Hz驱动时钟74.25MHz和ODDR2的驱动时钟,5倍的1280720@60Hz驱动时钟371.5MHz。
    2、pic_display
       这个模块的作用是输出RGB888数据,其中也例化了一个ROM用于存储RGB888图片数据。
    3、video_driver
       HDMI的驱动程序
    4、rgb2dvi
       主要作用是将rgb数据转换成可以转换成差分信号。
  接下来开始详细的介绍各个程序

程序设计

1、驱动时钟

  驱动时钟的设计就不详细介绍,可以自行百度。需要解释的是,我是基于1280*720@60Hz来驱动的,因此所需要的时钟频率为74.25MHz。
image.png

2、HDMI驱动

  直接上代码  

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/04 18:38:50
// Design Name: 
// Module Name: video_driver
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module video_driver(
    input           pixel_clk,
    input           sys_rst_n,
    
    //RGB接口
    output          video_hs,     //行同步信号
    output          video_vs,     //场同步信号
    output          video_de,     //数据使能
    output  [23:0]  video_rgb,    //RGB888颜色数据
    
    input   [23:0]  pixel_data,   //像素点数据
    output  [10:0]  pixel_xpos,   //像素点横坐标
    output  [10:0]  pixel_ypos    //像素点纵坐标
);

//parameter define

//1280*720 分辨率时序参数
parameter  H_SYNC   =  11'd40;   //行同步
parameter  H_BACK   =  11'd220;  //行显示后沿
parameter  H_DISP   =  11'd1280; //行有效数据
parameter  H_FRONT  =  11'd110;  //行显示前沿
parameter  H_TOTAL  =  11'd1650; //行扫描周期

parameter  V_SYNC   =  11'd5;    //场同步
parameter  V_BACK   =  11'd20;   //场显示后沿
parameter  V_DISP   =  11'd720;  //场有效数据
parameter  V_FRONT  =  11'd5;    //场显示前沿
parameter  V_TOTAL  =  11'd750;  //场扫描周期

//reg define
reg  [10:0] cnt_h;
reg  [10:0] cnt_v;

//wire define
wire       video_en;
wire       data_req;

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

assign video_de  = video_en;

assign video_hs  =  1'b1;  //行同步信号赋值
assign video_vs  =  1'b1;  //场同步信号赋值

//使能RGB数据输出
assign video_en  = (((cnt_h >= H_SYNC+H_BACK) && (cnt_h < H_SYNC+H_BACK+H_DISP))
                 &&((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
                 ?  1'b1 : 1'b0;

//RGB888数据输出
assign video_rgb = video_en ? pixel_data : 24'd0;

//请求像素点颜色数据输入
assign data_req = (((cnt_h >= H_SYNC+H_BACK-1'b1) && 
                    (cnt_h < H_SYNC+H_BACK+H_DISP-1'b1))
                  && ((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
                  ?  1'b1 : 1'b0;

//像素点坐标
assign pixel_xpos = data_req ? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 11'd0;
assign pixel_ypos = data_req ? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 11'd0;

//行计数器对像素时钟计数
always @(posedge pixel_clk ) begin
    if (!sys_rst_n)
        cnt_h <= 11'd0;
    else begin
        if(cnt_h < H_TOTAL - 1'b1)
            cnt_h <= cnt_h + 1'b1;
        else 
            cnt_h <= 11'd0;
    end
end

//场计数器对行计数
always @(posedge pixel_clk ) begin
    if (!sys_rst_n)
        cnt_v <= 11'd0;
    else if(cnt_h == H_TOTAL - 1'b1) begin
        if(cnt_v < V_TOTAL - 1'b1)
            cnt_v <= cnt_v + 1'b1;
        else 
            cnt_v <= 11'd0;
    end
end

endmodule

  在这里输入的时钟信号pixel_clk,代码修改于RGB888 驱动显示的代码,驱动采用DE模式驱动
image.png
  因此此时的VS信号与HS信号直接赋值为高电平信号。此外定义了一个video_en信号,来作为rgb数据输出的控制信号,同时也将这个信号作为DE模式的控制信号。既然采用DE模式驱动,DE信号在有效显示区域时为有效信号,那么我们就应该知道此时显示的位置。位置我们定义了一个行计数器与列计数器,用于有效显示区域的确认。当显示位置为有效显示区域时,我们将高电平赋值给video_en信号,同时也将此信号作为rgb数据的控制信号,高电平时接受rgb数据并且输出。为了实时输出像素点坐标数据,定义了一个data_req信号,为有限显示区域的前一个位置,因为该信号赋值给pixel_xpospixel_ypos存在一个时钟周期的延迟。
  特别注意,该模块使用的时钟信号为74.25MHz

并串转换模块

  该模块的功能也十分简单,就是将HDMI驱动模块输出的数据进行并串转换,并且输出为HDMI标准中的差分信号。详细的请参考HDMI——FPGA这篇文章。

RGB数据输出

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/04 18:50:05
// Design Name: 
// Module Name: block_move
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module pic_display (
    input                   pixel_clk,
    input                   sys_rst_n,
    input           [10:0]  pixel_xpos,
    input           [10:0]  pixel_ypos,

    output  reg     [23:0]  pixel_data

);


//parameter define
    parameter H_DISP = 11'd1280;
    parameter V_DISP = 11'd720;

    localparam PIC_X_START = 11'd1; //图片起始点横坐标
    localparam PIC_Y_START = 11'd1; //图片起始点纵坐标
    localparam PIC_WIDTH   = 11'd100; //图片宽度
    localparam PIC_HEIGHT  = 11'd62; //图片高度
    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;
    
//为 LCD 不同显示区域绘制图片、字符和背景色
    always @(posedge pixel_clk or negedge sys_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 pixel_clk or negedge sys_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 (pixel_clk), // 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

  这个模块的功能就是根据输入的坐标显示数据输出相对应的RGB数据。

顶层模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/04 18:44:46
// Design Name: 
// Module Name: hdmi_colorbar_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module  hdmi_pic_display_top(
  input        sys_clk,
  input        sys_rst_n, 
  output       tmds_clk_p,    // TMDS 时钟通道
  output       tmds_clk_n,
  output [2:0] tmds_data_p,   // TMDS 数据通道
  output [2:0] tmds_data_n,
  output       tmds_oen      // TMDS 输出使能

);

  //wire define
  wire          pixel_clk;
  wire          pixel_clk_5x;
  wire          clk_locked;

  wire  [10:0]  pixel_xpos_w;
  wire  [10:0]  pixel_ypos_w;
  wire  [23:0]  pixel_data_w;

  wire          video_hs;
  wire          video_vs;
  wire          video_de;
  wire  [23:0]  video_rgb;

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

  //assign hpdout = hpdin;

  //例化MMCM/PLL IP核
  clk_wiz_0  clk_wiz_0(
    .clk_in1        (sys_clk),
    .clk_out1       (pixel_clk),        //像素时钟
    .clk_out2       (pixel_clk_5x),     //5倍像素时钟

    .reset          (~sys_rst_n), 
    .locked         (clk_locked)
  );

  //例化视频显示驱动模块
  video_driver u_video_driver(
    .pixel_clk      (pixel_clk),
    .sys_rst_n      (sys_rst_n),

    .video_hs       (video_hs),
    .video_vs       (video_vs),
    .video_de       (video_de),
    .video_rgb      (video_rgb),

    .pixel_xpos     (pixel_xpos_w),
    .pixel_ypos     (pixel_ypos_w),
    .pixel_data     (pixel_data_w)
  );

  //例化视频显示模块
  pic_display  u_pic_display(
    .pixel_clk      (pixel_clk),
    .sys_rst_n      (sys_rst_n),
    .pixel_xpos     (pixel_xpos_w),
    .pixel_ypos     (pixel_ypos_w),
    
    .pixel_data     (pixel_data_w)
  );

  //例化HDMI驱动模块
  dvi_transmitter_top u_rgb2dvi_0(
    .pclk           (pixel_clk),
    .pclk_x5        (pixel_clk_5x),
    .reset_n        (sys_rst_n & clk_locked),

    .video_din      (video_rgb),
    .video_hsync    (video_hs), 
    .video_vsync    (video_vs),
    .video_de       (video_de),

    .tmds_clk_p     (tmds_clk_p),
    .tmds_clk_n     (tmds_clk_n),
    .tmds_data_p    (tmds_data_p),
    .tmds_data_n    (tmds_data_n), 
    .tmds_oen       (tmds_oen)
  );

endmodule

  顶层模块就是将所有的模块例化,这里并不加以讲解。

上板验证

  实际显示效果
image.png


工程源码:链接: https://pan.baidu.com/s/1mnDjYzFnM6fkJEbhfUKTyw?pwd=rats 提取码: rats 复制这段内容后打开百度网盘手机App,操作更方便哦


参考文献

  [1] 正点原子. 达芬奇之FPGA开发指南
  [2] 野火. FPGA+Verilog开发实战指南——基于Xilinx+Spartan6
  [3] 请叫我冻冻.不同分辨率对应的像素输出时钟以及同步信号参数的整理

      

标签:11,基于,ROM,HDMI,clk,PIC,video,data,pixel
From: https://www.cnblogs.com/fangrunze/p/17986836

相关文章

  • 在.framework框架下的winfrom中使用Castle.DynamicProxy实现AOP问题小记
    1.需求:为项目中通讯PLC模块实现AOP,实现统一的日志打印,参数校验,方法执行时间统计2.问题:①现有项目没有IOC容器,没法使用部分AOP库的方法注册到IOC,(注:如果要实现IOC对现有代码改动大,并且AOP只是针对部分模块实现)②要在尽量小的代码改动下实现针对以上问题选择使用Castle.DynamicProx......
  • prometheus基本使用
    参考链接:https://www.prometheus.wang/作者总结的很好,大家都可以跟着学习看看prometheus的由来受启发与google的brogmon监控系统,从2012年开始由前Google工程师在Soundcloud以开源软件的形式进行研发,并且于2015年早期对外发布早期版本。2016年5月继Kubernetes之后成为第二个正......
  • prometheus组件
    prometheusserverPrometheusServer是Prometheus组件中的核心部分,负责实现对监控数据的获取,存储以及查询。PrometheusServer可以通过静态配置管理监控目标,也可以配合使用ServiceDiscovery的方式动态管理监控目标,并从这些监控目标中获取数据。其次PrometheusServer需要对采......
  • 基于CefSharp开发浏览器(十)浏览器CefSharp.Wpf中文输入法偏移处理
    一、前言两年多来未曾更新博客,最近一位朋友向我咨询中文输入法问题。具体而言,他在使用CefSharpWPF版本时遇到了一个问题,即输入法突然出现在屏幕的左上角。在这里记录下处理这个问题的过程,希望能够帮助到其他遇到类似问题的开发者。让我们一起来探讨如何解决能更好的处理CefSharp......
  • Stable Diffusion Prompt
    Prompt俗称咒语,实际上也是很难完全把控,在实际生图过程中需要不断的摸索。本文从“规则”、“原理”、“结合扩散模型”三个角度对Prompt进行探讨,希望小伙伴们能对Prompt整体有立体的认识。一、规则1、增强/减弱(emphasized)实质是:缩放语义向量:::warning()强度变为1.1倍[]......
  • 基于vue个人健康管理系统
    前端:vue后端:springboot+mybatis管理员账号:admin管理员密码:123456可以帮忙远程调试或环境搭建(有偿)概述:健康管理系统主要针对需要进行健康管理的用户和机构提供健康管理服务。通过该系统,用户可以进行个性化的健康管理,包括健康监测、健康评估、健康干预等服务。机构可以通过健康......
  • 基于Redis的Stream类型的完美消息队列解决方案(全)
    1概述2追加新消息,XADD,生产消息3从消息队列中获取消息,XREAD,消费消息4消息ID说明5消费者组模式,consumergroup6Pending等待列表7消息转移8坏消息问题,DeadLetter,死信问题9信息监控,XINFO10命令一览11Stream数据结构,RadixTree,基数树12相关产品1概述Redis5.......
  • chrom本地调试 selenium调试本地浏览器
    chrom本地调试 selenium调试本地浏览器1、cmd命令窗口执行下面命令,生成指定端口的chrom窗口。终端执行chrome.exe完整路径--remote-debugging-port=9222--user-data-dir="自定义用户信息文件夹路径",端口可修改。D:\Desktop\item\chromtest\Chrome\Application>chrome.ex......
  • 基于范数求解缩放因子方法的MIMO系统预编码技术matlab仿真
    1.算法运行效果图预览  2.算法运行软件版本MATLAB2022A 3.算法理论概述        多输入多输出(MIMO)技术是无线通信领域的关键技术之一,它利用多个天线同时发送和接收信号,可以显著提高系统容量和传输可靠性。在MIMO系统中,预编码技术是一种重要的信号处理技术,它......
  • 基于GoogleNet深度学习网络的花朵类型识别matlab仿真
    1.算法运行效果图预览 2.算法运行软件版本matlab2022a 3.算法理论概述      花朵类型识别是计算机视觉领域中的一个重要任务。它在植物学研究、农业、园艺等领域有着广泛的应用。传统的花朵类型识别方法通常基于手工设计的特征提取器,这些方法的效果受限于特征提......