HDMI显示图片

1,HDMI简介

  VGA 接口体积较大,不利于便携设备的集成;且传输的模拟信号易受外界干扰,产生信号畸变。VGA接口之后,推出了DUI接口,DVI 是基于 TMDS(Transition Minimized Differential Signaling, 最小化传输差分信号)技术来传输数字信号。 TMDS 运用先进的编码算法把 8bit 数据(R、 G、 B 中的每路基色信号)通过最小转换编码为 10bit 数据(包含行场同步信息、时钟信息、数据 DE、纠错等),经过直流均衡后,采用差分信号传输数据,它和LVDS、 TTL 相比有较好的电磁兼容性能,可以用低成本的专用电缆实现长距离、高质量的数字信号传输。数字视频接口(DVI)是一种国际开放的接口标准,在 PC、 DVD、高清晰电视(HDTV)、高清晰投影仪等设备上有广泛的应用。

  DVI 接口分为 3 大类: DVI-Analog(DVI-A)接口(12+5)只传输模拟信号,实质就是 VGA 模拟传输接口规格; DVI-Digital(DVI-D)接口(18+1 和 24+1)是纯数字的接口,只能传输数字信号,不兼容模拟信号; DVI-Integrated(DVI-I)接口(18+5 和 24+5)是兼容数字和模拟接口的。

  DVI接口的缺点:对平板电视的兼容能力一般,对数字化的色差信号无法支持;由于考虑兼容性,预留不少引脚,造成接口体积较大;只能传输图像信号,对于数字音频信号的支持完全没有考虑。

  HDMI 全称“High Definition Multimedia Interface 高清多媒体接口”。是一种符合高清时代标准的全新数字化视频/音频接口技术。HDMI的传输原理依然是基于TMDS编码技术。相比于DVI,HDMI接口体积更小抗干扰能力强;针对大尺寸数字平板电视分辨率进行优化,兼容性好;拥有强大的版权保护机制(HDCP);支持24bit色深处理(RGB,YCbCr);一根线缆实现数字音频、视频信号同步传输,有效降低使用成本和繁杂程度。

2,HDMI接口及引脚定义

  HDMI 规格书中规定了 HDMI 的 4 种接口类型,但其中 HDMI B Type 接口类型未在市场中出现过,市面上流通最广的是 HDMI A Type、 HDMI C Type 和 HDMI D Type 接口类型。

  HDMI A Type 接口, 应用于 HDMI1.0 版本,总共有 19pin,为最常见的 HDMI 接头规格;HDMI C Type 接口, 俗称 mini-HDMI,应用于 HDMI1.3 版本,总共有 19pin,可以说是缩小版的 HDMI A type,但脚位定义有一定的改变;HDMI D Type 接口, 应用于 HDMI1.4 版本,总共有 19pin,脚位定义有所改变。

在这里插入图片描述
  HDMI 接口之间使用 HDMI 信号线连接,不同类型的 HDMI 接口之间也可以使用连接线进行转接。

HDMI A Type 接口引脚图
在这里插入图片描述

引脚定义引脚定义
1数据 2+ (TMDS Data2+)11时钟屏蔽 (TMDS Clock Shield)
2数据 2 屏蔽 (TMDS Data2 Shield)12时钟- (TMDS Clock–)
3数据 2- ( TMDS Data2-)13CEC
4数据 1+ (TMDS Data1+)14保留
5数据 1 屏蔽 (TMDS Data1 Shield)15DDC 时钟线(SCL)
6数据 1- ( TMDS Data1-)16DDC 数据线(SDA)
7数据 0+ (TMDS Data0+)17DDC/CEC 地 (DDC/CEC GND)
8数据 0 屏蔽 (TMDS Data0 Shield)18+5V 电源 (Power)
9数据 0- ( TMDS Data0-)19热插拔检测 (Hot Plug Detect)
10时钟+ (TMDS Clock+)

  由图表可知, HDMI 接口共有 19 个引脚,分上下两排,奇数在上,偶数在下,穿插排布。根据其功能,可以将引脚分为 4 类。

  • TMDS 通道:引脚 1-引脚 12。负责发送音频、视频及各种辅助数据; 遵循 DVI1.0 规格的信号编码方式; 视频像素带宽从 25 MHz 到 340 MHz(Type A, HDMI 1.3)或至680MHz (Type B)。带宽低于 25MHz 的视频信号如 NTSC480i 将以倍频方式输出; 每个像素的容许数据量从 24 位至 48 位。支持每秒 120 张画面 1080p 分辨率画面发送以及WQSXGA (3200 x 2048)分辨率;支持 RGB、 YCbCr 4:4:4(8-16 bits per component) 、 YCbCr 4:2:2(12bits per component) 、 YCbCr 4:2:0(HDMI 2.0) 等多种像素编码方式; 音频采样率支持32kHz、 44.1kHz、 48kHz、88.2kHz 96kHz、 176.4kHz、 192kHz、 1536kHz(HDMI2.0) ; 音频声道数量最大 8 声道。 HDMI 2.0 支持 32 声道。音频流规格为 IEC61937 兼容流,包括高流量无损信号如 Dolby TrueHD、 DTS-HD Master Audio。

  • DDC 通道:引脚 15、 16、 17。 DDC 全文为 Display Data Channel,译为“显示数据通道”; 发送端与接收端可利用 DDC 沟道得知彼此的发送与接收能力,但 HDMI 仅需单向获知接收端(显示器)的能力; DDC 通道使用 100kHz 时钟频率的 I²C 信号, 发送数据结构为 VESA Enhanced EDID(V1.3)。

  • CEC 通道:引脚 13、 17。 CEC 全文为 Consumer Electronics Control, CEC 通道为必须预留线路,但可以不必实现,作用是用来发送工业规格的 AV Link 协议信号,以便支持单一遥控器操作多台 AV 机器, 为单芯线双向串列总线。

  • 其他通道:引脚 14 位保留引脚,无连接;引脚 18 为+5V 电源;引脚 19 位热插拔检测引脚。

3,HDMI显示原理

  HDMI 系统架构由信源端和接收端组成。某个设备可能有一个或多个 HDMI 输入,一个或多个 HDMI 输出。这些设备上,每个 HDMI 输入都应该遵循 HDMI 接收端规则, 每个 HDMI 输出都应该遵循 HDMI 信源端规则。HDMI数据传输框图如下:

在这里插入图片描述

  HDMI 线缆和连接器提供四个差分线对,组成 TMDS 数据和时钟通道, 这些通道用于传递视频,音频和辅助数据; 另外, HDMI 提供一个 VESA DDC 通道, DDC 是用于配置和在一个单独的信源端和一个单独的接收端交换状态; 可选择的 CEC在用户的各种不同的音视频产品中, 提供高水平的控制功能; 可选择的 HDMI 以太网和音频返回(HEAC),在连接的设备中提供以太网兼容的网络数据和一个和 TMDS 相对方向的音频回返通道;此外还有热插拔检测信号 HDP, 当显示器等 HDMI 接口的显示设备通过 HDMI 接口与 HDMI 信源端相连或断开连接时, HDMI 信源端能够通过 HPD 引脚检测出
这一事件,并做出响应。

4,TMDS简介

  HDMI 中的 TMDS 传输系统分为两个部分:发送端和接收端。 TMDS 发送端收到HDMI 接口传来的表示 RGB 信号的 24 位并行数据(TMDS 对每个像素的 RGB 三原色分别按 8bit 编码,即 R 信号有 8 位, G 信号有 8 位, B 信号有 8 位),然后对这些数据和时钟信号进行编码和并/串转换,再将表示 3 个 RGB 信号的数据和时钟信号分别分配到独立的传输通道发送出去。接收端接收来自发送端的串行信号,对其进行解码和串/并转换,然后发送到显示器的控制端。与此同时也接收时钟信号,以实现同步。流程框图如下

在这里插入图片描述

  TMDS 通道包括 3 个 RGB 数据传输通道和 1 个时钟信号传输通道。每一通道都通过编码算法,将 8 位的视频、音频数据转换成最小化传输、直流平衡的 10 位数据, 8 位数据经过编码和直流平衡得到 10 位最小化数据,看似增加了冗余位,对传输链路的带宽要求会更高,但事实上,通过这种算法得到的 10 位数据在更长的同轴电缆中传输的可靠性增强了。最小化传输差分信号是通过异或及异或非等逻辑算法将原始 8 位数据转换成 10 位数据,前8 位数据由原始信号经逻辑运算后逻辑得到,第 9 位指示运算的方式,第 10 位用来对应直流平衡。

  要实现 TMDS 通道传输,首先要将传入的 8 位的并行数据进行编码、并/串转换,添加第 9 位编码位,将 8 位并行数据发送到 TMDS 接收端;将接收到的 8 位数据并/串转换;随后进行最小化传输处理,加上第 9 位,即编码过程。

  添加编码位的数据需要进行直流均衡处理。 直流平衡(DC-balanced)就是指在编码过程中保证信道中直流偏移为零,使信道中传输数据包含的 1 与 0 的个数相同。方法是在添加编码位的 9 位数据的后面加上第 10 位数据, 保证 10 位数据中 1 与 0 个数相同。这样,传输的数据趋于直流平衡,使信号对传输线的电磁干扰减少,提高信号传输的可靠性。

  直流均衡处理后的 10 位数据需要进行单端转差分处理。 TMDS 差分传动技术是一种利用 2 个引脚间电压差来传送信号的技术。传输数据的数值(“0”或者“1”)由两脚间电压正负极性和大小决定。即采用 2 根线来传输信号,一根线上传输原来的信号,另一根线上传输与原来信号相反的信号。这样接收端就可以通过让一根线上的信号减去另一根线上的信号的方式来屏蔽电磁干扰,从而得到正确的信号。

5,HDMI显示图片的实现

设计的整体框图如下

在这里插入图片描述

5.1 clk_gen 时钟产生模块

  通过PLL IP核产生两路输出时钟,分别为25MHz,125MHz为其他模块提供时钟。

5.2 vga_pic,vga_ctrl 显示数据的产生与控制

  vga_ctrl模块输出坐标数据,图像有效信号,行场同步信号以及像素数据。代码如下

module  vga_ctrl
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [15:0]  pix_data    ,   //输入像素点色彩信息

    output  wire    [11:0]  pix_x       ,   //输出VGA有效显示区域像素点X轴坐标
    output  wire    [11:0]  pix_y       ,   //输出VGA有效显示区域像素点Y轴坐标
    output  wire            hsync       ,   //输出行同步信号
    output  wire            vsync       ,   //输出场同步信号
    output  wire            rgb_valid   ,
    output  wire    [15:0]  rgb             //输出像素点色彩信息
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter H_SYNC    =   10'd96  ,   //行同步
          H_BACK    =   10'd40  ,   //行时序后沿
          H_LEFT    =   10'd8   ,   //行时序左边框
          H_VALID   =   10'd640 ,   //行有效数据
          H_RIGHT   =   10'd8   ,   //行时序右边框
          H_FRONT   =   10'd8   ,   //行时序前沿
          H_TOTAL   =   10'd800 ;   //行扫描周期
parameter V_SYNC    =   10'd2   ,   //场同步
          V_BACK    =   10'd25  ,   //场时序后沿
          V_TOP     =   10'd8   ,   //场时序上边框
          V_VALID   =   10'd480 ,   //场有效数据
          V_BOTTOM  =   10'd8   ,   //场时序下边框
          V_FRONT   =   10'd2   ,   //场时序前沿
          V_TOTAL   =   10'd525 ;   //场扫描周期

//wire  define
wire            pix_data_req    ;   //像素点色彩信息请求信号

//reg   define
reg     [11:0]  cnt_h           ;   //行同步信号计数器
reg     [11:0]  cnt_v           ;   //场同步信号计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_h:行同步信号计数器
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h   <=  12'd0   ;
    else    if(cnt_h == H_TOTAL - 1'd1)
        cnt_h   <=  12'd0   ;
    else
        cnt_h   <=  cnt_h + 1'd1   ;

//hsync:行同步信号
assign  hsync = (cnt_h  <=  H_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//cnt_v:场同步信号计数器
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v   <=  12'd0 ;
    else    if((cnt_v == V_TOTAL - 1'd1) &&  (cnt_h == H_TOTAL-1'd1))
        cnt_v   <=  12'd0 ;
    else    if(cnt_h == H_TOTAL - 1'd1)
        cnt_v   <=  cnt_v + 1'd1 ;
    else
        cnt_v   <=  cnt_v ;

//vsync:场同步信号
assign  vsync = (cnt_v  <=  V_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//rgb_valid:VGA有效显示区域
assign  rgb_valid = (((cnt_h >= H_SYNC + H_BACK + H_LEFT)
                    && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID))
                    &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                    && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                    ? 1'b1 : 1'b0;

//pix_data_req:像素点色彩信息请求信号,超前rgb_valid信号一个时钟周期
assign  pix_data_req = (((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)
                    && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1))
                    &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                    && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                    ? 1'b1 : 1'b0;

//pix_x,pix_y:VGA有效显示区域像素点坐标
assign  pix_x = (pix_data_req == 1'b1)
                ? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 12'hfff;
assign  pix_y = (pix_data_req == 1'b1)
                ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 12'hfff;

//rgb:输出像素点色彩信息
assign  rgb = (rgb_valid == 1'b1) ? pix_data : 16'b0 ;

endmodule

vga_pic模块,pix_x,pix_y坐标值处于图像显示有效区域时,从ROM中读取像素数据,然后输出,代码如下

module  vga_pic
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [11:0]  pix_x       ,   //输入VGA有效显示区域像素点X轴坐标
    input   wire    [11:0]  pix_y       ,   //输入VGA有效显示区域像素点Y轴坐标

    output          [15:0]  pix_data        //输出像素点色彩信息
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   CHAR_B_H =   10'd192 ,   
            CHAR_B_V =   10'd208 ;  

parameter   CHAR_W   =   10'd100 ,
            CHAR_H   =   10'd100  ;

parameter   BLACK    =   12'h000 ,
            WHITE    =   12'hfff ,
            BLUE     =   12'h00F ;   //蓝色


wire rom_req;

reg [13:0] rom_addr;
wire [15:0] rom_data;

//何时从rom中读取数据
assign rom_req = (((pix_x >= CHAR_B_H - 1'b1) && (pix_x < (CHAR_B_H + CHAR_W - 1'b1)))
                &&((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H)))) ? 1'b1:1'b0;

//产生rom地址
always @(posedge vga_clk,negedge sys_rst_n) begin
    if(!sys_rst_n)
        rom_addr <= 14'd0;
    else if(rom_req == 1'b1) begin
        if(rom_addr == 14'd9999)
            rom_addr <= 14'd0;
        else
            rom_addr <= rom_addr + 1;
    end
    else
        rom_addr <= rom_addr;
end

//输出数据
rom_pic rom_pic_inst(
    .clock    (vga_clk)   ,
    .address  (rom_addr)  ,
    .q        (rom_data)
);

assign pix_data = (rom_req == 1'b1) ? rom_data:WHITE;

endmodule

5.3 hdmi_ctrl模块

  该模块实现对输入的颜色分量及时钟进行编码,并串转换,差分输出的功能,模块框图如下
在这里插入图片描述

  按照上面的模块框图,首先对编码模块进行编写,编码模块按照官方手册进行编写。编码模块参考流程图中个参数说明。

符号说明
D, C0, C1, DE编码器输入数据。 D 是八位像素数据, C1 和 C0 是通道的控制数据,DE 是数据使能。
cnt寄存器,用来跟踪数据流的不一致,正值表示发送的 1 的个数超过的数目,负数表示发送的 0 的个数超过的数目。表达式 cnt{t-1}表示相对于输入数据前一个集的前一个不一致值。表达式 cnt{t}表示相对于输入数据当前集的新的不一致设置。
q_out完成编码后的 10bit 数据。
N1{x}返回参数 x 中“1”的个数。
N0{x}返回参数 x 中“1”的个数。

编码模块参考流程图
在这里插入图片描述
在这里插入图片描述
代码如下

module  encode
(
    input   wire            sys_clk     ,   //时钟信号
    input   wire            sys_rst_n   ,   //复位信号,低有效
    input   wire    [7:0]   data_in     ,   //输入8bit待编码数据
    input   wire            c0          ,   //控制信号c0
    input   wire            c1          ,   //控制信号c1
    input   wire            de          ,   //使能信号

    output  reg     [9:0]   data_out        //输出编码后的10bit数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   DATA_OUT0   =   10'b1101010100,
            DATA_OUT1   =   10'b0010101011,
            DATA_OUT2   =   10'b0101010100,
            DATA_OUT3   =   10'b1010101011;

//wire  define
wire            condition_1 ;   //条件1
wire            condition_2 ;   //条件2
wire            condition_3 ;   //条件3
wire    [8:0]   q_m         ;   //第一阶段转换后的9bit数据

//reg   define
reg     [3:0]   data_in_n1  ;   //待编码数据中1的个数
reg     [7:0]   data_in_reg ;   //待编码数据打一拍
reg     [3:0]   q_m_n1      ;   //转换后9bit数据中1的个数
reg     [3:0]   q_m_n0      ;   //转换后9bit数据中0的个数
reg     [4:0]   cnt         ;   //视差计数器,0-1个数差别,最高位为符号位
reg             de_reg1     ;   //使能信号打一拍
reg             de_reg2     ;   //使能信号打两拍
reg             c0_reg1     ;   //控制信号c0打一拍
reg             c0_reg2     ;   //控制信号c0打两拍
reg             c1_reg1     ;   //控制信号c1打一拍
reg             c1_reg2     ;   //控制信号c1打两拍
reg     [8:0]   q_m_reg     ;   //q_m信号打一拍

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//data_in_n1:待编码数据中1的个数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in_n1  <=  4'd0;
    else
        data_in_n1  <=  data_in[0] + data_in[1] + data_in[2]
                        + data_in[3] + data_in[4] + data_in[5]
                        + data_in[6] + data_in[7];

//data_in_reg:待编码数据打一拍
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in_reg <=  8'b0;
    else
        data_in_reg <=  data_in;

//condition_1:条件1
assign  condition_1 = ((data_in_n1 > 4'd4) || ((data_in_n1 == 4'd4)
                        && (data_in_reg[0] == 1'b0)));

//q_m:第一阶段转换后的9bit数据
assign q_m[0] = data_in_reg[0];
assign q_m[1] = (condition_1) ? (q_m[0] ^~ data_in_reg[1]) : (q_m[0] ^ data_in_reg[1]);
assign q_m[2] = (condition_1) ? (q_m[1] ^~ data_in_reg[2]) : (q_m[1] ^ data_in_reg[2]);
assign q_m[3] = (condition_1) ? (q_m[2] ^~ data_in_reg[3]) : (q_m[2] ^ data_in_reg[3]);
assign q_m[4] = (condition_1) ? (q_m[3] ^~ data_in_reg[4]) : (q_m[3] ^ data_in_reg[4]);
assign q_m[5] = (condition_1) ? (q_m[4] ^~ data_in_reg[5]) : (q_m[4] ^ data_in_reg[5]);
assign q_m[6] = (condition_1) ? (q_m[5] ^~ data_in_reg[6]) : (q_m[5] ^ data_in_reg[6]);
assign q_m[7] = (condition_1) ? (q_m[6] ^~ data_in_reg[7]) : (q_m[6] ^ data_in_reg[7]);
assign q_m[8] = (condition_1) ? 1'b0 : 1'b1;

//q_m_n1:转换后9bit数据中1的个数
//q_m_n0:转换后9bit数据中0的个数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            q_m_n1  <=  4'd0;
            q_m_n0  <=  4'd0;
        end
    else
        begin
            q_m_n1  <=  q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
            q_m_n0  <=  4'd8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
        end

//condition_2:条件2
assign  condition_2 = ((cnt == 5'd0) || (q_m_n1 == q_m_n0));

//condition_3:条件3
assign  condition_3 = (((~cnt[4] == 1'b1) && (q_m_n1 > q_m_n0))
                        || ((cnt[4] == 1'b1) && (q_m_n0 > q_m_n1)));

//数据打拍,为了各数据同步
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            de_reg1 <=  1'b0;
            de_reg2 <=  1'b0;
            c0_reg1 <=  1'b0;
            c0_reg2 <=  1'b0;
            c1_reg1 <=  1'b0;
            c1_reg2 <=  1'b0;
            q_m_reg <=  9'b0;
        end
    else
        begin
            de_reg1 <=  de;
            de_reg2 <=  de_reg1;
            c0_reg1 <=  c0;
            c0_reg2 <=  c0_reg1;
            c1_reg1 <=  c1;
            c1_reg2 <=  c1_reg1;
            q_m_reg <=  q_m;
        end

//data_out:输出编码后的10bit数据
//cnt:视差计数器,0-1个数差别,最高位为符号位
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            data_out    <=  10'b0;
            cnt         <=  5'b0;
        end
    else
        begin
            if(de_reg2 == 1'b1)
                begin
                    if(condition_2 == 1'b1)
                        begin
                            data_out[9]     <=  ~q_m_reg[8]; 
                            data_out[8]     <=  q_m_reg[8]; 
                            data_out[7:0]   <=  (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
                            cnt <=  (~q_m_reg[8]) ? (cnt + q_m_n0 - q_m_n1) : (cnt + q_m_n1 - q_m_n0);
                        end
                    else
                        begin
                            if(condition_3 == 1'b1)
                                begin
                                    data_out[9]     <= 1'b1;
                                    data_out[8]     <= q_m_reg[8];
                                    data_out[7:0]   <= ~q_m_reg[7:0];
                                    cnt <=  cnt + {q_m_reg[8], 1'b0} + (q_m_n0 - q_m_n1);
                                end
                            else
                                begin
                                    data_out[9]     <= 1'b0;
                                    data_out[8]     <= q_m_reg[8];
                                    data_out[7:0]   <= q_m_reg[7:0];
                                    cnt <=  cnt - {~q_m_reg[8], 1'b0} + (q_m_n1 - q_m_n0);
                                end
                            
                        end
                end
            else
                begin
                    case    ({c1_reg2, c0_reg2})
                        2'b00:  data_out <= DATA_OUT0;
                        2'b01:  data_out <= DATA_OUT1;
                        2'b10:  data_out <= DATA_OUT2;
                        default:data_out <= DATA_OUT3;
                    endcase
                    cnt <=  5'b0;
                end
        end

endmodule

并串转换模块代码

module par_to_ser
(
    input   wire            clk_5x      ,   //输入系统时钟
    input   wire    [9:0]   par_data    ,   //输入并行数据

    output  wire            ser_data_p  ,   //输出串行差分数据
    output  wire            ser_data_n      //输出串行差分数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire  define
wire    [4:0]   data_rise = {par_data[8],par_data[6],
                            par_data[4],par_data[2],par_data[0]};
wire    [4:0]   data_fall = {par_data[9],par_data[7],
                            par_data[5],par_data[3],par_data[1]};

//reg   define
reg     [4:0]   data_rise_s = 0;
reg     [4:0]   data_fall_s = 0;
reg     [2:0]   cnt = 0;


always @ (posedge clk_5x)
    begin
        cnt <= (cnt[2]) ? 3'd0 : cnt + 3'd1;
        data_rise_s  <= cnt[2] ? data_rise : data_rise_s[4:1];
        data_fall_s  <= cnt[2] ? data_fall : data_fall_s[4:1];

    end

//********************************************************************//
//**************************** Instantiate ***************************//
//********************************************************************//
//------------- ddio_out_inst0 -------------
altddio    ddio_out_inst0
(
    .datain_h   (data_rise_s[0] ),
    .datain_l   (data_fall_s[0] ),
    .outclock   (~clk_5x        ),
    .dataout    (ser_data_p     )
);

//------------- ddio_out_inst1 -------------
altddio     ddio_out_inst1
(
    .datain_h   (~data_rise_s[0]),
    .datain_l   (~data_fall_s[0]),
    .outclock   (~clk_5x        ),
    .dataout    (ser_data_n     )
);

endmodule

hdmi_ctrl顶层模块代码

module  hdmi_ctrl
(
    input   wire            clk_1x      ,   //输入系统时钟
    input   wire            clk_5x      ,   //输入5倍系统时钟
    input   wire            sys_rst_n   ,   //复位信号,低有效
    input   wire    [7:0]   rgb_blue    ,   //蓝色分量
    input   wire    [7:0]   rgb_green   ,   //绿色分量
    input   wire    [7:0]   rgb_red     ,   //红色分量
    input   wire            hsync       ,   //行同步信号
    input   wire            vsync       ,   //场同步信号
    input   wire            de          ,   //使能信号

    output  wire            hdmi_clk_p  ,
    output  wire            hdmi_clk_n  ,   //时钟差分信号
    output  wire            hdmi_r_p    ,
    output  wire            hdmi_r_n    ,   //红色分量差分信号
    output  wire            hdmi_g_p    ,
    output  wire            hdmi_g_n    ,   //绿色分量差分信号
    output  wire            hdmi_b_p    ,
    output  wire            hdmi_b_n        //蓝色分量差分信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
wire    [9:0]   red     ;   //8b转10b后的红色分量
wire    [9:0]   green   ;   //8b转10b后的绿色分量
wire    [9:0]   blue    ;   //8b转10b后的蓝色分量

//********************************************************************//
//**************************** Instantiate ***************************//
//********************************************************************//
//------------- encode_inst0 -------------
encode  encode_inst0
(
    .sys_clk    (clk_1x     ),
    .sys_rst_n  (sys_rst_n  ),
    .data_in    (rgb_blue   ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    .data_out   (blue       )
);

//------------- encode_inst1 -------------
encode  encode_inst1
(
    .sys_clk    (clk_1x     ),
    .sys_rst_n  (sys_rst_n  ),
    .data_in    (rgb_green  ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    .data_out   (green      )
);

//------------- encode_inst2 -------------
encode  encode_inst2
(
    .sys_clk    (clk_1x     ),
    .sys_rst_n  (sys_rst_n  ),
    .data_in    (rgb_red    ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    .data_out   (red        )
);

//------------- par_to_ser_inst0 -------------
par_to_ser  par_to_ser_inst0
(
    .clk_5x      (clk_5x    ),
    .par_data    (blue      ),

    .ser_data_p  (hdmi_b_p  ),
    .ser_data_n  (hdmi_b_n  )
);

//------------- par_to_ser_inst1 -------------
par_to_ser  par_to_ser_inst1
(
    .clk_5x      (clk_5x    ),
    .par_data    (green     ),

    .ser_data_p  (hdmi_g_p  ),
    .ser_data_n  (hdmi_g_n  )
);

//------------- par_to_ser_inst2 -------------
par_to_ser  par_to_ser_inst2
(
    .clk_5x      (clk_5x    ),
    .par_data    (red       ),

    .ser_data_p  (hdmi_r_p  ),
    .ser_data_n  (hdmi_r_n  )
);

//------------- par_to_ser_inst3 -------------
par_to_ser  par_to_ser_inst3
(
    .clk_5x      (clk_5x        ),
    .par_data    (10'b1111100000),

    .ser_data_p  (hdmi_clk_p    ),
    .ser_data_n  (hdmi_clk_n    )
);

endmodule

整个工程的顶层模块代码

module  hdmi_bar
(
    input   wire            sys_clk     ,   //输入工作时钟,频率50MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效

    output  wire            ddc_scl     ,
    output  wire            ddc_sda     ,
    output  wire            tmds_clk_p  ,
    output  wire            tmds_clk_n  ,   //HDMI时钟差分信号
    output  wire    [2:0]   tmds_data_p ,
    output  wire    [2:0]   tmds_data_n     //HDMI图像差分信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire            vga_clk ;   //VGA工作时钟,频率25MHz
wire            clk_5x  ;
wire            locked  ;   //PLL locked信号
wire            rst_n   ;   //VGA模块复位信号
wire    [11:0]  pix_x   ;   //VGA有效显示区域X轴坐标
wire    [11:0]  pix_y   ;   //VGA有效显示区域Y轴坐标
wire    [15:0]  pix_data;   //VGA像素点色彩信息
wire            hsync   ;   //输出行同步信号
wire            vsync   ;   //输出场同步信号
wire    [15:0]  rgb     ;   //输出像素信息
wire            rgb_valid;

//rst_n:VGA模块复位信号
assign  rst_n   = (sys_rst_n & locked);
assign  ddc_scl = 1'b1;
assign  ddc_sda = 1'b1;

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- clk_gen_inst -------------
clk_gen clk_gen_inst
(
    .areset     (~sys_rst_n ),  //输入复位信号,高电平有效,1bit
    .inclk0     (sys_clk    ),  //输入50MHz晶振时钟,1bit

    .c0         (vga_clk    ),  //输出VGA工作时钟,频率25Mhz,1bit
    .c1         (clk_5x     ),
    .locked     (locked     )   //输出pll locked信号,1bit
);

//------------- vga_ctrl_inst -------------
vga_ctrl  vga_ctrl_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
    .pix_data   (pix_data   ),  //输入像素点色彩信息,16bit

    .pix_x      (pix_x      ),  //输出VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输出VGA有效显示区域像素点Y轴坐标,10bit
    .hsync      (hsync      ),  //输出行同步信号,1bit
    .vsync      (vsync      ),  //输出场同步信号,1bit
    .rgb_valid  (rgb_valid  ),
    .rgb        (rgb        )   //输出像素点色彩信息,16bit
);

//------------- vga_pic_inst -------------
vga_pic vga_pic_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
    .pix_x      (pix_x      ),  //输入VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输入VGA有效显示区域像素点Y轴坐标,10bit

    .pix_data   (pix_data   )   //输出像素点色彩信息,16bit

);

//------------- hdmi_ctrl_inst -------------
hdmi_ctrl   hdmi_ctrl_inst
(
    .clk_1x      (vga_clk           ),   //输入系统时钟
    .clk_5x      (clk_5x            ),   //输入5倍系统时钟
    .sys_rst_n   (rst_n             ),   //复位信号,低有效
    .rgb_blue    ({rgb[4:0],3'b0}   ),   //蓝色分量
    .rgb_green   ({rgb[10:5],2'b0}  ),   //绿色分量
    .rgb_red     ({rgb[15:11],3'b0} ),   //红色分量
    .hsync       (hsync             ),   //行同步信号
    .vsync       (vsync             ),   //场同步信号
    .de          (rgb_valid         ),   //使能信号
    .hdmi_clk_p  (tmds_clk_p        ),
    .hdmi_clk_n  (tmds_clk_n        ),   //时钟差分信号
    .hdmi_r_p    (tmds_data_p[2]    ),
    .hdmi_r_n    (tmds_data_n[2]    ),   //红色分量差分信号
    .hdmi_g_p    (tmds_data_p[1]    ),
    .hdmi_g_n    (tmds_data_n[1]    ),   //绿色分量差分信号
    .hdmi_b_p    (tmds_data_p[0]    ),
    .hdmi_b_n    (tmds_data_n[0]    )    //蓝色分量差分信号
);

endmodule

6,显示结果

彩条显示
在这里插入图片描述

图片显示
在这里插入图片描述

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的内容,可以得知在FPGA上实现HDMI显示图片过程。首先,需要准备一张图片,并将其转化为FPGA所支持的coe文件格式。这个过程可以通过MATLAB代码实现,具体步骤如下: 1. 使用imread函数读取图片,将其分离为红色通道、绿色通道和蓝色通道。 2. 将每个通道的位宽修改为32位无符号整数。 3. 将每个通道的二维数据降维为一维数据。 4. 进行移位操作,将每个像素的RGB值合并为一个32位的RGB888格式的数据。 5. 将转化后的数据存储为coe文件。 接下来,需要编写Verilog代码来实现HDMI显示图片的功能。根据引用\[1\]的代码,可以看到Verilog模块`rgb2gray`接收一个RGB888格式的像素数据,并将其转化为灰度图像数据。这个模块可以作为后续图像处理的基础。 综上所述,要在FPGA上实现HDMI显示图片,需要准备一张图片并将其转化为coe文件,然后编写Verilog代码来处理图像数据。具体的实现细节可以根据引用\[1\]和引用\[3\]中提供的代码进行参考和修改。 #### 引用[.reference_title] - *1* *2* *3* [FPGA-HDMI-静态图片(灰度化)显示实验(ZYBO Z7)](https://blog.csdn.net/lihuanyu520/article/details/127141505)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值