赞
踩
在我们之前的学习中,了解到HDMI是一种全数字化视频和声音发送接口,可以发送音频以及视频信号。HDMI向下兼容DVI,DVI只能传输视频信号。HDMI和DVI接口协议在物理层均使用TMDS标准来传输音频或视频信号,接下来就着重了解一下TMDS编码。
TMDS(最小化传输差分信号)中,有四个通道,其中包含了三个数据通道和一个时钟通道。其中数据通道用来传输颜色、音频、控制等信号。HDMI默认使用RGB(RGB888)三个数据通道,当然也可以是亮度和色度信息(YCrCb,4:4:4或者4:2:2)。
image
上图为HDMI的链接框架; 通道0传输的数据为:B分量的视频数据、行场同步信号、音频信号。 通道0传输的数据为:G分量的视频数据、控制信号、音频信号。 通道0传输的数据为:R分量的视频数据、控制信号、音频信号。 不同的数据在TMDS数据通道中在三种不同的周期中发送。
image
在TMDS传输标准中,不论是视频信号、控制信号还是辅助信号,都是以10bit的数据传输,所以需要对这三个信号进行编码,分别采用不同的编码方式。
image
在此,我们着重说一下视频编码,在Xilinx官方给出的一个编码示意图中,我们可以清楚整个的编码流程:
image
图中也体现出了控制信号的编码方式:
image
会对应特定的四个值中的一个。
编码如下:
- 1 `timescale 1 ps / 1ps
- 2
- 3 module dvi_encoder (
- 4 input clkin, // pixel clock input
- 5 input rstin, // async. reset input (active high)
- 6 input [7:0] din, // data inputs: expect registered
- 7 input c0, // c0 input
- 8 input c1, // c1 input
- 9 input de, // de input
- 10 output reg [9:0] dout // data outputs
- 11 );
- 12
- 13 ///
- 14 // Counting number of 1s and 0s for each incoming pixel
- 15 // component. Pipe line the result.
- 16 // Register Data Input so it matches the pipe lined adder
- 17 // output
- 18 ///
- 19 reg [3:0] n1d; //number of 1s in din
- 20 reg [7:0] din_q;
- 21
- 22 //计算像素数据中“1”的个数
- 23 always @ (posedge clkin) begin
- 24 n1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];
- 25
- 26 din_q <=#1 din;
- 27 end
- 28
- 29 ///
- 30 // Stage 1: 8 bit -> 9 bit
- 31 // Refer to DVI 1.0 Specification, page 29, Figure 3-5
- 32 ///
- 33 wire decision1;
- 34
- 35 assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));
- 36
- 37 wire [8:0] q_m;
- 38 assign q_m[0] = din_q[0];
- 39 assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
- 40 assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
- 41 assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
- 42 assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
- 43 assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
- 44 assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
- 45 assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
- 46 assign q_m[8] = (decision1) ? 1'b0 : 1'b1;
- 47
- 48 /
- 49 // Stage 2: 9 bit -> 10 bit
- 50 // Refer to DVI 1.0 Specification, page 29, Figure 3-5
- 51 /
- 52 reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
- 53 always @ (posedge clkin) begin
- 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 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 end
- 57
- 58 parameter CTRLTOKEN0 = 10'b1101010100;
- 59 parameter CTRLTOKEN1 = 10'b0010101011;
- 60 parameter CTRLTOKEN2 = 10'b0101010100;
- 61 parameter CTRLTOKEN3 = 10'b1010101011;
- 62
- 63 reg [4:0] cnt; //disparity counter, MSB is the sign bit
- 64 wire decision2, decision3;
- 65
- 66 assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m);
- 67
- 68 // [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
- 69 ///
- 70 assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));
- 71
- 72
- 73 // pipe line alignment
- 74
- 75 reg de_q, de_reg;
- 76 reg c0_q, c1_q;
- 77 reg c0_reg, c1_reg;
- 78 reg [8:0] q_m_reg;
- 79
- 80 always @ (posedge clkin) begin
- 81 de_q <=#1 de;
- 82 de_reg <=#1 de_q;
- 83
- 84 c0_q <=#1 c0;
- 85 c0_reg <=#1 c0_q;
- 86 c1_q <=#1 c1;
- 87 c1_reg <=#1 c1_q;
- 88
- 89 q_m_reg <=#1 q_m;
- 90 end
- 91
- 92 ///
- 93 // 10-bit out
- 94 // disparity counter
- 95 ///
- 96 always @ (posedge clkin or posedge rstin) begin
- 97 if(rstin) begin
- 98 dout <= 10'h0;
- 99 cnt <= 5'h0;
- 100 end else begin
- 101 if (de_reg) begin
- 102 if(decision2) begin
- 103 dout[9] <=#1 ~q_m_reg[8];
- 104 dout[8] <=#1 q_m_reg[8];
- 105 dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
- 106
- 107 cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);
- 108 end else begin
- 109 if(decision3) begin
- 110 dout[9] <=#1 1'b1;
- 111 dout[8] <=#1 q_m_reg[8];
- 112 dout[7:0] <=#1 ~q_m_reg[7:0];
- 113
- 114 cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
- 115 end else begin
- 116 dout[9] <=#1 1'b0;
- 117 dout[8] <=#1 q_m_reg[8];
- 118 dout[7:0] <=#1 q_m_reg[7:0];
- 119
- 120 cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
- 121 end
- 122 end
- 123 end else begin
- 124 case ({c1_reg, c0_reg})
- 125 2'b00: dout <=#1 CTRLTOKEN0;
- 126 2'b01: dout <=#1 CTRLTOKEN1;
- 127 2'b10: dout <=#1 CTRLTOKEN2;
- 128 default: dout <=#1 CTRLTOKEN3;
- 129 endcase
- 130
- 131 cnt <=#1 5'h0;
- 132 end
- 133 end
- 134 end
- 135
- 136 endmodule
编码完成后,对数据我们需要进行并串转换,此操作我们可以使用原语OSERDES2实现10-to-1的过程。最后用OBUFDS将串行数据转换为差分信号输出即可。
完
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!
群号:173560979,进群暗语:FPGA技术江湖粉丝。
多年的FPGA企业开发、培训经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有8000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,FPGA技术江湖打造最纯净最专业的技术交流学习平台。
现微信交流群已建立14群,人数已达万人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。