当前位置:   article > 正文

基于FPGA的TMDS编码

基于FPGA的TMDS编码

基于FPGA的TMDS编码

在我们之前的学习中,了解到HDMI是一种全数字化视频和声音发送接口,可以发送音频以及视频信号。HDMI向下兼容DVI,DVI只能传输视频信号。HDMI和DVI接口协议在物理层均使用TMDS标准来传输音频或视频信号,接下来就着重了解一下TMDS编码。

TMDS(最小化传输差分信号)中,有四个通道,其中包含了三个数据通道和一个时钟通道。其中数据通道用来传输颜色、音频、控制等信号。HDMI默认使用RGB(RGB888)三个数据通道,当然也可以是亮度和色度信息(YCrCb,4:4:4或者4:2:2)。

image

image

上图为HDMI的链接框架; 通道0传输的数据为:B分量的视频数据、行场同步信号、音频信号。 通道0传输的数据为:G分量的视频数据、控制信号、音频信号。 通道0传输的数据为:R分量的视频数据、控制信号、音频信号。 不同的数据在TMDS数据通道中在三种不同的周期中发送。

image

image

在TMDS传输标准中,不论是视频信号、控制信号还是辅助信号,都是以10bit的数据传输,所以需要对这三个信号进行编码,分别采用不同的编码方式。

image

image

在此,我们着重说一下视频编码,在Xilinx官方给出的一个编码示意图中,我们可以清楚整个的编码流程:

image

image

图中也体现出了控制信号的编码方式:

image

image

会对应特定的四个值中的一个。

编码如下:

  1. 1    `timescale 1 ps / 1ps
  2. 2  
  3. 3    module dvi_encoder (
  4. 4      input            clkin,    // pixel clock input
  5. 5      input            rstin,    // async. reset input (active high)
  6. 6      input      [7:0] din,      // data inputs: expect registered
  7. 7      input            c0,       // c0 input
  8. 8      input            c1,       // c1 input
  9. 9      input            de,       // de input
  10. 10     output reg [9:0] dout      // data outputs
  11. 11   );
  12. 12 
  13. 13     ///
  14. 14     // Counting number of 1and 0for each incoming pixel
  15. 15     // component. Pipe line the result.
  16. 16     // Register Data Input so it matches the pipe lined adder
  17. 17     // output
  18. 18     ///
  19. 19     reg [3:0] n1d; //number of 1in din
  20. 20     reg [7:0] din_q;
  21. 21 
  22. 22   //计算像素数据中“1”的个数
  23. 23     always @ (posedge clkin) begin
  24. 24     n1<=#1 din[0+ din[1+ din[2+ din[3+ din[4+ din[5+ din[6+ din[7];
  25. 25 
  26. 26     din_q <=#1 din;
  27. 27     end
  28. 28 
  29. 29     ///
  30. 30     // Stage 18 bit -> 9 bit
  31. 31     // Refer to DVI 1.0 Specification, page 29, Figure 3-5
  32. 32     ///
  33. 33     wire decision1;
  34. 34 
  35. 35     assign decision1 = (n1> 4'h4) | ((n1d == 4'h4& (din_q[0== 1'b0));
  36. 36 
  37. 37     wire [8:0] q_m;
  38. 38     assign q_m[0] = din_q[0];
  39. 39     assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
  40. 40     assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
  41. 41     assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
  42. 42     assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
  43. 43     assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
  44. 44     assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
  45. 45     assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
  46. 46     assign q_m[8] = (decision1) ? 1'b0 : 1'b1;
  47. 47 
  48. 48     /
  49. 49     // Stage 2: 9 bit -> 10 bit
  50. 50     // Refer to DVI 1.0 Specification, page 29, Figure 3-5
  51. 51     /
  52. 52     reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
  53. 53     always @ (posedge clkin) begin
  54. 54     n1q_m  <=#1 q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
  55. 55     n0q_m  <=#1 4'h8 - (q_m[0+ q_m[1+ q_m[2+ q_m[3+ q_m[4+ q_m[5+ q_m[6+ q_m[7]);
  56. 56     end
  57. 57 
  58. 58     parameter CTRLTOKEN0 = 10'b1101010100;
  59. 59     parameter CTRLTOKEN1 = 10'b0010101011;
  60. 60     parameter CTRLTOKEN2 = 10'b0101010100;
  61. 61     parameter CTRLTOKEN3 = 10'b1010101011;
  62. 62 
  63. 63     reg [4:0] cnt; //disparity counter, MSB is the sign bit
  64. 64     wire decision2, decision3;
  65. 65 
  66. 66     assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m);
  67. 67     
  68. 68     // [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
  69. 69     ///
  70. 70     assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));
  71. 71 
  72. 72     
  73. 73     // pipe line alignment
  74. 74     
  75. 75     reg       de_q, de_reg;
  76. 76     reg       c0_q, c1_q;
  77. 77     reg       c0_reg, c1_reg;
  78. 78     reg [8:0] q_m_reg;
  79. 79 
  80. 80     always @ (posedge clkin) begin
  81. 81     de_q    <=#1 de;
  82. 82     de_reg  <=#1 de_q;
  83. 83     
  84. 84     c0_q    <=#1 c0;
  85. 85     c0_reg  <=#1 c0_q;
  86. 86     c1_q    <=#1 c1;
  87. 87     c1_reg  <=#1 c1_q;
  88. 88 
  89. 89     q_m_reg <=#1 q_m;
  90. 90     end
  91. 91 
  92. 92     ///
  93. 93     // 10-bit out
  94. 94     // disparity counter
  95. 95     ///
  96. 96     always @ (posedge clkin or posedge rstin) begin
  97. 97     if(rstin) begin
  98. 98       dout <= 10'h0;
  99. 99       cnt <= 5'h0;
  100. 100    end else begin
  101. 101      if (de_reg) begin
  102. 102      if(decision2) begin
  103. 103        dout[9]   <=#1 ~q_m_reg[8]; 
  104. 104        dout[8]   <=#1 q_m_reg[8]; 
  105. 105        dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
  106. 106
  107. 107        cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);
  108. 108      end else begin
  109. 109        if(decision3) begin
  110. 110        dout[9]   <=#1 1'b1;
  111. 111        dout[8]   <=#1 q_m_reg[8];
  112. 112        dout[7:0<=#1 ~q_m_reg[7:0];
  113. 113
  114. 114        cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
  115. 115        end else begin
  116. 116        dout[9]   <=#1 1'b0;
  117. 117        dout[8]   <=#1 q_m_reg[8];
  118. 118        dout[7:0<=#1 q_m_reg[7:0];
  119. 119
  120. 120        cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
  121. 121        end
  122. 122      end
  123. 123      end else begin
  124. 124      case ({c1_reg, c0_reg})
  125. 125        2'b00:   dout <=#1 CTRLTOKEN0;
  126. 126        2'b01:   dout <=#1 CTRLTOKEN1;
  127. 127        2'b10:   dout <=#1 CTRLTOKEN2;
  128. 128        default: dout <=#1 CTRLTOKEN3;
  129. 129      endcase
  130. 130
  131. 131      cnt <=#1 5'h0;
  132. 132      end
  133. 133    end
  134. 134    end
  135. 135    
  136. 136  endmodule

编码完成后,对数据我们需要进行并串转换,此操作我们可以使用原语OSERDES2实现10-to-1的过程。最后用OBUFDS将串行数据转换为差分信号输出即可。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!

【QQ交流群】

群号:173560979,进群暗语:FPGA技术江湖粉丝。

多年的FPGA企业开发、培训经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有8000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,FPGA技术江湖打造最纯净最专业的技术交流学习平台。

【微信交流群】

现微信交流群已建立14群,人数已达万人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。

欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式,更多精彩内容等你发现

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/331163
推荐阅读
相关标签
  

闽ICP备14008679号