前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HDMI驱动系列(二)、HDMI数据编码算法

HDMI驱动系列(二)、HDMI数据编码算法

作者头像
根究FPGA
发布2020-06-29 15:46:18
1.7K0
发布2020-06-29 15:46:18
举报
文章被收录于专栏:根究FPGA根究FPGA

数据编码分为两个阶段,第一个阶段是对输入的8bit数据进行异或(XOR)/异或非(XNOR)运算,拓宽频谱,减少原始数据的0、1跳变次数。再加上一位标志位表示那一种方式被采用来描述转换,分析程序感觉这个就是一个标志原始数据中0多还是1多的标志位,当0多时其为1,else 为0。

第二个阶段是数据发送阶段,注意,不是将数据通过电气接口发送出去,指的是传递给发送模块。此时会有一个计数器,每次发送时都计数多发送的0或者多发送的1,具体是计算多发送的0还是多发送的1要看采用的哪一种决策方式。

对于该计数器,手册中的解释大概意思是:该计数器是一个发送数据极性计数器,当其为负数时候表明上一次数据传输的数据流中传输了更多的0,直流平衡漂移到负极性,else上一次传输中传输更多的1,直流平衡漂移到正极性,正负是通过位[4]确定。

总之,就是两个阶段,第一个阶段是减少数据跳变沿,第二个阶段是保持直流平衡。

整体上来说,在数据有效信号使能时,进行数据发送,否则通过控制信号进行发送处理。

算法框图:

编码代码:
代码语言:javascript
复制
module dvi_encoder(
clkin,
rstin,
din,
c0,
c1,
de,
dout
);
input clkin;   //像素时钟输入
input rstin;   //同步复位输入
input[7:0]din; //数据输入
input c0,c1;    //控制信号输入
input de;       //数据使能信号输入
output reg[9:0]dout;//数据输出
//首先计算输入数据中1的个数
//同时对输入数据进行寄存
reg[7:0]din_q;
reg[3:0]n1d;
always@(posedge clkin)begin
 n1d<=din[0]+din[1]+din[2]+din[3]+din[4]+din[5]+din[6]+din[7];
 din_q<=din;
end 
/*
第一阶段:减少跳变沿
 将8bit数据转换为9bit:减少跳变沿
*/
wire decision1;
assign decision1=(n1d>4'd4)|((n1d==4'd4)&(din_q[0]==1'b0));  //当1的个数大于4或者1个数为4但是位0为0时,采用方案1
wire[8:0]q_m;  //第一级阶段数据寄存
assign q_m[0]=din_q[0];
assign q_m[1]=decision1?(din_q[1]^~q_m[0]):(din_q[1]^q_m[0]);
assign q_m[2]=decision1?(din_q[2]^~q_m[1]):(din_q[2]^q_m[1]);
assign q_m[3]=decision1?(din_q[3]^~q_m[2]):(din_q[3]^q_m[2]);
assign q_m[4]=decision1?(din_q[4]^~q_m[3]):(din_q[4]^q_m[3]);
assign q_m[5]=decision1?(din_q[5]^~q_m[4]):(din_q[5]^q_m[4]);
assign q_m[6]=decision1?(din_q[6]^~q_m[5]):(din_q[6]^q_m[5]);
assign q_m[7]=decision1?(din_q[7]^~q_m[6]):(din_q[7]^q_m[6]);
assign q_m[8]=decision1? 1 : 0 ;

/*
第二阶段:保持直流平衡
    对改善跳变次数的数据进行二次处理,跟踪传输过程中的01个数差异,以及当前码字中的01个数决定是否翻转字符,
    第10位表示是否进行了数据翻转
    该10位数据共460种组合,原始输入数据8位共256种组合,但是但考虑到到数据翻转以及bit8、bit9的规则约束,一共460种字符
*/
reg [3:0] n1q_m;
reg [3:0] n0q_m;  //计算q_m[8:0]中0和1的个数

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]+q_m[8]; 
 n0q_m<=#1 9-(q_m[0]+q_m[1]+q_m[2]+q_m[3]+q_m[4]+q_m[5]+q_m[6]+q_m[7]+q_m[8]); 
end
 
//控制字符参数定义
parameter CTRLTOKEN0=10'b1101010100;
parameter CTRLTOKEN1=10'b0010101011;
parameter CTRLTOKEN2=10'b0101010100;
parameter CTRLTOKEN3=10'b1010101011;

/*
这个cnt在协议中专门强调:
    1、cnt=0时表示上次传输无数据流极性差异
    2、cnt>0,即cnt[4]=0表示上次数据流中传输了更多的1
    3、cnt<0,即cnt[4]=1表示上次数据流中传输了更多的0
*/
reg [4:0]cnt;  //第二阶段类似于一个mealy型状态机,追踪传输流中的01个数差异,MSB为正负标志位置

wire decision2,decision3;  //进而做出决断

//cnt==0表示上次传输没有数据流极性差异
//本次传输没有极性差异
//所以运行无极性差异的流程
assign decision2=(cnt==5'd0)|(n1q_m==n0q_m);

//上次就传输的1多没本次数据中又是1多
//反
assign decision3=((~cnt[4])&(n1q_m>n0q_m))|((cnt[4])&(n0q_m>n1q_m));
 
/*
  流水线对齐   因为data经过了一个像素时钟的同步,此处控制信号还需要2次同步寄存,流水线时钟对齐
*/
reg[9:0]q_m_reg;
reg de_q,de_reg;
reg c0_q,c0_reg;
reg c1_q,c1_reg;
always@(posedge clkin)begin
 
 q_m_reg<=q_m;

 de_q<=de;
 de_reg<=de_q;
 
 c0_q<=c0;
 c0_reg<=c0_q;
 
 c1_q<=c1;
 c1_reg<=c1_q;
 
end 
//10bit输出
always@(posedge clkin)begin
 if(rstin)begin
  dout<=0;
  cnt<=0;
 end 
 else begin
  if(de_reg)begin  //数据使能
   if(decision2)begin
    dout[9]<=#1 ~q_m_reg[8];  //bit9是数据翻转标志位
    dout[8]<=#1 q_m_reg[8];  //符号位不变
    /*
    n0q_m-n1q_m=1时,0多,将数据直接发出去,0多
    n0q_m-n1q_m=0时,1多,将数据取反发出去,0多
    */
    dout[7:0]<=(q_m_reg[8])?q_m_reg[7:0]:~q_m_reg[7:0];
    /*
    在之前直流平衡状态时,q_m_reg[8]=0表示原始数据中1多,然后将数据取反发送出去,取反之后0多,所以用0个数-1个数
    若n0q_m=n1q_m,皆可
    该语句的变形
    if(cnt==0)begin
     if(1'b1==q_m_reg[8])  //即原始数据经过处理后0多
      cnt<=n1q_m-n0q_m;  //得到一个负值~~表示直流偏移负极性
     else                 //原始数据中1多,取反后0多
      cnt<=n0q_m-n1q_m;  //得到一个负值,表示多发了0,直流偏向负极性
    end 
    else begin 
         cnt<=cnt;  //不变
    end 
    */
    cnt<=#1 (~q_m_reg[8])?(cnt+(n0q_m-n1q_m)):(cnt-(n0q_m-n1q_m));
    
   end else begin
    if(decision3)begin
     dout[9]<=#1 1;  //极性必须翻转,因为不反转的话加重直流偏移
     dout[8]<=#1 q_m_reg[8];
     dout[7:0]<=#1 ~q_m_reg[7:0];
     cnt<=#1 cnt+{q_m_reg,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;
   2'b11: dout<=#1 CTRLTOKEN3;  
   endcase
   cnt<=#1 0;  //每次数据使能结束清零计数器
  end 
 end 
end  
endmodule

TMDS通过逻辑算法将8bit字符数据通过最小转换编码为10bit字符数据,前8bit由原始信号通过运算获得,第9位表示运算的方式。经过直流平衡后(第10位),采用差分信号传输数据。第10位是一个反转标志位,1:反转 0:没有反转。

接收端接收到信号后进行相反的运算即可获得原始数据。TMDS和LVDS、TTL相比具有较好的电磁兼容性能。算法可以减小传输信号的上冲和下冲(stage 1),而DC平衡使信号对传输线的电磁干扰减少(stage 2),可以用低成本的专用电缆实现长距离、高质量的数据信号传输。

下一篇预告:HDMI的串行化数据处理

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 根究FPGA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 编码代码:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档