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很简单,只要使用其中的4对差分信号就可以了。

video signal

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

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 799always @(posedge
pixclk) CounterX <= (CounterX==799) ? 0 : CounterX+1;reg [9:0] CounterY;
// counts from 0 to 524always @(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 counteralways @(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,可以得到相关的信息。

文章转载自:http://blog.csdn.net/github_33678609/article/details/53780753