[HDMI]FPGA上实现HDMI(1)

HDMI是一个数字视频接口,通过FPGA可以很快的实现驱动。下面可以看到HDMI是怎么工作的.

connector

标准的HDMI连接器称为"A型",有19个引脚,其中8个引脚是需要注意的,组成了四个差分对TMDS(Transition Min imized Differential Signaling)[过度调制差分信号]。

  1. TMDS data2+ and data2-
  2. TMDS data1+ and data1-
  3. TMDS data0+ and data0-
  4. TMDS clock+ and clock-

[HDMI]FPGA上实现HDMI(1)_第1张图片

我们链接HDMI和FPGA很简单,只要使用其中的4对差分信号就可以了。

[HDMI]FPGA上实现HDMI(1)_第2张图片

video signal

现在需要插入一个640x480 RGB 24bpp(一个像素需要的bit数) @ 60Hz。所以一帧数据需要307200像素,而且每个像素需要24bit(RGB各8bit),在60Hz中HDMI链路中有用信号信号的速率是0.44Gbps。同时在视频信号中存在“off-area”区域,在所有的HDMI驱动控制中是非常有用的。640x480格式的实际上需要800x525格式。

[HDMI]FPGA上实现HDMI(1)_第3张图片

TMDS signals

FPGA的TMDS驱动有4对不同的差分对。TMDS时钟是像素时钟 ,所以这里使用的是25MHz。其他3个差分对转化输出是红、绿、蓝信号。

但是事实上每一bit都会更复杂,HDMI要求使用“TMDS编码”来实现对应的显示数据,其中需要加2bit的加扰数据,所以实际上每通道是10bit而不是8bit,一帧数据传输需要30bit数据。

Source code

1、视频生成

reg [9:0] CounterX; // counts from 0 to 799
always @(posedge pixclk) 
    CounterX <= (CounterX==799) ? 0 : CounterX+1;

reg [9:0] CounterY; // counts from 0 to 524
always @(posedge pixclk) 
    if(CounterX==799) 
        CounterY <= (CounterY==524) ? 0 : CounterY+1;

 

2、加入HSYNC和VSYNC同步信号

wire hSync = (CounterX>=656) && (CounterX<752);
wire vSync = (CounterY>=490) && (CounterY<492);
wire DrawArea = (CounterX<640) && (CounterY<480);

 

3、生成红、绿、蓝信号(每个颜色8bit)

wire [7:0] red = {CounterX[5:0] & {6{CounterY[4:3]==~CounterX[4:3]}}, 2'b00};
wire [7:0] green = CounterX[7:0] & {8{CounterY[6]}};
wire [7:0] blue = CounterY[7:0];

 

4、通过"TMDS编码"将8bit数据展诚10bit

wire [9:0] TMDS_red, TMDS_green, TMDS_blue;
TMDS_encoder encode_R(
    .clk(pixclk), 
    .VD(red ), 
    .TMDS(TMDS_red) , 
    .CD(2'b00) , 
    .VDE(DrawArea));

TMDS_encoder encode_G(
    .clk(pixclk), 
    .VD(green),     
    .TMDS(TMDS_green), 
    .CD(2'b00) , 
    .VDE(DrawArea));

TMDS_encoder encode_B(
    .clk(pixclk), 
    .VD(blue ), 
    .TMDS(TMDS_blue) , 
    .CD({vSync,hSync}), 
    .VDE(DrawArea));

 

5、每个时钟需要去发送10bit的数据,我们使用的时钟是25MHz,所以需要乘以10倍,转换成250MHz的时钟。

wire clk_TMDS, DCM_TMDS_CLKFX;

DCM_SP #(
    .CLKFX_MULTIPLY(10)) 
DCM_TMDS_inst(
    .CLKIN(pixclk), 
    .CLKFX(DCM_TMDS_CLKFX), 
    .RST(1'b0));

BUFG BUFG_TMDSp(
    .I(DCM_TMDS_CLKFX), .
    O(clk_TMDS)); // 250 MHz

 

6、三个RGB的移位寄存器是在250MHz时钟上工作

reg [3:0] TMDS_mod10; // modulus 10 counter

always @(posedge clk_TMDS) 
    TMDS_mod10 <= (TMDS_mod10==9) ? 0 : TMDS_mod10+1;

reg TMDS_shift_load;
always @(posedge clk_TMDS) 
    TMDS_shift_load <= (TMDS_mod10==9);

reg [9:0] TMDS_shift_red, TMDS_shift_green, TMDS_shift_blue;
always @(posedge clk_TMDS)begin 
    TMDS_shift_red <= TMDS_shift_load ? TMDS_red : TMDS_shift_red [9:1]; 
    TMDS_shift_green <= TMDS_shift_load ? TMDS_green : TMDS_shift_green[9:1];                                                         
    TMDS_shift_blue <= TMDS_shift_load ? TMDS_blue : TMDS_shift_blue [9:1];
end

 

Higher resolutions

如果使用640x480分辨率,我们需要使用250MHz时钟的串行时钟, 但是如果要更高的分辨率,需要更高的频率,但是会超出FPGA本身的工作频率。可以选择使用一些特殊的FPGA IO引脚,譬如DDR输出和IO串行器。在更高频率是还有其他问题是,如何将像素时钟的数据转换到串行工作区中。一种可行的技术是使用一个浅(小)的FIFO。具体可以看xilinx XAPP460 和 XAPP495,可以得到相关的信息。

你可能感兴趣的:(协议原理)