由於最近實驗室有高速HDMI傳輸需求,所以不得不調試功能極多而傳輸速率高達297MHz,衆多HDMI解碼芯片中傳輸速率最高的一款。而關於這款芯片的使用記錄又很少,所以就在此記錄一下自己的調試心得和自己調試過程中收集到的相關資料及遇到的相關問題,方便後人能夠快速的對該芯片進行配置。
整個調試分爲這幾個階段:
1、查看數據手冊,熟悉各個寄存器的功能,記錄需要配置的額寄存器;
2、用verilog描述IIC協議,用來配置相關寄存器;
3、在2的基礎上添加讀相關寄存器的代碼,並用chipscope讀出相關位置的寄存器的內容,比較與寫入的是否相同。
接下來我就按照這三個階段的順序來講述以下自己苦逼的調試經歷。
一、查看數據手冊,熟悉各個寄存器的功能,記錄需要配置的額寄存器
這裏不得不吐槽以下ADI公司設計的ADV7619芯片,這款芯片的功能實在是太複雜了,所以手冊中寄存器就有一大堆,實現一個基本功能至少需要配置50個寄存器吧,其中還包括一些ADI Required Write,這類寄存器用戶不能更改,而且必須配置。如果你在找這款芯片的資料時,如果只找到了操作手冊(ADV7619 Reference Manual)是遠遠不夠的因爲這個手冊只是詳細的介紹了各個寄存器的功能,根據這個你可以確定一部分你需要配置的寄存器;你必須找同時到ADV7619 Required Manual(這個手冊中有寄存器的地址映射以及各個模式下ADI Required Write的寄存器);同時你還必須找到ADV7619 Register MAP Documenntation,這個文檔可以幫助你確定寄存器的映射關係。如果想更好更便捷的進行調試,你還需要HDMI_RX_FAQV1.0,這個手冊中對ADV7619/ADV7611常見問題進行解答。對於調試有很大幫助。
在最初調試階段由於缺乏寄存器配置經驗,還進入一個誤區,認爲寄存器一定需要自己逐個查看,弄清所有寄存器功能,才能進行配置,所以就花費了一天半的時間看寄存器手冊,基本熟悉各個寄存器功能。後來偶然一個機會點進去ADI官網,在ADI官網的中文論壇中找到了官方推薦的寄存器配置手冊,我的天哪!!!簡直不用努力了,爲什麼還要自己配置,官方推薦配置一定沒問題呀,官方簡直太貼心了,所以就按照官方推薦配置去配置寄存器。官方推薦配置的寄存器文檔名稱是ADV7619-VER.1.9c,大家有需要可以去官網下載。
所以我覺得以後配置什麼芯片都要去官網找這個芯片的所有資料,同時還要去相關論壇看看大家在使用這款芯片時遇到什麼樣的問題及如何解決的。
二、用verilog描述IIC協議,用來配置相關寄存器
在用verilog描述IIC協議時,我犯了一個大錯誤。我們知道,在使用IIC進行寄存器配置時,IIC協議的工作過程如下: 1開始------>2發送器件地址------>3從機應答------->4發送子地址------>5從機應答------>6發送數據------>7從機應答------->8停止,這表示配置一個寄存器的地址完成, 然後繼續循環2~8步。結果我在描述IIC協議的過程,爲了偷懶,我想當然的認爲進入一次寄存器配置開始狀態,如果器件地址相同只需要發送一次器件地址,然後就可以進行所有的寄存器配置,當所有的寄存器都配置完畢,這時,纔可以進入停止狀態,錯誤的工作過程描述如下: 1開始------>2發送器件地址------>3從機應答------->4發送子地址------>5從機應答------>6發送數據------>7從機應答------->8停止,每次配置不同的寄存器僅僅重複4~7步,直到所有的寄存器都配置完畢,才進入第8步,在實際使用中,我發現這樣理解是錯誤的,建議大家不要爲了偷懶而這樣做,這樣做絕對會出問題,如果你這樣做沒出問題,請和我聯繫,咱們一起討論一下這個問題。
接下來就是使用verilog描述IIC協議,這裏我將部分代碼貼出來,對於不同的寄存器的配置只需要在此代碼基礎上修改寄存器值和寄存器的個數即可,代碼如下:
module iic_cfg_hdmi_out(
output SCL,
inout SDA,
input clk35m, //system clk
input rst_n, //system rst
output cfig_done // 0: not config finished //1: finished
);
reg [7:0] sub_address [50:0]; // IIC register address
reg [7:0] data_table [50:0]; // IIC write in data
reg [7:0] device_address[9:0];
parameter i_max=50; //配置寄存器個數
//parameter device_address = 8'h76;
initial begin
/////////////////////////IO寄存器配置device_address[0] = 8'h98;
device_address[0] = 8'h98;////98
device_address[1] = 8'h68;
device_address[2] = 8'h44;
device_address[3] = 8'h64;
device_address[4] = 8'h4c;
device_address[5] = 8'h99;////98
device_address[6] = 8'h69;
device_address[7] = 8'h45;
device_address[8] = 8'h65;
device_address[9] = 8'h4d;
//////////////////////////IO寄存器配置device_address[0] = 8'h98;
sub_address[0] = 8'hff;////////I2C reset
data_table[0] = 8'h80;
sub_address[1] = 8'hf4;///////CEC
data_table[1] = 8'h80;///////////
sub_address[2] = 8'hf5;//////////INFOFRAME
data_table[2] = 8'h7c;
sub_address[3] = 8'hf8;/////////DPLL
data_table[3] = 8'h4c;/////////
sub_address[4] = 8'hf9;////////KSV
data_table[4] = 8'h64;
sub_address[5] = 8'hfa;//////////EDID
data_table[5] = 8'h6c;
sub_address[6] = 8'hfb;//////////HDMI
data_table[6] = 8'h68;
sub_address[7] = 8'hfd;//////////CP
data_table[7] = 8'h44;
///////////////////////////////
sub_address[8] = 8'hc0;///////0x68////////device_address[1] = 8'h68;////ADI Required Write
data_table[8] = 8'h03;
////////////////////////////////////////////
sub_address[9] = 8'h01;///////0x98//////////device_address[0] = 8'h98;///Prim_Mode =110b HDMI-GR
data_table[9] = 8'h06;//16-50hz///06-60hz
sub_address[10] = 8'h02;//////////////////////////////////////////Auto CSC, RGB out, Set op_656 bit
data_table[10] = 8'hf7;/////RGB???
sub_address[11] = 8'h03;////////////////////////////////////////////24 bit SDR 444 Mode 0
data_table[11] = 8'h40;
sub_address[12] = 8'h04;/////////////////參考晶振24Mhz及RGB與引腳關係
data_table[12] = 8'h66;
sub_address[13] = 8'h05;////////////////////////////////////AV Codes Off
data_table[13] = 8'h28;
sub_address[14] = 8'h06;////////hs vs正極性INV_HS_POL、INV_VS_POL should be set to 1 if not specified in Table 7
data_table[14] = 8'ha6;
sub_address[15] = 8'h0c;
data_table[15] = 8'h42;
sub_address[16] = 8'h15;
data_table[16] = 8'h80;
sub_address[17] = 8'h19;
data_table[17] = 8'h83;
sub_address[18] = 8'h33;
data_table[18] = 8'h40;///////////98 33 40///////
/////////////////////////////
sub_address[19] = 8'hba;//////0x44////////device_address[2] = 8'h44;
data_table[19] = 8'h01;
sub_address[20] = 8'h6c;
data_table[20] = 8'h00;
/////////////////////////////////
sub_address[21] = 8'h40;///////0x64/////device_address[3] = 8'h64;
data_table[21] = 8'h81;
///////////////////////////////////////
sub_address[22] = 8'hb5;//////////0x4c/////device_address[4] = 8'h4c;
data_table[22] = 8'h01;
//////////////////////////////////
sub_address[23] = 8'hc0;////////////0x68////device_address[1] = 8'h68;
data_table[23] = 8'h03;
sub_address[24] = 8'h00;
data_table[24] = 8'h00;/////Set HDMI Input Port A (BG_MEAS_PORT_SEL = 001b)
sub_address[25] = 8'h02;
data_table[25] = 8'h03;
sub_address[26] = 8'h03;
data_table[26] = 8'h98;
sub_address[27] = 8'h10;
data_table[27] = 8'ha5;
sub_address[28] = 8'h1b;///////////////
data_table[28] = 8'h08;
sub_address[29] = 8'h45;
data_table[29] = 8'h04;
sub_address[30] = 8'h97;
data_table[30] = 8'hc0;
sub_address[31] = 8'h3d;
data_table[31] = 8'h10;
sub_address[32] = 8'h3e;
data_table[32] = 8'h69;
sub_address[33] = 8'h3f;
data_table[33] = 8'h46;
sub_address[34] = 8'h4e;
data_table[34] = 8'hfe;
sub_address[35] = 8'h4f;
data_table[35] = 8'h08;
sub_address[36] = 8'h50;
data_table[36] = 8'h00;
sub_address[37] = 8'h57;
data_table[37] = 8'ha3;
sub_address[38] = 8'h58;
data_table[38] = 8'h07;
sub_address[39] = 8'h6f;////////////
data_table[39] = 8'h08;
sub_address[40] = 8'h83;
data_table[40] = 8'hfc;
sub_address[41] = 8'h84;
data_table[41] = 8'h03;
sub_address[42] = 8'h85;
data_table[42] = 8'h10;
sub_address[43] = 8'h86;
data_table[43] = 8'h9b;
sub_address[44] = 8'h89;
data_table[44] = 8'h03;
sub_address[45] = 8'h9b;
data_table[45] = 8'h03;
sub_address[46] = 8'h93;
data_table[46] = 8'h03;
sub_address[47] = 8'h5a;//////
data_table[47] = 8'h80;
sub_address[48] = 8'h9c;
data_table[48] = 8'h80;
sub_address[49] = 8'h9c;
data_table[49] = 8'hc0;
sub_address[50] = 8'h9c;
data_table[50] = 8'h00;
end
reg cfig_done_r=0;
assign cfig_done = cfig_done_r;
reg SDA_r;
reg SDA_link;//輸出數據sda信號inout方向控制: 1 output 0 input
reg SCL_r = 'd0;
assign SCL = SCL_r;
assign SDA = SDA_link ? SDA_r : 1'bz;
reg [8:0]cnt_SCL = 'd0;//循環計數,產生iic所需要的時鐘
always @ ( posedge clk35m )
if(cnt_SCL == 9'd349) //週期爲20us,即100KHz
cnt_SCL <= 9'd0;
else
cnt_SCL <= cnt_SCL + 9'b1;//時鐘計數;
`define SCL_pos cnt_SCL == 9'd87 //scl上升沿
`define SCL_hig cnt_SCL == 9'd174 //scl高電平中間,糜謔採樣
`define SCL_neg cnt_SCL == 9'd262 //scl下降沿
`define SCL_low cnt_SCL == 9'd349 //scl低點平中間,用於數據變化
always @ ( posedge clk35m ) // 產生100k SCL signal
if(!cfig_done_r) begin
if(`SCL_pos)
SCL_r<=1'b1; //scl信號上升沿
if(`SCL_neg)
SCL_r<=1'b0; //scl信號下降沿
end
else
SCL_r<=1'b1; // config finish ,scl output 1;
reg [3:0] state; //狀態寄存器
reg [4:0] step; //輸出8位數據串行計數
reg [7:0] data; //在IIC上傳送的數據寄存器
parameter IDLE = 4'D0, //the state during the IIC writing
START = 4'D1,
SLAVE_ADDR = 4'D2,
ACK1 = 4'D3,
SUB_ADDR = 4'D4,
ACK2 = 4'D5,
DATA = 4'D6,
ACK3 = 4'D7,
PAUSE = 4'D8,
OVER = 4'D9;
reg [7:0] i;//連續輸出寄存器地址和數據計數
always @ (posedge clk35m or negedge rst_n) begin
if(!rst_n) begin
data <= 16'd0;
SDA_link <= 1'b1;
SDA_r <= 1'b1;
step <= 5'd0;
state <= IDLE;
i <= 0;
cfig_done_r <= 1'b0;
end
else case(state)
IDLE: begin
SDA_link <= 1'b1;
SDA_r <= 1'b1;
i <= 0;
cfig_done_r <= 1'b0;
state<=START;
end
START: begin
if(`SCL_hig) begin
SDA_r <= 1'b0; //start low
data <= device_address;
state <= SLAVE_ADDR;
step <= 5'd0;
end
else
state<=START;
end
SLAVE_ADDR: begin
if(`SCL_low) begin//low level for transmit data
if(step==5'd8) begin
state <= ACK1;
SDA_link <= 1'b0;//after the 8 bits data,the sda become input
SDA_r <= 1'b1;
step <= 5'd0;
end
else begin
step <= step+5'd1;
SDA_r <= data[5'd7-step];
state <= SLAVE_ADDR;
end
end
else
state <= SLAVE_ADDR;
end
ACK1: begin //responsion
if((`SCL_hig) && (SDA==1'b0)) begin
state <= SUB_ADDR;
data <= sub_address[i];
end
else
state <= ACK1;
end
SUB_ADDR: begin
if(`SCL_low) begin
if(step==5'd8) begin
state<=ACK2;
SDA_link<=1'b0;
SDA_r<=1'b1;
step<=5'd0;
end
else begin
SDA_link<=1'b1;
step<=step+5'd1;
SDA_r<=data[5'd7-step];
state<=SUB_ADDR;
end
end
else
state<=SUB_ADDR;
end
ACK2: begin
if((`SCL_hig)&&(SDA==1'b0)) begin
state <= DATA;
data <= data_table[i];
end
else
state <= ACK2;
end
DATA: begin
if(`SCL_low) begin
if(step==5'd8) begin
state<=ACK3;
SDA_r<=1'b1;
SDA_link<=1'b0;
step<=5'd0;
end
else begin
SDA_link<=1'b1;
step<=step+5'd1;
SDA_r<=data[5'd7-step];
state<=DATA;
end
end
else
state<=DATA;
end
ACK3: begin
if((`SCL_hig) &&(SDA==1'b0)) begin
state <= PAUSE;
end
else
state<=ACK3;
end
PAUSE: begin// sent the stop signal
if (`SCL_low) begin
SDA_link<=1'b1;
SDA_r <= 1'b0;
state <= PAUSE;
end
else if(`SCL_hig) begin
SDA_r <= 1'b1;//scl爲高時,sda產生上升沿(結束信號)
if(i==i_max) begin
i <= 0;
state <= OVER;/////OVER
end
else begin
i <= i+ 8'd1;
state <= START;
end
end
else
state <= PAUSE;
end
OVER: begin
cfig_done_r <= 1'b1;
state <= OVER;
end
default:state <= IDLE;
endcase
end
endmodule
這裏使用的是一段式狀態機寫法,至於爲什麼用一段式狀態機,當然是一段式狀態機描述IIC協議最爲簡單咯。如果大家有用三段式狀態機描述IIC的代碼,又比較簡單的,歡迎一起交流,互相學習。
三、在2的基礎上添加讀相關寄存器的代碼,並用chipscope讀出相關位置的寄存器的內容,比較與寫入的是否相同
不要認爲使用上述代碼將寄存器配置好就一定不會出現問題。如果一次就配置好,芯片就能正常工作,當然是最好的。但是,如果寄存器按照上述代碼配置了,但是芯片不能正常工作,那麼我們該怎麼辦呢?總不能不做了吧,說不做就不做,你考慮過老闆的感受嗎?所以,那麼我們應該怎麼做呢?最好的方式當然是將寫進的寄存器讀出來看看讀出來的與理論上寫進去的是否一致,如果一致,那你就要返回去看數據手冊,看看是不是有什麼什麼寄存器遺漏了。那麼,如何寄存器中的值呢?整個操作過程與寫過程一模一樣,只不過在讀寄存器地址時,器件地址的最低位要設置爲1(寫的時候器件地址要設置爲0)。我們調試的思路一般是先將寫寄存器然後再讀,如果不寫直接讀有什麼意義呢?先寫後讀寄存器的verilog代碼描述如下(可以與上面的只是寫入寄存器的代碼進行比較看看有什麼異同):
module iic_cfg_hdmi_in(
output SCL,
inout SDA,
input clk35m, //system clk
input rst_n, //system rst
output reg[7:0]data,
output reg SDA_link,
output cfig_done // 0: not config finished //1: finished
);
reg [7:0] sub_address [50:0]; // IIC register address
reg [7:0] data_table [50:0]; // IIC write in data
reg [7:0] device_address[9:0];
parameter i_max=50; //配置寄存器個數
//parameter device_address = 8'h76;
initial begin
/////////////////////////IO寄存器配置device_address[0] = 8'h98;
device_address[0] = 8'h98;////98
device_address[1] = 8'h68;
device_address[2] = 8'h44;
device_address[3] = 8'h64;
device_address[4] = 8'h4c;
device_address[5] = 8'h99;////98
device_address[6] = 8'h69;
device_address[7] = 8'h45;
device_address[8] = 8'h65;
device_address[9] = 8'h4d;
//////////////////////////IO寄存器配置device_address[0] = 8'h98;
sub_address[0] = 8'hff;////////I2C reset
data_table[0] = 8'h80;
sub_address[1] = 8'hf4;///////CEC
data_table[1] = 8'h80;///////////
sub_address[2] = 8'hf5;//////////INFOFRAME
data_table[2] = 8'h7c;
sub_address[3] = 8'hf8;/////////DPLL
data_table[3] = 8'h4c;/////////
sub_address[4] = 8'hf9;////////KSV
data_table[4] = 8'h64;
sub_address[5] = 8'hfa;//////////EDID
data_table[5] = 8'h6c;
sub_address[6] = 8'hfb;//////////HDMI
data_table[6] = 8'h68;
sub_address[7] = 8'hfd;//////////CP
data_table[7] = 8'h44;
///////////////////////////////
sub_address[8] = 8'hc0;///////0x68////////device_address[1] = 8'h68;////ADI Required Write
data_table[8] = 8'h03;
////////////////////////////////////////////
sub_address[9] = 8'h01;///////0x98//////////device_address[0] = 8'h98;///Prim_Mode =110b HDMI-GR
data_table[9] = 8'h06;//16-50hz///06-60hz
sub_address[10] = 8'h02;//////////////////////////////////////////Auto CSC, RGB out, Set op_656 bit
data_table[10] = 8'hf7;/////RGB???
sub_address[11] = 8'h03;////////////////////////////////////////////24 bit SDR 444 Mode 0
data_table[11] = 8'h40;
sub_address[12] = 8'h04;/////////////////參考晶振24Mhz及RGB與引腳關係
data_table[12] = 8'h66;
sub_address[13] = 8'h05;////////////////////////////////////AV Codes Off
data_table[13] = 8'h28;
sub_address[14] = 8'h06;////////hs vs正極性INV_HS_POL、INV_VS_POL should be set to 1 if not specified in Table 7
data_table[14] = 8'ha6;
sub_address[15] = 8'h0c;
data_table[15] = 8'h42;
sub_address[16] = 8'h15;
data_table[16] = 8'h80;
sub_address[17] = 8'h19;
data_table[17] = 8'h83;
sub_address[18] = 8'h33;
data_table[18] = 8'h40;///////////98 33 40///////
/////////////////////////////
sub_address[19] = 8'hba;//////0x44////////device_address[2] = 8'h44;
data_table[19] = 8'h01;
sub_address[20] = 8'h6c;
data_table[20] = 8'h00;
/////////////////////////////////
sub_address[21] = 8'h40;///////0x64/////device_address[3] = 8'h64;
data_table[21] = 8'h81;
///////////////////////////////////////
sub_address[22] = 8'hb5;//////////0x4c/////device_address[4] = 8'h4c;
data_table[22] = 8'h01;
//////////////////////////////////
sub_address[23] = 8'hc0;////////////0x68////device_address[1] = 8'h68;
data_table[23] = 8'h03;
sub_address[24] = 8'h00;
data_table[24] = 8'h00;/////Set HDMI Input Port A (BG_MEAS_PORT_SEL = 001b)
sub_address[25] = 8'h02;
data_table[25] = 8'h03;
sub_address[26] = 8'h03;
data_table[26] = 8'h98;
sub_address[27] = 8'h10;
data_table[27] = 8'ha5;
sub_address[28] = 8'h1b;///////////////
data_table[28] = 8'h08;
sub_address[29] = 8'h45;
data_table[29] = 8'h04;
sub_address[30] = 8'h97;
data_table[30] = 8'hc0;
sub_address[31] = 8'h3d;
data_table[31] = 8'h10;
sub_address[32] = 8'h3e;
data_table[32] = 8'h69;
sub_address[33] = 8'h3f;
data_table[33] = 8'h46;
sub_address[34] = 8'h4e;
data_table[34] = 8'hfe;
sub_address[35] = 8'h4f;
data_table[35] = 8'h08;
sub_address[36] = 8'h50;
data_table[36] = 8'h00;
sub_address[37] = 8'h57;
data_table[37] = 8'ha3;
sub_address[38] = 8'h58;
data_table[38] = 8'h07;
sub_address[39] = 8'h6f;////////////
data_table[39] = 8'h08;
sub_address[40] = 8'h83;
data_table[40] = 8'hfc;
sub_address[41] = 8'h84;
data_table[41] = 8'h03;
sub_address[42] = 8'h85;
data_table[42] = 8'h10;
sub_address[43] = 8'h86;
data_table[43] = 8'h9b;
sub_address[44] = 8'h89;
data_table[44] = 8'h03;
sub_address[45] = 8'h9b;
data_table[45] = 8'h03;
sub_address[46] = 8'h93;
data_table[46] = 8'h03;
sub_address[47] = 8'h5a;//////
data_table[47] = 8'h80;
sub_address[48] = 8'h9c;
data_table[48] = 8'h80;
sub_address[49] = 8'h9c;
data_table[49] = 8'hc0;
sub_address[50] = 8'h9c;
data_table[50] = 8'h00;
end
reg cfig_done_r=0;
assign cfig_done = cfig_done_r;
always @ ( posedge clk35m )
if(cfig_done) begin
sub_address[17] <= 8'h6a;/////98
sub_address[2] <= 8'h6f;/////98
sub_address[39] <= 8'h04;////68
sub_address[41] <= 8'h05;//////68
sub_address[43] <= 8'h07;////////68
end
else begin
sub_address[17] <= 8'h19;
sub_address[2] <= 8'h44;
sub_address[39] <= 8'h6f;
sub_address[41] <= 8'h84;
sub_address[43] <= 8'h86;
end
reg SDA_r;
//reg SDA_link;//輸出數據sda信號inout方向控制: 1 output 0 input
reg SCL_r = 'd0;
assign SCL = SCL_r;
assign SDA = SDA_link ? SDA_r : 1'bz;
reg [8:0]cnt_SCL = 'd0;//循環計數,產生iic所需要的時鐘
always @ ( posedge clk35m )
if(cnt_SCL == 9'd349) //週期爲20us,即100KHz
cnt_SCL <= 9'd0;
else
cnt_SCL <= cnt_SCL + 9'b1;//時鐘計數;
`define SCL_pos cnt_SCL == 9'd87 //scl上升沿
`define SCL_hig cnt_SCL == 9'd174 //scl高電平中間,糜謔採樣
`define SCL_neg cnt_SCL == 9'd262 //scl下降沿
`define SCL_low cnt_SCL == 9'd349 //scl低點平中間,用於數據變化
always @ ( posedge clk35m ) // 產生100k SCL signal
// if(!cfig_done_r) begin
if(`SCL_pos)
SCL_r<=1'b1; //scl信號上升沿
else if(`SCL_neg)
SCL_r<=1'b0; //scl信號下降沿
// end
else
SCL_r<=/*1'b1*/SCL_r; // config finish ,scl output 1;
reg [3:0] state; //狀態寄存器
reg [4:0] step; //輸出8位數據串行計數
//reg [7:0] data; //在IIC上傳送的數據寄存器
parameter IDLE = 4'D0, //the state during the IIC writing
START = 4'D1,
SLAVE_ADDR = 4'D2,
ACK1 = 4'D3,
SUB_ADDR = 4'D4,
ACK2 = 4'D5,
DATA = 4'D6,
ACK3 = 4'D7,
PAUSE = 4'D8,
OVER = 4'D9;
reg [7:0] i;//連續輸出寄存器地址和數據計數
always @ (posedge clk35m or negedge rst_n) begin
if(!rst_n) begin
data <= 16'd0;
SDA_link <= 1'b1;
SDA_r <= 1'b1;
step <= 5'd0;
state <= IDLE;
i <= 0;
cfig_done_r <= 1'b0;
end
else case(state)
IDLE: begin
SDA_link <= 1'b1;
SDA_r <= 1'b1;
i <= 0;
cfig_done_r <= 1'b0;
state<=START;
end
START: begin
if(`SCL_hig) begin
SDA_r <= 1'b0; //start low
// data <= device_address[0];/////////////////////////器件地址
state <= SLAVE_ADDR;
step <= 5'd0;
if(!cfig_done_r)begin
if((i <= 'd7) ||((i >= 'd9)&&(i <= 'd18)))
data <= device_address[0];
else if(i == 'd8 || i >= 'd23 )
data <= device_address[1];
else if(i == 'd19 || i == 'd20)
data <= device_address[2];
else if(i == 'd21)
data <= device_address[3];
else if(i == 'd22)
data <= device_address[4];
else
data <= data;
end
else
if((i <= 'd7) ||((i >= 'd9)&&(i <= 'd18)))
data <= device_address[5];
else if(i == 'd8 || i >= 'd23 )
data <= device_address[6];
else if(i == 'd19 || i == 'd20)
data <= device_address[7];
else if(i == 'd21)
data <= device_address[8];
else if(i == 'd22)
data <= device_address[9];
else
data <= data;
end
else
state<=START;
end
SLAVE_ADDR: begin
if(`SCL_low) begin//low level for transmit data
if(step==5'd8) begin
state <= ACK1;
SDA_link <= 1'b0;//after the 8 bits data,the sda become input
SDA_r <= 1'b1;
step <= 5'd0;
end
else begin
step <= step+5'd1;
SDA_r <= data[5'd7-step];
state <= SLAVE_ADDR;
end
end
else
state <= SLAVE_ADDR;
end
ACK1: begin //responsion
if((`SCL_hig) && (SDA==1'b0)) begin
state <= SUB_ADDR;
data <= sub_address[i];
end
else
state <= ACK1;
end
SUB_ADDR: begin
if(`SCL_low) begin
if(step==5'd8) begin
state<=ACK2;
SDA_link<=1'b0;
SDA_r<=1'b1;
step<=5'd0;
end
else begin
SDA_link<=1'b1;
step<=step+5'd1;
SDA_r<=data[5'd7-step];
state<=SUB_ADDR;
end
end
else
state<=SUB_ADDR;
end
ACK2: begin
if((`SCL_hig)&&(SDA==1'b0)) begin
state <= DATA;
data <= data_table[i];
end
else
state <= ACK2;
end
DATA: begin
if(`SCL_low) begin
if(step==5'd8) begin
state<=ACK3;
SDA_r<=1'b1;
SDA_link<=1'b0;
step<=5'd0;
end
else begin
// SDA_link<=1'b1;
step<=step+5'd1;
// SDA_r<=data[5'd7-step];
state<=DATA;
if(cfig_done_r) begin
SDA_link<=1'b0;
data[5'd7-step] <= SDA;
end
else begin
SDA_link<=1'b1;
SDA_r<=data[5'd7-step];
end
end
end
else
state<=DATA;
end
ACK3: begin
if((`SCL_hig) &&(SDA==1'b0)) begin
state <= PAUSE;
end
else
state<=ACK3;
end
PAUSE: begin// sent the stop signal
if (`SCL_low) begin
SDA_link<=1'b1;
SDA_r <= 1'b0;
state <= PAUSE;
end
else if(`SCL_hig) begin
SDA_r <= 1'b1;//scl爲高時,sda產生上升沿(結束信號)
if(i==i_max) begin
i <= 0;
state <= OVER;/////OVER
end
else begin
i <= i+ 8'd1;
state <= START;
end
end
else
state <= PAUSE;
end
OVER: begin
cfig_done_r <= 1'b1;
// state <= OVER;
state <= START;
end
default:state <= IDLE;
endcase
end
endmodule
這樣,就可以使用Chipscope抓取這些要讀的數據,比較讀寫數據是否一致。
注意:有些芯片的寄存器配置需要復位一定長的時間,在配置芯片時,一定好好看數據手冊,如果復位時間不符合要求,那你IIC寫的再好也沒用咯。
祝大家都能正確的調試出IIC。