本设计使用Xilinx原语和自己手写的代码实现了HDMI发送功能,纯verilog手写,有源码,也提供封装好的IP,你喜欢用例化的方式就用源码,你喜欢搭建BD工程就用IP,目前IP的适应器件为zynq,如果是用7系列FPGA的兄弟可以改一下芯片型号即可使用。
这个HDMI发送模块我已在项目中多次使用,稳定性和实用性可以保证,最大支持1080P@60Hz帧率。
本文详细描述了设计方案,工程代码编译通过后上板调试验证,可直接项目移植,适用于在校学生、研究生项目开发,也适用于在职工程师做项目开发,可应用于医疗、军工等行业的数字成像和图像传输领域;
提供完整的、跑通的工程源码和技术支持;
工程源码和技术支持的获取方式放在了文章末尾,请耐心看到最后;
关于HDMI的理论介绍这里不多说,请自行搜索,很简单,本文只讲如何代码层级实现的干货。
HDMI编码框图如下:
Encoder 模块负责对数据进行编码,Serializer 模块对编码后的数据进行并串转换,最后
通过 OBUFDS 转化成 TMDS 差分信号传输。
整个系统需要两个输入时钟,一个是视频的像素时钟 Pixel Clk,另外一个时钟 Pixel Clk x5 的频率是像
素时钟的五倍。由前面的简介部分我们知道,并串转换过程的实现的是 10:1 的转换率,理论上转换器需要一个 10 倍像素时钟频率的串行时钟。这里我们只用了一个 5 倍的时钟频率,这是因为 OSERDESE2 模块可以实现 DDR 的功能,即它在五倍时钟频率的基础上又实现了双倍数据速率。
TMDS 连接的时钟通道我们采用与数据通道相同的并转串逻辑来实现。通过对 10 位二进制序列10’b11111_00000 在 10 倍像素时钟频率下进行并串转换,就可以得到像素时钟频率下的 TMDS 参考时钟。
另外需要注意的是,图中左下脚 HDMI 的音频/附加数据输入在本次实验中并未用到,因此以虚线表示。
Encoder 模块完成TMDS 编码算法,dvi_encoder 模块按照 DVI 接口规范中 TMDS 编码算法对输入的 8 位像素数据以及 2 位行场同步信号进行编码。该模块是 Xilinx 应用笔记 XAPP460 中所提供的编码模块,其具体实现的编码算法如下图所示:TMDS 通过逻辑算法将 8 位字符数据通过最小转换编码为 10 位字符数据,前 8 位数据由原始信号经运
算后获得,第 9 位表示运算的方式,1 表示异或 0 表示异或非。经过 DC 平衡后(第 10 位),采用差分信号传输数据。第 10 位实际是一个反转标志位,1 表示进行了反转而 0 表示没有反转,从而达到 DC 平衡。
接收端在收到信号后,再进行相反的运算。TMDS 和 LVDS、TTL 相比有较好的电磁兼容性能。这种算
法可以减小传输信号过程的上冲和下冲,而 DC 平衡使信号对传输线的电磁干扰减少,可以用低成本的专用电缆实现长距离、高质量的数字信号传输。
算法中各个参数的含义如下图所示:
Encoder 模块顶层接口如下:
module dvi_encoder (input clkin, // pixel clock inputinput rstin, // async. reset input (active high)input [7:0] din , // data inputs: expect registeredinput c0 , // c0 inputinput c1 , // c1 inputinput de , // de inputoutput reg [9:0] dout // data outputs
);
代码部分并不复杂,就是将TMDS 编码算法的流程图翻译成了 verilog语言。
TMDS 编码之后的数据由 Serializer 模块进行并串转换,通过调用 OSERDESE2 原语来实现 10:1 的并串转换。原语是 Xilinx 器件底层硬件中的功能模块,它使用专用的资源来实现一系列的功能。相比于 IP 核,原语的调用方法更简单,但是一般只用于实现一些简单的功能。
需要注意的是,一个 OSERDESE2 只能实现最多 8:1 的转换率,在这里我们通过位宽扩展实现了 10:1
的并串转换,如下图所示:
OSERDESE2 位宽扩展通过两个 OSERDESE2 模块来实现,其中一个作为 Master,
另一个作为 Slave,通过这种方式最多可实现 14:1 的并串转换。需要注意的是,在位宽扩展时,Slave 模块的数据输入端只能使用 D3 至 D8。
OSERDESE串并转换模块顶层接口如下:
module serializer_10_to_1(input reset, input paralell_clk, input serial_clk_5x, input [9:0] paralell_data, output serial_data_out );
将各个功能模块进行例化,即完成了本设计,为了适应不同的使用需求,提供源码的同时也将源码进行了IP封装,两者一并提供。
顶层源码如下:
module helai_hdmi_out(input clk_hdmi ,input clk_hdmix5 ,input reset_n ,input i_vga_hs ,input i_vga_vs ,input i_vga_de , input [23:0] i_vga_rgb , output o_hdmi_clk_p ,output o_hdmi_clk_n ,output [2: 0] o_hdmi_data_p,output [2: 0] o_hdmi_data_n
);wire reset;//²¢ÐÐÊý¾Ý
wire [9:0] red_10bit;
wire [9:0] green_10bit;
wire [9:0] blue_10bit;
wire [9:0] clk_10bit; //´®ÐÐÊý¾Ý
wire [2:0] tmds_data_serial;
wire tmds_clk_serial;//*****************************************************
//** main code
//*****************************************************
assign clk_10bit = 10'b1111100000;//Òì²½¸´Î»£¬Í¬²½ÊÍ·Å
asyn_rst_syn reset_syn(.reset_n (reset_n),.clk (clk_hdmi),.syn_reset (reset) //¸ßÓÐЧ);//¶ÔÈý¸öÑÕɫͨµÀ½øÐбàÂë
dvi_encoder encoder_b (.clkin (clk_hdmi),.rstin (reset),.din (i_vga_rgb[7:0]),.c0 (i_vga_hs),.c1 (i_vga_vs),.de (i_vga_de),.dout (blue_10bit)) ;dvi_encoder encoder_g (.clkin (clk_hdmi),.rstin (reset),.din (i_vga_rgb[15:8]),.c0 (i_vga_hs),.c1 (i_vga_vs),.de (i_vga_de),.dout (green_10bit)) ;dvi_encoder encoder_r (.clkin (clk_hdmi),.rstin (reset),.din (i_vga_rgb[23:16]),.c0 (i_vga_hs),.c1 (i_vga_vs),.de (i_vga_de),.dout (red_10bit)) ;//¶Ô±àÂëºóµÄÊý¾Ý½øÐв¢´®×ª»»
serializer_10_to_1 serializer_b(.reset (reset), // ¸´Î»,¸ßÓÐЧ.paralell_clk (clk_hdmi), // ÊäÈë²¢ÐÐÊý¾ÝʱÖÓ.serial_clk_5x (clk_hdmix5), // ÊäÈë´®ÐÐÊý¾ÝʱÖÓ.paralell_data (blue_10bit), // ÊäÈë²¢ÐÐÊý¾Ý
// .paralell_data (10'h146), // ÊäÈë²¢ÐÐÊý¾Ý.serial_data_out (tmds_data_serial[0]) // Êä³ö´®ÐÐÊý¾Ý); serializer_10_to_1 serializer_g(.reset (reset),.paralell_clk (clk_hdmi),.serial_clk_5x (clk_hdmix5),.paralell_data (green_10bit),// .paralell_data (10'h146), .serial_data_out (tmds_data_serial[1]));serializer_10_to_1 serializer_r(.reset (reset),.paralell_clk (clk_hdmi),.serial_clk_5x (clk_hdmix5),.paralell_data (red_10bit),// .paralell_data (10'h146), .serial_data_out (tmds_data_serial[2]));serializer_10_to_1 serializer_clk(.reset (reset),.paralell_clk (clk_hdmi),.serial_clk_5x (clk_hdmix5),.paralell_data (clk_10bit),.serial_data_out (tmds_clk_serial));//ת»»²î·ÖÐźÅ
OBUFDS #(.IOSTANDARD ("TMDS_33") // I/Oµçƽ±ê׼ΪTMDS
) TMDS0 (.I (tmds_data_serial[0]),.O (o_hdmi_data_p[0]),.OB (o_hdmi_data_n[0])
);OBUFDS #(.IOSTANDARD ("TMDS_33") // I/Oµçƽ±ê׼ΪTMDS
) TMDS1 (.I (tmds_data_serial[1]),.O (o_hdmi_data_p[1]),.OB (o_hdmi_data_n[1])
);OBUFDS #(.IOSTANDARD ("TMDS_33") // I/Oµçƽ±ê׼ΪTMDS
) TMDS2 (.I (tmds_data_serial[2]), .O (o_hdmi_data_p[2]), .OB (o_hdmi_data_n[2])
);OBUFDS #(.IOSTANDARD ("TMDS_33") // I/Oµçƽ±ê׼ΪTMDS
) TMDS3 (.I (tmds_clk_serial), .O (o_hdmi_clk_p),.OB (o_hdmi_clk_n)
);endmodule
封装后的IP如下:
福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料获取方式:点击获取
网盘资料如下: