FPGA实现HDMI传输(二)

2024-08-29 13:44
文章标签 实现 fpga 传输 hdmi

本文主要是介绍FPGA实现HDMI传输(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前的文章简单介绍了HDMI接口、TMDS编码以及ADV611工作原理和寄存器配置,本篇博客将给出具体的代码以及板级验证结果,代码参考自米联客的教程。

一.ADV7611配置

1.i2c驱动模块

`timescale 1ns / 1psmodule uii2c#
(parameter       WMEN_LEN        =       8'd0,                                           //写入字节长度parameter       RMEN_LEN        =       8'd0,                                           //读出字节长度parameter       CLK_DIV         =       16'd499                                         //i2c时钟分频系数
)
(input                                       clk_i,                                      //系统时钟input            [7:0]                      rd_cnt,                                     //读数据长度,包含器件地址input                                       iic_en,                                     //i2c使能信号input                                       iic_mode,                                   //i2c工作模式input            [WMEN_LEN*8-1'b1:0]        wr_data,                                    //写入数据input            [7:0]                      wr_cnt,                                     //写数据长度,包含器件地址output       reg [RMEN_LEN*8-1'b1:0]        rd_data     =   0,                          //读取数据output       reg                            iic_scl     =   0 ,                         //i2c时钟总线output       reg                            iic_busy    =   0,                          //i2c忙碌,拉高时不进行操作inout        wire                           iic_sda,                                    //i2c数据总线output       reg                            sda_dg      =   1'b1                        //用于调试
);parameter               IDLE        =       4'd0;                                       //空闲状态parameter               START       =       4'd1;                                       //开始parameter               W_WAIT      =       4'd2;                                       //写入数据parameter               W_ACK       =       4'd3;                                       //写响应parameter               R_WAIT      =       4'd4;                                       //读取数据parameter               R_ACK       =       4'd5;                                       //读响应parameter               STOP1       =       4'd6;                                       //停止信号1parameter               STOP2       =       4'd7;                                       //停止信号2parameter               OFFSET      =       CLK_DIV - CLK_DIV/4;                        //产生i2c时钟reg         [2:0]       IIC_S       =       4'd0;                                       //i2c工作状态reg         [15:0]      clkdiv      =       16'd0;                                      //时钟分频计数器reg                     scl_clk     =       1'b0;                                       //i2c工作时钟reg                     scl_r       =       1'b1;                                       //i2c时钟寄存器reg                     sda_o       =       1'b0;                                       //sda输出reg         [7:0]       sda_r       =       8'd0;                                       //i2c数据寄存器reg         [7:0]       sda_i_r     =       8'd0;                                       //i2c输入数据寄存器reg         [7:0]       wcnt        =       8'd0;                                       //写数据计数reg         [7:0]       rcnt        =       8'd0;                                       //读数据计数reg         [2:0]       bcnt        =       3'd0;                                       //读写字节计数reg                     rd_en       =       1'b0;                                       //读使能reg                     iic_sda_r   =       1'b1;                                       //数据总线缓存wire                    scl_offset  =       (clkdiv == OFFSET);                         //scl delay output to fit timingwire                    sda_i;                                                          //i2c数据总线输入//利用计数器产生i2c驱动时钟always@(posedge clk_i)beginif(clkdiv < CLK_DIV)    clkdiv <= clkdiv + 1'b1;else beginclkdiv <= 16'd0; scl_clk <= !scl_clk;endend//三态门处理IOBUF #(.DRIVE(12), // Specify the output drive strength.IBUF_LOW_PWR("TRUE"),  // Low Power - "TRUE", High Performance = "FALSE" .IOSTANDARD("DEFAULT"), // Specify the I/O standard.SLEW("SLOW") // Specify the output slew rate) IOBUF_inst (.O(sda_i),    // Buffer output.IO(iic_sda), // Buffer inout port (connect directly to top-level port).I(sda_o),    // Buffer input.T(sda_o)     // 3-state enable input, high=input, low=output);//时钟总线输出    always @(posedge clk_i) iic_scl <=  scl_offset ?  scl_r : iic_scl;       PULLUP PULLUP_inst (.O(iic_sda));always @(*) beginif(IIC_S == IDLE || IIC_S == STOP1 || IIC_S == STOP2)scl_r <= 1'b1;else scl_r <= ~scl_clk;end   //sda output always @(*) beginif(IIC_S == START || IIC_S == STOP1 || (IIC_S == R_ACK && (rcnt != rd_cnt)))sda_o <= 1'b0;else if(IIC_S == W_WAIT)sda_o <= sda_r[7]; else  sda_o <= 1'b1;end   //sda输出转换always @(negedge scl_clk) beginif(IIC_S == W_ACK || IIC_S == START)beginsda_r <= wr_data[(wcnt*8) +: 8];if( rd_en ) sda_r <= {wr_data[7:1],1'b1};endelse if(IIC_S == W_WAIT)sda_r <= {sda_r[6:0],1'b1};else sda_r <= sda_r;end//sda输入转换  always @(posedge scl_clk) beginif(IIC_S == R_WAIT ||IIC_S == W_ACK ) beginsda_i_r <= {sda_i_r[6:0],sda_i};endelse if(IIC_S == R_ACK)rd_data[((rcnt-1'b1)*8) +: 8] <= sda_i_r[7:0];else if(IIC_S == IDLE)beginsda_i_r <= 8'd0;end endalways @(posedge scl_clk) iic_sda_r <= sda_i;always @(posedge clk_i) sda_dg <= sda_i;//iic状态机always @(negedge scl_clk)begincase(IIC_S) //sda = 1 scl =1IDLE://idle wait iic_en == 1'b1 start trasmit   rd_en == 1'b1 restart if(iic_en == 1'b1 || rd_en == 1'b1)begin iic_busy <= 1'b1;        IIC_S  <= START;endelse beginiic_busy <= 1'b0;wcnt <= 8'd0;rcnt <= 8'd0;rd_en <= 1'b0;endSTART:begin //sda = 0  then scl_clk =0 scl =0 generate startbcnt <= 3'd7;          IIC_S  <= W_WAIT;end           W_WAIT://write data beginif(bcnt > 3'd0)bcnt  <= bcnt - 1'b1; else beginwcnt <= wcnt + 1'b1; IIC_S  <= W_ACK;endend W_ACK://write data ackbegin if(wcnt < wr_cnt)begin bcnt <= 3'd7;IIC_S <= W_WAIT;endelse if(rd_cnt > 3'd0)begin// read dataif(rd_en == 1'b0 && iic_mode == 1'b1)begin rd_en <= 1'b1;IIC_S <= IDLE;  endelse IIC_S <= R_WAIT;bcnt <= 3'd7;endelseIIC_S <= STOP1; if(iic_sda_r == 1'b1)IIC_S <= STOP1;end  R_WAIT://read databeginrd_en <= 1'b0;bcnt  <= bcnt - 1'b1; if(bcnt == 3'd0)beginrcnt <= (rcnt < rd_cnt) ? (rcnt + 1'b1) : rcnt;IIC_S  <= R_ACK;endendR_ACK://read date ackbeginbcnt <= 3'd7;IIC_S <= (rcnt < rd_cnt) ? R_WAIT : STOP1; end  STOP1://sda = 0 scl = 1IIC_S <= STOP2;STOP2://sda = 1 scl = 1IIC_S <= IDLE;          default:IIC_S <= IDLE;endcase
endendmodule

2.adv7611寄存器数据

`timescale 1ns / 1psmodule ui7611reg(input               [8 :0]              REG_INDEX,                      //对已配置寄存器计数output          reg [31:0]              REG_DATA,                       //寄存器地址+写入数据output              [8 :0]              REG_SIZE                        //需配置寄存器个数
);assign	                                REG_SIZE    =   9'd182;//-----------------------------------------------------------------
/	Config Data REG	  //	
always@(*)
case(REG_INDEX)
//write Data Index0   : REG_DATA	=	{8'h98,8'hF4, 8'h80};	//Manufacturer ID Byte - High (Read only)1   : REG_DATA	=	{8'h98,8'hF5, 8'h7c};	//Manufacturer ID Byte - Low (Read only)2   : REG_DATA	= 	{8'h98,8'hF8, 8'h4c};	// BIT[7]-Reset all the Reg 3   : REG_DATA	= 	{8'h98,8'hF9, 8'h64};	//DC offset for analog process4   : REG_DATA	= 	{8'h98,8'hFA, 8'h6c};	//COM10 : href/vsync/pclk/data reverse(Vsync H valid)5   : REG_DATA	= 	{8'h98,8'hFB, 8'h68};	//VGA :	8'h22;	QVGA :	8'h3f;6   : REG_DATA	= 	{8'h98,8'hFD, 8'h44};	//VGA :	8'ha4;	QVGA :	8'h50;7   : REG_DATA	=	{8'h98,8'h01, 8'h05};	//VGA :	8'h07;	QVGA :	8'h03;8   : REG_DATA	= 	{8'h98,8'h00, 8'h1F};	//VGA :	8'hf0;	QVGA :	8'h78;9   : REG_DATA	= 	{8'h98,8'h02, 8'hF7};	//HREF	/ 8'h8010  : REG_DATA  = 	{8'h98,8'h03, 8'h40};	//VGA :	8'hA0;	QVGA :	8'hF011  : REG_DATA  = 	{8'h98,8'h04, 8'h42};	//VGA :	8'hF0;	QVGA :	8'h7812  : REG_DATA	=	{8'h98,8'h05, 8'h28};	//13  : REG_DATA	= 	{8'h98,8'h06, 8'ha7};	//14  : REG_DATA	= 	{8'h98,8'h0b, 8'h44};	//BIT[6] :	0 :VGA; 1;QVGA15  : REG_DATA	= 	{8'h98,8'h0C, 8'h42};	//16  : REG_DATA	= 	{8'h98,8'h15, 8'h80};	//17  : REG_DATA	= 	{8'h98,8'h19, 8'h8a};	//18  : REG_DATA	= 	{8'h98,8'h33, 8'h40};	//19  : REG_DATA	= 	{8'h98,8'h14, 8'h3f};	//20  : REG_DATA	= 	{8'h44,8'hba, 8'h01};	//21  : REG_DATA	= 	{8'h44,8'h7c, 8'h01};	//	22  : REG_DATA	= 	{8'h64,8'h40, 8'h81};	//DSP_Ctrl4 :00/01 : YUV or RGB; 10 : RAW8; 11 : RAW10		23  : REG_DATA	=	{8'h68,8'h9b, 8'h03};   //ADI recommanded setting24  : REG_DATA	=	{8'h68,8'hc1, 8'h01};	//ADI recommanded setting25  : REG_DATA	=	{8'h68,8'hc2, 8'h01};	//ADI recommanded setting26  : REG_DATA	=	{8'h68,8'hc3, 8'h01};	//ADI recommanded setting27  : REG_DATA	=	{8'h68,8'hc4, 8'h01};	//ADI recommanded setting28  : REG_DATA	=	{8'h68,8'hc5, 8'h01};	//ADI recommanded setting29  : REG_DATA	=	{8'h68,8'hc6, 8'h01};	//ADI recommanded setting30  : REG_DATA	=	{8'h68,8'hc7, 8'h01};	//ADI recommanded setting31  : REG_DATA	=	{8'h68,8'hc8, 8'h01};	//ADI recommanded setting32  : REG_DATA	=	{8'h68,8'hc9, 8'h01};	//ADI recommanded settin g33  : REG_DATA	=	{8'h68,8'hca, 8'h01};	//ADI recommanded setting34  : REG_DATA	=	{8'h68,8'hcb, 8'h01};	//ADI recommanded setting35  : REG_DATA	=	{8'h68,8'hcc, 8'h01};	//ADI recommanded setting36  : REG_DATA	=	{8'h68,8'h00, 8'h00}; 	//Set HDMI input Port A37  : REG_DATA	=	{8'h68,8'h83, 8'hfe};	//terminator for Port A38  : REG_DATA	=	{8'h68,8'h6f, 8'h08};	//ADI recommended setting39  : REG_DATA	=	{8'h68,8'h85, 8'h1f};	//ADI recommended setting40  : REG_DATA	=	{8'h68,8'h87, 8'h70};	//ADI recommended setting41  : REG_DATA	=	{8'h68,8'h8d, 8'h04};	//LFG42  : REG_DATA	=	{8'h68,8'h8e, 8'h1e};	//HFG43  : REG_DATA	=	{8'h68,8'h1a, 8'h8a};	//unmute audio44  : REG_DATA	=	{8'h68,8'h57, 8'hda};	// ADI recommended setting45  : REG_DATA	=	{8'h68,8'h58, 8'h01};46  : REG_DATA	=	{8'h68,8'h75, 8'h10}; 47  : REG_DATA	= 	{8'h68,8'h6c ,8'ha3};//enable manual HPA48  : REG_DATA	= 	{8'h98,8'h20 ,8'h70};//HPD low49  : REG_DATA	= 	{8'h64,8'h74 ,8'h00};//disable internal EDID 
//edid 
//0: REG_DATA	= 	{8'h68,8'h6c ,8'ha3}; enable manual HPA
//1: REG_DATA	= 	{8'h98,8'h20 ,8'h70};//HPD low
//2: REG_DATA	= 	{8'h64,8'h74 ,8'h00};//disable internal EDID  
//edid par50  : REG_DATA	= 	{8'h6c,8'd0  , 8'h00};51  : REG_DATA	= 	{8'h6c,8'd1  , 8'hFF};52  : REG_DATA	= 	{8'h6c,8'd2  , 8'hFF};53  : REG_DATA	= 	{8'h6c,8'd3  , 8'hFF};54  : REG_DATA	= 	{8'h6c,8'd4  , 8'hFF};55  : REG_DATA	= 	{8'h6c,8'd5  , 8'hFF};56  : REG_DATA	= 	{8'h6c,8'd6  , 8'hFF};57  : REG_DATA	= 	{8'h6c,8'd7  , 8'h00};58  : REG_DATA	= 	{8'h6c,8'd8  , 8'h20};59  : REG_DATA	= 	{8'h6c,8'd9  , 8'hA3};60  : REG_DATA	= 	{8'h6c,8'd10 , 8'h29};61  : REG_DATA	= 	{8'h6c,8'd11 , 8'h00};62  : REG_DATA	= 	{8'h6c,8'd12 , 8'h01};63  : REG_DATA	= 	{8'h6c,8'd13 , 8'h00};64  : REG_DATA	= 	{8'h6c,8'd14 , 8'h00};65  : REG_DATA	= 	{8'h6c,8'd15 , 8'h00};66  : REG_DATA	= 	{8'h6c,8'd16 , 8'h23};67  : REG_DATA	= 	{8'h6c,8'd17 , 8'h12};68  : REG_DATA	= 	{8'h6c,8'd18 , 8'h01};69  : REG_DATA	= 	{8'h6c,8'd19 , 8'h03};70  : REG_DATA	= 	{8'h6c,8'd20 , 8'h80};71  : REG_DATA	= 	{8'h6c,8'd21 , 8'h73};72  : REG_DATA	= 	{8'h6c,8'd22 , 8'h41};73  : REG_DATA	= 	{8'h6c,8'd23 , 8'h78};74  : REG_DATA	= 	{8'h6c,8'd24 , 8'h0A};75  : REG_DATA	= 	{8'h6c,8'd25 , 8'hF3};76  : REG_DATA	= 	{8'h6c,8'd26 , 8'h30};77  : REG_DATA	= 	{8'h6c,8'd27 , 8'hA7};78  : REG_DATA	= 	{8'h6c,8'd28 , 8'h54};79  : REG_DATA	= 	{8'h6c,8'd29 , 8'h42};80  : REG_DATA	= 	{8'h6c,8'd30 , 8'hAA};81  : REG_DATA	= 	{8'h6c,8'd31 , 8'h26};82  : REG_DATA	= 	{8'h6c,8'd32 , 8'h0F};83  : REG_DATA	= 	{8'h6c,8'd33 , 8'h50};84  : REG_DATA	= 	{8'h6c,8'd34 , 8'h54};85  : REG_DATA	= 	{8'h6c,8'd35 , 8'h25};86  : REG_DATA	= 	{8'h6c,8'd36 , 8'hC8};87  : REG_DATA	= 	{8'h6c,8'd37 , 8'h00};88  : REG_DATA	= 	{8'h6c,8'd38 , 8'h61};89  : REG_DATA	= 	{8'h6c,8'd39 , 8'h4F};90  : REG_DATA	= 	{8'h6c,8'd40 , 8'h01};91  : REG_DATA	= 	{8'h6c,8'd41 , 8'h01};92  : REG_DATA	= 	{8'h6c,8'd42 , 8'h01};93  : REG_DATA	= 	{8'h6c,8'd43 , 8'h01};94  : REG_DATA	= 	{8'h6c,8'd44 , 8'h01};95  : REG_DATA	= 	{8'h6c,8'd45 , 8'h01};96  : REG_DATA	= 	{8'h6c,8'd46 , 8'h01};97  : REG_DATA	= 	{8'h6c,8'd47 , 8'h01};98  : REG_DATA	= 	{8'h6c,8'd48 , 8'h01};99  : REG_DATA	= 	{8'h6c,8'd49 , 8'h01};100  : REG_DATA	= 	{8'h6c,8'd50 , 8'h01};101  : REG_DATA	= 	{8'h6c,8'd51 , 8'h01};102  : REG_DATA	= 	{8'h6c,8'd52 , 8'h01};103  : REG_DATA	= 	{8'h6c,8'd53 , 8'h01};104  : REG_DATA	= 	{8'h6c,8'd54 , 8'h02};105  : REG_DATA	= 	{8'h6c,8'd55 , 8'h3A};106  : REG_DATA	= 	{8'h6c,8'd56 , 8'h80};107  : REG_DATA	= 	{8'h6c,8'd57 , 8'h18};108  : REG_DATA	= 	{8'h6c,8'd58 , 8'h71};109  : REG_DATA	= 	{8'h6c,8'd59 , 8'h38};110  : REG_DATA	= 	{8'h6c,8'd60 , 8'h2D};111  : REG_DATA	= 	{8'h6c,8'd61 , 8'h40};112  : REG_DATA	= 	{8'h6c,8'd62 , 8'h58};113  : REG_DATA	= 	{8'h6c,8'd63 , 8'h2C};114  : REG_DATA	= 	{8'h6c,8'd64 , 8'h45};115  : REG_DATA	= 	{8'h6c,8'd65 , 8'h00};116  : REG_DATA	= 	{8'h6c,8'd66 , 8'h80};117  : REG_DATA	= 	{8'h6c,8'd67 , 8'h88};118  : REG_DATA	= 	{8'h6c,8'd68 , 8'h42};119  : REG_DATA	= 	{8'h6c,8'd69 , 8'h00};120  : REG_DATA	= 	{8'h6c,8'd70 , 8'h00};121  : REG_DATA	= 	{8'h6c,8'd71 , 8'h1E};122  : REG_DATA	= 	{8'h6c,8'd72 , 8'h8C};123  : REG_DATA	= 	{8'h6c,8'd73 , 8'h0A};124  : REG_DATA	= 	{8'h6c,8'd74 , 8'hD0};125  : REG_DATA	= 	{8'h6c,8'd75 , 8'h8A};126  : REG_DATA	= 	{8'h6c,8'd76 , 8'h20};127  : REG_DATA	= 	{8'h6c,8'd77 , 8'hE0};128  : REG_DATA	= 	{8'h6c,8'd78 , 8'h2D};129  : REG_DATA	= 	{8'h6c,8'd79 , 8'h10};130  : REG_DATA	= 	{8'h6c,8'd80 , 8'h10};131  : REG_DATA	= 	{8'h6c,8'd81 , 8'h3E};132  : REG_DATA	= 	{8'h6c,8'd82 , 8'h96};133  : REG_DATA	= 	{8'h6c,8'd83 , 8'h00};134  : REG_DATA	= 	{8'h6c,8'd84 , 8'h80};135  : REG_DATA	= 	{8'h6c,8'd85 , 8'h88};136  : REG_DATA	= 	{8'h6c,8'd86 , 8'h42};137  : REG_DATA	= 	{8'h6c,8'd87 , 8'h00};138  : REG_DATA	= 	{8'h6c,8'd88 , 8'h00};139  : REG_DATA	= 	{8'h6c,8'd89 , 8'h18};140  : REG_DATA	= 	{8'h6c,8'd90 , 8'h00};141  : REG_DATA	= 	{8'h6c,8'd91 , 8'h00};142  : REG_DATA	= 	{8'h6c,8'd92 , 8'h00};143  : REG_DATA	= 	{8'h6c,8'd93 , 8'hFC};144  : REG_DATA	= 	{8'h6c,8'd94 , 8'h00};145  : REG_DATA	= 	{8'h6c,8'd95 , 8'h48};146  : REG_DATA	= 	{8'h6c,8'd96 , 8'h44};147  : REG_DATA	= 	{8'h6c,8'd97 , 8'h4D};148  : REG_DATA	= 	{8'h6c,8'd98 , 8'h49};149  : REG_DATA	= 	{8'h6c,8'd99 , 8'h20};150  : REG_DATA	= 	{8'h6c,8'd100 , 8'h20};151  : REG_DATA	= 	{8'h6c,8'd101 , 8'h20};152  : REG_DATA	= 	{8'h6c,8'd102 , 8'h20};153  : REG_DATA	= 	{8'h6c,8'd103 , 8'h0A};154  : REG_DATA	= 	{8'h6c,8'd104 , 8'h20};155  : REG_DATA	= 	{8'h6c,8'd105 , 8'h20};156  : REG_DATA	= 	{8'h6c,8'd106 , 8'h20};157  : REG_DATA	= 	{8'h6c,8'd107 , 8'h20};158  : REG_DATA	= 	{8'h6c,8'd108 , 8'h00};159  : REG_DATA	= 	{8'h6c,8'd109 , 8'h00};160  : REG_DATA	= 	{8'h6c,8'd110 , 8'h00};161  : REG_DATA	= 	{8'h6c,8'd111 , 8'hFD};162  : REG_DATA	= 	{8'h6c,8'd112 , 8'h00};163  : REG_DATA	= 	{8'h6c,8'd113 , 8'h32};164  : REG_DATA	= 	{8'h6c,8'd114 , 8'h55};165  : REG_DATA	= 	{8'h6c,8'd115 , 8'h1F};166  : REG_DATA	= 	{8'h6c,8'd116 , 8'h45};167  : REG_DATA	= 	{8'h6c,8'd117 , 8'h0F};168  : REG_DATA	= 	{8'h6c,8'd118 , 8'h00};169  : REG_DATA	= 	{8'h6c,8'd119 , 8'h0A};170  : REG_DATA	= 	{8'h6c,8'd120 , 8'h20};171  : REG_DATA	= 	{8'h6c,8'd121 , 8'h20};172  : REG_DATA	= 	{8'h6c,8'd122 , 8'h20};173  : REG_DATA	= 	{8'h6c,8'd123 , 8'h20};174  : REG_DATA	= 	{8'h6c,8'd124 , 8'h20};175  : REG_DATA	= 	{8'h6c,8'd125 , 8'h20};176  : REG_DATA	= 	{8'h6c,8'd126 , 8'h01};177  : REG_DATA	= 	{8'h6c,8'd127 , 8'h24};178  : REG_DATA	= 	{8'h64,8'h74  , 8'h01};// enable internal EDID179  : REG_DATA	= 	{8'h98,8'h20  , 8'hf0};// HPD high180  : REG_DATA	= 	{8'h68,8'h6c  , 8'ha2};// disable manual HPA	181  : REG_DATA	=   {8'h98,8'hf4  , 8'h00};default:REG_DATA =0;
endcaseendmodule

3.配置模块顶层

`timescale 1ns / 1psmodule uicfg7611#(parameter	        CLK_DIV         =           16'd999
)
(input                                   clk_i,                                          //系统时钟input                                   rst_n,                                          //系统复位output                                  adv_scl,                                        //i2c时钟总线inout                                   adv_sda,                                        //i2c数据总线output reg                              cfg_done                                        //寄存器配置完成信号
);	reg                     [8 :0]          rst_cnt     =   9'd0;                           //延迟复位计数器reg                                     iic_en;                                         //i2c使能信号reg                     [31:0]          wr_data;                                        //寄存器地址+写入数据reg                     [1 :0]          TS_S        =   2'd0;                           //状态机工作状态reg                     [8 :0]          byte_cnt    =   9'd0;                           //读写字节计数器reg                     [8 :0]          REG_INDEX;                                      //寄存器配置wire                                    iic_busy;                                       //i2c忙碌wire                    [23:0]          REG_DATA;wire                    [8 :0]          REG_SIZE;always@(posedge clk_i) beginif(!rst_n)rst_cnt <= 9'd0;else if(!rst_cnt[8]) rst_cnt <= rst_cnt + 1'b1;end//状态机工作状态转换以及输出always@(posedge clk_i) beginif(!rst_cnt[8])beginREG_INDEX<= 9'd0;iic_en  <= 1'b0;wr_data <= 32'd0;cfg_done<= 1'b0;TS_S    <= 2'd0;    endelse begincase(TS_S)0:if(cfg_done == 1'b0)TS_S <= 2'd1;1:if(!iic_busy)begin//write dataiic_en  <= 1'b1; wr_data[7  :0] <= REG_DATA[23:16];   wr_data[15 :8] <= REG_DATA[15: 8];   wr_data[23:16] <= REG_DATA[7 : 0];endelse TS_S    <= 2'd2;2:beginiic_en  <= 1'b0; if(!iic_busy)begin REG_INDEX<= REG_INDEX + 1'b1;TS_S    <= 2'd3;endend3:begin//read rtc registerif(REG_INDEX == REG_SIZE)begincfg_done <= 1'b1;endTS_S 	<= 2'd0;end endcaseend
enduii2c#(.WMEN_LEN(4),.RMEN_LEN(1),.CLK_DIV(CLK_DIV)//499 for 50M 999 for 100M)uii2c_inst(.clk_i(clk_i),.iic_scl(adv_scl),.iic_sda(adv_sda),.wr_data(wr_data),.wr_cnt(8'd3),//write data max len = 4BYTES.rd_data(),   //read not used.rd_cnt(8'd0),//read not used.iic_mode(1'b0),.iic_en(iic_en),.iic_busy(iic_busy));//7611regui7611reg  ui7611reg_inst(.REG_SIZE(REG_SIZE),.REG_INDEX(REG_INDEX),.REG_DATA(REG_DATA));   endmodule

二.HDMI输出

1.TMDS编码

module TMDSEncoder(input									    clk		        ,//系统时钟信号;input									    rst  	        ,//系统复位信号,高电平有效;input				[7 : 0]	                din		        ,//输入待编码数据input                                       c0              ,//控制信号C0input                                       c1              ,//控制信号c1input                                       de              ,//输入数据有效指示信号;output reg			[9 : 0]	                q_out	         //编码输出数据
);localparam          CTRLTOKEN0      =       10'b1101010100  ;localparam          CTRLTOKEN1      =       10'b0010101011  ;localparam          CTRLTOKEN2      =       10'b0101010100  ;localparam          CTRLTOKEN3      =       10'b1010101011  ;reg                 [7 : 0]                 din_r           ;//reg                 [1 : 0]                 de_r,c0_r,c1_r  ;reg                 [3 : 0]                 n1d,n1q_m,n0q_m ;reg                 [5 : 0]                 cnt             ;reg                 [8 : 0]                 q_m_r           ;wire                [8 : 0]                 q_m             ;//wire                                        condition1      ;wire                                        condition2      ;wire                                        condition3      ;//统计待编码输入数据中1的个数,最多8个1,所以位宽为4。always@(posedge clk)beginif(rst)begin//初始值为0;n1d <= 4'd0;endelse if(de)begin//当DE为高电平,统计输入数据中1的个数。n1d <= din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];endelse begin//当DE为低电平时,对控制信号编码,此时不需要统计输入信号中1的个数,故清零。n1d <= 4'd0;endend//移位寄存器将输入数据暂存,与后续信号对齐。always@(posedge clk)begindin_r   <= din;de_r    <= {de_r[0],de};c0_r    <= {c0_r[0],c0};c1_r    <= {c1_r[0],c1};q_m_r   <= q_m;end//判断条件1,输入数据1的个数多余4或者1的个数等于4并且最低位为0时拉高,其余时间拉低。assign condition1 = ((n1d > 4'd4) || ((n1d == 4'd4) && (~din_r[0])));//对输入的信号进行异或运算。assign q_m[0] = din_r[0];assign q_m[1] = condition1 ? ~((q_m[0] ^ din_r[1])) : (q_m[0] ^ din_r[1]);assign q_m[2] = condition1 ? ~((q_m[1] ^ din_r[2])) : (q_m[1] ^ din_r[2]);assign q_m[3] = condition1 ? ~((q_m[2] ^ din_r[3])) : (q_m[2] ^ din_r[3]);assign q_m[4] = condition1 ? ~((q_m[3] ^ din_r[4])) : (q_m[3] ^ din_r[4]);assign q_m[5] = condition1 ? ~((q_m[4] ^ din_r[5])) : (q_m[4] ^ din_r[5]);assign q_m[6] = condition1 ? ~((q_m[5] ^ din_r[6])) : (q_m[5] ^ din_r[6]);assign q_m[7] = condition1 ? ~((q_m[6] ^ din_r[7])) : (q_m[6] ^ din_r[7]);assign q_m[8] = ~condition1;always@(posedge clk)beginif(rst)begin//初始值为0;n1q_m <= 4'd0;n0q_m <= 4'd0;endelse if(de_r[0])begin//对输入有效数据时,q_m中1和0的个数进行统计;n1q_m <= q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];n0q_m <= 4'd8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);endelse begin//输入数据无效时清零。n1q_m <= 4'd0;n0q_m <= 4'd0;endend//判断条件2,一行已编码数据中1的个数等于0的个数或者本次编码数据中1的个数等于0的个数。assign condition2 = ((cnt == 6'd0) || (n1q_m == n0q_m));//判断条件3,已编码数据中1的多余0并且本次编码中间数据1的个数也多与0的个数或者已编码数据中0的个数较多并且此次编码中0的个数也比较多时拉高,其余时间拉低。assign condition3 = (((~cnt[5]) && (n1q_m > n0q_m)) || (cnt[5] && (n1q_m < n0q_m)));always@(posedge clk)beginif(rst)begin//初始值为0;cnt <= 6'd0;q_out <= 10'd0;endelse if(de_r[1])beginq_out[8] <= q_m_r[8];//第8位为编码方式位,直接输出即可。if(condition2)beginq_out[9] <= ~q_m_r[8];q_out[7:0] <= q_m_r[8] ? q_m_r[7:0] : ~q_m_r[7:0];//进行cnt的计算;cnt <= q_m_r[8] ? (cnt + n1q_m - n0q_m) : (cnt + n0q_m - n1q_m);endelse if(condition3)beginq_out[9] <= 1'b1;q_out[7:0] <= ~q_m_r[7:0];//进行cnt的计算;cnt <= cnt + {q_m_r[8],1'b0} + n0q_m - n1q_m;endelse beginq_out[9] <= 1'b0;q_out[7:0] <= q_m_r[7:0];//进行cnt的计算;cnt <= cnt - {~q_m_r[8],1'b0} + n1q_m - n0q_m;endendelse begincnt <= 6'd0;//对控制信号进行编码时,将计数器清零。case ({c1_r[1],c0_r[1]})2'b00   : q_out <= CTRLTOKEN0;2'b01   : q_out <= CTRLTOKEN1;2'b10   : q_out <= CTRLTOKEN2;2'b11   : q_out <= CTRLTOKEN3;endcaseendendendmodule

2.并串转换以及差分输出

`timescale 1ns / 1psmodule oserdese2_10to1(input                [9:0]             txdata,                                      //输入并行10位数据input                                  pclk,                                        //并行数据时钟input                                  clkdiv2,                                     //并串转换时钟input                                  txrst,                                       //复位信号output                                 tx_p,                                        //差分输出output                                 tx_n
); wire                 [13:0]            tx_data;wire                                   cascade_do, cascade_di, cascade_to, cascade_ti;reg                                    int_rst;wire                                   dai;assign tx_data = {4'd0,txdata[9:0]};                                                //最高支持14位并串转换always @(*)if(txrst == 1'b1)int_rst <= 1'b1;else if(pclk)int_rst <= 1'b0;else int_rst <= int_rst;OBUFDS #(.IOSTANDARD("DEFAULT"), // Specify the output I/O standard.SLEW("SLOW")           // Specify the output slew rate) OBUFDS_inst (.O(tx_p),     // Diff_p output (connect directly to top-level port).OB(tx_n),   // Diff_n output (connect directly to top-level port).I(dai)      // Buffer input);//----------------------------------------------------------------------------------
//-- Cascaded OSERDES for 10:1 ratio (DDR)
//----------------------------------------------------------------------------------
OSERDESE2 #(.DATA_RATE_OQ("DDR"),   // DDR, SDR.DATA_RATE_TQ("SDR"),   // DDR, BUF, SDR.DATA_WIDTH(10),         // Parallel data width (2-8,10,14).SERDES_MODE("MASTER"), // MASTER, SLAVE.TRISTATE_WIDTH(1)      // 3-state converter width (1,4))oserdese2_master (// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each).D1(tx_data[0]),.D2(tx_data[1]),.D3(tx_data[2]),.D4(tx_data[3]),.D5(tx_data[4]),.D6(tx_data[5]),.D7(tx_data[6]),.D8(tx_data[7]),  // T1 - T4: 1-bit (each) input: Parallel 3-state inputs.T1(1'b0),.T2(1'b0),.T3(1'b0),.T4(1'b0), // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each).SHIFTIN1(cascade_di),.SHIFTIN2(cascade_ti),// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each).SHIFTOUT1(),.SHIFTOUT2(),   .OCE(1'b1),             // 1-bit input: Output data clock enable    .CLK(clkdiv2),        // 1-bit input: High speed clock.CLKDIV(pclk),     // 1-bit input: Divided clock                       .OQ(dai),               // 1-bit output: Data path output.TQ(),               // 1-bit output: 3-state control.OFB(),             // 1-bit output: Feedback path for data.TBYTEIN(1'b0),     // 1-bit input: Byte group tristate      .TBYTEOUT(),   // 1-bit output: Byte group tristate.TFB(),             // 1-bit output: 3-state control.TCE(1'b0),          // 1-bit input: 3-state clock enable      .RST(int_rst)             // 1-bit input: Reset);OSERDESE2 #(.DATA_RATE_OQ("DDR"),   // DDR, SDR.DATA_RATE_TQ("SDR"),   // DDR, BUF, SDR.DATA_WIDTH(10),         // Parallel data width (2-8,10,14).SERDES_MODE("SLAVE"), // MASTER, SLAVE.TRISTATE_WIDTH(1)      // 3-state converter width (1,4))oserdese2_slave (// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each).D1(1'b0),.D2(1'b0),.D3(tx_data[8]),.D4(tx_data[9]),.D5(tx_data[10]),.D6(tx_data[11]),.D7(tx_data[12]),.D8(tx_data[13]),  // T1 - T4: 1-bit (each) input: Parallel 3-state inputs.T1(1'b0),.T2(1'b0),.T3(1'b0),.T4(1'b0), // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each).SHIFTOUT1(cascade_di),.SHIFTOUT2(cascade_ti),         // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each).SHIFTIN1(1'b0),.SHIFTIN2(1'b0),.OCE(1'b1),             // 1-bit input: Output data clock enable    .CLK(clkdiv2),        // 1-bit input: High speed clock.CLKDIV(pclk),     // 1-bit input: Divided clock                       .OQ(),               // 1-bit output: Data path output.TQ(),               // 1-bit output: 3-state control.OFB(),             // 1-bit output: Feedback path for data.TFB(),             // 1-bit output: 3-state control.TBYTEIN(1'b0),     // 1-bit input: Byte group tristate      .TBYTEOUT(),   // 1-bit output: Byte group tristate.TCE(1'b0),          // 1-bit input: 3-state clock enable      .RST(int_rst)             // 1-bit input: Reset); endmodule

三.顶层模块

`timescale 1ns / 1psmodule top(input                                               clk_i,                              //系统时钟input                                               hs_i,                               //行同步信号input                                               vs_i,                               //场同步信号input                                               de_i,                               //数据有效信号input                                               pclk_i,                             //像素时钟input               [23:0]                          rgb_i,                              //输入图像数据output                                              adv_rst,                            //adv7611复位信号output                                              adv_scl,                            //时钟总线inout                                               adv_sda,                            //数据总线output                                              HDMI_CLK_P,                         //差分时钟输出output                                              HDMI_CLK_N,output              [2:0]                           HDMI_TX_P,                          //差分数据输出output              [2:0]                           HDMI_TX_N
);assign                                              adv_rst = 1'b1;                     wire                                                cfg_done;                           //寄存器配置完成信号wire                                                locked ;                            //锁相环工作完成信号wire                                                pclkx1,pclkx5;                      //锁相环输出时钟reg                                                 hs_r_0,hs_r_1,hs_r;                 reg                                                 vs_r_0,vs_r_1,vs_r;reg                                                 de_r_0,de_r_1,de_r;reg                 [23:0]                          rgb_r_0;reg                 [23:0]                          rgb_r_1;reg                 [23:0]                          rgb_r;wire                                                rst_o1,rst_o2;wire                                                vid_rst,vid_clk,vid_vs,vid_hs,vid_de;reg                                                 tpg_vs_r = 1'b0;reg                                                 tpg_hs_r = 1'b0;clk_wiz_0 clk_wiz_inst(.clk_out1(pclkx1),.clk_out2(pclkx5),.locked(locked), .clk_in1(pclk_i));uihdmitx uihdmitx_inst
(
.RSTn_i(cfg_done&&locked),
.HS_i(hs_i),
.VS_i(vs_i),
.VDE_i(de_i),
.RGB_i({rgb_i[7:0],rgb_i[15:8],rgb_i[23:16]}),
.PCLKX1_i(pclkx1),
.PCLKX2_5_i(1'b0),
.PCLKX5_i(pclkx5),
.TMDS_TX_CLK_P(HDMI_CLK_P),
.TMDS_TX_CLK_N(HDMI_CLK_N),
.TMDS_TX_P(HDMI_TX_P),
.TMDS_TX_N(HDMI_TX_N)
);uicfg7611 uicfg7611_inst
(
.clk_i(clk_i),
.rst_n(1'b1), 
.adv_scl(adv_scl),
.adv_sda(adv_sda),
.cfg_done(cfg_done)
);endmodule

四.板级验证

这篇关于FPGA实现HDMI传输(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118027

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机