基于FPGA的HDMI开发

HDMI基本原理

一、原理

HDMI采用和DVI相同的传输原理-TMDS(Transition Minimized Differential signal),即最小化传输差分信号。
TMDS传输系统分为:发送端;接收端。
发送端:(RGB信号的24位并行数据,R,G,B三原色各8bit编码;-->  编码 --> 并串转换 --> 独立的通道发送)

接收端:(解码 --> 串并转换 --> 显示器控制端(同时接收时钟信号实现同步))

二、TMDS

每个TMDS链路包括:3个RGB信号数据通道和1个时钟信号通道。
8位的视频、音频信号转换为最小传输、直流平衡10位数据。
最小环传输差分信号是通过异或及异或非等逻辑算法进行转换,前8位位原始信号运算获得,第9位指示运算方式,第10位对应直流平衡。
一般来说,HDMI传输的编码格式中要包含视频数据、控制数据和数据包(数据包中包含音频数据和附加信息数据,例如纠错码等)。HDMI 信息传输过程中,可以分为上述三种数据传输阶段。

三、视频时序标准

HDMI 显示器扫描方式从屏幕左上角一点开始,从左向到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。
完成一行扫描的时间称为水平扫描时间,其对应的频率称为行率;完成一帧(整屏)扫描的时间称为垂直扫描时间,其对应的频率称为场频率,即刷新一屏的频率,常见的有60Hz和75Hz,标准的显示的场频 60Hz。
时钟频率:以 [email protected](60Hz),每场对应806个行周期,其中768为显示行,每显示行包括 1344 点时钟,其中1024为有效显示显示区,由此可见需要点频率806*1344*60约 65MHz。

FPGA程序

下面探讨了FPGA的HDMI Demo程序开发。

一、TOP顶层代码

FPGA顶层代码包括:

  • 时钟PLL用来产生HDMI视频点频率。
  • I2C Master用来配置HDMI芯片。
  • HDMI输入数据,生成HDMI帧数据包。

二、时钟

PLL产生148.5MHz的时钟,对应的显示分辨率为1920*1080,其行周期为1125行,每行对应的点为2200pix。1125*2200*60=148.5MHz。

三、I2C Master配置HDMI

device address: 0x72
register address: 0x08
write data: 0x35

device address: 0x7a
register address: 0x2f
write data: 0x00

四、HDMI帧数据包生成模块

1. 接口

  • Video CLK
  • Video horizon Sync
  • Video vertical Sync
  • Video DE signal
  • Video RGB data

2. 行扫描时序

Front Porch + Sync + Back Porch + Active Video

3. 场扫描时序

Front Porch + Sync + Back Porch + Active Video

4. 代码片段解析

//1920x1080 148.5Mhz
`ifdef  VIDEO_1920_1080
parameter H_ACTIVE = 16'd1920;
parameter H_FP = 16'd88;
parameter H_SYNC = 16'd44;
parameter H_BP = 16'd148; 
parameter V_ACTIVE = 16'd1080;
parameter V_FP  = 16'd4;
parameter V_SYNC  = 16'd5;
parameter V_BP  = 16'd36;
...
`endif

parameter H_TOTAL = H_ACTIVE + H_FP + H_SYNC + H_BP;//horizontal total time (pixels)
parameter V_TOTAL = V_ACTIVE + V_FP + V_SYNC + V_BP;//vertical total time (lines)

这段代码用来定义不同分辨率下的行扫描和场扫描的时钟周期。

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        h_cnt <= 12'd0;
    else if(h_cnt == H_TOTAL - 1)//horizontal counter maximum value
        h_cnt <= 12'd0;
    else
        h_cnt <= h_cnt + 12'd1;
end

这段代码定义了一个行扫描的计数器。

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        v_cnt <= 12'd0;
    else if(h_cnt == H_FP  - 1)//horizontal sync time
        if(v_cnt == V_TOTAL - 1)//vertical counter maximum value
            v_cnt <= 12'd0;
        else
            v_cnt <= v_cnt + 12'd1;
    else
        v_cnt <= v_cnt;
end

这段代码定义了一个场扫描的计数器(垂直方向)。

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        active_x <= 12'd0;
    else if(h_cnt >= H_FP + H_SYNC + H_BP - 1)//horizontal video active
        active_x <= h_cnt - (H_FP[11:0] + H_SYNC[11:0] + H_BP[11:0] - 12'd1);
    else
        active_x <= active_x;
end

active_x记录了当前扫描的行的位置,即x位置,单位为pixel。

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        hs_reg <= 1'b0;
    else if(h_cnt == H_FP - 1)//horizontal sync begin
        hs_reg <= HS_POL;
    else if(h_cnt == H_FP + H_SYNC - 1)//horizontal sync end
        hs_reg <= ~hs_reg;
    else
        hs_reg <= hs_reg;
end

hs_reg给出了行扫描的SYNC信号。

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        h_active <= 1'b0;
    else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//horizontal active begin
        h_active <= 1'b1;
    else if(h_cnt == H_TOTAL - 1)//horizontal active end
        h_active <= 1'b0;
    else
        h_active <= h_active;
end

h_active给出了行扫描的active Video信号。

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        vs_reg <= 1'd0;
    else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//vertical sync begin
        vs_reg <= HS_POL;
    else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//vertical sync end
        vs_reg <= ~vs_reg;  
    else
        vs_reg <= vs_reg;
end

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
        v_active <= 1'd0;
    else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//vertical active begin
        v_active <= 1'b1;
    else if((v_cnt == V_TOTAL - 1) && (h_cnt == H_FP - 1)) //vertical active end
        v_active <= 1'b0;   
    else
        v_active <= v_active;
end

上述代码分别是生成场扫描的SYNC信号和active video信号。

assign video_active = h_active & v_active;

video_active信号为行扫描和场扫描都进入有效显示时序的标识。

else if(video_active)
        if(active_x == 12'd0)
            begin
                rgb_r_reg <= WHITE_R;
                rgb_g_reg <= WHITE_G;
                rgb_b_reg <= WHITE_B;
            end
        else if(active_x == (H_ACTIVE/8) * 1)
            begin
                rgb_r_reg <= YELLOW_R;
                rgb_g_reg <= YELLOW_G;
                rgb_b_reg <= YELLOW_B;
            end         

上述代码片段为在行扫描和场扫描都进入有效显示时序时,根据x轴的位置给出具体的RGB的数据。

assign de = video_active_d0;

DE信号为active video信号延时一个时钟周期,这是应为输出RGB数据时用了active video信号做了条件判断,所以输出的RGB数据相对于active video信号本来就延时了一个时钟周期,因此输出的DE信号也需要延时一个时钟周期。

5. 输出信号

输出信号有:

  • video clk: 148.5MHz
  • 水平扫描SYNC信号
  • 场扫描SYNC信号
  • DE信号
  • RGB数据

你可能感兴趣的:(fpga开发)