基于Smart Artix 的FPGA实验十三  基于FPGA逻辑资源的HDMI 发送与接收的回环功能演示

本文演示了如何用FPGA逻辑资源去驱动板子上的HDMI 发送和接收资源,并实现HDMI的回环功能。

  • 此章节内容适用于Smart Artix 的主板,如是本站其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

实验具体实现流程:

  • 实验分3个阶段
  • 阶段一: HDMI IN (TMDS 8B/10B)-> (IP:DVI2RGB ) -> RGB888(数据流)
  • 阶段二: RGB888(数据流) -> (IP:RGB2DVI ) -> HDMI OUT (TMDS 8B/10B)

阶段一 其实就是阶段二的反向实现, 整个过程图像数据没有经过任何BRAM 或者DDR的缓存,数据流是直进直出的。

当然,如果你需要在数据流阶段对图像进行简单的处理(如灰度或二值化调整之类的),可以直接在 RGB888 的流水线阶段完成这些操作; 当然你也可以根据需求在 RGB888 阶段将图像缓存到 DDR 等缓存空间中,为后续更复杂的应用做准备。

一、硬件部分介绍:

HDMI部分的原理图:

HDMI 发送部分:

HDMI接收部分:

这里要注意下 HDMI的RX 中的 HP信号 是输出的。

如之前所说,Smart Artix 主板的HDMI 是没有接外部HDMI芯片的,而是通过差分线的方式直接连到FPGA的IO上,相当于用FPGA的逻辑来实现外部HDMI芯片的功能,该方法可以满足大部分HDMI输出显示的使用场景,并最高支持到1080P60帧的画面输出。

(因为是IO口模拟的HDMI,所以 HDMI 发送和HDMI接收不一定能适配所有的电脑和显示器,大家请自行尝试)

  • 想要驱动HDMI部分并输出图像,我们还需要用到 digilent官方设计的两个IP核
  • RGB2DVI : 负责HDMI的发送
  • DVI2RGB : 负责HDMI的接收

这两IP核的官方下载地址如下:https://github.com/Digilent/vivado-library,这里为了方便使用,我也把这个IP核下下来放在本站供大家参考(IP版权归digilent所有)http://www.hellofpga.com/wp-content/uploads/2021/07/rgb2dvi.zip

一、Vivado工程创建

工程创建的过程可以参考实验一中的内容,这里不详细描述了。基于Smart Artix 的FPGA实验一 用FPGA资源点亮一个LED(完整图文) (芯片型号选XC7A50TFGG484-2)

二、添加时钟模块

因为我们的HDMI 接收所用到的 DVI2RGB模块需要一个200M的RefClk 来驱动,而我们板子上焊接的有源晶体是50MHZ,这里就需要用时钟管理模块MMCM来生成我们要的200Mhz频率

像上一章节一样我们添加一个时钟模块。

1)第一步,点击IP Catalog 打开模块选择器, 在里面的搜索栏输入 CLOCKING ,系统会自动跳出符合的 Clocking Wizard选项,双击它

2)在弹出的窗口中我们将input Frequence 输入频率修改为板子上焊接的50M时钟, 右边改为单端输入

3)在output Clocks选项中 将clk_out1改成200m

4)将界面托到最下面,因为我们这里的要求并不高,所以把locked选项去除,这里保留reset功能,但是将reset 功能改成低电平复位(Active Low)最后点击ok生成模块

三、导入下下来的RGB2DVI模块和 DVI2RGB模块

将RGB2DVI和DVI2RGB的目录复制到工程目录下

1)点击Setting

2)在弹出的设置窗口,如下图,展开IP选项,选中Packager,在点击里面的加号增加目录,选中RGB2DVI和DVI2RGB的目录(可以按住CTRL一起选中),点击ok

3) 导入DVI to RGB 的 IP

a.如下图所示,在IP管理器里搜索DVI 双击并打开DVI to RGB 选项

b.设置DVI to RGB模块,这里按下图 使能serial clock output,这样 就能输出像素时钟外的5倍像素时钟了, 去掉Resets active high 前面的勾(系统为低电平复位),把速度模式切换成1080p(1920×1080)。

4)导入RGB2DVI IP

a .如下图所示,在IP管理器里搜索RGB 双击并打开RGB to DVI Video Encoder 选项

b.设置RGB2DVI模块,因为我们已经在DVI to RGB模块中输出了serial clock,所以上一节的5倍的编码时钟我们不需要额外再生成,模块里也不需要再生成模块时钟,如下图去掉高电平复位和内部串行时钟前面的勾,点击OK

5)完成之后 我们便得到了三个模块

这里需要注意一个事情 RGB2DVI 和DVI2RGB 官方手册上有明确说, 对应的24bit 线序是 RBG的 ,而不是 RGB使用时候需要格外注意。

四、增加我们的代码内容

2)创建一个顶层模块 TOP_MODULE,分别例化和调用时钟、RGB2DVI、DVI2RGB等子模块,这里注意vid_pData({R,B,G}),而不是R G B(原因是 RGB2DVI线序接口是 RBG顺序,而不是RGB)

`timescale 1ns / 1ps
module TOP_MODULE(
input CLK,
input RSTn,
output[2:0] TMDS_TX_DATA_p,
output[2:0] TMDS_TX_DATA_n,
output TMDS_TX_CLK_p,
output TMDS_TX_CLK_n,

input[2:0] TMDS_RX_DATA_p,
input[2:0] TMDS_RX_DATA_n,
input TMDS_RX_CLK_p,
input TMDS_RX_CLK_n,
inout SDA,
inout SCL,
output HDMI_IN_HPD
);

assign HDMI_IN_HPD=1'b1;

wire Clk_200m;
wire SerialClk;
wire PixelClk;
clk_wiz_0 u1(
.resetn(RSTn),
.clk_in1(CLK),
.clk_out1(Clk_200m)
);

wire RGB_HS,RGB_VS,RGB_DE;
wire[7:0] RGB_R,RGB_G,RGB_B;

rgb2dvi_0 u2(
.aRst_n(RSTn),
.SerialClk(SerialClk),
.PixelClk(PixelClk),
.TMDS_Clk_p(TMDS_TX_CLK_p),
.TMDS_Clk_n(TMDS_TX_CLK_n),
.TMDS_Data_p(TMDS_TX_DATA_p),
.TMDS_Data_n(TMDS_TX_DATA_n),
.vid_pData({RGB_R,RGB_B,RGB_G}),
.vid_pHSync(RGB_HS),
.vid_pVSync(RGB_VS),
.vid_pVDE(RGB_DE)
);


wire SDA_I,SDA_O,SDA_T,SCL_I,SCL_O,SCL_T;
dvi2rgb_0 u3 (
.TMDS_Clk_p(TMDS_RX_CLK_p),
.TMDS_Clk_n(TMDS_RX_CLK_n),
.TMDS_Data_p(TMDS_RX_DATA_p),
.TMDS_Data_n(TMDS_RX_DATA_n),
.RefClk(Clk_200m),
.aRst_n(RSTn),
.vid_pData({RGB_R,RGB_B,RGB_G}),
.vid_pVDE(RGB_DE),
.vid_pHSync(RGB_HS),
.vid_pVSync(RGB_VS),
.PixelClk(PixelClk),
.SerialClk(SerialClk),
.aPixelClkLckd(),
.pLocked(),
.SDA_I(SDA),
.SDA_O(SDA_O),
.SDA_T(SDA_T),
.SCL_I(SCL),
.SCL_O(SCL_O),
.SCL_T(SCL_T),
.pRst_n(RSTn)
);

assign SDA = SDA_T ? 1'bz : SDA_O;
assign SCL = SCL_T ? 1'bz : SCL_O;


endmodule

最后再增加约束文件 (HDMI_TEST.XDC)

# Clock Constraints
set_property PACKAGE_PIN Y18 [get_ports CLK]
set_property IOSTANDARD LVCMOS33 [get_ports CLK]

# Reset Constraints (active-low reset)
set_property PACKAGE_PIN T20 [get_ports RSTn]
set_property IOSTANDARD LVCMOS33 [get_ports RSTn]

# Hdmi TX Constraints
set_property PACKAGE_PIN C14 [get_ports {TMDS_TX_DATA_p[0]}]
set_property PACKAGE_PIN C13 [get_ports {TMDS_TX_DATA_p[1]}]
set_property PACKAGE_PIN E13 [get_ports {TMDS_TX_DATA_p[2]}]
set_property PACKAGE_PIN D17 [get_ports TMDS_TX_CLK_p]

# Hdmi RX Constraints
set_property PACKAGE_PIN B21 [get_ports {TMDS_RX_DATA_p[0]}]
set_property PACKAGE_PIN B20 [get_ports {TMDS_RX_DATA_p[1]}]
set_property PACKAGE_PIN A18 [get_ports {TMDS_RX_DATA_p[2]}]
set_property PACKAGE_PIN C18 [get_ports TMDS_RX_CLK_p]

set_property PACKAGE_PIN D15 [get_ports SDA]
set_property PACKAGE_PIN E16 [get_ports SCL]
set_property PACKAGE_PIN D16 [get_ports HDMI_IN_HPD]
set_property IOSTANDARD LVCMOS33 [get_ports SDA]
set_property IOSTANDARD LVCMOS33 [get_ports SCL]
set_property IOSTANDARD LVCMOS33 [get_ports HDMI_IN_HPD]

# Define the clock period
create_clock -period 20.000 -name CLK -waveform {0.000 10.000} [get_ports CLK]
create_clock -period 6.734 -name TMDS_RX_CLK_p -waveform {0.000 3.367} [get_ports TMDS_RX_CLK_p]

五、编译综合,并运行代码

  • 硬件连接分两部分
    • HDMI OUT(主板) —> HDMI数据线 —-> HDMI 显示器
    • HDMI IN(主板) <— HDMI数据线 <— HDMI信号源(带HDMI接口的电脑或者摄像头或者电视盒)

之后下载代码,如果一切顺利的话 HDMI信号源会检测到新的显示设备,并且在HDMI显示器上显示对应的图像画面(如未成功显示,可以适当调整HDMI输出设备的输出分辨率,或者输出的设置)

因为HDMI OUT 和HDMI IN 都是用IO来模拟HDMI 信号的,所以存在一定的兼容性问题,不一定适配所有的显示器和所有的HDMI输出设备,大家请自行尝试

本章节的工程:

  • 本文的完整工程下载:13_HDMI_TX_RX_LOOPBACK (Smart Artix 50T)
  • VIVADO的版本:2018.3
  • 工程创建目录:E:\Smart_Artix\4_Code\13_HDMI_TX_RX_LOOPBACK

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注