[HDMI]FPGA上实现HDMI(1)

≡放荡痞女 提交于 2020-02-05 00:56:28

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

connector

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

TMDS data2+ and data2-
TMDS data1+ and data1-
TMDS data0+ and data0-
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 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,可以得到相关的信息。
————————————————
版权声明:本文为CSDN博主「请叫我小菜鸡先生」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/github_33678609/article/details/53780753

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!