這個BT1120接口是在1080P 60Hz的視頻中驗證的,其它頻率的視頻使用時要修改對應的參數。另外由于接口代碼里面例化了一個深度位512的FIFO(quartus),所以在做仿真測試時需要quartus和modelsim聯合仿真。
bt1120接口最重要的部分是結束碼和起始碼(FF 00 00 XYZ)
前面3字節的FF 00 00 是固定不變的,最后一字節需要根據F V H來編碼,當FVH確定時P3 P2 P1 P0也確定了。使用8bit的數據位寬時保留高8位,舍去低2位。
整理后的接口
接口代碼
/* 定時基準碼
<0xff 0x00 0x00 xxx
>* 其中xxx為如下的取值范圍:*
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 / 1ps
module ycbcr422_to_bt1120
(input rst_n,input clk ,input data_de,input hsync,input vsync,input
[15:0
] ycbcr, output bt1120_pclk,output reg
[15:0
] bt1120_ycbcr
);localparam BLANKING
= 4'd0; //消隱階段 //SAVlocalparam CODE_SAV1 = 4'd1
; //數據開始碼階段localparam CODE_SAV2
= 4'd2;localparam CODE_SAV3 = 4'd3
;localparam CODE_SAV4
= 4'd4;//EAVlocalparam CODE_EAV1 = 4'd5
; //數據結束碼階段localparam CODE_EAV2
= 4'd6;localparam CODE_EAV3 = 4'd7
;localparam CODE_EAV4
= 4'd8;localparam VAILD_VIDEO = 4'd9
; //數據有效階段//在行場消隱區填充STUFFlocalparam STUFF
= 16'h8010;localparam BSAV = 8'hab
;localparam BEAV
= 8'hb6;localparam VSAV = 8'h80
;localparam VEAV
= 8'h9d;//1080p 60hz
localparam WIDTH_TOTAL = 12'd2200
; //一行的寬度
localparam
HEIGHT_TOTAL= 12'd1125 ; //一幀的高度
localparam VIDEO_BEFORE_BLANK_NUM = 6'd41
; //一幀開始前的幀消隱行數
localparam VIDEO_AFTER_BLANK_NUM
= 3'd4 ; //一幀結束后的幀消隱行數
localparam BLANK_NUM = 12'd280
;wire full
;
reg rd_en
;
wire
[15:0
] rd_data
;
wire empty
;reg
[3:0
] state_c
;
reg
[3:0
] state_n
;
wire blank2sav
;
wire video2eav
;reg data_de0
;
reg hsync0
;
reg vsync0
;
reg
[15:0
] ycbcr0
;
reg data_de1
;
reg hsync1
;
reg vsync1
;
reg
[15:0
] ycbcr1
;
wire v_pos
;reg
[11:0
] cnt_h
;
reg
[11:0
] cnt_v
; wire
[7:0
] Lumi
;
wire
[7:0
] cbcr
;assign bt1120_pclk
= clk
;yc2bt_fifo yc2bt_fifo_inst0
(.clock
(clk
),.data
(ycbcr1
),.wrreq
(data_de1
),.full
(full
),.rdreq
(rd_en
),.q
(rd_data
),.empty
(empty
)
);always@
(posedge clk or negedge rst_n
)beginif
(!rst_n
)beginstate_c
<= BLANKING
;end
else beginstate_c
<= state_n
;end
endalways@
(*
)begincase
(state_c
)BLANKING:beginif
(blank2sav
)beginstate_n
= CODE_SAV1
;end
else beginstate_n
= state_c
;endendCODE_SAV1:beginstate_n
= CODE_SAV2
;endCODE_SAV2:beginstate_n
= CODE_SAV3
;endCODE_SAV3:beginstate_n
= CODE_SAV4
;endCODE_SAV4:beginstate_n
= VAILD_VIDEO
;endVAILD_VIDEO:beginif
(video2eav
)beginstate_n
= CODE_EAV1
;end
else beginstate_n
= state_c
;endendCODE_EAV1:beginstate_n
= CODE_EAV2
;endCODE_EAV2:beginstate_n
= CODE_EAV3
;endCODE_EAV3:beginstate_n
= CODE_EAV4
;endCODE_EAV4:beginstate_n
= BLANKING
;end default:beginstate_n
= BLANKING
;endendcase
endassign blank2sav
= state_c==BLANKING
&& cnt_h==12'd275;
assign video2eav = state_c==VAILD_VIDEO && cnt_h==12'd2199
;//輸入打拍
always @
(posedge clk or negedge rst_n
)beginif
(rst_n
==1'b0)begindata_de0 <= 1'b0
;hsync0
<= 1'b0 ;vsync0 <= 1'b0
;ycbcr0
<= 16'b0 ;endelse begindata_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 clk )beginif(v_pos || cnt_h == WIDTH_TOTAL-1)cnt_h <= 12'b0
;else cnt_h
<= cnt_h +
1;
end//一幀計數器
always @
(posedge clk
)beginif
(v_pos
)cnt_v
<= 12'b0;else if(cnt_h == WIDTH_TOTAL-1)beginif(cnt_v == HEIGHT_TOTAL-1)cnt_v <= 12'b0
;elsecnt_v
<= cnt_v +
1;end
end //出數據
always @
(posedge clk or negedge rst_n
)beginif
(rst_n
==1'b0)beginbt1120_ycbcr <= STUFF ;endelse begin case(state_c)BLANKING:begin bt1120_ycbcr<= STUFF ; endCODE_SAV1:begin bt1120_ycbcr<= 16'hffff
; endCODE_SAV2:begin bt1120_ycbcr
<= 16'h0 ; end CODE_SAV3:begin bt1120_ycbcr<= 16'h0
; end CODE_SAV4:beginif
(cnt_v
<12'd41 ||(cnt_v >= 12'd1121
&& cnt_v
< 12'd1125)) bt1120_ycbcr<= 16'habab
;else if
(cnt_v
>=12'd41 && cnt_v<12'd1121
)bt1120_ycbcr
<= 16'h8080 ; endVAILD_VIDEO:begin bt1120_ycbcr<= rd_data ; endCODE_EAV1:beginbt1120_ycbcr <= 16'hffff
;endCODE_EAV2:beginbt1120_ycbcr
<= 16'h0;endCODE_EAV3:beginbt1120_ycbcr <= 16'h0
;endCODE_EAV4:beginif
(cnt_v
<12'd41 ||(cnt_v >= 12'd1121
&& cnt_v
< 12'd1125)) bt1120_ycbcr<= 16'hb6b6
;else if
(cnt_v
>=12'd41 && cnt_v<12'd1121
)bt1120_ycbcr
<= 16'h9d9d ;end endcase end
endassign Lumi = bt1120_ycbcr[15:8] ;
assign cbcr = bt1120_ycbcr[7:0] ;
//read en
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0
)beginrd_en
<= 1'b0 ;endelse if(cnt_v>=12'd41
&& cnt_v
< 12'd1121 )beginif(cnt_h>=12'd279
&& cnt_h
<12'd2200)rd_en <= 1'b1
;elserd_en
<= 1'b0 ;endelse beginrd_en <= 1'b0
;end
endendmodule
測試文件
`timescale
1 ns/1psmodule tb_bt1120
();reg clk
;
reg rst_n
;
wire
[15:0
] ycrcb
;
reg de
;
reg vsync
;
reg hsync
;
reg
[11:0
] cnt_h
;
reg
[11:0
] cnt_v
;
reg
[7:0
] lumi
;
reg
[7:0
] cbcr
;//uut的輸出信號
wire bt1120_clk
;
wire
[15:0
] bt1120_data
;//時鐘周期,單位為ns,可在此修改時鐘周期。
parameter CYCLE
= 7;//復位時間,此時表示復位3個時鐘周期的時間。
parameter RST_TIME
= 20 ;ycbcr422_to_bt1120 u_ycbcr422_to_bt1120
(.rst_n
(rst_n
), //input .clk
(clk
), //input .data_de
(de
), //input
[15:0
] .hsync
(hsync
), //input .vsync
(vsync
), //input .ycbcr
(ycrcb
), //input //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'd1120
; //有效數據的最后一行,以行為單位parameter data_de_start
= 8'd192 ; //數據有效開始,以時鐘為單位
parameter data_de_end = 12'd2112
; //數據有效結束,以時鐘為單位//生成本地時鐘50M
initial beginclk
= 0;forever
clk=~clk
;
end//產生復位信號
initial beginrst_n
= 1;rst_n
= 0;rst_n
= 1;
end//一行數據的計數器
always @
(posedge clk or negedge rst_n
)beginif
(rst_n
==1'b0)begincnt_h <= 12'b0
;end
else beginif
(cnt_h
== h_total-1
)cnt_h
<= 12'b0 ;elsecnt_h <= cnt_h + 1 ;end
end//一幀數據的計數器,1080P 60hz的一幀數據共有1125行
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0
)begincnt_v
<= 12'b0 ;endelse if(cnt_h == h_total-1)beginif(cnt_v == v_total-1)cnt_v <= 12'b0
;elsecnt_v
<= cnt_v +
1 ;end
end//產生行信號
always @
(posedge clk or negedge rst_n
)beginif
(rst_n
==1'b0)beginhsync <= 1'b0
;end
else if
(cnt_h
< hsync_pw
)beginhsync
<= 1'b1 ;endelse beginhsync <= 1'b0
;end
end//產生場信號
always @
(posedge clk or negedge rst_n
)beginif
(rst_n
==1'b0)beginvsync <= 1'b0
;end
else if
(cnt_v
< vsync_pw
)beginvsync
<= 1'b1 ;endelse beginvsync <= 1'b0
;end
end//產生數據有效信號
always @
(posedge clk or negedge rst_n
)beginif
(rst_n
==1'b0)beginde <= 1'b0
;lumi
<= 8'b0;cbcr <= 8'b0
;end
else if
(cnt_v
>= data_f_enabel-1
&& cnt_v
<= data_e_enabel
)beginif
(cnt_h
>= data_de_start-1
&& cnt_h
< data_de_end-1
)beginde
<= 1'b1 ;lumi <= lumi+1;cbcr <= cbcr+1;endelse beginde <= 1'b0
;lumi
<= 8'b0;cbcr <= 8'b0
;endend
endassign ycrcb
= {lumi,cbcr
} ;endmodule
總結
以上是生活随笔為你收集整理的基于FPGA的1080P 60Hz BT1120接口调试过程记录的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。