FPGA - 基于FPGA的HDMI显示

写在前面

HDMI接口很早之前就想调试了,由于没有时间,就拖到了现在,而且毕业设计也是和视频处理系统有关,就趁这个机会把这个接口调试下。

开发环境

vivado 18.3
pynq - z2

HDMI简介

高清晰度多媒体接口(英文:High Definition Multimedia Interface,HDMI)是一种数字化视频/音频接口技术,是适合影像传输的专用型数字化接口,其可同时传送音频和影像信号,最高数据传输速度为2.25GB/s,同时无需在信号传送前进行数/模或者模/数转换。

FPGA - 基于FPGA的HDMI显示 - 第1张

HDMI接口设计说明

HDMI输出驱动接口在FPGA方面应用时,主要有两种方式:

一种是采用HDMI( DVI)编码芯片。这种操作只需要对对应芯片进行操作配置即可实现功能。

FPGA - 基于FPGA的HDMI显示 - 第2张

另外一种方式就是使用FPGA进行编写,由 IO 模拟方式实现。这里贴出我所使用的pynq-z2的对应模块的电路图并给出板子对应的信号引脚分配信息。

FPGA - 基于FPGA的HDMI显示 - 第3张
  1. ##HDMI Tx
  2.  
  3. set_property -dict { PACKAGE_PIN L17 IOSTANDARD TMDS_33 } [get_ports { TMDS_Clk_n }]; #IO_L11N_T1_SRCC_35 Sch=hdmi_tx_clk_n
  4. set_property -dict { PACKAGE_PIN L16 IOSTANDARD TMDS_33 } [get_ports { TMDS_Clk_p }]; #IO_L11P_T1_SRCC_35 Sch=hdmi_tx_clk_p
  5. set_property -dict { PACKAGE_PIN K18 IOSTANDARD TMDS_33 } [get_ports { TMDS_Data_n[0] }]; #IO_L12N_T1_MRCC_35 Sch=hdmi_tx_d_n[0]
  6. set_property -dict { PACKAGE_PIN K17 IOSTANDARD TMDS_33 } [get_ports { TMDS_Data_p[0] }]; #IO_L12P_T1_MRCC_35 Sch=hdmi_tx_d_p[0]
  7. set_property -dict { PACKAGE_PIN J19 IOSTANDARD TMDS_33 } [get_ports { TMDS_Data_n[1] }]; #IO_L10N_T1_AD11N_35 Sch=hdmi_tx_d_n[1]
  8. set_property -dict { PACKAGE_PIN K19 IOSTANDARD TMDS_33 } [get_ports { TMDS_Data_p[1] }]; #IO_L10P_T1_AD11P_35 Sch=hdmi_tx_d_p[1]
  9. set_property -dict { PACKAGE_PIN H18 IOSTANDARD TMDS_33 } [get_ports { TMDS_Data_n[2] }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=hdmi_tx_d_n[2]
  10. set_property -dict { PACKAGE_PIN J18 IOSTANDARD TMDS_33 } [get_ports { TMDS_Data_p[2] }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=hdmi_tx_d_p[2]
  11. set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { HDMI_OEN[0] }]; #IO_0_34 Sch=hdmi_tx_hpdn

HDMI和DVI(Digital Visual Interface)数字视频接口这两种数字视频传输标准的要求几乎完全相同,并同时处理一组高频和低频信号。这两种标准均采用TMDS(最小跳变差分信号又称最小化传输差分信号)技术来传输数据的高频(视频)部分。

HDMI/DVI数字视频接口的设计思想采用了DVI用于至数字显示器的高速数字连接。DVI采用了TMDS技术来传输数据的高频(视频)信号(见图1红色块所示)。

FPGA - 基于FPGA的HDMI显示 - 第4张

要实现HDMI和DVI系统中的“即插即用”功能,源端(通常是一台电脑、DVD播放器或游戏机)和接收端(通常是监视器或接收机)必须连接起来。HDMI 和DVI借用VESA (视频电子标准协会)的开放标准,采用DDC(数字显示通道)、一个称为HPD的新信号(热插拔检测)

标准HDMI接口

FPGA - 基于FPGA的HDMI显示 - 第5张

TYPE A,包括19个PIN,主要是4对差分信号线

TMDS clock+TMDS clock-
TMDS data0+TMDS data0-
TMDS data1+TMDS data1-
TMDS data2+TMDS data2-

TMDS(最小跳变差分信号)

最小化传输差分信号(TMDS)作为电气电平的标准。被应用于发送数字视频接口(DVl)及高清晰度多媒体接口(HDMl)的数据。其设计考虑因素之包括:

对内偏斜(Intra-Pai rSkew)。在给定的一对差分信号上,真(true)信号及其互补信号之间的时间差应尽可能的小;

残余抖动(Residual Jitter)。测试点与信号源之间所测量到的抖动数量的差异。可接受的最大残余抖动等价于发射机与接收机之间最小的抖动预计量(budget);

静电放电(ESD)。外部连接器因曝露于外界,因而更易受到静电放电的影响。更高的静电放电率可提供更良好的保护。

TMDS 包括3个RGB数据和1个时钟,共计4个通道(称为1个TMDS连接或Single-link)的传输回路。TMDS是把8位的RGB视频数据变换成10 位转换最小化、DC平衡的数据,再完成数据的串行处理;接收端设备对串行数据解串行变成并行数据,再转换成8位视频信号。因此,传输数字RGB数据需要3 个转换最小化差分采样信号构成一个TMDS连接。

HDMI系统框图

FPGA - 基于FPGA的HDMI显示 - 第6张

HDMI传输由三组TMDS通道和一组TMDS clock通道组成,TMDS clock的运行频率是video信号的pixel频率,在每个cycle,每个TMDS data通道发送10bit数据。

FPGA - 基于FPGA的HDMI显示 - 第7张

项目设计

整体的项目结构(因为也只是验证别人写好的程序为后续的毕设做准备,就没有直接移植的别人写好的程序):

FPGA - 基于FPGA的HDMI显示 - 第8张

hdmi的驱动这里使用的是迪芝伦的github上面开源的ip,链接如下:

​​hdmi ip链接​​ ip系统框图:

FPGA - 基于FPGA的HDMI显示 - 第9张

添加ip进入工程,后设置时钟ip的参数

FPGA - 基于FPGA的HDMI显示 - 第10张

彩条测试文件

  1. module color_bar(
  2. input clk, //像素时钟输入,1280x720@60P的像素时钟为74.25
  3. input rst, //复位,高有效
  4. output hs, //行同步、高有效
  5. output vs, //场同步、高有效
  6. output de, //数据有效
  7. output[7:0] rgb_r, //像素数据、红色分量
  8. output[7:0] rgb_g, //像素数据、绿色分量
  9. output[7:0] rgb_b //像素数据、蓝色分量
  10. );
  11. /*********视频时序参数定义******************************************/
  12. parameter H_ACTIVE = 16'd1280; //行有效长度(像素时钟周期个数)
  13. parameter H_FP = 16'd110; //行同步前肩长度
  14. parameter H_SYNC = 16'd40; //行同步长度
  15. parameter H_BP = 16'd220; //行同步后肩长度
  16. parameter V_ACTIVE = 16'd720; //场有效长度(行的个数)
  17. parameter V_FP = 16'd5; //场同步前肩长度
  18. parameter V_SYNC = 16'd5; //场同步长度
  19. parameter V_BP = 16'd20; //场同步后肩长度
  20.  
  21. //parameter H_FP = 16'd88;
  22. //parameter H_SYNC = 16'd44;
  23. //parameter H_BP = 16'd148;
  24. //parameter V_ACTIVE = 16'd1080;
  25. //parameter V_FP = 16'd4;
  26. //parameter V_SYNC = 16'd5;
  27. //parameter V_BP = 16'd36;
  28. parameter H_TOTAL = H_ACTIVE + H_FP + H_SYNC + H_BP;//行总长度
  29. parameter V_TOTAL = V_ACTIVE + V_FP + V_SYNC + V_BP;//场总长度
  30. /*********彩条RGB color bar颜色参数定义*****************************/
  31. parameter WHITE_R = 8'hff;
  32. parameter WHITE_G = 8'hff;
  33. parameter WHITE_B = 8'hff;
  34. parameter YELLOW_R = 8'hff;
  35. parameter YELLOW_G = 8'hff;
  36. parameter YELLOW_B = 8'h00;
  37. parameter CYAN_R = 8'h00;
  38. parameter CYAN_G = 8'hff;
  39. parameter CYAN_B = 8'hff;
  40. parameter GREEN_R = 8'h00;
  41. parameter GREEN_G = 8'hff;
  42. parameter GREEN_B = 8'h00;
  43. parameter MAGENTA_R = 8'hff;
  44. parameter MAGENTA_G = 8'h00;
  45. parameter MAGENTA_B = 8'hff;
  46. parameter RED_R = 8'hff;
  47. parameter RED_G = 8'h00;
  48. parameter RED_B = 8'h00;
  49. parameter BLUE_R = 8'h00;
  50. parameter BLUE_G = 8'h00;
  51. parameter BLUE_B = 8'hff;
  52. parameter BLACK_R = 8'h00;
  53. parameter BLACK_G = 8'h00;
  54. parameter BLACK_B = 8'h00;
  55. reg hs_reg;//定义一个寄存器,用于行同步
  56. reg vs_reg;//定义一个寄存器,用户场同步
  57. reg hs_reg_d0;//hs_reg一个时钟的延迟
  58. //所有以_d0、d1、d2等为后缀的均为某个寄存器的延迟
  59. reg vs_reg_d0;//vs_reg一个时钟的延迟
  60. reg[11:0] h_cnt;//用于行的计数器
  61. reg[11:0] v_cnt;//用于场(帧)的计数器
  62. reg[11:0] active_x;//有效图像的的坐标x
  63. reg[11:0] active_y;//有效图像的坐标y
  64. reg[7:0] rgb_r_reg;//像素数据r分量
  65. reg[7:0] rgb_g_reg;//像素数据g分量
  66. reg[7:0] rgb_b_reg;//像素数据b分量
  67. reg h_active;//行图像有效
  68. reg v_active;//场图像有效
  69. wire video_active;//一帧内图像的有效区域h_active & v_active
  70. reg video_active_d0;
  71. assign hs = hs_reg_d0;
  72. assign vs = vs_reg_d0;
  73. assign video_active = h_active & v_active;
  74. assign de = video_active_d0;
  75. assign rgb_r = rgb_r_reg;
  76. assign rgb_g = rgb_g_reg;
  77. assign rgb_b = rgb_b_reg;
  78. always@(posedge clk or posedge rst)
  79. begin
  80. if(rst)
  81. begin
  82. hs_reg_d0 <= 1'b0;
  83. vs_reg_d0 <= 1'b0;
  84. video_active_d0 <= 1'b0;
  85. end
  86. else
  87. begin
  88. hs_reg_d0 <= hs_reg;
  89. vs_reg_d0 <= vs_reg;
  90. video_active_d0 <= video_active;
  91. end
  92. end
  93.  
  94. always@(posedge clk or posedge rst)
  95. begin
  96. if(rst)
  97. h_cnt <= 12'd0;
  98. else if(h_cnt == H_TOTAL - 1)//行计数器到最大值清零
  99. h_cnt <= 12'd0;
  100. else
  101. h_cnt <= h_cnt + 12'd1;
  102. end
  103.  
  104. always@(posedge clk or posedge rst)
  105. begin
  106. if(rst)
  107. active_x <= 12'd0;
  108. else if(h_cnt >= H_FP + H_SYNC + H_BP - 1)//计算图像的x坐标
  109. active_x <= h_cnt - (H_FP[11:0] + H_SYNC[11:0] + H_BP[11:0] - 12'd1);
  110. else
  111. active_x <= active_x;
  112. end
  113.  
  114. always@(posedge clk or posedge rst)
  115. begin
  116. if(rst)
  117. v_cnt <= 12'd0;
  118. else if(h_cnt == H_FP - 1)//在行数计算器为H_FP - 1的时候场计数器+1或清零
  119. if(v_cnt == V_TOTAL - 1)//场计数器到最大值了,清零
  120. v_cnt <= 12'd0;
  121. else
  122. v_cnt <= v_cnt + 12'd1;//没到最大值,+1
  123. else
  124. v_cnt <= v_cnt;
  125. end
  126.  
  127. always@(posedge clk or posedge rst)
  128. begin
  129. if(rst)
  130. hs_reg <= 1'b0;
  131. else if(h_cnt == H_FP - 1)//行同步开始了...
  132. hs_reg <= 1'b1;
  133. else if(h_cnt == H_FP + H_SYNC - 1)//行同步这时候要结束了
  134. hs_reg <= 1'b0;
  135. else
  136. hs_reg <= hs_reg;
  137. end
  138.  
  139. always@(posedge clk or posedge rst)
  140. begin
  141. if(rst)
  142. h_active <= 1'b0;
  143. else if(h_cnt == H_FP + H_SYNC + H_BP - 1)
  144. h_active <= 1'b1;
  145. else if(h_cnt == H_TOTAL - 1)
  146. h_active <= 1'b0;
  147. else
  148. h_active <= h_active;
  149. end
  150.  
  151. always@(posedge clk or posedge rst)
  152. begin
  153. if(rst)
  154. vs_reg <= 1'd0;
  155. else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))
  156. vs_reg <= 1'b1;
  157. else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))
  158. vs_reg <= 1'b0;
  159. else
  160. vs_reg <= vs_reg;
  161. end
  162.  
  163. always@(posedge clk or posedge rst)
  164. begin
  165. if(rst)
  166. v_active <= 1'd0;
  167. else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))
  168. v_active <= 1'b1;
  169. else if((v_cnt == V_TOTAL - 1) && (h_cnt == H_FP - 1))
  170. v_active <= 1'b0;
  171. else
  172. v_active <= v_active;
  173. end
  174.  
  175. always@(posedge clk or posedge rst)
  176. begin
  177. if(rst)
  178. begin
  179. rgb_r_reg <= 8'h00;
  180. rgb_g_reg <= 8'h00;
  181. rgb_b_reg <= 8'h00;
  182. end
  183. else if(video_active)
  184. if(active_x == 12'd0)
  185. begin
  186. rgb_r_reg <= WHITE_R;
  187. rgb_g_reg <= WHITE_G;
  188. rgb_b_reg <= WHITE_B;
  189. end
  190. else if(active_x == (H_ACTIVE/8) * 1)
  191. begin
  192. rgb_r_reg <= YELLOW_R;
  193. rgb_g_reg <= YELLOW_G;
  194. rgb_b_reg <= YELLOW_B;
  195. end
  196. else if(active_x == (H_ACTIVE/8) * 2)
  197. begin
  198. rgb_r_reg <= CYAN_R;
  199. rgb_g_reg <= CYAN_G;
  200. rgb_b_reg <= CYAN_B;
  201. end
  202. else if(active_x == (H_ACTIVE/8) * 3)
  203. begin
  204. rgb_r_reg <= GREEN_R;
  205. rgb_g_reg <= GREEN_G;
  206. rgb_b_reg <= GREEN_B;
  207. end
  208. else if(active_x == (H_ACTIVE/8) * 4)
  209. begin
  210. rgb_r_reg <= MAGENTA_R;
  211. rgb_g_reg <= MAGENTA_G;
  212. rgb_b_reg <= MAGENTA_B;
  213. end
  214. else if(active_x == (H_ACTIVE/8) * 5)
  215. begin
  216. rgb_r_reg <= RED_R;
  217. rgb_g_reg <= RED_G;
  218. rgb_b_reg <= RED_B;
  219. end
  220. else if(active_x == (H_ACTIVE/8) * 6)
  221. begin
  222. rgb_r_reg <= BLUE_R;
  223. rgb_g_reg <= BLUE_G;
  224. rgb_b_reg <= BLUE_B;
  225. end
  226. else if(active_x == (H_ACTIVE/8) * 7)
  227. begin
  228. rgb_r_reg <= BLACK_R;
  229. rgb_g_reg <= BLACK_G;
  230. rgb_b_reg <= BLACK_B;
  231. end
  232. else
  233. begin
  234. rgb_r_reg <= rgb_r_reg;
  235. rgb_g_reg <= rgb_g_reg;
  236. rgb_b_reg <= rgb_b_reg;
  237. end
  238. else
  239. begin
  240. rgb_r_reg <= 8'h00;
  241. rgb_g_reg <= 8'h00;
  242. rgb_b_reg <= 8'h00;

顶层模块

  1. `timescale 1ns / 1ps
  2. module pro_hdmi_top(
  3. input clk,
  4. output [0:0] HDMI_OEN,
  5. output TMDS_Clk_n,
  6. output TMDS_Clk_p,
  7. output [2:0] TMDS_Data_n,
  8. output [2:0] TMDS_Data_p
  9. );
  10.  
  11. wire Pixel_clk;
  12. wire Serial_clk;
  13. wire video_hs;
  14. wire video_vs;
  15. wire video_de;
  16. wire [7:0] video_r;
  17. wire [7:0] video_g;
  18. wire [7:0] video_b;
  19.  
  20. assign HDMI_OEN = 1'b1;
  21.  
  22. //实例化色彩模?
  23. color_bar uut_color_bar(
  24. .clk (Pixel_clk),
  25. .rst (1'b0),
  26. .hs (video_hs),
  27. .vs (video_vs),
  28. .de (video_de),
  29. .rgb_r (video_r),
  30. .rgb_g (video_g),
  31. .rgb_b (video_b)
  32. );
  33.  
  34. //时钟信号
  35. clk_wiz_0 uut_clk(
  36. // Clock out ports
  37. .clk_out1(Pixel_clk), // output clk_out1
  38. .clk_out2(Serial_clk), // output clk_out2
  39. // Status and control signals
  40. .reset(1'b0), // input reset
  41. .locked(), // output locked
  42. // Clock in ports
  43. .clk_in1(clk)
  44. ); // input clk_in1
  45.  
  46.  
  47. //hdmi驱动
  48. hdmi_disp_0 uut_hdmi_disp_0 (
  49. .TMDS_Clk_p(TMDS_Clk_p), // output wire TMDS_Clk_p
  50. .TMDS_Clk_n(TMDS_Clk_n), // output wire TMDS_Clk_n
  51. .TMDS_Data_p(TMDS_Data_p), // output wire [2 : 0] TMDS_Data_p
  52. .TMDS_Data_n(TMDS_Data_n), // output wire [2 : 0] TMDS_Data_n
  53. .aRst(1'b0), // input wire aRst
  54. .aRst_n(1'b1), // input wire aRst_n
  55. .vid_pData({video_r,video_b,video_g}), // input wire [23 : 0] vid_pData
  56. .vid_pVDE(video_de), // input wire vid_pVDE
  57. .vid_pHSync(video_hs), // input wire vid_pHSync
  58. .vid_pVSync(video_vs), // input wire vid_pVSync
  59. .PixelClk(Pixel_clk), // input wire PixelClk
  60. .SerialClk(Serial_clk) // input wire SerialClk
  61. );

实验效果

FPGA - 基于FPGA的HDMI显示 - 第11张

reference

​​HDMI/DVI新技术与芯片及其应用​​​​HDMI的FPGA实现(一)​​​​基于FPGA的HDMI高清显示接口驱动​​​​基于FPGA的HDMI显示(二)​​​​基于FPGA的HDMI显示(一)​​

本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/9599.html

"愿我的文字能带给您一丝美好"

还没有人赞赏,支持一下

评论

A 为本文作者,G 为游客总数:0
加载中…

提交评论

游客,您好,欢迎参与讨论。

我的购物车

购物车为空

优惠券

没有优惠券