quartus Ⅱ 12.1 使用教程(5) eeprom 讀寫測試

開發板使用的是EP4CE15F23C8,軟件使用的是quartus  12.1 ,工程主要是對24c04進行讀寫

eeprom頂層

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name:    eeprom_top 
// Function: write and read eeprom using I2C bus
//////////////////////////////////////////////////////////////////////////////////
module eeprom_top
(
    input CLK_50M,
	 input RSTn,
	 output [3:0]LED,
	 
	 output SCL,
	 inout SDA
);
  
  
wire [7:0] RdData;
wire Done_Sig;

reg [3:0] i;
reg [3:0] rLED;

reg [7:0] rAddr;
reg [7:0] rData;
reg [1:0] isStart;

assign LED = rLED;

/***************************/
/*   EEPROM write and read */
/***************************/	  
always @ ( posedge CLK_50M or negedge RSTn )	
	 if( !RSTn ) begin
			i <= 4'd0;
			rAddr <= 8'd0;
			rData <= 8'd0;
			isStart <= 2'b00;
         rLED <= 4'b0000;
	 end
	 else
		case( i )
				
	     0:
		  if( Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end
		  else begin isStart <= 2'b01; rData <= 8'h12; rAddr <= 8'd0; end              //eeprom write 0x12 to EEPROM addr 0
					 
		  1:
		  if( Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end
		  else begin isStart <= 2'b10; rAddr <= 8'd0; end                              //eeprom read data from EEPROM addr 0
					 
		  2:
		  begin rLED <= RdData[3:0]; end		
		
		endcase	
	 
/***************************/
//I2C通信程序//
/***************************/				
iic_control U1
	 (
	     .CLK         ( CLK_50M ),
		  .RSTn        ( RSTn ),
		  .Start_Sig   ( isStart ),
		  .Addr_Sig    ( rAddr ),
		  .WrData      ( rData ),
		  .RdData      ( RdData ),
		  .Done_Sig    ( Done_Sig ),
	     .SCL         ( SCL ),
		  .SDA         ( SDA )
);


endmodule

iic 控制模塊

module iic_control
(
    input CLK,
	 input RSTn,
	 
	 input [1:0] Start_Sig,             //read or write command
	 input [7:0] Addr_Sig,              //eeprom words address
	 input [7:0] WrData,                //eeprom write data
	 output [7:0] RdData,               //eeprom read data
	 output Done_Sig,                   //eeprom read/write finish
	 
	 output SCL,
	 inout SDA
	 
);

parameter F100K = 9'd500;              //100Khz的時鐘分頻係數  
              
	 
reg [4:0]i;
reg [4:0]Go;
reg [9:0]C1;
reg [7:0]rData;
reg rSCL;
reg rSDA;
reg isAck;
reg isDone;
reg isOut;	
 
assign Done_Sig = isDone;
assign RdData = rData;
assign SCL = rSCL;
assign SDA = isOut ? rSDA : 1'bz;       //SDA數據輸出選擇

//****************************************// 
//*             I2C讀寫處理程序            *// 
//****************************************// 
always @ ( posedge CLK or negedge RSTn )
	 if( !RSTn )  begin
			i <= 5'd0;
			Go <= 5'd0;
			C1 <= 9'd0;
			rData <= 8'd0;
			rSCL <= 1'b1;
			rSDA <= 1'b1;
			isAck <= 1'b1;
			isDone <= 1'b0;
			isOut <= 1'b1;
	 end
	 else if( Start_Sig[0] )                     //I2C 數據寫
	     case( i )
				    
		    0: // iic Start
			 begin
					isOut <= 1;                         //SDA端口輸出
					
					if( C1 == 0 ) rSCL <= 1'b1;
					else if( C1 == 400 ) rSCL <= 1'b0;       //SCL由高變低
							  
					if( C1 == 0 ) rSDA <= 1'b1; 
					else if( C1 == 200 ) rSDA <= 1'b0;        //SDA先由高變低 
							  
					if( C1 == F100K -1) begin C1 <= 9'd0; i <= i + 1'b1; end
					else C1 <= C1 + 1'b1;
			 end
					  
			 1: // Write Device Addr
			 begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end         
				 
			 2: // Wirte Word Addr
			 begin rData <= Addr_Sig; i <= 5'd7; Go <= i + 1'b1; end
					
			 3: // Write Data
			 begin rData <= WrData; i <= 5'd7; Go <= i + 1'b1; end
	 
			 4: //iic Stop
			 begin
			    isOut <= 1'b1;
						  
			    if( C1 == 0 ) rSCL <= 1'b0;
			    else if( C1 == 100 ) rSCL <= 1'b1;     //SCL先由低變高       
		
				 if( C1 == 0 ) rSDA <= 1'b0;
				 else if( C1 == 300 ) rSDA <= 1'b1;     //SDA由低變高  
					 	  
				 if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
				 else C1 <= C1 + 1'b1; 
			 end
					 
			 5:
			 begin isDone <= 1'b1; i <= i + 1'b1; end       //寫I2C 結束
					 
			 6: 
			 begin isDone <= 1'b0; i <= 5'd0; end
				 
			 7,8,9,10,11,12,13,14:                         //發送Device Addr/Word Addr/Write Data
			 begin
			     isOut <= 1'b1;
				  rSDA <= rData[14-i];                      //高位先發送
					  
				  if( C1 == 0 ) rSCL <= 1'b0;
			     else if( C1 == 100 ) rSCL <= 1'b1;
				  else if( C1 == 300 ) rSCL <= 1'b0; 
						  
				  if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
				  else C1 <= C1 + 1'b1;
			 end
					 
			 15:                                          // waiting for acknowledge
			 begin
			     isOut <= 1'b0;                            //SDA端口改爲輸入
			     if( C1 == 100 ) isAck <= SDA;
						  
				  if( C1 == 0 ) rSCL <= 1'b0;
				  else if( C1 == 100 ) rSCL <= 1'b1;
				  else if( C1 == 300 ) rSCL <= 1'b0;
						  
				  if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
				  else C1 <= C1 + 1'b1; 
			 end
					 
			 16:
			 if( isAck != 0 ) i <= 5'd0;
			 else i <= Go; 
					
  		    endcase
	
	  else if( Start_Sig[1] )                     //I2C 數據讀
		    case( i )
				
			 0: //iic Start
			 begin
			      isOut <= 1;                      //SDA端口輸出
					      
			      if( C1 == 0 ) rSCL <= 1'b1;
			 	   else if( C1 == 400 ) rSCL <= 1'b0;      //SCL由高變低
						  
					if( C1 == 0 ) rSDA <= 1'b1; 
					else if( C1 == 200 ) rSDA <= 1'b0;     //SDA先由高變低 
						  
					if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
					 else C1 <= C1 + 1'b1;
			 end
					  
			 1: // Write Device Addr
			 begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd9; Go <= i + 1'b1; end
					 
			 2: // Wirte Word Addr
			 begin rData <= Addr_Sig; i <= 5'd9; Go <= i + 1'b1; end
					
			 3: //iic Start again
			 begin
			     isOut <= 1'b1;
					      
			     if( C1 == 0 ) rSCL <= 1'b0;
				  else if( C1 == 100 ) rSCL <= 1'b1;
				  else if( C1 == 500 ) rSCL <= 1'b0;                //SCL後變低      
						  
			     if( C1 == 0 ) rSDA <= 1'b0; 
				  else if( C1 == 100 ) rSDA <= 1'b1;
				  else if( C1 == 300 ) rSDA <= 1'b0;                //SDA先變低
						  
				  if( C1 == 600 -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
				  else C1 <= C1 + 1'b1;
			 end
					 
			 4: // Write Device Addr ( Read )
			 begin rData <= {4'b1010, 3'b000, 1'b1}; i <= 5'd9; Go <= i + 1'b1; end
					
			 5: // Read Data
			 begin rData <= 8'd0; i <= 5'd19; Go <= i + 1'b1; end
				 
			 6: //iic Stop
			 begin
			     isOut <= 1'b1;
			     if( C1 == 0 ) rSCL <= 1'b0;
				  else if( C1 == 100 ) rSCL <= 1'b1;            //SCL先變高
		
				  if( C1 == 0 ) rSDA <= 1'b0;
				  else if( C1 == 300 ) rSDA <= 1'b1;            //SDA後變高
					 	  
				  if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
				  else C1 <= C1 + 1'b1; 
			 end
					 
			 7:                                                       //寫I2C 結束
			 begin isDone <= 1'b1; i <= i + 1'b1; end
					 
			 8: 
			 begin isDone <= 1'b0; i <= 5'd0; end
				 
					
			 9,10,11,12,13,14,15,16:                                  //發送Device Addr(write)/Word Addr/Device Addr(read)
			 begin
			      isOut <= 1'b1;					      
			 	   rSDA <= rData[16-i];
						  
				   if( C1 == 0 ) rSCL <= 1'b0;
					else if( C1 == 100 ) rSCL <= 1'b1;
					else if( C1 == 300 ) rSCL <= 1'b0; 
						  
					if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
					else C1 <= C1 + 1'b1;
			 end
			       
			 17: // waiting for acknowledge
			 begin
			      isOut <= 1'b0;                                       //SDA端口改爲輸入
					     
			 	   if( C1 == 200 ) isAck <= SDA;
						  
					if( C1 == 0 ) rSCL <= 1'b0;
					else if( C1 == 100 ) rSCL <= 1'b1;
					else if( C1 == 300 ) rSCL <= 1'b0;
						  
					if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
					else C1 <= C1 + 1'b1; 
			 end
					 
			 18:
			      if( isAck != 0 ) i <= 5'd0;
					else i <= Go;
					 
					 
			 19,20,21,22,23,24,25,26: // Read data
			 begin
			     isOut <= 1'b0;
			     if( C1 == 200 ) rData[26-i] <= SDA;
						  
				  if( C1 == 0 ) rSCL <= 1'b0;
				  else if( C1 == 100 ) rSCL <= 1'b1;
				  else if( C1 == 300 ) rSCL <= 1'b0; 
						  
				  if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
				  else C1 <= C1 + 1'b1;
			 end	  
					 
			 27: // no acknowledge
			 begin
			     isOut <= 1'b1;
					  
				  if( C1 == 0 ) rSCL <= 1'b0;
				  else if( C1 == 100 ) rSCL <= 1'b1;
				  else if( C1 == 300 ) rSCL <= 1'b0;
						  
				  if( C1 == F100K -1 ) begin C1 <= 9'd0; i <= Go; end
				  else C1 <= C1 + 1'b1; 
			end
				
			endcase	
	   	
		

	
				
endmodule

使用iic對eeprom進行讀寫,這個工程主要要注意iic協議的起始信號,停止信號,以及ack,並且要清楚如何使用三態門,將一個

IO口設置爲雙向口,程序部分要注意狀態機裏GO這個是如何跳轉的

設置管腳

點擊工具欄快捷按鈕進行編譯

使用Signaltap 觀測端口信號
點擊工具欄上的Open按鈕,然後選擇Signaltap Ⅱ Logic Analyzer File,點擊OK

點擊截圖中的紅色方框添加採樣時鐘

這裏的CLK_50M來自頂層,點擊List將CLK_50M添加進來

選擇CLK_50M,點擊 > 將CLK_50M添加進來

點擊OK

雙擊空白添加想要觀測的信號管腳

添加管腳SCL,點擊List

這裏因頂層例化的模塊裏有相同的管腳名所以都加進來,但我們只選外接的eeprom模塊的這個管腳,點擊 >  加入進來

點擊OK

添加SDA管腳,輸入管腳名SDA,點擊List,在下面的管腳列表裏選擇SDA,再點擊 > 添加進去 

添加RdData,輸入RdData名稱,點擊List,選擇列表裏的RdData,點擊 >  添加進來

點擊OK

SignalTap 就配置完了,按ctrl+s保存 SignalTap 文件爲 stp1.stp

關閉SignalTap 界面在quartus裏重新編譯工程,雙擊者個Files裏的step1.stp文件打開 SignalTap

連接USB Blaster 下載器,可以看到我們的開發板型號

點擊 SOF Manager 最右邊的按鈕,並選擇生成的 eeprom_test.sof 文件

點擊Open添加進來

點擊下載按鈕下載進去

下載完成後,如下圖所示

將SDA設置爲下降沿觸發

點擊 Run Analysis 按鈕開始運行一次 SignalTap 的數據採集

SignalTap  處於等待狀態,按一下開發板的reset按鍵

觸發IIC總線,採集到的波形如下圖所示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章