友晶科技的DE10-Nano 开发板和 C5G 开发板上都配备ADV7513芯片,这两个板子都能支持最高1080P高清HDMI 显示接口。
关于ADV7513芯片的控制实现分三个.v 文件:
I2C_HDMI_Config.v解析:
系统时钟是50MHz,但是I2C 的时钟不能太高,从ADV7513手册上看, 最大不能超过400KHz:
所以代码里面设计了一个分频电路,设置I2C频率是20K:
I2C_HDMI_Config.v状态机框图:
关于状态图里面的 mI2C_ACK 信号, 可以参考下面 I2C_WRITE_WDATA.v 的时序图, 正好每27bit传输完ACK信号就是0了。
关于ADV7513的寄存器配置, 代码里面主要配置了31个寄存器,其他的没有配置的就表示使用的是默认的配置,具体可以参考ADV7513芯片控制解读(中文版)--基于DE10-Nano开发板--C5G 开发板
I2C_HDMI_Config.v代码:
module I2C_HDMI_Config ( // Host Side iCLK, iRST_N, // I2C Side I2C_SCLK, I2C_SDAT, HDMI_TX_INT, READY ); // Host Side input iCLK; input iRST_N; // I2C Side output I2C_SCLK; inout I2C_SDAT; input HDMI_TX_INT; output READY ; // Internal Registers/Wires reg [15:0] mI2C_CLK_DIV; reg [23:0] mI2C_DATA; reg mI2C_CTRL_CLK; reg mI2C_GO; wire mI2C_END; wire mI2C_ACK; reg [15:0] LUT_DATA; reg [5:0] LUT_INDEX; reg [3:0] mSetup_ST; reg READY ; // Clock Setting parameter CLK_Freq = 50000000; // 50 MHz parameter I2C_Freq = 20000; // 20 KHz // LUT Data Number parameter LUT_SIZE = 31; ///////////////////// I2C Control Clock //////////////////////// always@(posedge iCLK or negedge iRST_N) begin if(!iRST_N) begin mI2C_CTRL_CLK <= 0; mI2C_CLK_DIV <= 0; end else begin if( mI2C_CLK_DIV < (CLK_Freq/I2C_Freq) ) mI2C_CLK_DIV <= mI2C_CLK_DIV+1; else begin mI2C_CLK_DIV <= 0; mI2C_CTRL_CLK <= ~mI2C_CTRL_CLK; end end end //////////////////////////////////////////////////////////////////// I2C_Controller u0 ( .CLOCK(mI2C_CTRL_CLK), // Controller Work Clock .I2C_SCLK(I2C_SCLK), // I2C CLOCK .I2C_SDAT(I2C_SDAT), // I2C DATA .I2C_DATA(mI2C_DATA), // DATA:[SLAVE_ADDR,SUB_ADDR,DATA] .GO(mI2C_GO), // GO transfor .END(mI2C_END), // END transfor .ACK(mI2C_ACK), // ACK .RESET(iRST_N) ); //////////////////////////////////////////////////////////////////// ////////////////////// Config Control //////////////////////////// always@(posedge mI2C_CTRL_CLK or negedge iRST_N) begin if(!iRST_N) begin READY<=0; LUT_INDEX <= 0; mSetup_ST <= 0; mI2C_GO <= 0; end else begin if(LUT_INDEX<LUT_SIZE) begin READY<=0; case(mSetup_ST) 0: begin mI2C_DATA <= {8'h72,LUT_DATA}; mI2C_GO <= 1; mSetup_ST <= 1; end 1: begin if(mI2C_END) begin if(!mI2C_ACK) mSetup_ST <= 2; else mSetup_ST <= 0; mI2C_GO <= 0; end end 2: begin LUT_INDEX <= LUT_INDEX+1; mSetup_ST <= 0; end endcase end else begin READY<=1; if(!HDMI_TX_INT) begin LUT_INDEX <= 0; end else LUT_INDEX <= LUT_INDEX; end end end //////////////////////////////////////////////////////////////////// ///////////////////// Config Data LUT ////////////////////////// always begin case(LUT_INDEX) // Video Config Data 每一个16位值的前8bit是寄存器的地址,后面的8bit是要填入寄存器的值。这里设定的只是我们用到的,其他的没有设定的直接用default值即可。 0 : LUT_DATA <= 16'h9803; //Must be set to 0x03 for proper operation 1 : LUT_DATA <= 16'h0100; //Set 'N' value at 6144 2 : LUT_DATA <= 16'h0218; //Set 'N' value at 6144 3 : LUT_DATA <= 16'h0300; //Set 'N' value at 6144 4 : LUT_DATA <= 16'h1470; // Set Ch count in the channel status to 8. 5 : LUT_DATA <= 16'h1520; //Input 444 (RGB or YCrCb) with Separate Syncs, 48kHz fs 6 : LUT_DATA <= 16'h1630; //Output format 444, 24-bit input 7 : LUT_DATA <= 16'h1846; //Disable CSC 8 : LUT_DATA <= 16'h4080; //General control packet enable 9 : LUT_DATA <= 16'h4110; //Power down control 10 : LUT_DATA <= 16'h49A8; //Set dither mode - 12-to-10 bit 11 : LUT_DATA <= 16'h5510; //Set RGB in AVI infoframe 12 : LUT_DATA <= 16'h5608; //Set active format aspect 13 : LUT_DATA <= 16'h96F6; //Set interrup 14 : LUT_DATA <= 16'h7307; //Info frame Ch count to 8 15 : LUT_DATA <= 16'h761f; //Set speaker allocation for 8 channels 16 : LUT_DATA <= 16'h9803; //Must be set to 0x03 for proper operation 17 : LUT_DATA <= 16'h9902; //Must be set to Default Value 18 : LUT_DATA <= 16'h9ae0; //Must be set to 0b1110000 19 : LUT_DATA <= 16'h9c30; //PLL filter R1 value 20 : LUT_DATA <= 16'h9d61; //Set clock divide 21 : LUT_DATA <= 16'ha2a4; //Must be set to 0xA4 for proper operation 22 : LUT_DATA <= 16'ha3a4; //Must be set to 0xA4 for proper operation 23 : LUT_DATA <= 16'ha504; //Must be set to Default Value 24 : LUT_DATA <= 16'hab40; //Must be set to Default Value 25 : LUT_DATA <= 16'haf16; //Select HDMI mode 26 : LUT_DATA <= 16'hba60; //No clock delay 27 : LUT_DATA <= 16'hd1ff; //Must be set to Default Value 28 : LUT_DATA <= 16'hde10; //Must be set to Default for proper operation 29 : LUT_DATA <= 16'he460; //Must be set to Default Value 30 : LUT_DATA <= 16'hfa7d; //Nbr of times to look for good phase default: LUT_DATA <= 16'h9803; endcase end //////////////////////////////////////////////////////////////////// endmodule
另外说明下HDMI_TX_INT信号:低电平有效。ADV7513_Hardware_User's_Guide_R0.pdf的第17页:
I2C_Controller.v解析:
例化了一个I2C_WRITE_WDATA.v模块,将I2C_WRITE_WDATA.v模块的SDAI 和SDAO 之间增加了一个三态缓冲电路,具体原理可参考博客:
module I2C_Controller (
input CLOCK,
input [23:0]I2C_DATA,
input GO,
input RESET,
input W_R,
inout I2C_SDAT,
output I2C_SCLK,
output END,
output ACK
);
wire SDAO ;
assign I2C_SDAT = SDAO?1'bz :0 ;
I2C_WRITE_WDATA wrd(
.RESET_N ( RESET),
.PT_CK ( CLOCK),
.GO ( GO ),
.END_OK ( END ),
.ACK_OK ( ACK ),
.BYTE_NUM ( 2 ), //2byte
.SDAI ( I2C_SDAT ),//IN
.SDAO ( SDAO ),//OUT
.SCLO ( I2C_SCLK ),
.SLAVE_ADDRESS( I2C_DATA[23:16] ),
.REG_DATA ( I2C_DATA[15:0] )
);
endmodule
I2C_WRITE_WDATA.v解析:
实现I2C 的写时序。根据I2C协议:
-
I2C 的开始条件是 SCLK保持高电平时,SDA电平有一个由高到低的变化。
-
接着开始传输地址和数据。
-
I2C的结束条件是 SCLK保持高电平时,SDA电平有一个由低到高的变化。
I2C写时序:
状态机框图
时序框图
I2C_WRITE_WDATA.v 代码:
module I2C_WRITE_WDATA (
input RESET_N , //复位信号,低有效
input PT_CK, //输入时钟
input GO, //I2C起始标志,1表示起始,0表示停止
input [15:0] REG_DATA, //REG_DATA[15:8] 是register number,REG_DATA[7:0]是data
input [7:0] SLAVE_ADDRESS, //I2C Slave address 8bit输入
input SDAI, //I2C data输入
output reg SDAO, //I2C data输出
output reg SCLO, //I2C的clock (scl)輸出
output reg END_OK, //I2C 传输结束通知, 1表示结束,0 表示还在传输
//--for test
output reg [7:0] ST , //状态机的状态值
output reg [7:0] CNT, //计数传输了数据第几bit
output reg [7:0] BYTE, //要输入到寄存器的 数据 是在第 1~2 byte
output reg ACK_OK, //I2C的ack回应,0表示有ack,1表示没有ack
input [7:0] BYTE_NUM // 4 : 4 byte 輸入設定要寫入register是幾byte的資料 ,”1”表 寫入1byte資料 ,”2”表寫入2byte 資料
);
//===reg/wire
reg [8:0]A ;
always @( negedge RESET_N or posedge PT_CK )begin
if (!RESET_N ) ST <=0;
else
case (ST)
0: begin //start
SDAO <=1;
SCLO <=1;
ACK_OK <=0;
CNT <=0;
END_OK <=1;
BYTE <=0;
if (GO) ST <=30 ; // inital
end
1: begin //start
ST <=2 ;
{ SDAO, SCLO } <= 2'b01;
A <= {SLAVE_ADDRESS ,1'b1 };//WRITE COMMAND
end
2: begin //start
ST <=3 ;
{ SDAO, SCLO } <= 2'b00;
end
3: begin
ST <=4 ;
{ SDAO, A } <= { A ,1'b0 };
end
4: begin
ST <=5 ;
SCLO <= 1'b1 ;
CNT <= CNT +1 ;
end
5: begin
SCLO <= 1'b0 ;
if (CNT==9) begin
if ( BYTE == BYTE_NUM ) ST <= 6 ;
else begin
CNT <=0 ;
ST <= 2 ;
if ( BYTE ==0 ) begin BYTE <=1 ; A <= {REG_DATA[15:8] ,1'b1 }; end
else if ( BYTE ==1 ) begin BYTE <=2 ; A <= {REG_DATA[7:0] ,1'b1 }; end
end
if (SDAI ) ACK_OK <=1 ;
end
else ST <= 2;
end
6: begin //stop
ST <=7 ;
{ SDAO, SCLO } <= 2'b00;
end
7: begin //stop
ST <=8 ;
{ SDAO, SCLO } <= 2'b01;
end
8: begin //stop
ST <=9 ;
{ SDAO, SCLO } <= 2'b11;
end
9: begin
ST <= 30;
SDAO <=1;
SCLO <=1;
CNT <=0;
END_OK <=1;
BYTE <=0;
end
//--- END ---
30: begin
if (!GO) ST <=31;
end
31: begin //
END_OK<=0;
ACK_OK<=0;
ST <=1;
end
endcase
end
endmodule
相关阅读:
友晶科技FPGA开发板DE10-Nano的HDMI彩条实验(一)——HDMI简介
友晶科技FPGA开发板DE10-Nano的HDMI彩条实验(二)——TMDS算法
友晶科技FPGA开发板DE10-Nano的HDMI彩条实验(三)——DE10-Nano 的HDMI电路简介
友晶科技FPGA开发板DE10-Nano的HDMI彩条实验(四)——实验源码及现象演示
ADV7513芯片控制解读(中文版)——基于DE10-NANO开发板——C5G 开发板
DE10-Nano 的HDMI显示彩条实验遇到显示器显示“超频”
友晶科技FPGA开发板DE10-NANO的HDMI 方块移动实验
无