赞
踩
笔者在这里使用的开发板是正点原子的达芬奇开发板,FPGA型号为XC7A35TFGG484-2。参考的课程是正点原子的课程手把手教你学达芬奇&达芬奇Pro之FPGA开发篇。
HDMI,全称为High Definition Multimedia Interface,即高清多媒体接口。它不仅可以传输视频信号,还可以传输音频信号。上图所示的HDMI接口即为最常见的HDMI-A型接口。有19个引脚,尺寸为13.9×4.45mm,广泛应用于笔记本,投影仪,显示器等,工作频率约为160MHz。MDMI有不同的协议版本,比较重要的几个协议版本如1.0(2002.12)、1.3(2006.6)、2.0(2013.9)、2.1(2017.1),协议版本越高级,HDMI信号的传输速率、支持的分辨率以及帧率就越高。目前主流的HDMI协议版本为2.0。
HDMI的引脚及其定义如下图所示:
在HDMI协议中,总共有4组差分线,每组分别由+信号
、-信号
、屏蔽信号
组成。四组信号线分别传输R、G、B信号以及时钟信号。CEC
为HDMI的扩展功能,可以使用这一条线传输两个设备之间的控制信息,SCL
、SDA
是HDMI的I2C接口,可以实现不同设备之间EDID信息传输(Extended Display Identification Data 、外部显示设备标识数据——指DDC通讯中传输的显示设备数据)。热插拔检测线用于检测是否有从机连接到主机。
HDMI的工作原理图如下所示。图中,TMDS指最小化传输差分信号(Transition Minimized Differential Signaling),是指被转换后的传输信号。视频信号Video
和音频信号Audio
通过一种特定的编码方式转换为10bit的串行差分信号,这种信号即成为TMDS信号。在主机上进行编码,在从机上进行解码,从而实现两个设备之间的信息交互。
上图展示了RGB-888格式下的TMDS信号和TERC4转换以及连接方式。视频信息采用TMDS进行编码,音频信号采用TERC4进行编码。每一路信号都是并行信号,HSYNC
和VSYNC
是显示的水平同步信号和竖直同步信号,这两个信号只和蓝色通道一起编码。绿色通道和红色通道的CTL0-3
用来传输控制信号。TERC4频编码较为复杂,本文章不涉及。时钟信号也需要编码,但是较为简单,上图中没有展示出来。
当HDMI只传递视频信息不传递音频信息,HDMI协议就可以退化为DVI协议。DVI也使用
TMDS进行编码。DVI编码中有一个视频数据使能VDE
信号,当它拉高时传递像素信号,当它拉低时传递控制信号和水平数值同步信号。
TMDS指最小化传输差分信号(Transition Minimized Differential Signaling),主要适用于HDMI和DVI视频信号的编码。它的编码方式是将原有的8bit数据编码为10bit数据。
8bit
数据:通过同或/异或算法得到。bit9
:反映前8bit数据的运算方式,如果是0,则说明前8bit通过异或非(同或)方式得到的,如果是1,就说明是通过异或方式得到的。bit10
:直流平衡位。在高速的差分信号传输中,通常在接口处采用交流耦合,即会在接口处添加一个隔直电容去掉交流量。如果传输的信号长时间保持不变,就有可能在信号接收端出现直流偏移,导致解码错误。所以我们在编码时添加一个直流平衡位,如果前面数据1比较多,那么bit10 = 0
,反之,如果前面数据0比较多,那么bit10 = 1
。
TMDS的编码过程可以由下图所示:
参数名称 | 含义 |
---|---|
D C1 C0 DE | D 是视频信号, C 是控制信号, DE 是使能信号 |
Cnt(t) | 寄存器参数,用来存储第t次编码中1的个数比0的个数多多少(为了满足TMDS减少上冲下冲和确保直流平衡的要求) |
N1{x} | 输入信号中1的个数 |
N0{x} | 输入信号中0的个数 |
q_m | 临时寄存的数据输出 |
q_out | 编码输出 |
场同步信号VSYNC
是一张图片开始的起始标志。在显示一张图片时,各个像素逐行点亮。行同步信号HSYNC
是上一行像素数据切换到下一行像素数据的标志。每当它有效(不同厂家的行同步信号的有效电平可能不同,可能是高电平有效,也有可能是低电平有效,也有可能是一段特定的波形有效)时,切换像素数据显示的行。
在老式电视机中,每当一行数据显示完成后,电子束轰击位置切换到下一行显示需要一定的时间,这一段时间称为准备时间(行同步时间)。随着时间的推移,定义这一段时间成为一种行业规范,通常被称为消影时间。每一行像素数据的传输从行同步后延HBP
开始,从行同步前沿HFP
结束,从前一行的行同步前沿到下一行的行同步后沿的时间就是准备时间,在这一段时间内显示屏不点亮任何的像素点。
显示到一幅图像的最后一个像素点时,需要转移到显示屏的第一个像素点刷新数据,这一段准备时间甚至比行同步前后沿之间的准备时间更长(场同步时间),同样可以定义场同步前沿VFP
和场同步后沿VBP
。循环往复,不断切换,就会形成动态的动画。
不同大小的屏幕驱动时钟频率不同,原因在于像素点的数量不同,要实现近似的帧率和显示效果,就需要不同的驱动频率。
图像(视频)的显示时序如下所示:
原语:英文名称Primitive,是Xilinx针对其器件特征开发的一系列常用模块名称,涵盖了FPGA开发过程中的常用领域,方便用户直接调用FPGA的底层组件。以Xilinx为例,共分为10类:计算组件、IO端口组件、寄存器/锁存器、时钟组件、处理器组件、移位寄存器、配置和检测组件、RAM/ROM组件、Slice/CLB组件以及G-tranceiver。可以将原语理解为一段特殊的代码。实际上,调用原语是在实例化某个Xilinx的内置模块。
原语的好处在于原语可以之间看作为“库函数”,可以直接例化调用,比创建IP要更加方便,功能也更全面,可以有效提高开发效率。
IO端口组件是Xilinx的一类原语。IO组件中一共包含了21个原语,对应21个功能。在本次实验中主要采用并转串OSERDES
和单端转差分OBUFDS
两个原语。
IO组件的结构如下图所示。图中IDELAYE2
和ODELAYE2
分别是输入延迟和输出延迟,主要作用是为了解决高速信号传输中信号线可能不等长的问题(等待最长的一根线数据到来后再读取数据)。ILOGICE2
和OLOGICE2
中主要包含了IDDR
和ODDR
的资源,用于双边沿取样。ISERDESE2
的作用是将单端输入的串行数据转换为并行数据,OSERDESE2
的作用是将并行数据转换为单端串行数据输出。
达芬奇使用的FPGA芯片为A7系列,其中没有
HPBANK
,所以没有ODELAYE2
。ZYNQ也只有7030以上系列才有HPBANK
,所以一般使用的FPGA芯片是没有ODELAYE2
的。
IOB的结构如下所示,在本次实验中它主要完成单端转差分的操作。因为差分信号至少需要两条线,所以一个IOB是无法完成的,至少需要两个IOB才能完成这个功能。
OSERDESE2
OSERDESE2
工作原理对于一个并行数据,要想把它转换为串行数据有以下两种做法:
OSERDESE2
的结构如下图所示。该组件可以分成三部分,上面的TCE
,TBYTEIN
和一部分电路组成三态控制;中间的CLK
、CLKIDIV
、RST
组成时钟控制部分,CLK
为快速时钟(5倍频),CLKDIV
是低速时钟(1倍频);下面的OCE
、D1-D8
、OQ
、OFB
等组成并转穿的转换部分。数据转换数据只有8个数据输入口,要想实现10转1,则需要将两个OSERDESE2
级联使用。
OSERDESE2
级联示意图 级联时需要注意:根据硬件的硬性要求,从模式的OSERDESE2
的D1-D2
不支持输入,只能从D3
开始输入引脚,即可以选择D3-D8
。
OSERDESE2
工作时序图 下面是OSERDESE2
工作在普通模式和三态模式的两种时序工作图。第一张图数据为8位并行转串行,CLK
和CLKDIV
的周期之比为4:1。第二张图数据为4位并行转串行,并且包含T1-T4
三态门控制,CLK
和CLKDIV
的周期之比为2:1。
T1-T4
均为高电平有效,对应TQ
将要输出的数据。且在当前CLKDIV
周期采样,下个周期输出。在TQ
高电平期间,可以执行输入操作。
OSERDESE2
原语调用实例
在原语调用实例中,需要特别注意以下几个参数:
.DATA_RATE_OQ("DDR")
:采用双边沿采样;.DATA_WIDTH(10)
:将要转换的数据宽度;.SERDES_MODE("MASTER")
:设置级联下的主从模式;.SHIFTOUT1/2(SHIFTOUT1/2)
、.SHIFTIN1/2(SHIFTIN1/2)
:级联下的数据线连接方式,注意不要连错。OSERDESE2 #( .DATA_RATE_OQ("DDR"), // DDR, SDR .DATA_RATE_TQ("DDR"), // DDR, BUF, SDR .DATA_WIDTH(10), // Parallel data width (2-8,10,14) .INIT_OQ(1'b0), // Initial value of OQ output (1'b0,1'b1) .INIT_TQ(1'b0), // Initial value of TQ output (1'b0,1'b1) .SERDES_MODE("MASTER"), // MASTER, SLAVE .SRVAL_OQ(1'b0), // OQ output value when SR is used (1'b0,1'b1) .SRVAL_TQ(1'b0), // TQ output value when SR is used (1'b0,1'b1) .TBYTE_CTL("FALSE"), // Enable tristate byte operation (FALSE, TRUE) .TBYTE_SRC("FALSE"), // Tristate byte source (FALSE, TRUE) .TRISTATE_WIDTH(4) // 3-state converter width (1,4) ) OSERDESE2_inst ( .OFB(OFB), // 1-bit output: Feedback path for data .OQ(OQ), // 1-bit output: Data path output // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) .SHIFTOUT1(SHIFTOUT1), .SHIFTOUT2(SHIFTOUT2), .TBYTEOUT(TBYTEOUT), // 1-bit output: Byte group tristate .TFB(TFB), // 1-bit output: 3-state control .TQ(TQ), // 1-bit output: 3-state control .CLK(CLK), // 1-bit input: High speed clock .CLKDIV(CLKDIV), // 1-bit input: Divided clock // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) .D1(D1), .D2(D2), .D3(D3), .D4(D4), .D5(D5), .D6(D6), .D7(D7), .D8(D8), .OCE(OCE), // 1-bit input: Output data clock enable .RST(RST), // 1-bit input: Reset // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each) .SHIFTIN1(SHIFTIN1), .SHIFTIN2(SHIFTIN2), // T1 - T4: 1-bit (each) input: Parallel 3-state inputs .T1(T1), .T2(T2), .T3(T3), .T4(T4), .TBYTEIN(TBYTEIN), // 1-bit input: Byte group tristate .TCE(TCE) // 1-bit input: 3-state clock enable );
OBUFDS
OBUFDS
的调用较为简单,直接按照如下的格式调用即可。
OBUFDS #(
.IOSTANDARD("TMDS_33")
) OBUFDS_inst (
.O(O), // 1-bit output: Diff_p output (connect directly to top-level port)
.OB(OB), // 1-bit output: Diff_n output (connect directly to top-level port)
.I(I) // 1-bit input: Buffer input
);
以正点原子的达芬奇开发板为例,HDMI A和HDMI B的结构完全相同:
达芬奇Pro上的HDMI B接口只做输出使用,不作输入使用,故电路结构有所不同:
当仅需要将HDMI作为输出使用时,正点原子历程的做法是不检测HOT PLUG
信号,在任何时刻都将信号输出到端口,但是这样的做法明显不够严谨,这样做会白白增加FPGA的功耗,可以根据需要对正点原子的代码进行改进。但作为彩条显示实验,重点在于视频信号的TMDS编码,以及并串转换原语。
本次实验的目标是驱动FPGA上的HDMI接口,在显示器上显示720p(1280*720)的彩条图案,像素时钟约为75MHz(根据标准应该是74.25MHz,设置为75MHz可以简化约束操作)。
asyn_rst_syn
:异步复位,同步释放:人为的复位信号来临时,不需要考虑同步和异步的问题,因为复位按键按下的持续时间至少是毫秒级别,远远大于一个时钟周期;但是复位信号释放时,如果没有同步释放模块,就会因为芯片内部不同模块电路复位信号端口距离复位引脚的远近不同而导致各个模块接收到复位信号的时间可能不同。为了解决这个问题,将原始的rst_n
信号打两拍输出,并且根据后接模块的需要将复位信号改为高电平有效:module asyn_rst_syn ( input clk, //目的时钟域 input reset_n, //异步复位,低有效 output syn_reset //高有效 ); // reg define reg reset_1; reg reset_2; 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
持续不定期更新完善中……
原创笔记,码字不易,欢迎点赞,收藏~ 如有谬误敬请在评论区不吝告知,感激不尽!博主将持续更新有关嵌入式开发、FPGA方面的学习笔记。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。