HDMI图像传输(等宽十色彩条)

发布时间 2023-07-31 20:54:58作者: jasonlee~

第41章、HDMI(等宽十色彩条)

41.1 DVI(数字视频接口)

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

DVI 接口分为 3 大类:

(1)DVI-Analog(DVI-A)接口(12+5) :只传输模拟信号,实质就 是 VGA 模拟传输接口规格;

(2)DVI-Digital(DVI-D)接口(18+1 和 24+1) :是纯数字的接口,只能传输数字信号,不兼容模拟信号;

(3)DVI-Integrated(DVI-I)接口(18+5 和 24+5):是兼容数字和模拟接口的。

41.2 HDMI(高清多媒体接口)

HDMI 全称“High Definition Multimedia Interface 高清多媒体接口”。2002 年 4 月,来自 电子电器行业的 7 家公司——日立、松下、飞利浦、Silicon Image、索尼、汤姆逊、东芝 共同组建了 HDMI 高清多媒体接口接口组织 HDMI Founders(HDMI 论坛),开始着手制 定一种符合高清时代标准的全新数字化视频/音频接口技术。经过半年多时间的准备工作, HDMI founders 在 2002 年 12 月 9 日正式发布了 HDMI 1.0 版标准,标志着 HDMI 技术正式 进入历史舞台。

HDMI 的整个传输原理依然是基于 TMDS 编码技术。 HDMI 接口体积更小,各种设备都能轻松安装可用于机顶盒、DVD 播放机、个人计算机、 电视、游戏主机、综合扩大机、数字音响与电视机等设备;抗干扰能力更强,能实现最长 20 米的无增益传输;针对大尺寸数字平板电视分辨率进行优化,兼容性好;拥有强大的版 权保护机制(HDCP),有效防止盗版现象;支持 24bit 色深处理,(RGB、YCbCr4-4-4、 YCbCr4-2-2);一根线缆实现数字音频、视频信号同步传输,有效降低使用成本和繁杂程度。

41.2.1 HDMI 分类

(1)HDMI A Type 接口:应用于 HDMI1.0 版本,总共有 19pin,规格为 4.45mm×13.9mm, 为最常见的 HDMI 接头规格;

(2)HDMI C Type 接口:俗称 mini-HDMI,应用于 HDMI1.3 版 本,总共有 19pin,可以说是缩小版的 HDMI A type,规格为 2.42mm×10.42mm,但脚位定 义有所改变。主要是用在便携式设备上,例如 DV、数字相机、便携式多媒体播放机等。 由于大小所限,一些显卡会使用 mini-HDMI,用家须使用转接头转成标准大小的 Type A 再连接显示器;

(3)HDMI D Type 接口:应用于 HDMI1.4 版本,总共有 19pin,规格为 2.8mm×6.4mm,但脚位定义有所改变。新的 Micro HDMI 接口将比现在 19 针 MINI HDMI 版接口小 50%左右,可为相机、手机等便携设备带来最高 1080p 的分辨率支持及最快 5GB 的传输速度。三种接口如图 41-2 所示。

41.2.2 HDMI 引脚

HDMI 接口共有 19 个引脚,分上下两排,奇数在上,偶数在下。根据功能,19个引脚可划分到 4 类通道。

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

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

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

(4) 其他通道引脚 14 ,保留引脚,无连接;引脚 18 ,+5V 电源;引脚 19 ,热插拔检测引脚。

41.2.3 HDMI 显示原理

HDMI 系统架构由 信源端 接收端 组成。某个设备可能有一个或多个 HDMI 输入,一 个或多个 HDMI 输出。这些设备上,每个 HDMI 输入都应该遵循 HDMI 接收端规则, 每个 HDMI 输出都应该遵循 HDMI 信源端规则。 如图 41-5 所示,

(1) TMDS 数据和时钟通道 HDMI 线缆和连接器提供四个差分线对,这些通道用于传递视频,音频和辅助数据

(2) VESA DDC 通 道 :用于配置和在一个单独的信源端和一个单独的接收端交换状态;

(3) CEC 通道 :在用户的各种不同的音视频产品中, 提供高水平的控制功能

(4)HDMI 以太网和音频返回(HEAC):在连接的设备中提供以太网兼容的网络数据和一个和 TMDS 相对方向的音频回返通道

(5)热插拔检测信号 HPD :当显示器等 HDMI 接口的显示设备通 过 HDMI 接口与 HDMI 信源端相连或断开连接时,HDMI 信源端能够通过 HPD 引脚检测出这一事件,并做出响应。

41.2.3.1【TMDS 传输原理】

HDMI 采用和 DVI 相同的传输原理 --- TMDS(Transition Minimized Differential signal),最小化传输差分信号

HDMI 中的 TMDS 传输系统分为两个部分:发送端接收端

(1)TMDS 发送端:收到 HDMI 接口传来的表示 RGB888 信号的 24 位并行数据(TMDS 对每个像素的 RGB 三原色分别按 8bit 编码,即 R 信号有 8 位,G 信号有 8 位,B 信号有 8 位),然后对这些数据和时钟信号进行 编码 并/串转换,再将表示 3 个 RGB 信号的数据和时钟信号分别分配到 独立的传输通道发送 出去。(编码->并串转换->独立通道传输

(2)TMDS接收端:接收来自发送端的串行信号,对其进行 解码 串/并转换,然后发送到显示器的控制端。与此同时也接收时钟信号,以实现同步。(解码->串并转换->发送到显示器

流程框图如图 41-6 所 示。

TMDS 通道包括 3 个 RGB数据传输通道 1 个时钟信号传输通道。每一通道都通过编码算法,将 8 位的视频、音频数据转换成最小化传输、直流平衡的 10 位数据,8 位数据经过编码直流平衡得到 10 位最小化数据,看似增加了冗余位,对传输链路的带宽要求会更高,但事实上,通过这种算法得到的 10 位数据在更长的同轴电缆中传输的可靠性增强了。

要实现 TMDS 通道传输,首先要将传入的 8 位的并行数据进行编码、并/串转换,添加 第 9 位编码位,如下图所示。

rgb信号(8位)--> TMDS信号(10位):编码(过程中直流平衡)

(1)前 8 位数据:由原始信号经逻辑运算(异或异或非后逻辑得到

(2)第 9 位指示运算的方式 :编码

(3)第 10 位用来对应直流平衡

【直流平衡】

直流平衡(DC-balanced):在编码过程中保证信道中直流偏移为零,使信道中传输数据包含的 1 与 0 的个数相同

方法:在添加编码位的 9 位数据的后面加上第 10 位数据,保证 10 位数据中 1 与 0 个数相同。

这样, 传输的数据趋于直流平衡,使信号对传输线的电磁干扰减少,提高信号传输的可靠性。 直流均衡处理后的 10 位数据需要进行单端转差分处理。

【差分传动技术】

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

经过上述处理,我们得到了可以进行 TMDS 通道传输的差分信号,使用这种方法对 24 位图像数据(RGB888)和时钟信号进行处理,将 4 对差分信号通过 HDMI 接口发到接收设备;接收设备通过解码等一系列操作,实现图像后音频再现。

fpga数字信号-> 权电阻网络转换为模拟信号->vga模块生成行场信号及rgb信号->hdmi模块(编码、并串转换)->显示器

41.3 实战演练

41.3.1 实验目标

编写 HDMI 驱动,使用 FPGA 开发板驱动 HDMI 显示器显示十色等宽彩条, HDMI 显示模式为 640*480@60

41.3.2 实验设计

【整体模块图】

由图 41-12、表格 41-2 可知,HDMI 的彩条显示是基于 VGA 彩条显示的基础上的,是在 VGA 彩条显示工程的基础上修改的得到的。其中改动较大的有两部分:一是时钟生成模块输出时钟频率时钟个数做了改动;二是增加了 HDMI 驱动控制模块 hdmi_ctrl。

【注】其他从VGA模块中调用即可,只需要 hdmi_ctrl 模块 和 clk_gen 模块编写。

【1、clk_gen模块】

由上文可知,本次实验工程中,HDMI 显示模式为 640*480@60。

模块功能 :生成 25MHZ125MHZ(5倍) 2路时钟信号

实现方法 : 调用 IP 核

【2、 HDMI 驱动控制模块】

HDMI 驱动控制模块,实际就是 HDMI 驱动控制的顶层模块,功能是实现 VGA 图像信息到 HDMI 图像信息的转化。实现这一功能的转化,需要对输入的 VGA 图像信息进行编码并串转换单端信号转差分信号单沿采样转双沿采样

模块功能:将 VGA 控制模块传入的行场同步信号rgb信息转换为 HDMI接口能读取的差分信号

由图 41-14 可知,HDMI 驱动控制模块共有 17 路输入输出信号,输入信号 9 路输出 信号 8 路。输入输出信号简介具体见表格 41-4。

HDMI 驱动控制模块就是 HDMI 驱动控制部分的顶层模块,内部实例化 编码模块(encode) 并串转换模块(par_to_ser) ,连接各自对应信号,代码编写较为简单,无需波形图绘制。

【2.1 en_code 编码模块】

功能:完成 VGA 图像数据 8b 转 10b 的编码。

关于 8b 转 10b 编码的理论知识我们在前面的理论小节已经做了详细介绍。

对于编码模块的代码编写,我们不再进行波形图的绘制,以官方手册的流程图为参照进行代码编写。

【代码】

也可下载官方.v文件,直接调用

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'b1)));

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

【2.2 par_to_ser 并串转换模块】

功能 :

① 并行信号-->串行信号(位宽设置成1位:10bit -->1bit)

② 单沿采样-->双沿采样(调用ALTDDIO_OUT核)

③ 单端信号-->差分信号

【注】

(1)传入的时钟信号 clk_5x:

频率 125MHz,为输出串行差分信号 ser_data_p、 ser_data_n 的同步时钟;25x10/2=125

(2)时钟信号 clk_1x 与 clk_5x,时钟频率为 5 倍关系

因为并行数据信号 par_data 位宽 10bit,若转换为串行信号,需要在时钟信号 clk_1x 的一个时钟周期内完成数据转换,转换后的串行数据信号的同步时钟频率必须为 clk_1x 的 10 倍,使用双沿采样则为 5 倍。

【①并->串行数据的实现方法】

S1.拆分 :将输入的 10bit 并行数据 par_data 拆分两个位宽 5bit 的数据信号。

拆分规则 :将会在时钟上升沿输出的偶数位 par_data[8] 、 par_data[6] 、 par_data[4]、 par_data[2] 、 par_data[0]赋值给变量 data_rise[4:0];将会在时钟下降沿输出的 奇数位 par_data[9]、par_data[7]、 par_data[5]、par_data[3]、par_data[1]赋值给变量 data_fall[4:0]。

S2. 声明计数器 cnt,以 clk_5x 为计数时钟进行循环计数,计数范围 0-4,每个时钟周期自加 1。当 cnt 计数值为最大值 4 时,将拆分得到的变量 data_rise、data_fall 分别赋 值给 data_rise_s、data_fall_s;

S3. 将 data_rise_s[0]、data_fall_s[0]分别写入 ALTDDIO_OUT IP 核的 datain_h、 datain_l 接口;同时,每个时钟周期将 data_rise_s、data_fall_s 右移一位

经过上述三步操作后,位宽 10bit 的并行数据 par_data 转换为两路串行数据传入 ALTDDIO_OUT IP 核的 datain_h、datain_l 接口,经过 IP 核处理后,输出以 clk_5x 为同步时钟的串行双沿采样信号。 同时再次调用 ALTDDIO_OUT IP 核,将~data_rise_s[0]、~data_fall_s[0]分别写入 ALTDDIO_OUT IP 核的 datain_h、datain_l 接口,输出的串行双沿采样信号之前生成的串行双沿采样信号,构成差分信号对。

【②ALTDDIO_OUT IP核】(xilinx-oddr)

ALTDDIO_OUT 是 Altera 提供的双数据速率 (DDR) IP 核的一部分。双数据速率 (DDR) IP 核可以用于在逻辑资源中实现 DDR 寄存器

①ALTDDIO_BIDIR 可实现双向 DDR 输入输出 接口。

②ALTDDIO_IN 可实现 DDR 输入接口;

ALTDDIO_OUT 可实现 DDR 输出接口 (单沿转双沿,并在时钟上升沿和下降沿分别发送);

本模块使用的是 ALTDDIO_OUT IP 核,用以实现 DDR 输出接口,将两路单沿信号, 转换为双沿信号,在参考时钟的上升沿和下降沿发送数据

【ALTDDIO_OUT IP核调用】

【代码】
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 和 reg 均可在声明变量时直接赋值
wire [4:0] data_rise ;
wire [4:0] data_fall ;

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

assign data_rise = {par_data[8],par_data[6],par_data[4],par_data[2],par_data[0]}; //共10位并行数据分成奇偶位
assign data_fall = {par_data[9],par_data[7],par_data[5],par_data[3],par_data[1]};

always @ (posedge clk_5x)begin
cnt <= (cnt[2]) ? 3'd0 : cnt + 3'd1;//或者 “if (cnt==3'd5)”
data_rise_s <= cnt[2] ? data_rise : data_rise_s[4:1];
data_fall_s <= cnt[2] ? data_fall : data_fall_s[4:1];//5位中的高4位依次赋值
end

//***************************//
//**************************** Instantiate //
//
//
//------------- ddio_out_inst0 -------------
ddio_out 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 -------------
ddio_out ddio_out_inst1(
.datain_h (~data_rise_s[0]),
.datain_l (~data_fall_s[0]),
.outclock (~clk_5x ),
.dataout (ser_data_n ) //单端到差分信号的转换
);

endmodule

【代码】
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 top_hdmi_colorbar(
    input  sys_clk     ,
    input  sys_rst_n   , 
output hdmi_clk_p  ,//输出的是4条TDMS通道中的差分信号
output hdmi_clk_n  ,
output hdmi_g_p    ,
output hdmi_g_n    , 
output hdmi_r_p    ,
output hdmi_r_n    ,
output hdmi_b_p    ,
output hdmi_b_n    ,
output ddc_scl     ,
output ddc_sda    

);

wire clk_1x ;
wire clk_5x ;
wire locked ;
wire hdmi_rst_n ;
wire [11:0] pix_x ;
wire [11:0] pix_y ;
wire [15:0] pix_data ;
wire hsync ;
wire vsync ;
wire rgb_valid ;
wire [15:0] pic_rgb ;
wire de ;

assign hdmi_rst_n = (sys_rst_n & locked);
assign ddc_scl = 1'b1 ;
assign ddc_sda = 1'b1 ;

clk_gen clk_gen_inst01(
. sys_clk (sys_clk ) ,
. areset (~sys_rst_n) ,

. clk_1x  (clk_1x    )  ,
. clk_5x  (clk_5x    )  ,
. locked  (locked    )  

);

vga_pic vga_pic_inst01(
. vga_clk (clk_1x ),
. vga_rst_n (hdmi_rst_n),
. pix_x (pix_x ),
. pix_y (pix_y ),

.  pix_data  (pix_data  )

);

vga_ctrl vga_ctrl_inst01 (
. vga_clk (clk_1x ) ,
. vga_rst_n (hdmi_rst_n) ,
. pix_data (pix_data ) ,

. pix_x     (pix_x     ) ,
. pix_y     (pix_y     ) ,
. hsync     (hsync     ) ,
. vsync     (vsync     ) ,
. rgb_valid (rgb_valid ) ,
. pic_rgb   (pic_rgb   )  

);

hdmi_ctrl hdmi_ctrl_inst01(
. clk_1x (clk_1x ) ,
. clk_5x (clk_5x ) ,
. sys_rst_n (hdmi_rst_n ) ,
. rgb_blue ({pic_rgb[4:0],3'b0} ) ,
. rgb_green ({pic_rgb[5:0],2'b0} ) ,
. rgb_red ({pic_rgb[4:0],3'b0} ) ,
. hsync (hsync ) ,
. vsync (vsync ) ,
. de (rgb_valid ) ,

. hdmi_clk_p  (hdmi_clk_p           )  ,
. hdmi_clk_n  (hdmi_clk_n           )  ,
. hdmi_r_p    (hdmi_r_p             )  ,
. hdmi_r_n    (hdmi_r_n             )  , 
. hdmi_g_p    (hdmi_g_p             )  ,
. hdmi_g_n    (hdmi_g_n             )  , 
. hdmi_b_p    (hdmi_b_p             )  ,
. hdmi_b_n    (hdmi_b_n             )    

);

endmodule

管脚绑定: