[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_GTX光通信连载-03光通信之HDMI视频回环传输

文档创建者:FPGA课程
浏览次数:110
最后更新:2024-09-24
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 5-FPGA GTX光通信
本帖最后由 FPGA课程 于 2024-9-24 19:17 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1 概述
通过前文中实验的学习,相信读者已经掌握了7SeriesFPGAsTransceiverswizard这个IP的基本使用,本文将使用这个IP以aurora8b10b的方式去实现光口传输HDMI视频数据。
本文实验目的:
1:使用7SeriesFPGAsTransceiverswizard去实现实际传输案例
2:对整个工程的功能进行仿真和测试
2 系统框架
根据实验目的,首先我们设计出基于光口的视频传输实验的系统框图,如下图所示:
本次实验包括以下模块:时钟模块、adv7611驱动模块、视频编码解码模块、数据对齐模块、和HDMI输出模块。从上面的系统框图,我们可以看到,首先时钟模块给adv7611iic驱动模块提供配置时钟,当adv7611芯片被驱动成功,开始接收HDMI输入的视频数据信号并将其传入encode模块进行编码,然后将编码后的数据送给UltrascaleFPGAsTransceiverswizard去传输,最后将rx接收到的数据进行对齐并解码出图像数据,输出到HDMI。
a8dbc7e43eb44562a826207c0fbd2cb4.jpg
时钟模块:时钟模块是使用官方的 MMCM IP 核实现,这里使用了两个时钟模块,一个时钟模块提供adv7611_iic的配置时钟和光口传输的的drp_clk。另一个时钟模块用来产生1080P的像素时钟(148.5MHZ),用作视频编解码以及视频传输的参考时钟,148.5MHZ(像素时钟)、371.25MHZ(像素时钟的2.5倍频)、742.5MHZ(像素时钟的5倍频)负责驱动HDMI输出模块。
HDMI驱动模块:米联客的HDMI输入方案是使用ADI公司的ADV7611信号接收芯片实现的,需要通过iic对adv7611进行配置,从而驱动芯片正常工作,把接收到的HDMI输入的TMDS信号转换成RGB数据及对应的行场信号。
视频编码模块:7SeriesFPGAsTransceiverswizard的外部数据位宽是32bit,我们需要将每一幅图像的行长信号及对应图像数据编码成32bit的数据流,传输给光口传输模块进行外部回环,再将回环过来的数据进行对齐,
然后通过视频解码模块将对应的图像数据及行场解码出来,给到HDMI输出。
数据对齐模块:在光通信的传输链路中,数据是以串行的方式进行传输的,在接收端就需要对数据进行串并转换。而串行数据必须重新对齐,然后才能用作并行数据,由于无法直接获取串行数据中的每个数据的最高位或者最低位。为了方便校准数据流,发送端会发送一个可识别的码列,通常称为comma码,8B/10B编码中常用的comma是K28.5(16’hbc)。由于comma只能用作控制字符出现,在数据部分不会出现,comma字符还可以用来指示指示帧的开始和结束标志。
视频解码模块:对从rx端接收回来的32bit数据进行解码,将它还原成对应的图像数据以及行场信号。
Vtc时序模块:用来生成对应分辨率的视频时序Videotostream/streamtovideo模块:使用
video_in_to_stream和stream_to_video_out这两个IP是用来检测输入进来的视频时序是否满足相应的行场标准,例如每一行的有效像素的个数以及有效行数是否准确。
HDMI输出模块:根据其他模块提供行、场同步信号、数据有效信号和数据信号,将对应的图像数据转换成TMDS信号去驱动显示器输出。
3  系统工程搭建
Step1:首先按照上一节课的内容,创建一个7SeriesFPGAsTransceiverswizardIP。
ccca77dbf09b4aad9d32084f733a13be.jpg
在配置这个ip的时候,我们可以配置成单通道的模式,也可以配置成多通道的模式,如下图所示单通道配置方式如下
94825fdef69e4d098108dd9175457f03.jpg
双通道配置方式如下
bbf33e0664fb43ddae2855333a131c00.jpg
Step2:右击打开example工程,这个example工程是xilinx官方提供的一个示例工程,这个示例工程已经完成了光口传输的时序控制,满足了光通信通信需求,用户只需要把顶层的数据接口开放出来,放入需要传输的数据即可。
02bca87245f04f98876fecaf143c1b38.jpg
3.1uiAurora_8b10b_vid.v
  1. //////////////////////////////////////////////////////////////////////////////////
  2. // Company: msxbo cz124
  3. // Engineer: tjy
  4. //
  5. // Create Date: 2019/05/10 11:10:06
  6. // Design Name: 8b10b video loop back
  7. // Module Name: aurora_top
  8. // Project Name:
  9. // Target Devices:
  10. // Tool Versions:
  11. // Description:
  12. //
  13. // Dependencies:
  14. //
  15. // Revision:
  16. // Revision 0.01 - File Created
  17. // Additional Comments:
  18. //
  19. module uiAurora_8b10b_vid #(
  20.         parameter VID_H        =        1920        ,
  21.         parameter VID_V        =        1080        ,
  22.         parameter FIFO_VTH =   200
  23. )
  24. (
  25.         input               clk_100M        ,
  26.         
  27.         input                             vid_in_clk                ,        
  28.         input                             vid_in_vs                ,
  29.         input                             vid_in_de                ,
  30.         input     [15:0]         vid_in_data          ,
  31.         
  32.         input               vid_out_clk                ,        
  33.         output                                vid_out_vs                ,
  34.         output                                vid_out_de           ,        
  35.         output          [15:0]    vid_out_data         ,        
  36.         
  37.         input               GT_REF_P    ,
  38.     input               GT_REF_N    ,
  39.    
  40.         input     [0:0]     rxn                        ,
  41.         input     [0:0]     rxp         ,
  42.         output    [0:0]     txn         ,
  43.         output    [0:0]     txp         ,
  44.         output    [0:0]                tx_disable               
  45. );

  46. //gtx        
  47. wire                       tx_clk                                           ;
  48. wire  [31:0]    tx_data                                       ;
  49. wire  [3:0]     tx_kchar                               ;
  50. wire                       rx_clk                                           ;
  51. wire  [31:0]    rx_data                                ;
  52. wire  [3:0]     rx_kchar                    ;

  53. wire                       tx0_clk                                   ;
  54. wire  [31:0]    tx0_data                               ;
  55. wire  [3:0]     tx0_kchar                               ;
  56. wire                       rx0_clk                                   ;

  57. wire            gt0_tx_rstn;
  58. wire            gt0_rx_rstn;

  59. (*mark_debug = "TRUE" *)wire  [31:0]   rx0_data                        ;
  60. (*mark_debug = "TRUE" *)wire  [3:0]    rx0_kchar                        ;


  61. (*mark_debug = "TRUE" *)wire  [31:0]           rx_data_align                        ;
  62. (*mark_debug = "TRUE" *)wire  [3:0]            rx_ctrl_align                        ;


  63. assign                         tx_disable = 1'b0                ;

  64. assign          tx_clk             =  tx0_clk                        ;
  65. assign          tx0_data         =  tx_data                         ;
  66. assign          tx0_kchar         =  tx_kchar                 ;
  67. assign          rx_clk                 =  rx0_clk                 ;
  68. assign          rx_data      =  rx0_data             ;
  69. assign          rx_kchar     =  rx0_kchar            ;


  70. //瀵硅棰戞祦杩涜缂栫爜
  71. video_encode        #(
  72.         .VID_H                (VID_H                ),
  73.         .VID_V                (VID_V                ),
  74.         .VID_DW          (16          ),
  75.         .CODED_DW          (32          ),
  76.         .FIFO_VTH   (FIFO_VTH        )
  77. )
  78. u1_video_encode
  79. (
  80.         .rst_n                        (gt0_tx_rstn ),
  81.         .vid_clk                (vid_in_clk         ),
  82.         .vid_vs               (vid_in_vs         ),
  83.         .vid_de                 (vid_in_de         ),
  84.         .vid_data            (vid_in_data ),  
  85.         
  86.         .coded_clk             (tx_clk             ),                                    
  87.         .coded_data           (tx_data         ),
  88.         .coded_ctr            (tx_kchar    )
  89. );
  90. //瀵硅棰戞祦杩涜瑙g爜
  91. video_decode        #(
  92.         .VID_H            (VID_H         ),
  93.         .VID_V            (VID_V         ),   
  94.         .VID_DW          (16           ),
  95.         .CODED_DW          (32           ),        
  96.         .FIFO_VTH   (FIFO_VTH)
  97. )
  98. u1_video_decode
  99. (
  100.         .rst_n                    (gt0_rx_rstn        ),
  101.         .vid_clk              (vid_out_clk        ),
  102.         .vid_vs               (vid_out_vs                ),
  103.         .vid_de             (vid_out_de                ),      
  104.         .vid_data       (vid_out_data   ),
  105.         
  106.         .coded_clk                (rx_clk                    ),         
  107.     .coded_data     (rx_data_align  ),
  108.     .coded_ctr      (rx_ctrl_align  )
  109. );
  110. //濡傛灉鏁版嵁閿欎綅杩涜绾犳瀵归綈
  111. data_align        u1_data_align(
  112.         .rst_n                                (gt0_rx_rstn        ),
  113.         .rx_clk                                (rx_clk                        ),
  114.         .rx_data                        (rx_data                ),
  115.         .rx_ctrl                        (rx_kchar                ),
  116.         .rx_data_align                (rx_data_align        ),
  117.         .rx_ctrl_align      (rx_ctrl_align  )
  118. );
  119. //gtx浼犺緭瑙嗛娴?
  120. gtx_aurora_exdes u1_gtx_aurora_exdes(   
  121.         .Q1_CLK1_GTREFCLK_PAD_N_IN                (GT_REF_N                                        ),
  122.     .Q1_CLK1_GTREFCLK_PAD_P_IN                (GT_REF_P                                        ),        
  123.         .drp_clk                                                (clk_100M                                        ),
  124.         .tx0_clk                                                (tx0_clk                                        ),
  125.         .tx0_data                                                (tx0_data                                        ),
  126.     .tx0_kchar                                                (tx0_kchar                                        ),
  127.         .rx0_clk                                                (rx0_clk                                        ),
  128.     .rx0_data                                                (rx0_data                                        ),
  129.     .rx0_kchar                                                (rx0_kchar                                        ),
  130.     .gt0_tx_system_rstn             (gt0_tx_rstn                ),
  131.     .gt0_rx_system_rstn             (gt0_rx_rstn                ),
  132.     .RXN_IN                                                        (rxn                                                ),
  133.     .RXP_IN                                                        (rxp                                                ),
  134.     .TXN_OUT                                                (txn                                                ),
  135.     .TXP_OUT                        (txp                                    )
  136. );        
  137. /*ila_0 u1_ila_0 (
  138.         .clk                (rx_clk                ),                         // input wire clk
  139.         .probe0                ({tx_data,tx_kchar,rx_data,rx_kchar})                 // input wire [99:0] probe0
  140. ); */
  141. endmodule
复制代码
3.2video_encode.v
video_encode模块对视频流进行编码,外部HDMI进来的视频流是16位的,首先使用异步FIFO进行缓冲,16位进32位出,以视频vsync信号上升沿时刻算起,当vsync上升沿到来时,将上升沿编码为:
32'h55_00_00_bc,32'h55_00_01_bc,当FIFO中的数据量达不到要求时,发送无效数据:32'h55_00_02_bc,
32'h55_00_03_bc交替发送,当FIFO中有一定量的数据后,首先发送1个32位的32'h55_00_04_bc表明一行就要开始传输,然后发送每行数据行号+bc,紧接着将FIFO中的数据依次发出去,发送完一行数据后,发送32'h55_00_05_bc,表明一行数据发送完成,紧接着发送上述的无效数据:32'h55_00_02_bc,32'h55_00_03_bc交替发送,等待vsync下降沿到来,将其编码为32'h55_00_06_bc,32'h55_00_07_bc发出,到此一行发送结束,以同样的编码将视频流每一行的数据发送给gtx即可。
上述中的同步信号以及穿插的无用信号的高24位皆为自定义,低8位为bc,bc是k28.5的控制字符,这个在IP核中会进行设置。代码中有txctrl[2:0]和rxctrl[3:0]两种控制信号,如下图所示,在8B10B的编码格式下,用户只需要关注rxctrl[0]和txctrl[2],由于我们的外部用户数据只有32位,所以rxctrl[0]和txctrl[2]都只用到了低四位,rxctrl[0]和txctrl[2]每个bit对应coded_data的一个字节,表示发送数据或者接收数据的相应字节为K码,也就是我们所说的bc,由于bc在低8位,因此把4bit中的0位置1。
c8a2f929734f4efc92b150fa5664e8d1.jpg
953fcd45d82b43af81374d9f54e80074.jpg
上述中有一个描述:"当FIFO中有一定量的数据后是"什么意思?对于1080P的视屏,16位为一个像素点,他的时钟是148.5Mhz左右,gtx在此工程中设置为5gbps,在IP核中可以看到,user_clk2为125M,这是相对于32位数据而言,相对于16位数据而言,它相当于250M,也就是说在此模块FIFO的写时钟是148.5,FIFO的读时钟是148.5,但是是32位的读时钟,对于16位数据也就相当于FIFO读时钟是297,250和297基本差距不大,因此我们的FIFO不需要缓存一行再开始读,这个FIFO_VTH的设置和视频输入分辨率和gtx的传输速率相关,不同的情况具体分析。
  1. module video_encode        #(
  2.         parameter VID_H        =        1920,
  3.         parameter VID_V        =        1080,
  4.         parameter VID_DW          =        16 ,
  5.         parameter CODED_DW  =   32 ,
  6.         parameter FIFO_VTH         =   500
  7. )
  8. (
  9.         input                                      rst_n    ,
  10.         input                                           vid_clk  ,
  11.         input                                  coded_clk,
  12.         input                                      vid_vs   ,
  13.         input                                      vid_de   ,
  14.         input   [VID_DW-1  :0]     vid_data ,                              
  15.         output         [CODED_DW-1:0]     coded_data,
  16.         output         [3:0]              coded_ctr        
  17. );


  18. localparam  CODE_H =  VID_H/2;
  19. localparam  FIFO_VTH_SET = FIFO_VTH/2;

  20. localparam frame_sys0                 = 0,
  21.            frame_sys1                 = 1,
  22.            h_data_begin          = 2,
  23.                    h_data_index          = 3,
  24.            h_data                   = 4,
  25.            h_data_end            = 5,
  26.            unuse_data0      = 6,
  27.            unuse_data1      = 7,
  28.                    frame_end0                  = 8,
  29.                    frame_end1                  = 9;
  30.                   
  31.         
  32.         
  33. wire                                  vs_pose                          ;
  34. wire                                  vs_nege                          ;

  35. wire  [CODED_DW-1:0]    dout                  ;
  36. wire                        full                          ;
  37. wire                        empty                          ;
  38. wire  [10 : 0]      coded_data_count ;
  39. wire  [11 : 0]      vid_data_count          ;

  40. //(*mark_debug = "TRUE" *)
  41. reg   [31:0]                 hcnt                          ;
  42. reg   [31:0]                 vcnt                          ;
  43. reg          [3:0]                  state                          ;
  44. reg   [3:0]                 vid_vs_r                  ;
  45. reg                            rd_en                          ;
  46. reg        [CODED_DW-1:0] coded_data         ;
  47. reg        [3:0]          coded_ctr          ;        
  48.                
  49. always@(posedge coded_clk)        
  50.         if(!rst_n)
  51.                 vid_vs_r <= 'd0;
  52.         else
  53.                 vid_vs_r <= {vid_vs_r[2:0],vid_vs};
  54.         
  55. assign vs_pose        =         ~vid_vs_r[3]&&vid_vs_r[2];        
  56. assign vs_nege        =         vid_vs_r[3]&&~vid_vs_r[2];


  57. always@(posedge coded_clk )
  58.         if(!rst_n || vs_pose)
  59.                 vcnt <= 'd0;
  60.         else if(vcnt == VID_V)
  61.                 vcnt <= 'd0;
  62.         else if(coded_data == 32'h55_00_04_bc)
  63.                 vcnt <= vcnt + 1'b1;
  64.         else
  65.                 vcnt <= vcnt;

  66. always@(posedge coded_clk)
  67.         if(!rst_n || vs_pose)
  68.                 hcnt <= 'd0;
  69.         else if(hcnt == (CODE_H - 11'b1))
  70.                 hcnt <= 'd0;
  71.         else if(rd_en==1'b1)
  72.                 hcnt <= hcnt + 1'b1;
  73.         else
  74.                 hcnt <= hcnt;
  75.                
  76.                
  77. always@(posedge coded_clk)begin
  78.         if(!rst_n) begin
  79.                         rd_en                 <= 1'b0;
  80.                         state                 <= unuse_data0;
  81.                         coded_data         <= 32'd0;
  82.                         coded_ctr         <= 4'd0;
  83.         end
  84.         else if(vs_pose==1'b1) begin
  85.                         state       <= frame_sys0;
  86.                         rd_en       <= 1'b0;
  87.         end
  88.         else if(vs_nege==1'b1) begin
  89.                         state       <= frame_end0;
  90.                         rd_en       <= 1'b0;
  91.         end
  92.         else begin
  93.                 case(state)
  94.                         frame_sys0:begin                    //发送帧同步信号55_00_00_bc
  95.                             state                 <= frame_sys1;
  96.                                 coded_data         <= 32'h55_00_00_bc;
  97.                                 coded_ctr         <= 4'b0001;
  98.                         end
  99.                         frame_sys1:begin                    //发送帧同步信号55_00_01_bc
  100.                                 state            <= unuse_data0;
  101.                                 coded_data <= 32'h55_00_01_bc;
  102.                                 coded_ctr  <= 4'b0001;
  103.                         end
  104.                         unuse_data0:                        //发送无用的信号55_00_02_bc
  105.                                 begin
  106.                                         state      <= unuse_data1;
  107.                                         coded_data  <= 32'h55_00_02_bc;
  108.                                         coded_ctr  <= 4'b0001;
  109.                                 end
  110.                         unuse_data1:                       //发送无用的信号55_00_03_bc
  111.                                 begin
  112.                                         if(coded_data_count >= FIFO_VTH_SET)   //当FIFO 中有一行数据
  113.                                                 begin
  114.                                                         state <= h_data_begin;        
  115.                                                 end
  116.                                         else
  117.                                                 begin
  118.                                                         state           <= unuse_data0;
  119.                                                         coded_data <= 32'h55_00_03_bc;
  120.                                                 end        
  121.                                 end
  122.                         h_data_begin:               //发送一行数据开始同步信号
  123.                                 begin
  124.                                         state       <= h_data_index;
  125.                                         coded_data  <= 32'h55_00_04_bc;
  126.                                         coded_ctr   <= 4'b0001;
  127.                                 end
  128.                         h_data_index:               //发送每行数据行号+bc
  129.                                 begin
  130.                                         state       <= h_data;
  131.                                         coded_data  <= {vcnt[23:0],8'hbc};
  132.                                         coded_ctr   <= 4'b0001;
  133.                                 end
  134.                         h_data:               //开始发送FIFO中的一行视频图像数据
  135.                                 begin
  136.                                         if(hcnt < CODE_H - 1'b1) begin
  137.                                                         state      <= h_data;
  138.                             coded_data <= dout;
  139.                             coded_ctr  <= 4'b0000;
  140.                             rd_en      <= 1'b1;
  141.                                         end                                                
  142.                                         else begin
  143.                                                         state      <= h_data_end;
  144.                             coded_data <= dout;
  145.                             rd_en      <= 1'b0;
  146.                                         end               
  147.                                 end
  148.                         h_data_end:           //发送一行数据已接收信号
  149.                                 begin
  150.                                         state      <= unuse_data0;
  151.                                         coded_data <= 32'h55_00_05_bc;
  152.                                         coded_ctr  <= 4'b0001;
  153.                                 end        
  154.                         frame_end0:                         //发送帧结束信号55_00_06_bc
  155.                                 begin
  156.                                         state      <= frame_end1;
  157.                                         coded_data <= 32'h55_00_06_bc;
  158.                                         coded_ctr  <= 4'b0001;
  159.                                 end        
  160.                         frame_end1:                        //发送帧结束信号55_00_07_bc
  161.                                 begin
  162.                                         state      <= unuse_data0;
  163.                                         coded_data <= 32'h55_00_07_bc;
  164.                                         coded_ctr  <= 4'b0001;
  165.                                 end                                
  166.                         default:;
  167.                 endcase
  168.         end
  169. end

  170. reg [7:0] fifo_rst_cnt;
  171. always@(posedge coded_clk)
  172.     if(vs_pose == 1'b1 )begin
  173.         fifo_rst_cnt <= 8'd50;
  174.     end
  175.     else begin
  176.         if(fifo_rst_cnt >8'd0)
  177.             fifo_rst_cnt<=fifo_rst_cnt-1'b1;
  178.     end
  179.            
  180. wire fifo_rst = (fifo_rst_cnt>=8'd10)&&(fifo_rst_cnt<8'd50)||(!rst_n);

  181. tx_fifo u1_tx_fifo (
  182.   .rst(fifo_rst),
  183.   .wr_clk                    (vid_clk                ),
  184.   .rd_clk                        (coded_clk                ),
  185.   .din                                (vid_data                ),
  186.   .wr_en                        (vid_de                        ),
  187.   .rd_en                        (rd_en                        ),
  188.   .dout                                (dout                        ),
  189.   .full                                (full                        ),
  190.   .empty                        (empty                        ),
  191.   .rd_data_count        (coded_data_count),
  192.   .wr_data_count        (vid_data_count        )
  193. );
  194.         
  195. endmodule
复制代码
3.3video_decode.v
video_decode是用来将对齐之后的数据进行解码,将对齐的过后的编码数据通过异步FIFO进行缓冲,把32位的
编码数据转换成相应的rgb565的图像数据,当检测到帧同步信号(32'h55_00_00_bc、32'h55_00_01_bc)和帧结束信号(32'h55_00_06_bc,32'h55_00_07_bc),会去恢复出vsync信号上升和下降沿。当检测到行传输信号(32'h55_00_04_bc)之后,将hsync信号拉高至行计数结束。当检测到Vsync上升沿,一旦FIFO中有一行数据之后,会去恢复出数据有效de信号。
  1. module video_decode        #(
  2.         parameter VID_H            =        640,
  3.         parameter VID_V            =        480,
  4.         parameter VID_DW      =   16 ,
  5.         parameter CODED_DW    =        32 ,
  6.         parameter FIFO_VTH    =   500
  7. )
  8. (
  9.         input                                                 rst_n            ,
  10.         
  11.         input                               vid_clk     ,        
  12.         output                                  vid_vs      ,
  13.         output                               vid_de      ,        
  14.         output     [VID_DW-1 :0]        vid_data           ,
  15.         
  16.         input                                                 coded_clk        ,
  17.         input            [CODED_DW-1:0]         coded_data        ,
  18.         input            [3:0]                          coded_ctr           
  19. );

  20. parameter  CODE_H = VID_H/2;

  21. localparam  IDLE           = 0,
  22.                         READ_LINE      = 1;

  23. (*mark_debug = "TRUE" *) reg   [2:0]             state      ;            
  24. reg   [CODED_DW-1:0]         coded_data_r;
  25. (*mark_debug = "TRUE" *) reg                         vid_vs      ;
  26. (*mark_debug = "TRUE" *) reg                          vid_de      ;     

  27. (*mark_debug = "TRUE" *) reg                             wr_en                ;
  28. reg                             wr_en_r                ;
  29. reg   [31:0]                     wr_cnt          ;

  30. wire                            full                ;
  31. wire                            empty                ;
  32. wire  [11 : 0]          rd_data_count;
  33. wire  [10 : 0]          wr_data_count;
  34. reg   [31:0]                      hcnt                ;

  35. always@(posedge coded_clk or negedge rst_n)
  36.         if(!rst_n)
  37.                 coded_data_r <= 'd0;
  38.         else
  39.                 coded_data_r <= coded_data;
  40.         
  41. always@(posedge coded_clk or negedge rst_n)
  42.         if(!rst_n)
  43.                 vid_vs <= 1'b0;
  44.         else if(coded_ctr == 4'b0001 && coded_data == 32'h55_00_01_bc&&coded_data_r==32'h55_00_00_bc)//甯т笂鍗囨部鎭㈠
  45.                 vid_vs <= 1'b1;
  46.         else if(coded_ctr == 4'b0001 && coded_data == 32'h55_00_07_bc&&coded_data_r == 32'h55_00_06_bc)//甯т笅闄嶆部鎭㈠
  47.                 vid_vs <= 1'b0;
  48.         else
  49.                 vid_vs <= vid_vs;

  50. always@(posedge coded_clk or negedge rst_n)
  51.         if(!rst_n  || vid_vs)
  52.                 wr_en <= 1'b0;
  53.         else if((wr_cnt == CODE_H - 1'b1 ))
  54.                 wr_en <= 1'b0;
  55.         else if(coded_ctr == 4'b0001 && coded_data == 32'h55_00_04_bc)//妫?娴嬪埌涓?琛屾暟鎹紑濮嬩俊鍙?
  56.                 wr_en <= 1'b1;
  57.         else
  58.                 wr_en <= wr_en;
  59.                
  60. always@(posedge coded_clk or negedge rst_n)//鎵撲竴鎷嶅拷鐣ヨ鍙?
  61.         if(!rst_n)
  62.                 wr_en_r <= 'd0;
  63.         else
  64.                 wr_en_r <= wr_en;

  65. always@(posedge coded_clk or negedge rst_n)//wr_en_r鎷夐珮涓?琛岀殑闀垮害锛屾妸32浣嶈棰戞暟鎹啓鍏IFO
  66.         if(!rst_n  || vid_vs)
  67.                 wr_cnt <= 'd0;
  68.         else if((wr_cnt == CODE_H -1'b1))
  69.                 wr_cnt <= 'd0;
  70.         else if(wr_en == 1'b1)
  71.                 wr_cnt <= wr_cnt + 1'b1;
  72.         else
  73.                 wr_cnt <= wr_cnt;

  74. reg [3:0]vid_vs_r;
  75. always@(posedge vid_clk )
  76.     vid_vs_r <= {vid_vs_r[2:0],vid_vs};

  77. always@(posedge vid_clk )
  78.         if(!rst_n || vid_vs_r[3])
  79.                 hcnt <= 'd0;
  80.         else if(hcnt == VID_H - 1'b1)
  81.                 hcnt <= 'd0;
  82.         else if(vid_de == 1'b1)
  83.                 hcnt <= hcnt + 1'b1;

  84. always@(posedge vid_clk)//浠嶧IFO涓鍙?16浣嶈棰戞暟鎹?
  85.         if(!rst_n || vid_vs_r[3]) begin
  86.                         state <= IDLE;
  87.                         vid_de <= 1'b0;
  88.         end               
  89.         else begin
  90.                 case(state)
  91.                         IDLE:
  92.                                 if(rd_data_count >= FIFO_VTH) begin //FIFO 有一行数据
  93.                                         state   <= READ_LINE;
  94.                                 end        
  95.                         READ_LINE:
  96.                                 if(hcnt < VID_H - 1'b1) begin
  97.                     vid_de  <= 1'b1;
  98.                                 end        
  99.                                 else begin
  100.                                         state   <= IDLE;
  101.                     vid_de  <= 1'b0;
  102.                                 end        
  103.                         default:state   <= IDLE ;        
  104.                 endcase
  105.         end

  106. reg [7:0] fifo_rst_cnt;
  107. always@(posedge coded_clk)
  108.     if(vid_vs == 1'b1 )begin
  109.         fifo_rst_cnt <= 8'd50;
  110.     end
  111.     else begin
  112.         if(fifo_rst_cnt >8'd0)
  113.             fifo_rst_cnt<=fifo_rst_cnt-1'b1;
  114.     end
  115.            
  116. wire fifo_rst = (fifo_rst_cnt>=8'd10)&&(fifo_rst_cnt<8'd50)||(!rst_n);

  117. rx_fifo u1_rx_fifo (
  118.   .rst(fifo_rst),
  119.   .wr_clk            (coded_clk                ),
  120.   .rd_clk                (vid_clk                ),
  121.   .din                        (coded_data                ),
  122.   .wr_en                (wr_en_r                ),
  123.   .rd_en                (vid_de                   ),
  124.   .dout                        (vid_data                 ),
  125.   .full                        (full                        ),
  126.   .empty                (empty                        ),
  127.   .rd_data_count(rd_data_count        ),
  128.   .wr_data_count(wr_data_count        )
  129. );
  130. endmodule
复制代码


3.4data_align.v
data_align将GTX接收后的数据利用k码进行对齐,上面已经讲解过k码了,k码可以帮我们查看数据是否错位,如果错位可以将数据对齐。通过逻辑分析仪抓取调试过程中,有时候会出现,发送的32位数据可能出现16位数据移位,也就是上一个32位的数据低16位可能和下一个32位数据的高16位拼接在一起,我们如何知道我们发出的数据,通过光纤传输接收后进行了错位,此时就轮到K码大显威力了,当我们接收的数据错位时,K码也会错位,此前我们发送的0001,可能会变为0100,然后我们根据这个0100来把接收到的数据重新组合,就可以得到正确的结果。

  1. module data_align(
  2.         input                                         rst_n                        ,
  3.         input                                         rx_clk                        ,
  4.         input                [31:0]                 rx_data                        ,
  5.         input                [3:0]                 rx_ctrl                        ,
  6.         output reg        [31:0]                 rx_data_align        ,
  7.         output reg        [3:0]                 rx_ctrl_align
  8. );


  9. reg[31:0] rx_data_r        ;
  10. reg[3:0]  align_bit        ;
  11. reg[3:0]  rx_ctrl_r        ;


  12. always@(posedge rx_clk or negedge rst_n)
  13.         if(!rst_n)
  14.                 align_bit <= 4'd0;
  15.         else if(rx_ctrl != 4'd0)
  16.                 align_bit <= rx_ctrl;
  17.         else
  18.                 align_bit <= align_bit;

  19. always@(posedge rx_clk or negedge rst_n)
  20.         if(!rst_n)
  21.                 rx_data_r <= 'd0;
  22.         else
  23.                 rx_data_r <= rx_data;
  24.                
  25. always@(posedge rx_clk or negedge rst_n)
  26.         if(!rst_n)
  27.                 rx_ctrl_r <= 4'd0;
  28.         else
  29.                 rx_ctrl_r <= rx_ctrl;
  30.                
  31. always@(posedge rx_clk or negedge rst_n)
  32.         if(!rst_n)
  33.                 rx_data_align <= 32'd0;
  34.         else
  35.                 case(align_bit)
  36.                         4'b0001:
  37.                                 rx_data_align <= rx_data;//没错位直接赋值
  38.                         4'b0100:
  39.                                 rx_data_align <= {rx_data[15:0],rx_data_r[31:16]};//错位进行拼接
  40.                         default:
  41.                                 rx_data_align <= 32'd0;
  42.                 endcase


  43. always@(posedge rx_clk or negedge rst_n)
  44.         if(!rst_n)
  45.                 rx_ctrl_align <= 4'd0;
  46.         else
  47.                 case(align_bit)
  48.                         4'b0001:
  49.                                 rx_ctrl_align <= rx_ctrl;
  50.                         4'b0100:
  51.                                 rx_ctrl_align <= {rx_ctrl[1:0],rx_ctrl_r[3:2]};
  52.                         default:
  53.                                 rx_ctrl_align <= 4'd0;
  54.                 endcase

  55. /* ila_0 u1_ila_1 (
  56.         .clk                (rx_clk                ),                         // input wire clk
  57.         .probe0                ({rx_ctrl,align_bit,rx_data,rx_data_r,rx_ctrl_r,rx_data_align,rx_ctrl_align}                )                 // input wire [99:0] probe0
  58. ); */




  59. endmodule        
  60.         
复制代码

        

4 硬件工程搭建
4ec7c5994d8d4ce497b197d9a14da3d5.jpg
然后添加adv7611的HDMI输入方案,搭建完成后的demo如下图所示:
e678d5f8cf374420aa0a0e3b556e8200.jpg

5 硬件电路分析
5.1FEP扩展接口
MZ7035板卡的外设没有HDMI输入接口,我们需要使用到米联客推出的一款HDMI7611图像采集卡,这个HMDI模块专门针对图像采集应用,最高可实现1080P@60fps视频输入输出。模块输入部分采用ADI公司的ADV7611信号接收芯片实现HDMI视频信号的接收。模块输出部分采用了IO模拟HDMI信号,输出最高可达到1080P@60HZ高清传输,如下图所示:
406b24fed42c415da8ad2f7268034501.jpg
HDMI扩展卡安装在FEP位置上,下图中左边图纸为MZ7035底板的FEP连接器定义,右边为HDMI7611视频卡上的FEP定义。
2cc5c5884e1f428087802977e9b240da.jpg
5.2参考时钟和HDMI输入输出IO约束
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/fpga_pin.xdc。
6 硬件连接

fb9865b3063540b4b305098c793ffdb4.jpg                         
1
                        
                        
2
                        
                        
3
                        
                        
4
                        
                        
5
                        
                        
6
                        
                        
时钟
                        
                        
                        
                        
OFF
                        
                        
OFF
                        
                        
ON
                        
                        
OFF
                        
                        
OFF
                        
                        
OFF
                        
                        
125M
                        
​对应工程目录下提供了三种测试demo,分别是单通道光口回环传输、双通道光口回环传输、双板间光口传输
5c3fbccfa8864504b4880864541061d9.jpg
Singlelane连接方式
3d66d5e1832c47ad9bf9d77743f3d2aa.jpg
multilanes连接方式
a50dab00ff274c869e60fd2882917c5f.jpg
boardtoboard连接方式
f5466d2c623649beaa9d152d7a141e11.jpg
eb8377a148d34d8dbc4f9b0b04a10715.jpg

7 实验结果
f7a1722a9e874d9b969e15533693d2d9.jpg


image.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则