本文主要是介绍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 ) begini <= 4'd0;rAddr <= 8'd0;rData <= 8'd0;isStart <= 2'b00;rLED <= 4'b0000;endelsecase( i )0:if( Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; endelse begin isStart <= 2'b01; rData <= 8'h12; rAddr <= 8'd0; end //eeprom write 0x12 to EEPROM addr 01:if( Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; endelse begin isStart <= 2'b10; rAddr <= 8'd0; end //eeprom read data from EEPROM addr 02: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 commandinput [7:0] Addr_Sig, //eeprom words addressinput [7:0] WrData, //eeprom write dataoutput [7:0] RdData, //eeprom read dataoutput Done_Sig, //eeprom read/write finishoutput 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 ) begini <= 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;endelse if( Start_Sig[0] ) //I2C 数据写case( i )0: // iic StartbeginisOut <= 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; endelse C1 <= C1 + 1'b1;end1: // Write Device Addrbegin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end 2: // Wirte Word Addrbegin rData <= Addr_Sig; i <= 5'd7; Go <= i + 1'b1; end3: // Write Databegin rData <= WrData; i <= 5'd7; Go <= i + 1'b1; end4: //iic StopbeginisOut <= 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; endelse C1 <= C1 + 1'b1; end5:begin isDone <= 1'b1; i <= i + 1'b1; end //写I2C 结束6: begin isDone <= 1'b0; i <= 5'd0; end7,8,9,10,11,12,13,14: //发送Device Addr/Word Addr/Write DatabeginisOut <= 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; endelse C1 <= C1 + 1'b1;end15: // waiting for acknowledgebeginisOut <= 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; endelse C1 <= C1 + 1'b1; end16:if( isAck != 0 ) i <= 5'd0;else i <= Go; endcaseelse if( Start_Sig[1] ) //I2C 数据读case( i )0: //iic StartbeginisOut <= 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; endelse C1 <= C1 + 1'b1;end1: // Write Device Addrbegin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd9; Go <= i + 1'b1; end2: // Wirte Word Addrbegin rData <= Addr_Sig; i <= 5'd9; Go <= i + 1'b1; end3: //iic Start againbeginisOut <= 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; endelse C1 <= C1 + 1'b1;end4: // Write Device Addr ( Read )begin rData <= {4'b1010, 3'b000, 1'b1}; i <= 5'd9; Go <= i + 1'b1; end5: // Read Databegin rData <= 8'd0; i <= 5'd19; Go <= i + 1'b1; end6: //iic StopbeginisOut <= 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; endelse C1 <= C1 + 1'b1; end7: //写I2C 结束begin isDone <= 1'b1; i <= i + 1'b1; end8: begin isDone <= 1'b0; i <= 5'd0; end9,10,11,12,13,14,15,16: //发送Device Addr(write)/Word Addr/Device Addr(read)beginisOut <= 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; endelse C1 <= C1 + 1'b1;end17: // waiting for acknowledgebeginisOut <= 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; endelse C1 <= C1 + 1'b1; end18:if( isAck != 0 ) i <= 5'd0;else i <= Go;19,20,21,22,23,24,25,26: // Read databeginisOut <= 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; endelse C1 <= C1 + 1'b1;end 27: // no acknowledgebeginisOut <= 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; endelse C1 <= C1 + 1'b1; endendcase 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总线,采集到的波形如下图所示
这篇关于quartus Ⅱ 12.1 使用教程(5) eeprom 读写测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!