目录

FPGA有关HDMI的一些知识,程序源自bilibi正点原子

目录

FPGA有关HDMI的一些知识,程序源自bilibi正点原子

回顾串口知识,RS232(两路单端信号传输);RS422(四路差分信号传输,两路接收两路发送)延长数据的传输距离和抗干扰能力;RS485(两路差分信号传输),简化电路,将原本的四路差分信号缩减为两路差分信号,既能接收也可发送。

VGA、DVI和HDMI三种接口,VGA接口最初针对模拟设备,故传输模拟信号,而随后的DVI和HDMI则传输数字信号,dvi接口一共被划分了5种,一般最常见的也就是效果最好的dvi_d双通道,而HDMI接口则是当下的主流音视频接口,以其传输的数据量、支持的高分辨率和刷新率饱受好评。至于最新兴起的DP接口,规格已经发展到dp2.1标准,但还没有具体设备应用此标准。

接下来附上正点原子有关hdmi实验的程序源码,另外结合自己在理解代码中碰上的问题先附上一下几张图和一些说明:

首先是整个实验的RTL视图:

https://i-blog.csdnimg.cn/direct/eb404d79886d482f94c3612831cf5059.png

本实验采用的是RGB888格式,也就是R、G、B分别为8bit大小,1:1:1,在下图1中将本次HDMI实验分为了两个大部分,第一个是编码,也就是tmds最小化差分传输协议的第一部分,将原本的8位数据经过编码转换为10位的数据,编码过程数据都是并行传输。结合下面的图2,3可知,编码过程是将数据传输过程分成了4个通道,R、G、B以及时钟通道,因为编码过程是并行传输,而后面第二大部分涉及到数据传输的并串转换,在整个实验过程设置了两个时钟速率,分别对应并行数据传输速率(由驱动的显示屏的分辨率和刷新率决定),以及串行数据传输速率(5倍于并行数据传输速率),在此说明,理论上串行速率应为并行速率的10倍(并串转换为10bit输出),但本次实验中采用了ddr,因此在PLL锁相环设置速率时将串行速率设置为了并行速率的5倍。

再对数据传输的编码过程做简单说明,8位到10位的转换,转换后的10位数据前八位依旧为原始的RGB数据,第9位来确定异或或者异或非运算,第10位则是进行电流平衡,尽量保证每组数据的0和1数量相同。而对于tmds协议在编码过程中,除了三个颜色通道每个通道对应的8位数据,还有两位的控制信号,对于本次实验不需要传输音频,所以R、G两个通道对应的控制信号均为0,仅有B通道的控制信号传输行场同步信号(HSYNC/VSYNC)。

https://i-blog.csdnimg.cn/direct/ffa6b6522d4a4d0bade73aca50072579.png

https://i-blog.csdnimg.cn/direct/d781faf60bc14c0db1706de7e439a130.png

https://i-blog.csdnimg.cn/direct/913eae4538c74ffcaaa96038316364de.png

以下,首先需要了解,HDMI在扫描过程中是从屏幕左上角逐行扫描,每行结束后从下一行再开始,这也说明为什么1920*1020为什么被称为1080P(行),而对应则会有一段时间的消隐期,也就是非有效数据的区间,而对应消隐期则包含显示后沿,显示前沿,同步信号,如下图,而整个扫描周期也就包含了消隐期和有效数据(行、场都是)。

https://i-blog.csdnimg.cn/direct/621fca2915f54b5cad9a446609e56d50.png

以下是在电子束扫描过程中的有效信号区域的示意图:

https://i-blog.csdnimg.cn/direct/0e49708db5ab4c2f9836790c3a643d3e.jpeg

而对于程序中的"-2’d2"、"+1’d1"的偏移量的处理,则是保证上图中有效显示区域的开始点和结束点正确,以及确保数据的起始点正确对齐。

//video_driver
module video_driver(
    input           	pixel_clk	,
    input           	sys_rst_n	,
		
    //RGB接口	
    output          	video_hs	,     //行同步信号
    output          	video_vs	,     //场同步信号
    output          	video_de	,     //数据使能
    output  	[23:0]  video_rgb	,    //RGB888颜色数据
    output	reg			data_req 	,
	
    input   	[23:0]  pixel_data	,   //像素点数据
    output  reg	[10:0]  pixel_xpos	,   //像素点横坐标
    output  reg	[10:0]  pixel_ypos    //像素点纵坐标
);

//parameter define

//1280*720 分辨率时序参数
parameter  H_SYNC   =  11'd40;   //行同步
parameter  H_BACK   =  11'd220;  //行显示后沿
parameter  H_DISP   =  11'd1280; //行有效数据
parameter  H_FRONT  =  11'd110;  //行显示前沿
parameter  H_TOTAL  =  11'd1650; //行扫描周期

parameter  V_SYNC   =  11'd5;    //场同步
parameter  V_BACK   =  11'd20;   //场显示后沿
parameter  V_DISP   =  11'd720;  //场有效数据
parameter  V_FRONT  =  11'd5;    //场显示前沿
parameter  V_TOTAL  =  11'd750;  //场扫描周期

//1920*1080分辨率时序参数
//parameter  H_SYNC   =  12'd44;   //行同步
//parameter  H_BACK   =  12'd148;  //行显示后沿
//parameter  H_DISP   =  12'd1920; //行有效数据
//parameter  H_FRONT  =  12'd88;  //行显示前沿
//parameter  H_TOTAL  =  12'd2200; //行扫描周期
//
//parameter  V_SYNC   =  12'd5;    //场同步
//parameter  V_BACK   =  12'd36;   //场显示后沿
//parameter  V_DISP   =  12'd1080;  //场有效数据
//parameter  V_FRONT  =  12'd4;    //场显示前沿
//parameter  V_TOTAL  =  12'd1125;  //场扫描周期

//reg define
reg  [11:0] cnt_h;
reg  [11:0] cnt_v;
reg       	video_en;

//*****************************************************
//**                    main code
//*****************************************************

assign video_de  = video_en;
assign video_hs  = ( cnt_h < H_SYNC ) ? 1'b0 : 1'b1;  //行同步信号赋值
assign video_vs  = ( cnt_v < V_SYNC ) ? 1'b0 : 1'b1;  //场同步信号赋值

//使能RGB数据输出
always @(posedge pixel_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		video_en <= 1'b0;
	else
		video_en <= data_req;
end

//RGB888数据输出
assign video_rgb = video_de ? pixel_data : 24'd0;

//请求像素点颜色数据输入
always @(posedge pixel_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		data_req <= 1'b0;
	else if(((cnt_h >= H_SYNC + H_BACK - 2'd2) && (cnt_h < H_SYNC + H_BACK + H_DISP - 2'd2))
                  && ((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK+V_DISP)))
		data_req <= 1'b1;
	else
		data_req <= 1'b0;
end

//像素点x坐标
always@ (posedge pixel_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        pixel_xpos <= 11'd0;
    else if(data_req)
        pixel_xpos <= cnt_h + 2'd2 - H_SYNC - H_BACK ;
    else 
        pixel_xpos <= 11'd0;
end
    
//像素点y坐标	
always@ (posedge pixel_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        pixel_ypos <= 11'd0;
    else if((cnt_v >= (V_SYNC + V_BACK)) && (cnt_v < (V_SYNC + V_BACK + V_DISP)))
        pixel_ypos <= cnt_v + 1'b1 - (V_SYNC + V_BACK) ;
    else 
        pixel_ypos <= 11'd0;
end

//行计数器对像素时钟计数
always @(posedge pixel_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        cnt_h <= 11'd0;
    else begin
        if(cnt_h < H_TOTAL - 1'b1)
            cnt_h <= cnt_h + 1'b1;
        else 
            cnt_h <= 11'd0;
    end
end

//场计数器对行计数
always @(posedge pixel_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        cnt_v <= 11'd0;
    else if(cnt_h == H_TOTAL - 1'b1) begin
        if(cnt_v < V_TOTAL - 1'b1)
            cnt_v <= cnt_v + 1'b1;
        else 
            cnt_v <= 11'd0;
    end
end

其他程序可参考:

补充:

对异步复位信号的同步处理,连续两次赋值,若只赋值一次则可能会出现亚稳态情况,若要求同步处理的复位信号高电平有效,则需在第一次赋值时赋低电平,否则则需赋值高电平。

module asyn_rst_syn(
    input clk,          //目的时钟域
    input reset_n,      //异步复位,低有效
    
    output syn_reset    //高有效
    );
    
//reg define
reg reset_1;
reg reset_2;
    
//*****************************************************
//**                    main code
//***************************************************** 
assign syn_reset  = reset_2;
    
//对异步复位信号进行同步释放,并转换成高有效
always @ (posedge clk or negedge reset_n) begin
    if(!reset_n) begin
        reset_1 <= 1'b1;
        reset_2 <= 1'b1;
    end
    else begin
        reset_1 <= 1'b0;
        reset_2 <= reset_1;
    end
end
    
endmodule

https://i-blog.csdnimg.cn/direct/d410f34d70f741b191382e68eb3bc5e8.jpeg