HDMI采用和DVI相同的传输原理-TMDS(Transition Minimized Differential signal),即最小化传输差分信号。
TMDS传输系统分为:发送端;接收端。
发送端:(RGB信号的24位并行数据,R,G,B三原色各8bit编码;--> 编码 --> 并串转换 --> 独立的通道发送)
接收端:(解码 --> 串并转换 --> 显示器控制端(同时接收时钟信号实现同步))
每个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的HDMI Demo程序开发。
FPGA顶层代码包括:
PLL产生148.5MHz的时钟,对应的显示分辨率为1920*1080,其行周期为1125行,每行对应的点为2200pix。1125*2200*60=148.5MHz。
device address: 0x72
register address: 0x08
write data: 0x35
device address: 0x7a
register address: 0x2f
write data: 0x00
Front Porch + Sync + Back Porch + Active Video
Front Porch + Sync + Back Porch + Active Video
//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信号也需要延时一个时钟周期。
输出信号有: