一、基于FPGA的GV7600驱动控制器设计,按照BT1120协议传输YCbCr数据
二、模块名称
三、模块输入输出端口定义(interface)
四、模块功能(functions)
五、模块行为描述(behavior descriptions)
六、时序说明图(diagrams)
七、注意事项
八、参考文献及代码
九、经验总结
SDI Data Interface
PCB板号:176-A-1,根据10bit HD模式,在硬件pcb上配置如下4个引脚(红色字体)
信号名称 |
信号属性 |
信号说明 |
Sys_clk |
input |
系统时钟:30 MHz |
Pclk |
output |
锁相环输出给GV7600时钟:148.5MHZ |
Reset |
output |
GV7600低电平复位1.8ms |
Sdi_data |
output |
输出数据给GV7600 |
|
|
|
DETECT_TRS |
硬件拉高 |
将H:V:F timing信号嵌入到并行输入数据流 |
656_BYPASS |
硬件拉高 |
选择video模式 |
20BIT/10BIT |
硬件拉低 |
选择输入10bit数据位数 |
RATE_SEL0 |
硬件拉低 |
根据分辨率要求 |
|
|
|
根据项目需求,通过FPGA驱动GV7600输出SDI信号
(输入:Sys_clk,
输出:Pclk,Sdi_data,Reset);
(输入:Clk,Sys_rstn,BT1120_data_out,
输出:Pclk,Sdi_data,Reset,);
(输入:Clk,Sys_rstn,
输出:BT1120_data_out,);
(输入:Sys_clk,
输出:c0,locked,);
模块分为4个子模块:1.顶层模块:做例化;2.驱动模块:驱动GV7600芯片,FPGA输出GV7600复位,时钟和数据信号;3. BT1120模块:按照BT1120协议传输数据;4.锁相环调用模块:输出148.5Mhz时钟(根据分辨率决定时钟频率);
图1 SDI接口流程图
图2 10bit复用 SDI接口时序
根据《GV7600-SDI并转串datasheet》,FPGA主要实现驱动GV7600功能,具体需求如下:
1080p
|
20位 |
10位复用 |
并行数据流中的数字行 |
2200 |
4400 |
并行数据流中的数字行消隐 |
4+272+4 |
8+544+8 |
并行数据流中的有效行 |
1920 |
3840 |
10bit
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
SAV0 |
SAV1 |
SAV2 |
SAV3 |
SAV4 |
SAV5 |
SAV6 |
SAV7 |
`ifdef BT1120_1080P_30HZ
parameter ROW_MAX = 1124; //每场总计行数
parameter COL_MAX = 4399; //每行总计像素点数
parameter ROW_BLACK_S = 41; //开始场有效
parameter ROW_BLACK_E = 1121; //开始场消隐
parameter SAV_COL = 552; //276*2
parameter BLANK_START = 7; //开始272*2=544个消隐区域
parameter SAV_START = 551; //开始4*2=8个SAV定时基准码
parameter VIDEO_START = 559; //开始每行有效像素点区域,560也可以正常显示图像
parameter EAV_START = 4399; //开始4*2=8个EAV定时基准码
parameter DATA_CNT = 1919; //每行有效像素点
parameter VCNT_SUM = 1079; //每场有效行
`endif
文档一:ITU-R BT.1120-7 建议书
高清晰度电视演播室信号数字接(https://wenku.baidu.com/view/920afe2d2af90242a895e501.html)
文档二:SMPTE STANDARD for Television — 1280 × 720 Progressive Image Sample Structure — Analog and Digital Representation and Analog Interface(https://wenku.baidu.com/view/8de63ec22cc58bd63186bd93.html)
文档三:GV7600 Aviia™ Transmitter 芯片手册(http://www.doc88.com/p-2456927070001.html)
附核心模块代码(通过BT1120协议将YCbCr转换SDI输出)
// BT1120 Encoder
//****************************************************************//
//Company : ##
//Author : MZH
//Version : 1.0
//Data of Creation :2017/05/22
//****************************************************************//
//BT1120 EAV, SAV Description
//BIT6:F ODD EVEN Sign (ODD=0)
//BIT5:V FIELD BLANKING Sign (1=BLANKING)
//BIT4:H EAV SAV Sign (1=EAV)
//BIT3-0 CRC BIT3=V(XOR)H;BIT2=F(XOR)H;BIT1=F(XOR)V;BIT0=F(XOR)V(XOR)H
//
//Bit7 Bit6 Bit5 Bit4 Bit3-0(P3P2P1P0) Hex Description
// 1 0 0 0 0000 0x80 Odd,Active,SAV 10'h200
// 1 0 0 1 1101 0x9d Odd,Active,EAV 10'h274
// 1 0 1 0 1011 0xab Odd,Blank, SAV 10'h2AC
// 1 0 1 1 0110 0xb6 Odd,Blank, EAV 10'h2d8
//
// Every line(4400Bytes):
// EAV(8Bytes:3FF 3FF 000 000 000 000 XYZ XYZ)
// LineBlanking(560Bytes: 80 10 80 10....)
// SAV(8Bytes:3FF 3FF 000 000 000 000 XYZ XYZ)
// ActiveVideo(3840Bytes:Cb0 Y0 Cr0 Y1 Cb2 Y2 Cr2 Y3 Cb4 Y4 Cr4 Y5 .... Cb1918 Y1918 Cr1918 Y1919 )
//
// Every Field = 1125Lines
// Line 0 - 40:odd field blanking
// Line 41 - 1121:odd field active
// Line 1122 - 1124:odd field blanking
//
// Clk:
// 2200*1125 = 2475000
// 2475000 * 60 = 148.5M
//****************************************************************//
// COLORBAR DEFINE //生成颜色测试数据
//`define COLOR_HOR_TEST //横向渐变条纹
`define COLOR_VER_TEST //竖向渐变条纹
`define TB_DATA
`define BT1120_1080P_30HZ //选用1280p 30hz
//`define BT1120_720P_30HZ //选用720p 30hz
module BT1120_1080p_720p (
input Sys_rstn,
input Clk,
//input [7: 0] DataY_input,
//input [7: 0] DataCb_input,
//input [7: 0] DataCr_input,
output reg Field_sync, //Odd signal
output reg DataY_req, //1280x720 每场
output reg DataCr_req, //640x720 每场
output reg DataCb_req, //640x720 每场
output [9: 0] BT1120_data_out
);
`ifdef BT1120_1080P_30HZ
parameter ROW_MAX = 1124; //每场总计行数
parameter COL_MAX = 4399; //每行总计像素点数
parameter ROW_BLACK_S = 41; //开始场有效
parameter ROW_BLACK_E = 1121; //开始场消隐
parameter SAV_COL = 552; //276*2
parameter BLANK_START = 7; //开始272*2=544个消隐区域
parameter SAV_START = 551; //开始4*2=8个SAV定时基准码
parameter VIDEO_START = 559; //开始每行有效像素点区域,560也可以正常显示图像
parameter EAV_START = 4399; //开始4*2=8个EAV定时基准码
parameter DATA_CNT = 1919; //每行有效像素点
parameter VCNT_SUM = 1079; //每场有效行
`endif
`ifdef BT1120_720P_30HZ
parameter ROW_MAX = 749;
parameter COL_MAX = 6599;
parameter ROW_BLACK_S = 25;
parameter ROW_BLACK_E = 745;
parameter SAV_COL = COL_MAX - 2567;// SAV_COL = 4032
parameter BLANK_START = 7;
parameter SAV_START = 4031;
parameter VIDEO_START = 4039;
parameter EAV_START = 6599;
parameter DATA_CNT = 1279;
parameter VCNT_SUM = 719;
`endif
`ifdef TB_DATA
reg[7:0] DataY,DataCr,DataCb;
reg[11:0] cnt_Y; //计数:每行有效像素点数
reg[11:0] cntt; //计数:每场有效行数
wire[7:0] DataY_input,DataCr_input,DataCb_input;
assign DataY_input = DataY;
assign DataCr_input = 8'd128;
assign DataCb_input = 8'd128;
`endif
`ifdef COLOR_VER_TEST //竖条纹
always@(posedge Clk or negedge Sys_rstn)begin //create tb data
if(!Sys_rstn)begin
DataY <= 255;
cnt_Y <= 12'd0;
end
else if (DataY_req) begin
if (cnt_Y==DATA_CNT) begin
DataY <= 255;
cnt_Y <= 12'd0;
end
else begin
DataY <= DataY-1;
cnt_Y <= cnt_Y+1;
end
end
end
`endif
`ifdef COLOR_HOR_TEST //横条纹
always @(posedge Clk or negedge Sys_rstn) begin //creat tb data
if (!Sys_rstn) begin
cnt_Y <= 12'd0;
end
else if (DataY_req)
begin
if (cnt_Y==DATA_CNT)
begin
cnt_Y <= 12'd0;
end
else
begin
cnt_Y <= cnt_Y+1;
end
end
end
always @(posedge Clk or negedge Sys_rstn) begin //creat tb data
if (!Sys_rstn) begin
DataY <= 8'd0;
cntt <= 12'd0;
end
else if (DataY_req)
begin
if (cnt_Y==DATA_CNT)
begin
DataY <= DataY+1;
cntt <= cntt+1;
if (cntt==VCNT_SUM)
begin
DataY <= 0;
cntt <= 0;
end
end
end
end
`endif
reg [12:0] hcnt;
reg [11:0] vcnt;
reg [9:0] data_out_temp;
assign BT1120_data_out = data_out_temp;
wire [9: 0] dataY_input_temp;
wire [9: 0] dataCb_input_temp;
wire [9: 0] dataCr_input_temp;
// REAL DATA
assign dataCb_input_temp = {DataCb_input,2'b00};
assign dataY_input_temp = {DataY_input,2'b00};
assign dataCr_input_temp = {DataCr_input,2'b00};
always @ (posedge Clk or negedge Sys_rstn ) //行场计数
begin
if (!Sys_rstn) begin
hcnt <= 13'd0;
vcnt <= 12'd0;
end
else begin
if (hcnt == COL_MAX) begin
hcnt <= 13'd0;
vcnt <= (vcnt == ROW_MAX) ? 12'd0: (vcnt + 1'b1);
end
else begin
hcnt <= hcnt + 1'b1;
end
end
end
always@(posedge Clk or negedge Sys_rstn)begin //输出奇偶场同步
if(!Sys_rstn)begin
Field_sync <= 1'b0;
end
else begin
Field_sync <= ((hcnt==13'd0)&&((vcnt==12'd0)))? 1:0;
end
end
reg V_VALID;
always @ (posedge Clk or negedge Sys_rstn ) //输出有效标志
begin
if (!Sys_rstn) begin
V_VALID = 1'b1;
end
else begin
case (vcnt)
0: V_VALID = 1'b1;
ROW_BLACK_S: V_VALID = 1'b0; //偶场有效区
ROW_BLACK_E: V_VALID = 1'b1;
default: V_VALID = V_VALID;
endcase
end
end
reg[1:0] h_state;
always@(posedge Clk or negedge Sys_rstn)begin //表示每行四个不同区间
if(!Sys_rstn)begin
h_state <= 2'd0;
end
else if(hcnt==10'd0)begin
h_state <= 2'd0;
end
else begin
case(h_state)
2'd0:begin //EAV
h_state <= (hcnt==BLANK_START)? 2'd1:2'd0;
end
2'd1:begin //BLANK
h_state <= (hcnt==SAV_START)? 2'd2:2'd1;
end
2'd2:begin //SAV
h_state <= (hcnt==VIDEO_START)? 2'd3:2'd2;
end
2'd3:begin //VIDEO
h_state <= (hcnt==EAV_START)? 2'd0:2'd3; //每行有效数据区
end
default:begin
h_state <= 2'd0;
end
endcase
end
end
always@(posedge Clk or negedge Sys_rstn)begin //产生输入请求信号
if(!Sys_rstn)begin
DataY_req <= 1'b0;
DataCr_req <= 1'b0;
DataCb_req <= 1'b0;
end
else begin
if( h_state==2'd3 )begin
DataY_req <= ( V_VALID == 1'b0 )? hcnt[0]:1'b0;
DataCb_req <= ( V_VALID == 1'b0 )? (hcnt[1:0]==2'b00):1'b0;
DataCr_req <= ( V_VALID == 1'b0 )? (hcnt[1:0]==2'b10):1'b0;
end
else begin
DataY_req <= 1'b0;
DataCr_req <= 1'b0;
DataCb_req <= 1'b0;
end
end
end
always @ (posedge Clk or negedge Sys_rstn ) //BT_1120协议
begin
if (!Sys_rstn) begin
data_out_temp <= 10'h200;
end
else begin
//发EAV和SAV前两个数据
if ((hcnt == 0 )|| (hcnt == 1) || (hcnt == SAV_COL) || (hcnt == (SAV_COL+1))) begin
data_out_temp <= 10'h3FF;
end
else if ( (hcnt == 2) || (hcnt == 3) ||(hcnt == 4) ||(hcnt == 5) || (hcnt == (SAV_COL+2)) || (hcnt == (SAV_COL+3))|| (hcnt == (SAV_COL+4))|| (hcnt == (SAV_COL+5)) ) begin
data_out_temp <= 10'h000;
end
else if ((hcnt == 6) || (hcnt == 7)) begin //发EAV最后两个数据
//if (((vcnt >= 0) && (vcnt <= ROW_BLACK_S)) || ((vcnt >= ROW_BLACK_E) && (vcnt <= ROW_MAX))) begin
if (V_VALID) begin
data_out_temp <= 10'h2D8; //{8'hB6,2'b00}; EAV odd field blanking
end
else begin
data_out_temp <= 10'h274; //{8'h9D,2'b00}; EAV odd field active
end
end
// BLACKING
else if ((hcnt > 7) && (hcnt < SAV_COL) ) begin
data_out_temp <= 10'h200;
end
else if ((hcnt == (SAV_COL+6)) || (hcnt == (SAV_COL+7))) begin //发SAV最后两个数据
if (V_VALID) begin
data_out_temp <= 10'h2AC; //{8'hAB,2'b00}; SAV odd field blanking
end
else begin
data_out_temp <= 10'h200; //{8'h80,2'b00}; SAV odd field active
end
end
// DATA
else begin
if (V_VALID) begin
data_out_temp <= 10'h200;
end
else begin
case (hcnt[1:0])
2'd0: begin
data_out_temp <= dataCb_input_temp;
end
2'd1,2'd3: begin
data_out_temp <= dataY_input_temp;
end
2'd2: begin
data_out_temp <= dataCr_input_temp;
end
default: begin
data_out_temp <= 10'h200;
end
endcase
end
end
end
end
endmodule
/*-----------------------------------------------
SDI总结(调试包括:在不同分辨率下的BT656,BT1120)
SDI调试的关键是行计数,每行EAV和SAV的起始计数至关重要;10bit SDI_1080p和10bit SDI_sd存在两方面差异:1、bt656和bt1120的协议不同,2、硬件Pcb上RATE_SEL0引脚配置不同;
1、每一行的组成
行(line)=结束码(EAV)+水平消隐(Horizontal blanking)+起始码(SAV)+有效数据(Active Video)
起始码(SAV)和结束码(EAV),它是标志着一行开始结束的重要标记,bt656协议:
图3 10bit复用 SDI_sd接口时序
2、为什么一行中的有效数据是 1440 字节,因为PAL制式的SDTV的分辨率为 720*576,即一行有720个有效点,由于采集的是彩色图像,那么一行就是由亮度信息(Y)和色差信息(CbCr)组成的,由于YCbCr是422格式,故一行中有720列Y,720列CbCr,因此,一行的有效字节数就为 720 x 2 = 1440 字节。bt1120协议:
图4 10bit复用 SDI_hd接口时序
3、定义行计数器时,需要明确每行的总数据和有效数据,总数据和有效数据即(EAV和SAV的起始计数)正确与否决定了是否显示图像,在整个模块代码编写中查阅总数据和有效数据的数值花费了80%的时间,最终在(bt1120文档(P12):数据流定时规范)中找到确定数值;
4、10bit复用时,每行有4400个数据,3840个有效数据,故一行中有1920列Y,1920列CbCr,分辨率:1920*1080