TMDS,Transition Minimized Differential Signaling,即最小化差分传输信号,在DVI(数字视频接口,只能传输视频)和HDMI(音视频均可传输)协议中用于传输音视频数据,使用差分信号传输高速串行数据。
1、TMDS接口
TMDS连接从逻辑功能上可以划分成两个阶段:编码和并串转换。在编码阶段,编码器将视频源中的像素数据、HDMI的音频/附加数据,以及行同步和场同步信号分别编码成10位的字符流。然后在并串转换阶段将上述的字符流转换成串行数据流,并将其从三个差分输出通道发送出去。
2、TMDS算法
TMDS算法框图
TMDS通过逻辑算法将8bit字符数据通过最小转换编码为10bit字符数据,前8bit由原始信号通过运算获得,第9位表示运算的方式,1表示异或,0表示异或非。经过直流平衡后(第10位),采用差分信号传输数据。第10位是一个反转标志位,1表示反转,0表示没有反转,从而达到DC平衡。
接收端在收到信号后,再进行相反的运算。TMDS 和 LVDS、TTL 相比有较好的电磁兼容性能。这种算法可以减小传输信号过程的上冲和下冲,而 DC 平衡使信号对传输线的电磁干扰减少,可以用低成本的专用电缆实现长距离、高质量的数字信号传输。
3、TMDS逻辑代码
module Encoder(
input i_pixel_clk , //像素时钟
input i_rst , //复位信号,高有效
input [07:00] i_data , //输入8位数据
input i_de , //像素数据有效信号
input i_ctrl_1 , //控制信号1
input i_ctrl_2 , //控制信号2
output reg [09:00] o_data //输出10位数
);
//计算数据中1的个数
reg [02:00] num_1_data; //1的个数
reg [07:00] data_temp1;
always@(posedge i_pixel_clk)
begin
num_1_data <= i_data[7] + i_data[6] + i_data[5] + i_data[4] + i_data[3] + i_data[2] + i_data[1] + i_data[0];
data_temp1 <= i_data;
end
//判断条件1 8bit转变成9bit,减少跳变沿
wire decision1;
wire [08:00] q_m;
assign decision1 = (num_1_data > 3'd4) | ((num_1_data == 3'd4) & (data_temp1[0] == 0));
assign q_m[0] = data_temp1 [0];
assign q_m[1] = decision1 ? (q_m[0] ^ (~ data_temp1 [1])) : (q_m[0] ^ data_temp1[1]);
assign q_m[2] = decision1 ? (q_m[1] ^ (~ data_temp1 [2])) : (q_m[1] ^ data_temp1[2]);
assign q_m[3] = decision1 ? (q_m[2] ^ (~ data_temp1 [3])) : (q_m[2] ^ data_temp1[3]);
assign q_m[4] = decision1 ? (q_m[3] ^ (~ data_temp1 [4])) : (q_m[3] ^ data_temp1[4]);
assign q_m[5] = decision1 ? (q_m[4] ^ (~ data_temp1 [5])) : (q_m[4] ^ data_temp1[5]);
assign q_m[6] = decision1 ? (q_m[5] ^ (~ data_temp1 [6])) : (q_m[5] ^ data_temp1[6]);
assign q_m[7] = decision1 ? (q_m[6] ^ (~ data_temp1 [7])) : (q_m[6] ^ data_temp1[7]);
assign q_m[8] = decision1 ? 1'b0 : 1'b1;
//计算q_m中1的个数和0的个数
reg [03:00] num_1_q_m;
reg [03:00] num_0_q_m;
always@(posedge i_pixel_clk)
begin
num_1_q_m <= q_m[7] + q_m[6] + q_m[5] + q_m[4] + q_m[3] + q_m[2] + q_m[1] + q_m[0];
num_0_q_m <= 4'd8 - (q_m[7] + q_m[6] + q_m[5] + q_m[4] + q_m[3] + q_m[2] + q_m[1] + q_m[0]);
end
parameter CTRLTOKEN0 = 10'b11_0101_0100;
parameter CTRLTOKEN1 = 10'b00_1010_1011;
parameter CTRLTOKEN2 = 10'b01_0101_0100;
parameter CTRLTOKEN3 = 10'b10_1010_1011;
reg de_temp1;
reg de_temp2;
reg ctrl_1_temp1;
reg ctrl_1_temp2;
reg ctrl_2_temp1;
reg ctrl_2_temp2;
reg [08:00] q_m_temp;
//流水线时钟对齐,i_data已延迟一个时钟,其余延迟两个时钟后输出
always@(posedge i_pixel_clk)
begin
de_temp1 <= i_de;
de_temp2 <= de_temp1;
ctrl_1_temp1 <= i_ctrl_1;
ctrl_1_temp2 <= ctrl_1_temp1;
ctrl_2_temp1 <= i_ctrl_2;
ctrl_2_temp2 <= ctrl_2_temp1;
q_m_temp <= q_m;
end
// 1、cnt=0时表示上次传输无数据流极性差异
// 2、cnt>0,即cnt[4]=0表示上次数据流中传输了更多的1
// 3、cnt<0,即cnt[4]=1表示上次数据流中传输了更多的0
wire decision2;
wire decision3;
reg [04:00] cnt;
// cnt=0时表示上次传输无数据流极性差异
assign decision2 = (cnt == 5'd0) | (num_1_q_m == num_0_q_m);
assign decision3 = ((~cnt[4]) & (num_1_q_m > num_0_q_m)) | (cnt[4] & (num_1_q_m < num_0_q_m));
always@(posedge i_pixel_clk or posedge i_rst)
begin
if(i_rst)
begin
o_data <= 10'd0;
cnt <= 5'd0;
end
else begin
if(de_temp2)
begin
if(decision2)
begin
o_data[9] <= ~q_m_temp[8];
o_data[8] <= q_m_temp[8];
o_data[07:00] <= q_m_temp[8] ? q_m_temp[07:00] : (~q_m_temp[07:00]);
cnt <= q_m_temp[8] ? (cnt + num_1_q_m - num_0_q_m) : (cnt + num_0_q_m - num_1_q_m);
end
else begin
if(decision3)
begin
o_data[9] <= 1'b1;
o_data[8] <= q_m_temp[8];
o_data[07:00] <= ~q_m_temp[07:00];
cnt <= cnt + 2*q_m_temp[8] + num_0_q_m - num_1_q_m;
end
else begin
o_data[9] <= 1'b0;
o_data[8] <= q_m_temp[8];
o_data[07:00] <= q_m_temp[07:00];
cnt <= cnt - 2*(~q_m_temp[8]) + num_1_q_m - num_0_q_m;
end
end
end
else begin
case({ctrl_2_temp2,ctrl_1_temp2})
2'b00 : o_data <= CTRLTOKEN0;
2'b01 : o_data <= CTRLTOKEN1;
2'b10 : o_data <= CTRLTOKEN2;
2'b11 : o_data <= CTRLTOKEN3;
endcase
cnt <= 5'd0;
end
end
end
endmodule