#基于FPGA的SDI发送接口调试,FPGA+GV7700实现1080p和720p的显示
上一篇文章已经调试了bt11200接口,本章将基于bt1120接口完善代码,实现1080p60Hz和720p60Hz的显示兼容。
720p60Hz的数据格式
1080p60Hz的数据格式
上板测试,显示彩条
顶层文件
module rgb_to_bt1120_top (
input rst_n ,
input pclk ,
// input t_de ,
// input t_hsync,
// input t_vsync,
// input [23:0] t_rgb ,
// input [11:0] hactive,
// input [11:0] htotal ,
// input [11:0] vactive,
// input [11:0] vtotal ,
output bt1120_pclk ,
output [15:0] bt1120_ycbcr
);
parameter HACTIVE = 12'd1920;
parameter HTOTAL = 12'd2200;
parameter VACTIVE = 12'd1080;
parameter VTOTAL = 12'd1125;
wire hsync;
wire vsync;
wire de ;
wire[15:0] ycbcr;
wire t_de ;
wire t_hsync;
wire t_vsync;
wire[23:0] t_rgb ;
reg [4:0] cnt ;
reg param_en;
tpg_ctr(
.clk (pclk ), //input
.rst_n(rst_n ), //input
.de (t_de ), //output reg
.hsync(t_hsync), //output reg
.vsync(t_vsync), //output reg
.rgb (t_rgb ) //output reg[23:0]
);
rgb_to_ycbcr422_top rgb_to_ycbcr422_top(
.clk (pclk ),
.rst_n (rst_n ),
.i_de (t_de ),
.i_hsync(t_hsync),
.i_vsync(t_vsync),
.i_data (t_rgb ),
.o_hsync (hsync ),
.o_vsync (vsync ),
.o_data_vld (de ),
.o_ycbcr (ycbcr )
);
ycbcr422_to_bt1120 ycbcr422_to_bt1120(
.rst_n (rst_n ),
.pclk (pclk ),
.param_vld (param_en),
.hactive (HACTIVE ), //参数获取 :一行有效数据个数 例1920 、1280
.htotal (HTOTAL ), //参数获取 :一行数据总数 例2200 、1650
.vactive (VACTIVE ), //参数获取 :一帧数据的有效行数 例1080 、720
.vtotal (VTOTAL ), //参数获取 :一帧数据的行总数 例1125 、750
.data_de (de ),
.hsync (hsync ),
.vsync (vsync ),
.ycbcr (ycbcr ),
.bt1120_pclk (bt1120_pclk ),
.bt1120_ycbcr (bt1120_ycbcr)
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 5'b0;
end
else if(cnt<5'd30)begin
cnt <= cnt + 1;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
param_en <= 1'b0;
end
else if(cnt==5'd30)begin
param_en <= 1'b1;
end
end
endmodule
GBR to YUV422顶层
module rgb_to_ycbcr422_top(
input clk ,
input rst_n ,
input i_de ,
input i_hsync,
input i_vsync,
input[23:0] i_data ,
output o_hsync,
output o_vsync,
output o_data_vld,
output[15:0] o_ycbcr
);
wire hsync ;
wire vsync ;
wire data_vld ;
wire [7:0] lumi ;
wire [7:0] cb ;
wire [7:0] cr ;
rgb_to_ycbcr444 rgb_to_ycbcr444(
.clk (clk),
.i_r_8b (i_data[23:16]),
.i_g_8b (i_data[15:8] ),
.i_b_8b (i_data[7:0] ),
.i_h_sync (i_hsync ),
.i_v_sync (i_vsync ),
.i_data_en(i_de ),
.o_y_8b (lumi ),
.o_cb_8b (cb ),
.o_cr_8b (cr ),
.o_h_sync (hsync ),
.o_v_sync (vsync ),
.o_data_en(data_vld )
);
ycbcr444_to_ycbcr422 ycbcr444_to_ycbcr422(
.clk (clk ),
.rst_n (rst_n),
.i_h_sync (hsync ),
.i_v_sync (vsync ),
.i_data_en(data_vld ),
.i_y (lumi ),
.i_cb (cb ),
.i_cr (cr ),
.o_h_sync (o_hsync ),
.o_v_sync (o_vsync ),
.o_data_en(o_data_vld),
.o_ycbcr (o_ycbcr )
);
endmodule
RGB to YUV444
/*
RGB 转 Ycbcr 算法
计算公式:
Y = 0.183R + 0.614G + 0.062B + 16;
cb = -0.101R - 0.338G + 0.439B + 128;
cr = 0.439R - 0.399G - 0.040B + 128;
其中,时序在计算过程中完全没有用到
输入到输出有三个 clock 的时延。
第一级流水线计算所有乘法;
第二级流水线计算所有加法,把正的和负的分开进行加法;
第三级流水线计算最终的和,若为负数取 0;
*/
`timescale 1ns/1ps
module rgb_to_ycbcr444(
input clk,
input [7 : 0] i_r_8b,
input [7 : 0] i_g_8b,
input [7 : 0] i_b_8b,
input i_h_sync,
input i_v_sync,
input i_data_en,
output [7 : 0] o_y_8b,
output [7 : 0] o_cb_8b,
output [7 : 0] o_cr_8b,
output o_h_sync,
output o_v_sync,
output o_data_en
);
//multiply 256
parameter para_0183_10b = 10'd47; //0.183 定点数
parameter para_0614_10b = 10'd157;
parameter para_0062_10b = 10'd16;
parameter para_0101_10b = 10'd26;
parameter para_0338_10b = 10'd86;
parameter para_0439_10b = 10'd112;
parameter para_0399_10b = 10'd102;
parameter para_0040_10b = 10'd10;
parameter para_16_18b = 18'd4096;
parameter para_128_18b = 18'd32768;
wire sign_cb;
wire sign_cr;
reg[17: 0] mult_r_for_y_18b;
reg[17: 0] mult_r_for_cb_18b;
reg[17: 0] mult_r_for_cr_18b;
reg[17: 0] mult_g_for_y_18b;
reg[17: 0] mult_g_for_cb_18b;
reg[17: 0] mult_g_for_cr_18b;
reg[17: 0] mult_b_for_y_18b;
reg[17: 0] mult_b_for_cb_18b;
reg[17: 0] mult_b_for_cr_18b;
reg[17: 0] add_y_0_18b;
reg[17: 0] add_cb_0_18b;
reg[17: 0] add_cr_0_18b;
reg[17: 0] add_y_1_18b;
reg[17: 0] add_cb_1_18b;
reg[17: 0] add_cr_1_18b;
reg[17: 0] result_y_18b;
reg[17: 0] result_cb_18b;
reg[17: 0] result_cr_18b;
reg[9:0] y_tmp;
reg[9:0] cb_tmp;
reg[9:0] cr_tmp;
reg i_h_sync_delay_1;
reg i_v_sync_delay_1;
reg i_data_en_delay_1;
reg i_h_sync_delay_2;
reg i_v_sync_delay_2;
reg i_data_en_delay_2;
reg i_h_sync_delay_3;
reg i_v_sync_delay_3;
reg i_data_en_delay_3;
reg i_h_sync_delay_4 ;
reg i_v_sync_delay_4 ;
reg i_data_en_delay_4;
initial begin
mult_r_for_y_18b <= 18'd0;
mult_r_for_cb_18b <= 18'd0;
mult_r_for_cr_18b <= 18'd0;
mult_g_for_y_18b <= 18'd0;
mult_g_for_cb_18b <= 18'd0;
mult_g_for_cr_18b <= 18'd0;
mult_b_for_y_18b <= 18'd0;
mult_g_for_cb_18b <= 18'd0;
mult_b_for_cr_18b <= 18'd0;
add_y_0_18b <= 18'd0;
add_cb_0_18b <= 18'd0;
add_cr_0_18b <= 18'd0;
add_y_1_18b <= 18'd0;
add_cb_1_18b <= 18'd0;
add_cr_1_18b <= 18'd0;
result_y_18b <= 18'd0;
result_cb_18b <= 18'd0;
result_cr_18b <= 18'd0;
i_h_sync_delay_1 <= 1'd0;
i_v_sync_delay_1 <= 1'd0;
i_data_en_delay_1 <= 1'd0;
i_h_sync_delay_2 <= 1'd0;
i_v_sync_delay_2 <= 1'd0;
i_data_en_delay_2 <= 1'd0;
end
//LV1 pipeline : mult
always @ (posedge clk)begin
mult_r_for_y_18b <= i_r_8b * para_0183_10b;
mult_r_for_cb_18b <= i_r_8b * para_0101_10b;
mult_r_for_cr_18b <= i_r_8b * para_0439_10b;
end
always @ (posedge clk)begin
mult_g_for_y_18b <= i_g_8b * para_0614_10b;
mult_g_for_cb_18b <= i_g_8b * para_0338_10b;
mult_g_for_cr_18b <= i_g_8b * para_0399_10b;
end
always @ (posedge clk)begin
mult_b_for_y_18b <= i_b_8b * para_0062_10b;
mult_b_for_cb_18b <= i_b_8b * para_0439_10b;
mult_b_for_cr_18b <= i_b_8b * para_0040_10b;
end
//LV2 pipeline : add
always @ (posedge clk)begin
add_y_0_18b <= mult_r_for_y_18b + mult_g_for_y_18b;
add_y_1_18b <= mult_b_for_y_18b + para_16_18b;
add_cb_0_18b <= mult_b_for_cb_18b + para_128_18b;
add_cb_1_18b <= mult_r_for_cb_18b + mult_g_for_cb_18b;
add_cr_0_18b <= mult_r_for_cr_18b + para_128_18b;
add_cr_1_18b <= mult_g_for_cr_18b + mult_b_for_cr_18b;
end
//LV3 pipeline : y + cb + cr
assign sign_cb = (add_cb_0_18b >= add_cb_1_18b);
assign sign_cr = (add_cr_0_18b >= add_cr_1_18b);
always @ (posedge clk)begin
result_y_18b <= add_y_0_18b + add_y_1_18b;
result_cb_18b <= sign_cb ? (add_cb_0_18b - add_cb_1_18b) : 18'd0;
result_cr_18b <= sign_cr ? (add_cr_0_18b - add_cr_1_18b) : 18'd0;
end
always @ (posedge clk)begin
y_tmp <= result_y_18b[17:8] + {9'd0,result_y_18b[7]};
cb_tmp <= result_cb_18b[17:8] + {9'd0,result_cb_18b[7]};
cr_tmp <= result_cr_18b[17:8] + {9'd0,result_cr_18b[7]};
end
//output
assign o_y_8b = (y_tmp[9:8] == 2'b00) ? y_tmp[7 : 0] : 8'hFF;
assign o_cb_8b = (cb_tmp[9:8] == 2'b00) ? cb_tmp[7 : 0] : 8'hFF;
assign o_cr_8b = (cr_tmp[9:8] == 2'b00) ? cr_tmp[7 : 0] : 8'hFF;
always @ (posedge clk)begin
i_h_sync_delay_1 <= i_h_sync;
i_v_sync_delay_1 <= i_v_sync;
i_data_en_delay_1 <= i_data_en;
i_h_sync_delay_2 <= i_h_sync_delay_1;
i_v_sync_delay_2 <= i_v_sync_delay_1;
i_data_en_delay_2 <= i_data_en_delay_1;
i_h_sync_delay_3 <= i_h_sync_delay_2;
i_v_sync_delay_3 <= i_v_sync_delay_2;
i_data_en_delay_3 <= i_data_en_delay_2;
i_h_sync_delay_4 <= i_h_sync_delay_3 ;
i_v_sync_delay_4 <= i_v_sync_delay_3 ;
i_data_en_delay_4 <= i_data_en_delay_3;
end
assign o_h_sync = i_h_sync_delay_4;
assign o_v_sync = i_v_sync_delay_4;
assign o_data_en = i_data_en_delay_4;
endmodule
YUV444 to YUV422
`timescale 1ns/1ps
module ycbcr444_to_ycbcr422(
input clk ,
input rst_n ,
input i_h_sync ,
input i_v_sync ,
input i_data_en ,
input [7:0] i_y ,
input [7:0] i_cb ,
input [7:0] i_cr ,
output reg o_h_sync ,
output reg o_v_sync ,
output reg o_data_en ,
output [15:0] o_ycbcr
);
reg flag ;
reg [7:0] o_y;
reg [7:0] o_cbcr;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
flag <= 1'b1 ;
end
else if(i_data_en)begin
flag <= ~flag ;
end
else begin
flag <= 1'b1 ;
end
end
always @(posedge clk )begin
if(flag)begin
o_cbcr <= i_cb;
end
else begin
o_cbcr <= i_cr;
end
end
always @(posedge clk )begin
o_h_sync <= i_h_sync;
o_v_sync <= i_v_sync;
o_data_en <= i_data_en;
o_y <= i_y;
end
assign o_ycbcr = {o_y ,o_cbcr} ;
endmodule
YUV422 to BT1120
/* 定时基准码 <0xff 0x00 0x00 xyz>
* 其中xyz为如下的取值范围:
* 1 0 1 0 1 0 1 1 0 0 0xab(帧消隐期间,SAV)
* 1 0 1 1 0 1 1 0 0 0 0xb6(帧消隐期间,EAV)
* 1 0 0 0 0 0 0 0 0 0 0x80(视频有效区时间,SAV)
* 1 0 0 1 1 1 0 1 0 0 0x9d(视频有效区时间,EAV)
*/
`timescale 1ns / 100ps
module ycbcr422_to_bt1120(
input rst_n ,
input pclk ,
input param_vld , //参数有效
input [11:0] para_hactive, //参数获取 :一行有效数据个数 例1920 、1280
input [11:0] para_htotal , //参数获取 :一行数据总数 例2200 、1650
input [11:0] para_vactive, //参数获取 :一帧数据的有效行数 例1080 、720
input [11:0] para_vtotal , //参数获取 :一帧数据的行总数 例1125 、750
input data_de,
input hsync ,
input vsync ,
input [15:0] ycbcr ,
output bt1120_pclk,
output reg [15:0] bt1120_ycbcr
);
localparam BLANKING = 4'd0; //消隐阶段
//SAV
localparam CODE_SAV1 = 4'd1; //数据开始码阶段
localparam CODE_SAV2 = 4'd2;
localparam CODE_SAV3 = 4'd3;
localparam CODE_SAV4 = 4'd4;
//EAV
localparam CODE_EAV1 = 4'd5; //数据结束码阶段
localparam CODE_EAV2 = 4'd6;
localparam CODE_EAV3 = 4'd7;
localparam CODE_EAV4 = 4'd8;
localparam VAILD_VIDEO = 4'd9; //数据有效阶段
//在行场消隐区填充STUFF
localparam STUFF = 16'h8010;
localparam BSAV = 8'hab;
localparam BEAV = 8'hb6;
localparam VSAV = 8'h80;
localparam VEAV = 8'h9d;
wire full ;
reg rd_en ;
wire[15:0] rd_data /* synthesis keep */;
wire empty ;
reg [3:0] state_c /* synthesis preserve */;
reg [3:0] state_n ;
wire blank2sav ;
wire video2eav ;
reg data_de0 ;
reg hsync0 /* synthesis noprune*/ ;
reg vsync0 ;
reg [15:0] ycbcr0 ;
reg data_de1 ;
reg hsync1 /* synthesis noprune*/ ;
reg vsync1 ;
reg [15:0] ycbcr1 ;
wire v_pos ;
reg [11:0] cnt_h ;
reg [11:0] cnt_v ;
reg param_vld0;
reg param_vld1;
reg param_gain;
reg [11:0] hactive;
reg [11:0] htotal ;
reg [11:0] vactive;
reg [11:0] vtotal ;
reg [11:0] hactive0;
reg [11:0] htotal0 ;
reg [11:0] vactive0;
reg [11:0] vtotal0 ;
reg [11:0] hactive1;
reg [11:0] htotal1 ;
reg [11:0] vactive1;
reg [11:0] vtotal1 ;
reg [15:0] bt1120_ycbcr1;
reg [15:0] bt1120_ycbcr0;
///下面是视频参数获取部分///
//上游传过来的参数有效脉冲打拍
always @(posedge pclk)begin
param_vld0 <= param_vld ;
param_vld1 <= param_vld0;
end
always @(posedge pclk)begin
hactive0 <= para_hactive;
htotal0 <= para_htotal ;
vactive0 <= para_vactive;
vtotal0 <= para_vtotal ;
hactive1 <= hactive0;
htotal1 <= htotal0 ;
vactive1 <= vactive0;
vtotal1 <= vtotal0 ;
end
//assign param_gain = !param_vld1 && param_vld0 ;
always @(posedge pclk or negedge rst_n)begin
if(rst_n==1'b0)
param_gain <= 1'b0;
else if(!param_vld1 && param_vld0)
param_gain <= 1'b1;
else
param_gain <= 1'b0;
end
//获取时序参数
always @(posedge pclk or negedge rst_n)begin
if(rst_n==1'b0)begin
hactive <= 12'b0;
htotal <= 12'b0;
vactive <= 12'b0;
vtotal <= 12'b0;
end
else if(param_gain && htotal != htotal1)begin
hactive <= hactive1;
htotal <= htotal1 ;
vactive <= vactive1;
vtotal <= vtotal1 ;
end
else begin
hactive <= hactive ;
htotal <= htotal ;
vactive <= vactive ;
vtotal <= vtotal ;
end
end
///下面是视频输入输出部分///
assign bt1120_pclk = pclk ;
yc2bt_fifo yc2bt_fifo_inst0
(
.clock (pclk ),
.data (ycbcr1 ),
.wrreq (data_de1),
.full (full ),
.rdreq (rd_en ),
.q (rd_data ),
.empty (empty )
);
//read en
always @(posedge pclk or negedge rst_n)begin
if(rst_n==1'b0)begin
rd_en <= 1'b0 ;
end
else if(cnt_v >= vstart && cnt_v < (vactive + vstart))begin
if(cnt_h >= (htotal-hactive - 1) && cnt_h < htotal-1)
rd_en <= 1'b1 ;
else
rd_en <= 1'b0 ;
end
else begin
rd_en <= 1'b0 ;
end
end
always@(posedge pclk or negedge rst_n)begin
if(!rst_n)begin
state_c <= BLANKING;
end
else begin
state_c <= state_n;
end
end
always@(*)begin
case(state_c)
BLANKING:begin
if(blank2sav)begin
state_n = CODE_SAV1;
end
else begin
state_n = state_c;
end
end
CODE_SAV1:begin
state_n = CODE_SAV2;
end
CODE_SAV2:begin
state_n = CODE_SAV3;
end
CODE_SAV3:begin
state_n = CODE_SAV4;
end
CODE_SAV4:begin
state_n = VAILD_VIDEO;
end
VAILD_VIDEO:begin
if(video2eav)begin
state_n = CODE_EAV1;
end
else begin
state_n = state_c;
end
end
CODE_EAV1:begin
state_n = CODE_EAV2;
end
CODE_EAV2:begin
state_n = CODE_EAV3;
end
CODE_EAV3:begin
state_n = CODE_EAV4;
end
CODE_EAV4:begin
state_n = BLANKING;
end
default:begin
state_n = BLANKING;
end
endcase
end
assign blank2sav = state_c==BLANKING && cnt_h == htotal-hactive-5; //提前5个时钟进入start active ,因为要发送ff 00 00 xyz
assign video2eav = state_c==VAILD_VIDEO && cnt_h == htotal-1; //发送一行数据结束
//视频输入打拍
always @(posedge pclk or negedge rst_n)begin
if(rst_n==1'b0)begin
data_de0 <= 1'b0 ;
hsync0 <= 1'b0 ;
vsync0 <= 1'b0 ;
ycbcr0 <= 16'b0 ;
end
else begin
data_de0 <= data_de ;
hsync0 <= hsync ;
vsync0 <= vsync ;
ycbcr0 <= ycbcr ;
data_de1 <= data_de0 ;
hsync1 <= hsync0 ;
vsync1 <= vsync0 ;
ycbcr1 <= ycbcr0 ;
end
end
//获取场信号上升沿
assign v_pos = !vsync1 && vsync0 ;
//一行计数器
always @(posedge pclk )begin
if(v_pos || cnt_h == htotal)
cnt_h <= 12'b1;
else
cnt_h <= cnt_h + 1;
end
//一帧计数器
always @(posedge pclk )begin
if(v_pos)
cnt_v <= 12'b1;
else if(cnt_h == htotal)begin
if(cnt_v == vtotal)
cnt_v <= 12'b0;
else
cnt_v <= cnt_v + 1;
end
end
//出数据
always @(posedge pclk or negedge rst_n)begin
if(rst_n==1'b0)begin
bt1120_ycbcr1 <= STUFF ;
end
else begin
case(state_c)
BLANKING:begin
bt1120_ycbcr1<= STUFF ;
end
CODE_SAV1:begin
bt1120_ycbcr1<= 16'hffff ;
end
CODE_SAV2:begin
bt1120_ycbcr1<= 16'h0 ;
end
CODE_SAV3:begin
bt1120_ycbcr1<= 16'h0 ;
end
CODE_SAV4:begin
if(cnt_v < vstart ||(cnt_v >= (vactive + vstart) && cnt_v <= vtotal)) //消隐阶段要发送的start active
bt1120_ycbcr1<= 16'habab ;
else if(cnt_v >= vstart && cnt_v <(vactive + vstart)) //非消隐阶段要发送的start active
bt1120_ycbcr1<= 16'h8080 ;
end
VAILD_VIDEO:begin
bt1120_ycbcr1<= rd_data ;
end
CODE_EAV1:begin
bt1120_ycbcr1 <= 16'hffff;
end
CODE_EAV2:begin
bt1120_ycbcr1 <= 16'h0;
end
CODE_EAV3:begin
bt1120_ycbcr1 <= 16'h0;
end
CODE_EAV4:begin
if(cnt_v < vstart ||(cnt_v >= (vactive + vstart) && cnt_v <= vtotal)) //消隐阶段要发送的end active
bt1120_ycbcr1<= 16'hb6b6 ;
else if(cnt_v >= vstart && cnt_v < (vactive + vstart) ) //非消隐阶段要发送的end active
bt1120_ycbcr1<= 16'h9d9d ;
end
endcase
end
end
//output data
always @(posedge pclk )begin
bt1120_ycbcr0 <= bt1120_ycbcr1;
bt1120_ycbcr <= bt1120_ycbcr0;
end
endmodule
彩条数据文件
module tpg_ctr(
input clk ,
input rst_n,
output reg de ,
output reg hsync,
output reg vsync,
output reg[23:0] rgb
);
parameter h_total = 12'd2200;
parameter hsync_pw = 6'd44 ; //行消隐脉冲宽度,以时钟为单位
parameter v_total = 12'd1125;
parameter vsync_pw = 3'd5 ; //行消隐脉冲宽度,以行为单位
parameter data_f_enabel = 6'd42 ; //有效数据的第一行,以行为单位
parameter data_e_enabel = 12'd1120; //有效数据的最后一行,以行为单位
parameter data_de_start = 8'd192 ; //数据有效开始,以时钟为单位
parameter data_de_end = 12'd2112; //数据有效结束,以时钟为单位
reg [11:0] cnt_h;
reg [11:0] cnt_v;
reg [11:0] cnt_de;
//一行数据的计数器
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt_h <= 12'b0 ;
end
else begin
if(cnt_h == h_total-1)
cnt_h <= 12'b0 ;
else
cnt_h <= cnt_h + 1 ;
end
end
//一帧数据的计数器,1080P 60hz的一帧数据共有1125行
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt_v <= 12'b0 ;
end
else if(cnt_h == h_total-1)begin
if(cnt_v == v_total-1)
cnt_v <= 12'b0 ;
else
cnt_v <= cnt_v + 1 ;
end
end
//产生行信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
hsync <= 1'b0 ;
end
else if(cnt_h < hsync_pw )begin
hsync <= 1'b1 ;
end
else begin
hsync <= 1'b0 ;
end
end
//产生场信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
vsync <= 1'b0 ;
end
else if(cnt_v < vsync_pw )begin
vsync <= 1'b1 ;
end
else begin
vsync <= 1'b0 ;
end
end
//对DE信号进行计数
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_de <= 12'b0;
end
else if(de)begin
cnt_de <= cnt_de + 1;
end
else begin
cnt_de <= 12'b0;
end
end
//产生数据有效信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
de <= 1'b0 ;
rgb <= 24'b0;
end
else if(cnt_v >= data_f_enabel-1 && cnt_v <= data_e_enabel)begin
if(cnt_h >= data_de_start-1 && cnt_h < data_de_end-1 )begin
de <= 1'b1 ;
if(cnt_de<12'd383)
rgb <= 24'hffffff; //白
else if(cnt_de>=12'd383 && cnt_de<12'd767)
rgb <= 24'h000000; //黑
else if(cnt_de>=12'd767 && cnt_de<12'd1152)
rgb <= 24'hff0000; //红
else if(cnt_de>=12'd1152 && cnt_de<12'd1536)
rgb <= 24'h00ff00; //绿
else if(cnt_de>=12'd1536)
rgb <= 24'h0000ff; //蓝
end
else begin
de <= 1'b0 ;
rgb <= 24'b0;
end
end
end
endmodule
modelsim仿真文件
`timescale 1 ns/1ps
module tb_bt1120();
reg clk ;
reg rst_n;
reg[11:0] hactive;
reg[11:0] hsyncw ;
reg[11:0] hstart ;
reg[11:0] htotal ;
reg[11:0] vactive;
reg[11:0] vsyncw ;
reg[11:0] vstart ;
reg[11:0] vtotal ;
reg t_de ;
reg t_vsync ;
reg t_hsync ;
reg[23:0] t_rgb ;
reg[11:0] cnt_h ;
reg[11:0] cnt_v ;
reg[11:0] tcnt_h;
reg[11:0] tcnt_v;
//uut的输出信号
wire bt1120_clk;
wire[15:0] bt1120_data;
//时钟周期,单位为ns,可在此修改时钟周期。
parameter CYCLE = 7;
//复位时间,此时表示复位3个时钟周期的时间。
parameter RST_TIME = 20 ;
rgb_to_bt1120 u_rgb_to_bt1120(
.rst_n (rst_n ), //input
.pclk (clk ), //input
.t_de (t_de ), //input [15:0]
.t_hsync (t_hsync), //input
.t_vsync (t_vsync), //input
.t_rgb (t_rgb ), //input
.param_vld(param_en),
.hactive (hactive ),
.htotal (htotal ),
.vactive (vactive ),
.vtotal (vtotal ),
//bt.1120接口
.bt1120_pclk (bt1120_clk ) , //output
.bt1120_ycbcr(bt1120_data) //output reg[15:0]
);
//1080P 60Hz
parameter h_total = 12'd2200;
parameter hsync_pw = 6'd44 ; //行消隐脉冲宽度,以时钟为单位
parameter v_total = 12'd1125;
parameter vsync_pw = 3'd5 ; //行消隐脉冲宽度,以行为单位
parameter data_f_enabel = 6'd42 ; //有效数据的第一行,以行为单位
parameter data_e_enabel = 12'd1121; //有效数据的最后一行,以行为单位
parameter data_de_start = 8'd192 ; //数据有效开始,以时钟为单位
parameter data_de_end = 12'd2112; //数据有效结束,以时钟为单位
//生成本地时钟50M
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//产生复位信号
initial begin
rst_n = 1;
param_en= 1'b0 ;
hactive = 12'd0 ;
htotal = 12'd0 ;
vactive = 12'd0 ;
vtotal = 12'd0 ;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);
rst_n = 1;
param_en= 1'b0 ;
hactive = 12'd1920 ;
htotal = 12'd2200 ;
vactive = 12'd1080 ;
vtotal = 12'd1125 ;
end
//一行数据的计数器
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt_h <= 12'b1 ;
end
else begin
if(cnt_h == h_total)
cnt_h <= 12'b1 ;
else
cnt_h <= cnt_h + 1 ;
end
end
//一帧数据的计数器,1080P 60hz的一帧数据共有1125行
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt_v <= 12'b1 ;
end
else if(cnt_h == h_total)begin
if(cnt_v == v_total)
cnt_v <= 12'b1 ;
else
cnt_v <= cnt_v + 1 ;
end
end
//产生行信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
t_hsync <= 1'b0 ;
end
else if(cnt_h <= hsync_pw )begin
t_hsync <= 1'b1 ;
end
else begin
t_hsync <= 1'b0 ;
end
end
//产生场信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
t_vsync <= 1'b0 ;
end
else if(cnt_v <= vsync_pw )begin
t_vsync <= 1'b1 ;
end
else begin
t_vsync <= 1'b0 ;
end
end
//产生rgb数据和de有效信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
t_de <= 1'b0 ;
t_rgb <= 24'b0;
end
else if(cnt_v >= data_f_enabel && cnt_v <= data_e_enabel)begin
if(cnt_h > data_de_start && cnt_h <= 12'd576 )begin
t_de <= 1'b1 ;
t_rgb <= 24'hffffff;
end
else if(cnt_h > 12'd576 && cnt_h <= 12'd960)begin
t_de <= 1'b1 ;
t_rgb <= 24'h000000; //黑
end
else if(cnt_h > 12'd960 && cnt_h <= 12'd1344)begin
t_de <= 1'b1 ;
t_rgb <= 24'hff0000; //红
end
else if(cnt_h > 12'd1344 && cnt_h <= 12'd1728)begin
t_de <= 1'b1 ;
t_rgb <= 24'h00ff00; //绿
end
else if(cnt_h > 12'd1728 && cnt_h <= 12'd2112)begin
t_de <= 1'b1 ;
t_rgb <= 24'hff; //蓝
end
else begin
t_de <= 1'b0 ;
t_rgb <= 24'h0;
end
end
else begin
t_de <= 1'b0 ;
t_rgb <= 24'h0;
end
end
always @(posedge clk)begin
tcnt_h <= cnt_h ;
tcnt_v <= cnt_v ;
end
endmodule
对顶层文件做一些修改,用于modelsim测试
module rgb_to_bt1120 (
input rst_n ,
input pclk ,
input t_de ,
input t_hsync,
input t_vsync,
input [23:0] t_rgb ,
input param_vld,
input [11:0] hactive,
input [11:0] htotal ,
input [11:0] vactive,
input [11:0] vtotal ,
output bt1120_pclk ,
output [15:0] bt1120_ycbcr
);
wire hsync;
wire vsync;
wire de ;
wire[15:0] ycbcr;
wire param_vld;
rgb_to_ycbcr422_top rgb_to_ycbcr422_top(
.clk (pclk ),
.rst_n (rst_n ),
.i_de (t_de ),
.i_hsync(t_hsync),
.i_vsync(t_vsync),
.i_data (t_rgb ),
.o_hsync (hsync ),
.o_vsync (vsync ),
.o_data_vld (de ),
.o_ycbcr (ycbcr )
);
ycbcr422_to_bt1120 ycbcr422_to_bt1120(
.rst_n (rst_n ),
.pclk (pclk ),
.param_vld (param_vld),
.hactive (hactive), //参数获取 :一行有效数据个数 例1920 、1280
.htotal (htotal ), //参数获取 :一行数据总数 例2200 、1650
.vactive (vactive), //参数获取 :一帧数据的有效行数 例1080 、720
.vtotal (vtotal ), //参数获取 :一帧数据的行总数 例1125 、750
.data_de (de ),
.hsync (hsync ),
.vsync (vsync ),
.ycbcr (ycbcr ),
.bt1120_pclk (bt1120_pclk ),
.bt1120_ycbcr (bt1120_ycbcr)
);
endmodule
测试结果