基于FPGA的SDI发送接口调试,FPGA+GV7700实现1080p和720p的显示

#基于FPGA的SDI发送接口调试,FPGA+GV7700实现1080p和720p的显示
上一篇文章已经调试了bt11200接口,本章将基于bt1120接口完善代码,实现1080p60Hz和720p60Hz的显示兼容。
720p60Hz的数据格式
720p60Hz bt1120数据格式
720p60Hz 861数据格式

1080p60Hz的数据格式
1080p60Hz bt1120格式
1080p60Hz 861数据格式

上板测试,显示彩条

顶层文件

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


测试结果
在这里插入图片描述

  • 3
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值