TMDS编解码原理与实现

一、TMDS简介

HDMI和DVI协议使用TMDS作为它们的物理层。支持高达225MHz的传输速率,一个传输链路能满足高2048*1536分辨率电视信号。一般来说,一个HDMI/DVI接口包含四个TMDS通道,三条数据通道和一条时钟通道,每条通道采用差分电平传输,即一条通道要2根线,正极和负极。TMDS编解码算法可以使得被传输信号过渡过程的上冲和下冲减小,传输的数据趋于直流平衡,使信号对传输线的电磁干扰减少,提高信号传输的速度和可靠性。

二、TMDS编码

q_out[9]表示q_out[0:7]与q_m[0:7]的关系,q_out[9]==1表示q_out[0:7] = ~q_m[0:7],q_out[9]==0表示q_out[0:7] = q_m[0:7]

q_out[8]表示q_m[0:7]是用什么方式产生的,q_out[8]==1表示q_m[0:7]是用XOR方式产生的,q_out[8]==0表示q_m[0:7]是用XNOR方式产生的,q_out[8]永远等于q_m[8]

在算法流程上,首先,它会根据输入的8bit数据中1的个数来决定中间值q_m的产生方式,这里大概是为了满足最后输出数据的跳变次数要求。对于输入8bit像素数据,其输出的10bit数据中0-1或1-0的跳变次数要小于5次;对于输入控制数据,其输出的10bit数据中0-1或1-0的跳变次数要大于等于7次。然后,它根据上一次记录的cnt值(该值表示了上次输出的10bit数据中1的个数比0的个数多几个,最高位为符号位,取值范围为-7~7)和本次生成的中间值的0、1个数比,来决定输出的10bit数据q_out与中间值的关系。大致思路如下:上一次输出1的个数偏多了,这一次如果中间值还是1多,那么把中间值每个位取反,这一次如果中间值还是0多,那么照常输出,保证这一次的输出可以补偿上一次的不足,已达到直流平衡。最后,它会计算这一次输出的10bit数据中1比0多了几个,存到变量cnt中。

Verilog实现l:

`timescale 1 ps / 1ps

module dvi_encoder (
  input            clkin,    // pixel clock input
  input            rstin,    // async. reset input (active high)
  input      [7:0] din,      // data inputs: expect registered
  input            c0,       // c0 input
  input            c1,       // c1 input
  input            de,       // de input
  output reg [9:0] dout      // data outputs
);

  
  // Counting number of 1s and 0s for each incoming pixel
  // component. Pipe line the result.
  // Register Data Input so it matches the pipe lined adder
  // output
  
  reg [3:0] n1d; //number of 1s in din
  reg [7:0] din_q;

//计算像素数据中“1”的个数
  always @ (posedge clkin) begin
    n1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];

    din_q <=#1 din;
  end

  ///
  // Stage 1: 8 bit -> 9 bit
  // Refer to DVI 1.0 Specification, page 29, Figure 3-5
  ///
  wire decision1;

  assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));

  wire [8:0] q_m;
  assign q_m[0] = din_q[0];
  assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
  assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
  assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
  assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
  assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
  assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
  assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
  assign q_m[8] = (decision1) ? 1'b0 : 1'b1;

  /
  // Stage 2: 9 bit -> 10 bit
  // Refer to DVI 1.0 Specification, page 29, Figure 3-5
  /
  reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
  always @ (posedge clkin) begin
    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];
    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]);
  end

  parameter CTRLTOKEN0 = 10'b1101010100;
  parameter CTRLTOKEN1 = 10'b0010101011;
  parameter CTRLTOKEN2 = 10'b0101010100;
  parameter CTRLTOKEN3 = 10'b1010101011;

  reg [4:0] cnt; //disparity counter, MSB is the sign bit
  wire decision2, decision3;

  assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m);
  /
  // [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
  /
  assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));

  
  // pipe line alignment
  
  reg       de_q, de_reg;
  reg       c0_q, c1_q;
  reg       c0_reg, c1_reg;
  reg [8:0] q_m_reg;

  always @ (posedge clkin) begin
    de_q    <=#1 de;
    de_reg  <=#1 de_q;
    
    c0_q    <=#1 c0;
    c0_reg  <=#1 c0_q;
    c1_q    <=#1 c1;
    c1_reg  <=#1 c1_q;

    q_m_reg <=#1 q_m;
  end

  ///
  // 10-bit out
  // disparity counter
  ///
  always @ (posedge clkin or posedge rstin) begin
    if(rstin) begin
      dout <= 10'h0;
      cnt <= 5'h0;
    end else begin
      if (de_reg) begin
        if(decision2) begin
          dout[9]   <=#1 ~q_m_reg[8]; 
          dout[8]   <=#1 q_m_reg[8]; 
          dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];

          cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);
        end else begin
          if(decision3) begin
            dout[9]   <=#1 1'b1;
            dout[8]   <=#1 q_m_reg[8];
            dout[7:0] <=#1 ~q_m_reg[7:0];

            cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
          end else begin
            dout[9]   <=#1 1'b0;
            dout[8]   <=#1 q_m_reg[8];
            dout[7:0] <=#1 q_m_reg[7:0];

            cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
          end
        end
      end else begin
        case ({c1_reg, c0_reg})
          2'b00:   dout <=#1 CTRLTOKEN0;
          2'b01:   dout <=#1 CTRLTOKEN1;
          2'b10:   dout <=#1 CTRLTOKEN2;
          default: dout <=#1 CTRLTOKEN3;
        endcase

        cnt <=#1 5'h0;
      end
    end
  end
  
endmodule

三、TMDS解码

Verilog实现

module dvi_decoder(
	input        sys_clk,
	input        sys_rst,
	input [9:0]  Blue_out,
	output [7:0] data
);
	reg [7:0]    data_frame;
	reg [7:0]    data_frame1;
	reg [9:0]    data_in_frame;
	reg [9:0]    data_in_frame14;
	wire         desion1;
	wire         desion2;
	assign desion1 = (Blue_out[9]== 1)?1'b1:1"b0;
	assign desion2 =(Blue_out[8]== 1)?1"b1:1"bO;
	alwayse(posedge sys_clk or negedge sys_rst)begin
		if(!sys_rst) data_in_frame <= 'd0;
		else data_in_frame <= Blue_out;
	end
	always@(posedge sys_clk or negedge sys_rst)begin
		if(!sys_rst)begin
			data_frame <= "d0;
			data_frame1 <= "d0;
			data_in_frame1 <= "d0;
		end
		else if(desion1)begin
				data_in_frame1[7:0]<= ~data_in_frame[7:0];
				data_frame1[0]<= (desion2)?data_in_frame1[0]:data_in_frame1[0];
				data_frame1[1]<=(desion2)?data_in_frame1[1]^ data_in_frame1[0]:data_in_frame1[0]^~data in_frame1[1];
				data_frame1[2]<=(desion2)?data_in_frame1[2]^ data_in_frame1[1];:data_in_frame1[1]^-data_in frame1[2];
				data_frame1[3]<=(desion2)?data_in_frame1[3]^ data_in_frame1[2]:data_in_frame1[2]^~data_in_frame1[3];
				data_frame1[4]<=(desion2)?data_in_frame1[4]^ data_in_frame1[3]:data_in_frame1[3]^-data_in_frame1[4];
				data_frame1[5]<=(desion2)?data_in_frame1[5]^ data_in_frame1[4]:data_in_frame1[4]^~data_in_frame1[5];
				data_frame1[6]<=(desion2)?data_in_frame1[6]^ data _in_frame1[5]:data_in_frame1[5]^-data _in frame1[6];
				data_frame1[7]<= (desion2)?data_in_frame1[7]^ data_in_frame1[6]:data in_frame1[6]^~data_in_frame1[7];
		end
		else if( !desion1)begin
				data_frame[0]<= (desion2)?data_in_frame[0]:data_in_frame[0];
				data_frame[1]〈=(desion2)?data_in_frame[1]^ data_in_frame[0]:data_in_frame[0]^~data_in_frame[1];
				data_frame[2]<=(desion2)?data_in_frame[2]^ data_in_frame[1]:data_in_frame[1]^~data in_frame[2];
				data_frame[3]<=(desion2)?data_in_frame[3]^ data_in_frame[2]:data_in_frame[2]^~data_in_frame[3];
				data_frame[4]<=(desion2)?data_in_frame[4]^ data_in_frame[3]:data_in_frame[3]^~data_in_frame[4];
				data_frame[5]<=(desion2)?data_in_frame[5]^ data_in_frame[4]:data_in_frame[4]^~-data_in_frame[5];
				data_frame[6]<=(desion2)?data_in_frame[6] ^ data_in_frame[5]:data_in_frame[5]^data_in_frame[6];
				data_frame[7]〈= (desion2)?data_in_frame[7]^ data_in_frame[6]:data_in_frame[6]^~data_in_frame[7];
		end
	end
	assign data =(desion1)?data_frame1[7:0]: data_frame;
endmodule
  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值