当前位置:网站首页>基于FPGA的1080P 60Hz BT1120接口调试过程记录
基于FPGA的1080P 60Hz BT1120接口调试过程记录
2022-07-25 19:00:00 【丹霞山下的FPGA少年】
这个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; //消隐阶段 //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; //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 )
);
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= BLANKING;
end
else begin
state_c <= state_n;
end
end
[email protected](*)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==12'd275; assign video2eav = state_c==VAILD_VIDEO && cnt_h==12'd2199;
//输入打拍
always @(posedge clk 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 clk )begin if(v_pos || cnt_h == WIDTH_TOTAL-1) cnt_h <= 12'b0;
else
cnt_h <= cnt_h + 1;
end
//一帧计数器
always @(posedge clk )begin
if(v_pos)
cnt_v <= 12'b0; else if(cnt_h == WIDTH_TOTAL-1)begin if(cnt_v == HEIGHT_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 bt1120_ycbcr <= STUFF ; end else begin case(state_c) BLANKING:begin bt1120_ycbcr<= STUFF ; end CODE_SAV1:begin bt1120_ycbcr<= 16'hffff ;
end
CODE_SAV2:begin
bt1120_ycbcr<= 16'h0 ; end CODE_SAV3:begin bt1120_ycbcr<= 16'h0 ;
end
CODE_SAV4:begin
if(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 ; end VAILD_VIDEO:begin bt1120_ycbcr<= rd_data ; end CODE_EAV1:begin bt1120_ycbcr <= 16'hffff;
end
CODE_EAV2:begin
bt1120_ycbcr <= 16'h0; end CODE_EAV3:begin bt1120_ycbcr <= 16'h0;
end
CODE_EAV4:begin
if(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 end assign Lumi = bt1120_ycbcr[15:8] ; assign cbcr = bt1120_ycbcr[7:0] ; //read en always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin
rd_en <= 1'b0 ; end else if(cnt_v>=12'd41 && cnt_v < 12'd1121 )begin if(cnt_h>=12'd279 && cnt_h<12'd2200) rd_en <= 1'b1 ;
else
rd_en <= 1'b0 ; end else begin rd_en <= 1'b0 ;
end
end
endmodule
测试文件
`timescale 1 ns/1ps
module 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 begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);
rst_n = 1;
end
//一行数据的计数器
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
//产生数据有效信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin de <= 1'b0 ;
lumi <= 8'b0; cbcr <= 8'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 ; lumi <= lumi+1; cbcr <= cbcr+1; end else begin de <= 1'b0 ;
lumi <= 8'b0; cbcr <= 8'b0;
end
end
end
assign ycrcb = {
lumi,cbcr} ;
endmodule
边栏推荐
- PHP 中的跨站请求伪造
- #yyds干货盘点# 面试必刷TOP101:反转链表
- Pixel2Mesh从单个RGB图像生成三维网格ECCV2018
- The auction house is a VC, and the first time it makes a move, it throws a Web3
- jmeter性能测试实战视频(常用性能测试工具有哪些)
- 无惧高温暴雨,有孚网络如何保您无忧?
- Process communication (Systemv communication mode: shared memory, message queue, semaphore)
- Youwei low code: use resolutions
- Software testing (mind mapping)
- 接口自动化测试平台FasterRunner系列(一)- 简介、安装部署、启动服务、访问地址、配置补充
猜你喜欢

C 调的满级和玄

优秀的测试/开发程序员突破,不忘初心,方得始终......

Alibaba cloud technology expert Qin long: reliability assurance is a must - how to carry out chaos engineering on the cloud?

人人可参与开源活动正式上线,诚邀您来体验!

HTTP缓存通天篇,可能有你想要的

The understanding of domain adaptation in transfer learning and the introduction of three technologies

Northeast people know sexiness best

Excellent test / development programmers should make breakthroughs and never forget their original intentions, so that they can always
![[encryption weekly] has the encryption market recovered? The cold winter has not thawed yet! Check the major events in the encryption market last week!](/img/6d/b037208996ce52016d014062deaa1f.jpg)
[encryption weekly] has the encryption market recovered? The cold winter has not thawed yet! Check the major events in the encryption market last week!

With a market value of 30billion yuan, the largest IPO in Europe in the past decade was re launched on the New York Stock Exchange
随机推荐
「跨链互连智能合约」解读
Pymoo学习 (8):Gradients
【开源工程】STM32C8T6+ADC信号采集+OLED波形显示
阿里云技术专家郝晨栋:云上可观测能力——问题的发现与定位实践
阿里云技术专家邓青琳:云上跨可用区容灾和异地多活最佳实践
Pyqt5 click qtableview vertical header to get row data and click cell to get row data
ES6 implements the observer mode through proxy and reflection
jmeter性能测试实战视频(常用性能测试工具有哪些)
歌曲转调之后和弦如何转换
聚智云算,向新而生| 有孚网络“专有云”开启新纪元
HTTP cache tongtianpian, there may be something you want
PHP等于==和恒等于===的区别
QT compiled successfully, but the program could not run
Interpretation of "cross chain interconnection smart contract"
[encryption weekly] has the encryption market recovered? The cold winter has not thawed yet! Check the major events in the encryption market last week!
优秀的测试/开发程序员突破,不忘初心,方得始终......
Typescript reflection object reflection use
#yyds干货盘点# 面试必刷TOP101:反转链表
SQL 实现 Excel 的10个常用功能,附面试原题
Yyds dry inventory interview must brush top101: reverse linked list