作者:MiS603开发团队
日期:20150911
公司:南京米联电子科技有限公司
论坛:www.osrc.cn
EAT博客:http://blog.chinaaet.com/whilebreak
博客园:http://www.cnblogs.com/milinker/
MiS603开发板 第十八章 模拟视频输入及测试
18.1模拟视频概述
大自然的信号都是模拟的,视频信号也不例外。视频信号是指电视信号、静止图象信号和可视电视图像信号。视频信号分为三种制式:PAL、NTSC和SECAM,接下来简单介绍一下这对于后期调试电路很有帮助。
PAL制又称为帕尔制。PAL是英文Phase Alteration Line的缩写,意思是逐行倒相,也属于同时制。“PAL”有时亦被用来指625 线,每秒25格,隔行扫描,PAL色彩编码的电视制式。NTSC是National Television Standards Committee的缩写,意思是“(美国)国家电视标准委员会”。NTSC负责开发一套美国标准电视广播传输和接收协议。SECAM制式,又称塞康制,SECAM是法文Sequentiel Couleur A Memoire缩写,意为“按顺序传送彩色与存储”,是一个首先用在法国模拟彩色电视系统。这只是简单的概述,关于PAL、NTSC和SECAM更详细的资料请参考视频技术手册。
既然PAL、NTSC、SECAM都是模拟信号,FPGA处理的是数字信号(有些FPGA内部自带AD,可以处理模拟信号,例如Altera的MAX10),因此中间需要一个芯片做转换,也就是一个ADC,学名叫做视频解码芯片。
18.2颜色空间
颜色空间也就是颜色的集合。有3个最常用的模型:RGB(计算机图形学)、YUV/YCbCr(视频系统)和CMYK(打印系统)。在此只介绍RGB和YUV/YCbCr。
RGB就是red、green、blue的缩写,也就是三原色,常用于计算机图像学中。常用的RGB格式有RGB555、RGB565、RGB888等。RGB565含义是red占5bit,green占6bit,blue占5biit,一个占16bit,颜色深度为65536色,常见的存储器有8bit、16bit等,RGB565的显示系统非常适合使用这种存储器。对于RGB555和RGB888也是一样。下表给出了常见的RGB888的颜色值,也就是前面做的彩条实验。
在YUV/YCbCr空间中,Y表示明亮度(Luminance、Luma)信号,U表示色度(Chrominance)信号,V表示浓度(Chroma)信号,只是对颜色空间另一种表示方法。常见的YUV格式有YUV422、YUV444等。YUV444格式如下图所示,每一个像素分别用24bit量化,分别量化成Y、Cb、Cr,各占8bit,从另一个方面说YUV444相当于RGB888,数据量是一样的。
YUV422格式如下图所示,它相当于在YUV444基础之上丢掉Cb和Cr数据,2个像素量化成32bit数据,包括2个Y,1个Cb,1个Cr,相当于1个像素需要16bit表示,相当于RGB565数据量。
除了YUV422、YUV444以外还有YUV411、YUV420,这些格式用于数据压缩,在此不做介绍。接下来解释一下YUV422中为啥丢失Cb和Cr数据,不丢失Y数据。Y是亮度信号,也就是以前的黑白电视机显示的信号,后来出现了彩色电视机,为了和黑白电视机兼容,于是出现了YUV格式数据。
下表是YUV空间模型给出的常用颜色值的Y、Cb、Cr数值,YUV444数值。
注:YUV空间中Y、Cb、Cr取值有范围限制
既然YUV和RGB都是对颜色空间表示,他们之间肯定有转换关系的。
YUV444和RGB888公式:
在这里要做2个文件,他们是yuv422_yuv444.v和yuv444_rgb888.v,yuv422_yuv444.v是讲YUV422格式视频流转换成YUV444视频流,采用简单的复制补充丢失的数据。
yuv444_rgb888.v模块仿真:
使用的公式:
这只是书本的公式,实际使用时要做一下变形。
R = 1.164(Y - 16) + 1.793(Cr - 128)
= 1.164Y + 1.793Cr - 248.128;
G = 1.164(Y - 16) - 0.534(Cr - 128) - 0.213(CB - 128)
= 1.164Y - 0.213Cb - 0.534Cr + 76.992;
B = 1.164(Y - 16) + 2.115(Cb - 128)
= 1.164Y + 2.115Cb - 289.344;
FPGA处理的数字数据,处理小数数据需要做一些转换,在这个模块中采用8bit量化小数,即对数据统一乘以256,到数据输出时在除以256,小数部分可以进行四舍五入,实际就是这么简单,值得注意的是在这个模块中设计了3级流水线,数据输出有3级延迟,为了同步,其余输入信号也做了3级延迟,如下图所示。从图中可以看到hs、vs、de、field信号有3个clock延迟,数据输入和输出也有3个clock延时,可以根据上面的公式检验一下输出对不对。
详细代码参考:6_03_MiS603_X25_YUVRGB_Sim
18.3隔行与逐行
先简单区分一个概念,隔行扫描(Interlace scan)和逐行扫描(Progressive scan)。如下图所示,这是隔行扫描示意图,也就是先显示奇数行,然后再显示偶数行,这只是其中一种隔行扫描的方式,用途比较广泛,除此之外还有隔2行、隔3行扫描。
隔行扫描示意图
如下图所示,这是逐行扫描示意图,也就从第一行扫描,一直扫描到最后一行。目前显示器是逐行扫描的。
逐行扫描示意图
隔行转逐行是通过DDR3内存实现的,详细内容请参考工程文件。
18.4 BT656数据格式
BT656是一种视频输出格式,TW2867视频输出是BT656格式,只有一小部分不一样,BT656格式时钟是27MHz,输出视频格式是YUV422,隔行输出。
BT656行数据结构
如上图所示是一行BT656数据结构,分成4段:EAV(4-byte)、BLANKING(280-byte)、SAV(4-byte)和有效数据(1440-byte),接下来分别介绍。
BLANKING:280-byte,0x80和0x10交替出现。
有效数据:1440-byte,一共720个像素,Y占720个数据,Cb和Cr分别占360个数据。
EAV和SAV:分别占4-byte,前三个字节相同,是0XFF,0X00,0X00,最后一个不同,根据这个字节进行解码。
EAV和SAV的4个字节结构
EAV和SAV的结构如上图所示,其中F、V、H含义:
F是场信号,0表示场1,1表示场2,也就是奇偶场。V表示场有效,0表示场数据有效,1表示是垂直消隐。H区分EAV和SAV信号。P3-P0只是校验保护位,由F、V、H进行异或运算得到。
如下图所示,这是一帧BT656数据格式,一共包括625行,每行1728个字节,有效数据大小是720x576,分成2场,每场720x288,其余行是消隐信号。
一场数据格式
BT656规定一行有1728个字节,一帧有625行,每秒传输25帧数据,8bit总线并行传输。1728x625x25=27000000=27M,经过计算就知道27MHz的来历了。在这625行中有用的数据是576行,在BT656视频格式中有效视频大小是720x576,其余的当做消隐处理。
18.5 BT656格式解码
压力来了,怎样才能做好BT656解码来适应不同的模块呢?^_^经过几次修改终于完成了,接下来分析一下。
在来看一下上图,这可是一个神奇的图,通过它可以解码BT656视频数据,看一下F、V、H信号,当H=0时是有效数据,H=1时是消隐信号;当V=1时是垂直消隐,V=0时是有效数据;当F=0时是奇数场数据,F=1时是是偶数场数据。
1)、寻找开始标志,分离H/V/F信号
//--寻找开始标志信号--// wire w_frame_start,H,F,V; assign w_frame_start = (data_i_d4 == 8‘hff)&&(data_i_d3 == 8‘h00)&&(data_i_d2 == 8‘h00); //--分析出H/V/F信号--// assign H = data_i_d1[4]; assign V = data_i_d1[5]; assign F = data_i_d1[6]; |
2)、数据缓存
reg hs_d0,vs_d0,filed_d0; /*generate hs signal,when hs = 0 is data,when hs =1 is blank.*/ [email protected](posedge clk_i) begin if(w_frame_start) begin hs_d0 <= H; end else begin hs_d0 <= hs_d0; end end /*generate vs signal,when vs = 0 is data,when vs =1 is blank.*/ [email protected](posedge clk_i) begin if(w_frame_start) begin vs_d0 <= V; end else begin vs_d0 <= vs_d0; end end /*generate filed signal.*/ [email protected](posedge clk_i) begin if(w_frame_start) begin filed_d0 <= F; end else begin filed_d0 <= filed_d0; end end reg hs_d1,vs_d1,filed_d1; [email protected](posedge clk_i) begin hs_d1 <= hs_d0; vs_d1 <= vs_d0; filed_d1 <= filed_d0; end |
H/V/F信号有了,接下来开始解码,根据这3个信号产生水平计数器和垂直计数器,关键代码如下。
1)、水平计数器
//--水平计数器--// [email protected](posedge clk_i) begin if((!hs_d1) && hs_d0)/*hs rising edge检测上升沿计数器清零*/ begin x_cnt <= 12‘d0; end else begin x_cnt <= x_cnt +1‘b1; end end |
水平计数器范围0-1727。
2)、垂直计数器
//--垂直计数器--// [email protected](posedge clk_i) begin if((!filed_d1) && filed_d0) /*检测到场信号上升沿计数器清0*/ begin y_cnt <= 12‘d0; end else if((!hs_d1) && hs_d0)/*检测到hs上升垂直计数器加1*/ begin y_cnt <= y_cnt + 1‘b1; end else begin y_cnt <= y_cnt; end end |
垂直计数器范围0-624。
根据水平计数器和垂直计数器可以重新生成行同步信号(hs)、场同步信号(vs)、数据有效信号(de)和场信号(field),从而实现和内存模块对接,实现视频缓存。
代码仿真:
bt656_decode模块是在bt656_encode模块基础之上完成,bt656_encode模块只是为了产生一个数据源,产生的数据红色和白色相见的YUV422数据,数据值如下图所示。
在编码输出时为了更好区分数据,第1个Y值加1。
垂直计数器计数范围0-624。
垂直计数器计数范围0-1727。
BT656输出100,66,212,65,128,181,120,180,对应Cb0,Y0,Cr1,Y1,Cb2,Y2,Cr3,Y3,转换成并行输出,即{Y0,Cb0},{Y1,Cr1},{Y2,Cb2},{Y3,Cr3},如下图所示。
场信号(vs)和奇数偶数场信号(filed)
行同步信号(hs)和数据有效信号(de)
更多详细代码请参考:6_03_MiS603_X25_BT656_Decode_Sim
18.6 TW2867硬件电路解析
本次设计使用的是专用模拟视频解码芯片TW2867,支持4路模拟视频输入,4路模拟音频输入,1路音频输出,视频输出是标准BT656格式。由于FPGA引脚限制,MIS603音频部分没有做,后续升级开发平台会加入这些功能。
TW2867电路图
如上图所示,输入4路模拟视频信号,经过TW2867输出数字视频流,每路视频流是BT656格式,视频接口连接到FPGA,TW2867配置引脚连接到STM32。由于FPGA引脚受限,MIS603没有把音频接口引出,后续退出的开发平台会完善此功能。TW2867和FPGA、STM32的连接方式如下表所示。
TW2867和FPGA连接方式
标号 |
对应的FPGA引脚 |
描述 |
CH1_CLKP |
P7 |
108MHz输入时钟 |
CH1_CLKN |
M7 |
27MHz输入时钟 |
CH1_D7 |
M9 |
第7位数据 |
CH1_D6 |
L7 |
第6位数据 |
CH1_D5 |
L8 |
第5位数据 |
CH1_D4 |
T7 |
第4位数据 |
CH1_D3 |
P6 |
第3位数据 |
CH1_D2 |
T6 |
第2位数据 |
CH1_D1 |
M6 |
第1位数据 |
CH1_D0 |
N6 |
第0位数据 |
注:TW2867输出BT656格式视频,BT656视频时钟27MHz,4路复合108MHz
TW2867和STM32连接方式
标号 |
对应的STM32引脚 |
描述 |
2867_reset |
PA8 |
TW2867复位引脚,低电平有效 |
scl |
PC9 |
I2C总线时钟 |
sda |
PC8 |
I2C总线数据 |
注:TW2867内部寄存器少于255个,一个I2C地址即可,地址为:0X50。
对于4路复合视频时钟108MHz,对硬件要求很高,数据线和时钟线等长布线。
18.7 TW2867寄存器配置
TW2867内部有很多寄存器,在此给出几个常用的寄存器及其含义,更多的内容请参考TW2867数据手册。
设备ID和芯片版本ID寄存器:
TW2867设备ID是0X19,通过读取0XFF的bit2-0确定版本信息。芯片ID正确读取以后才可以进行初始化。
软件复位控制寄存器:
这个是控制4路视频输出,音频输入,视频输出复位,写入1后复位,能够自恢复。上点后对芯片软件复位,向该寄存器写入0x3f。
锁相环时钟控制:
Bit6:PLL掉电控制,配置为0。
Bit5:PLL时钟电流偏置基准,配置为0。
Bit4:PLL时钟输出模式,TW2867外部时钟是27MHz,配置为1。
Bit3-2:PLL回路阻抗,配置为1。
Bit1-0:PLL电荷泵电流,配置为1。
这个寄存器主要是根据外部晶振配置PLL时钟的,配置值为0x15。
使能视频和音频检测:
这个寄存器是使能4路音频和4路视频检测,配置值为0xf
输出使能控制和时钟输出控制:
在这个寄存器中主要关心bit6配置为1,输出使能;bit3-2配置为0,CLKNO1输出27MHz时钟,bit1-0配置为2,CLKPO1输出108MHz时钟,通过这2个时钟可以把4路视频
信号分开。这个寄存器配置为0x42。
Bit6:配置为1,标准ITU-R656格式。
Bit5-4:选择视频复合后输出引脚,配置为1,从CHID1输出。
Bit3:配置为0,正常ITU-R656格式。
Bit2:配置为0,输出视频中有EAV-SAV信号。
Bit1:配置为1,bit7-4是EAV/SAV编码。
Bit0:配置为0,奇数场和偶数场行数相等。
综上,这个寄存器配置为0x52。
视频通道输出控制:
这个寄存器配置为0x02,4路视频通过时分复用到VD1[7:0]输出,硬件设计连接到VD1。
视频功能控制:
Bit7:配置为0,视频视频数据输出限制到0-254。
Bit6:配置为1,ACKG的输入参考是ASYNP。
Bit5:配置为0,输出格式是YUV422格式。
Bit4:配置为1。
Bit3:配置为0,仅用于测试。
Bit2:配置为0,消隐时数据输出0x80和0x10。
Bit1:配置为0,ITU-R BT656同步信号在消隐部分。、
Bit0:配置为1,HACTIVE在垂直消隐期间使能。
这个寄存器配置为0x51。视频状态寄存器:
Bit7:0 = 检测到视频;1 = 没有检测到视频。
Bit6:0 = 水平同步锁相环没有锁住;1 = 水平同步锁相环视频锁住。
Bit5:0 = 载波锁相环没有锁住;1 = 载波锁相环锁住了。
Bit4:0 = 检测到奇数场视频;1 = 检测到偶数场视频。
Bit3:0 = 垂直逻辑信号被锁住;1 = 垂直逻辑信号没有锁住。
Bit1:0 = 检测到颜色信号;1 =没有检测到颜色信号。
Bit0:0 = 检测到奇数场视频;1 = 检测到偶数场视频。
这4个寄存器是只读寄存器,通过读取每个视频通道对应的寄存器可以确定通道视频的状态,对于初期调试电路很方便。关于其他配置参考STM32配置文件。
18.8 TW2867时序分析
之前介绍了BT656格式时钟27MHz的来源,TW2867支持4路实时BT656视频,采样时分复用,最大时钟频率是108MHz,因此需要一个108MHz的时钟输入引脚,考虑到方便解调出每路视频信号增加了一个27MHz的时钟输入信号,再加上8根数据,这样10根线就可以输入4路视频信号,在硬件设计上大大简化,降低了布线的复杂度。
如下图所示,TW2867在4路视频复合时的时序图,那就是4个通道视频轮流输出,即通道1视频数据、通道2视频数据、通道3视频数据、通道4视频数据,然后重复。
TW2867的4路视频时分复用
通过了解视频数据复合方式,那解复合程序就可以设计了,那面说说思路。采用时分复用,每个通道数据轮流输出,那就需要一个计数器实现把每个通道的数据分离,即将108MHz时钟数据分成4个27MHz时钟数据。由于是4路视频,需要产生一个模长为4的计数器,根据计数器的数据把数据分配到4个视频通道上。
1)、模4计数器
reg[1:0]data_cnt = 2‘d0; [email protected](posedge clk_108m_i) begin data_cnt <= data_cnt + 2‘d1; end |
2)、根据计数器将数据108MHz数据分成4部分
//put 1-multiple channel data into 4-channel separately. //--数据分成4部分,不管是哪个通道--// [email protected](posedge clk_108m_i) begin case(data_cnt) 2‘d0://-第1部分数据-// begin data0 <= mux_data_i; data1 <= data1; data2 <= data2; data3 <= data3; end 2‘d1://-第2部分数据-// begin data0 <= data0; data1 <= mux_data_i; data2 <= data2; data3 <= data3; end 2‘d2://-第3部分数据-// begin data0 <= data0; data1 <= data1; data2 <= mux_data_i; data3 <= data3; end 2‘d3://-第4部分数据-// begin data0 <= data0; data1 <= data1; data2 <= data2; data3 <= mux_data_i; end default://-默认-// begin data0 <= data0; data1 <= data1; data2 <= data2; data3 <= data3; end endcase end |
Chipscope测试:
注:连接上摄像头
采样时钟108MHz,从图中可以看到这个108MHz的时钟数据被分成4部分,每个部分之间呈对应关系。
4个通道视频分出来了,但是怎样知道哪个视频通道对应的标号呢?这的确是一个问题。那看看下面这个表格吧,不知道发现了没,就是那个在SAV/EAV的4个字节中的第4个字节有每个通道的标志,通过它就行可以区分每个视频通道了。
TW2867的4路视频复合后每个通道的标志
第4个字节就是前文提到的含有F、V、H信号的字节,标准BT656视频流的这个字节低4位是校验信号,但是TW2867是用来做了通道标志,这个一个和标准BT656视频格式不同的地方。通过这个标志就可以解析出来通道标志了。
代码解析:
1)、寻找通道ID
//--找到帧头--// wire w_frame_start; assign w_frame_start = (data0_d4 == 8‘hff)&&(data0_d3 == 8‘h00)&&(data0_d2 == 8‘h00); reg[3:0]data0_id; //--找到一个通道的标志ID--// [email protected](posedge clk_27m_i) begin if(w_frame_start) begin data0_id <= data0_d1[3:0]; end else begin data0_id <= data0_id; end end |
2)、根据通道ID把数据分配到每个通道上
reg[7:0]ch0_data_d0; reg[7:0]ch1_data_d0; reg[7:0]ch2_data_d0; reg[7:0]ch3_data_d0; //--根据通道ID分配区分每个通道--// [email protected](clk_27m_i) begin case(data0_id) 2‘d0://-通道0-// begin ch0_data_d0 <= data0_d0; ch1_data_d0 <= data1_d0; ch2_data_d0 <= data2_d0; ch3_data_d0 <= data3_d0; end 2‘d1://-通道1-// begin ch0_data_d0 <= data3_d0; ch1_data_d0 <= data0_d0; ch2_data_d0 <= data1_d0; ch3_data_d0 <= data2_d0; end 2‘d2://-通道2-// begin ch0_data_d0 <= data2_d0; ch1_data_d0 <= data3_d0; ch2_data_d0 <= data0_d0; ch3_data_d0 <= data1_d0; end 2‘d3://-通道3-// begin ch0_data_d0 <= data2_d0; ch1_data_d0 <= data2_d0; ch2_data_d0 <= data3_d0; ch3_data_d0 <= data0_d0; end default: begin ch0_data_d0 <= ch0_data_d0; ch1_data_d0 <= ch1_data_d0; ch2_data_d0 <= ch2_data_d0; ch3_data_d0 <= ch3_data_d0; end endcase end |
Chipscope测试:
通道1上的标志的低4bit为0H,刚好为第1通道数据。
通道2上的标志的低4bit为1H,刚好为第2通道数据。
通道3上的标志的低4bit为2H,刚好为第3通道数据。
通道4上的标志的低4bit为2H,刚好为第4通道数据。
18.9 YUV422转YUV444
在颜色空间中给讲解了YUV422和YUV444格式视频流,TW2867输出的YUV422,显示器能够接受RGB数据,YUV444能够转换成YUV444,前面已经做了讲解,要想顺利实现显示,那就需要将YUV422数据格式转换成YUV444格式。在YUV422转换到YUV444有很多种算法,其中最简单的就是直接复制补充丢失的数据。
1)、产生分离cb cr标志
//-产生分离cb cr标志-// reg cb_cr_flag; [email protected](posedge clk_i) begin if(!de_i) begin cb_cr_flag <= 1‘b0; end else begin cb_cr_flag <= cb_cr_flag + 1‘b1; end end |
2)、分离cb cr
//-分离cb cr-// reg[7:0]y_d0,cb_d0,cr_d0; [email protected](posedge clk_i) begin y_d0 <= y_cbcr_i[15:8]; if(!cb_cr_flag) begin cb_d0 <= y_cbcr_i[7:0]; cr_d0 <= cr_d0; end else begin cb_d0 <= cb_d0; cr_d0 <= y_cbcr_i[7:0]; end end |
18.10基于FPGA的模拟输入视频模块测试
前面讲解了许多模块,有的给出了仿真文件,有的给出了ChipScope分析,正式这些文件组成了整个TW2867测试工程。
TW2867测试框图
如上图所示,整个TW2867测试过程,首先是思路视频解调模块,分出4路视频,然后进行解码,视频进入DDR3缓存,出DDR3缓存,VGA/HDMI驱动,格式转换,最后显示,通过判断显示图像的质量来确定解码芯片是否正常工作。
1:HDMI时序参数定义文件,支持不同分辨率,只需要更改宏定义即可实现。
2:TW2867测试顶层文件。
3:TW2867输入时钟管理,复位。
4:VGA/HDMI驱动时钟产生。
5:TW2867视频解调顶层模块。
6:DDR3顶层封装,包含输入输出FIFO、突发控制全部封装在内部。
7:yuv422转yuv444模块。
8:显示模块,包含VGA/HDMI驱动,yuv444转rgb888模块。
9:ucf文件,包括引脚分配和时钟约束。
关于其他代码参考:6_03_MiS603_X25_TW2867_Test
18.11小结
在本节了解了BT656视频格式、隔行扫描、逐行扫描、TW2867软件硬件设计。本章给出了一个完成是视频采集、缓存、显示的例程,这是视频图像处理的前提,大家好好学习。有问题到论坛发帖。