EEPROM的操作---SPI接口和I2C接口
參考:http://blog.csdn.net/yuanlulu/article/details/6163106
ROM最初不能編程,出廠什么內容就永遠什么內容,不靈活。后來出現了PROM,可以自己寫入一次,要是寫錯了,只能換一片,自認倒霉。人類文明不斷進步,終于出現了可多次擦除寫入的EPROM,每次擦除要把芯片拿到紫外線上照一下,想一下你往單片機上下了一個程序之后發(fā)現有個地方需要加一句話,為此你要把單片機放紫外燈下照半小時,然后才能再下一次,這么折騰一天也改不了幾次。歷史的車輪不斷前進,偉大的EEPROM出現了,拯救了一大批程序員,終于可以隨意的修改rom中的內容了
EEPROM的全稱是“電可擦除可編程只讀存儲器”,即Electrically Erasable Programmable Read-Only Memory。是相對于紫外擦除的rom來講的。但是今天已經存在多種EEPROM的變種,變成了一類存儲器的統稱.這種rom的特點是可以隨機訪問和修改任何一個字節(jié),可以往每個bit中寫入0或者1。這是最傳統的一種EEPROM,掉電后數據不丟失,可以保存100年,可以擦寫100w次。具有較高的可靠性,但是電路復雜/成本也高。因此目前的EEPROM都是幾十千字節(jié)到幾百千字節(jié)的,絕少有超過512K的。
EEPROM的接口分為兩種:SPI和I2C。
? ? ? SPI接口為四線,型號如AT25XXX。?
?
? ? ? I2C接口為2線,型號如24CL02/04/XX.
? ? ??
這兩種EEPROM的操作主要按SPI 和I2C的協議操作就可以了,不過也有一些需要注意的地方。在這里記錄下來,不涉及細節(jié)的處理。
? ? ? 對于SPI接口的EEPROM:
1、在寫數據的時候需要先寫WR_EN的命令,然后在按SPI寫寫操作。讀的時候不需要先寫WR_EN.
? ? ? ? ? ? ? ? ?
?? 2、WR_EN 和WR_DATA 的操作之間要隔一段時間,如10us,不能寫完WR_EN就寫WR_DATA,否則數據將不能被寫入。
? ? ? ? ?3、WR_DATA操作送入EEPROM之后,要等待一段時間,等EEPROM將數據寫入內部,時間長短可以參考datasheet中的一個參數 write_cycle。
? ? ? ?
? ? 4、RD_DATA操作到下一次的WR_EN/WR_DATA命令之間也要間隔一段時間,如400us.
? ? 5、SPI協議的最后一個SPI_CLK也要保證完整,有低有高,不能只有一半,如將SPI_CLK拉高之后不拉低就將SPI_CS信號拉低。
? ? ??
? ?example: verilog?
? EEPROM--SPI interface ? ??
module EE_WR( //------------outputs----------- output EE_SI, output EE_CSb, output EE_SCK, input EE_SO, //------------inputs------------ input clk,//50MHZ input rst )/*synthesis noprune*/;parameter cmd_wr_en =8'h06 /* synthesis keep */;parameter cmd_wr_sr =16'h0180 /* synthesis keep */; //16'h018C all block are protectedparameter cmd_rd_sr =8'h05 /* synthesis keep */;parameter cmd_wr_op =536'h020000_63555560595857565554535251504948474645444342414039383736353433323130292827262524232221201918171615141312111009080706050403020100 /* synthesis keep */;//parameter cmd_wr_op =32'h020000_f5 /* synthesis keep */;parameter cmd_rd_op =24'h030000 /* synthesis keep */;parameter tck_delay = 4'd6;parameter num_data_bit = 12'd512;parameter IDLE = 5'd0;parameter WR_EN_1 = 5'd1;parameter WR_EN_2 = 5'd2;parameter WR_EN_3 = 5'd3;parameter WR_EN_4 = 5'd4;parameter WR_EN_5 = 5'd5;parameter WR_SR_1 = 5'd6;parameter WR_SR_2 = 5'd7;parameter WR_SR_3 = 5'd8;parameter WR_SR_4 = 5'd9;parameter WR_SR_5 = 5'd10; parameter RD_SR_1 = 5'd11;parameter RD_SR_2 = 5'd12;parameter RD_SR_3 = 5'd13;parameter RD_SR_4 = 5'd14;parameter RD_SR_5 = 5'd15;parameter RD_SR_6 = 5'd16;parameter RD_SR_7 = 5'd17; parameter WR_DATA_1 = 5'd18;parameter WR_DATA_2 = 5'd19;parameter WR_DATA_3 = 5'd20;parameter WR_DATA_4 = 5'd21;parameter WR_DATA_5 = 5'd22; parameter RD_DATA_1 = 5'd23;parameter RD_DATA_2 = 5'd24;parameter RD_DATA_3 = 5'd25;parameter RD_DATA_4 = 5'd26;parameter RD_DATA_5 = 5'd27;parameter RD_DATA_6 = 5'd28;parameter RD_DATA_7 = 5'd29; reg [31:0] cnt;always @(posedge clk or negedge rst ) beginif(rst == 0 ) cnt <= 0;else if(cnt == 32'd500_000_000) cnt <= 32'd500_000_000; else cnt <= cnt + 1;endwire wr_en /* synthesis keep */;wire wr_op /* synthesis keep */;wire rd_op /* synthesis keep */;wire rd_sr /* synthesis keep */;wire wr_sr /* synthesis keep */; assign wr_en = (cnt == 32'd000_000_500); assign rd_sr = (cnt == 32'd000_000_000); assign wr_sr = (cnt == 32'd000_000_000); assign wr_op = (cnt == 32'd000_001_000); assign rd_op = (cnt == 32'd001_000_000);reg [4:0] state;reg [3:0] delay;reg [11:0] num;reg [7:0] data_sr;reg [7:0] data_rd;reg spi_clk;reg spi_cs;reg spi_si; always @(posedge clk or negedge rst ) beginif(rst == 0 ) beginspi_clk <= 0;spi_cs <= 1;spi_si <= 0;delay <= 0;num <= 0;state <= IDLE;data_sr <= 0; data_rd<= 0;endelse begincase(state) IDLE : beginspi_clk <= 0;spi_cs <= 1;spi_si <= 0;delay <= 0;num <= 0;data_sr <= 0; data_rd <= 0;if(wr_en) state <= WR_EN_1; // else if(wr_sr) state <= WR_SR_1; // else if(rd_sr) state <= RD_SR_1; else if(wr_op) state <= WR_DATA_1; else if(rd_op) state <= RD_DATA_1 ; else state <= state;end //-------------wr_en------------- WR_EN_1: begin //拉低CSspi_clk <= 0;spi_cs <= 0;num <= 7;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend WR_EN_2: begin //sck 下降沿spi_clk <= 0;spi_si <= cmd_wr_en[num];if(delay == tck_delay) begin state <= state + 1; delay <= 0; end else begin state <= state; delay <= delay + 1; endend WR_EN_3: begin //sck 上升沿spi_clk <= 1;spi_si <= spi_si;if(delay == tck_delay) beginif(num == 0) begin state <= state + 1; delay <= 0; endelse begin state <= WR_EN_2; delay <= 0; num <= num - 1; end endelse begin state <= state; delay <= delay + 1; endend WR_EN_4: begin //SCK 下降沿延時一個spi_clk <= 0;spi_si <= spi_si;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend WR_EN_5: begin //CS 拉高spi_cs <= 1;spi_clk<= 0;spi_si <= 0;if(delay == tck_delay) begin state <= IDLE; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend //-------------wr_sr-------------WR_SR_1: begin //拉低CSspi_clk <= 0;spi_cs <= 0;num <= 15;spi_si <= 0;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endendWR_SR_2: begin //sck 下降沿spi_clk <= 0; spi_si <= cmd_wr_sr[num];if(delay == tck_delay) begin state <= state + 1; delay <= 0; end else begin state <= state; delay <= delay + 1; endend WR_SR_3: begin //sck 上升沿spi_clk <= 1;spi_si <= spi_si;if(delay == tck_delay) begin if(num == 0) begin state <= state + 1; delay <= 0; endelse begin state <= WR_SR_2; delay <= 0; num <= num -1; endendelse begin state <= state; delay <= delay + 1; endend WR_SR_4: begin //SCK 下降沿延時一個spi_clk <= 0;spi_si <= spi_si;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend WR_SR_5: begin //CS 拉高spi_cs <= 1;spi_clk<= 0;spi_si <= 0;if(delay == tck_delay) begin state <= IDLE; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend //-----rd_sr-----------RD_SR_1: begin //拉低CSspi_clk <= 0;spi_cs <= 0;num <= 7;data_sr <= 0; spi_si <= 0;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <=delay + 1; endendRD_SR_2: begin //sck 下降沿spi_clk <= 0;spi_si <= cmd_rd_sr[num];if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend RD_SR_3: begin //sck 上升沿spi_clk <= 1;spi_si <= spi_si;if(delay == tck_delay) begin if(num == 0) begin state <= state + 1; delay <= 0; num <= 7; endelse begin state <= RD_SR_2; delay <= 0; num <= num - 1; endend else begin state <= state; delay <= delay + 1; endend RD_SR_4: begin //read SCK 下降沿spi_clk <= 0;spi_si <= 0; data_sr <= data_sr;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend RD_SR_5: begin //READ sck 上升沿spi_clk <= 1;data_sr[num] <= EE_SO;if(delay == tck_delay) begin if(num == 0) begin state <= state + 1; delay <= 0; endelse begin state <= RD_SR_4; delay <= 0; num <= num - 1; endend else begin state <= state; delay <= delay + 1; endend RD_SR_6: begin //SCK 下降沿延時一個spi_clk <= 0;data_sr <= data_sr;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend RD_SR_7: begin //CS拉高 spi_cs <= 1;spi_clk<= 0;spi_si <= 0;if(delay == tck_delay) begin state <= IDLE; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend //---------------------wr_data------------------WR_DATA_1: begin //拉低CSspi_clk <= 0;spi_cs <= 0;spi_si <= 0;num <= num_data_bit + 23;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endendWR_DATA_2: begin //SCK下降沿spi_clk <= 0;spi_si <= cmd_wr_op[num];if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend WR_DATA_3: begin //SCK 上升沿 spi_clk <= 1;spi_si <= spi_si;if(delay == tck_delay) begin if(num == 0) begin state <= state + 1; delay <= 0; endelse begin state <= WR_DATA_2; delay <= 0; num <= num - 1; endendelse begin state <= state; delay <= delay + 1; endend WR_DATA_4: begin //SCK延時下降沿spi_clk <= 0;spi_si <= 0;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend WR_DATA_5: begin //CS拉高 spi_cs <= 1;spi_clk<= 0;spi_si <= 0;if(delay == tck_delay) begin state <= IDLE; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend //---------------------rd_data-------------------RD_DATA_1: begin //拉低CSspi_clk <= 0;spi_cs <= 0;spi_si <= 0;num <= 23;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endendRD_DATA_2: begin //SCK下降沿spi_clk <= 0;spi_si <= cmd_rd_op[num];if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend RD_DATA_3: begin //SCK 上升沿 spi_clk <= 1;spi_si <= spi_si;if(delay == tck_delay) begin if(num == 0) begin state <= state + 1; delay <= 0; num <= num_data_bit - 1; endelse begin state <= RD_DATA_2; delay <= 0; num <= num - 1; endendelse begin state <= state; delay <= delay + 1; endend RD_DATA_4: begin //read SCK 下降沿spi_clk <= 0;spi_si <= 0; data_rd <= data_rd;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend RD_DATA_5: begin //READ sck 上升沿spi_clk <= 1;data_rd[num] <= EE_SO;if(delay == tck_delay) begin if(num == 0) begin state <= state + 1; delay <= 0; endelse begin state <= RD_DATA_4; delay <= 0; num <= num - 1; endend else begin state <= state; delay <= delay + 1; endend RD_DATA_6: begin //SCK 下降沿延時一個spi_clk <= 0;data_rd <= data_rd;if(delay == tck_delay) begin state <= state + 1; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend RD_DATA_7 :begin //CS拉高 spi_cs <= 1;spi_clk<= 0;spi_si <= 0;if(delay == tck_delay) begin state <= IDLE; delay <= 0; endelse begin state <= state; delay <= delay + 1; endend default : state <= 0;endcaseend end assign EE_CSb = spi_cs;assign EE_SCK = spi_clk;assign EE_SI = spi_si;endmodule View Code? tb:?
`timescale 1 ps/1 psmodule EE_WR_tb ;wire EE_SI; wire EE_CSb;wire EE_SCK; reg EE_SO;//------------inputs------------reg clk;//50MHZreg rst;EE_WR u0_EE_WR( //------------outputs----------- .EE_SI(EE_SI), .EE_CSb(EE_CSb),.EE_SCK(EE_SCK), .EE_SO(EE_SO),//------------inputs------------.clk(clk),//50MHZ .rst(rst))/*synthesis noprune*/;parameter T = 20000;always #(T/2) clk = ~clk;initial beginclk = 0;rst =0;#(300*T) $stop;#(200*T) rst =1; endendmodule View Code?對于I2C的接口:
? ? 1、讀寫之間按I2C的協議進行就可以。
? ? 2、在讀取數據時候,master在接收完8bit數據之后,需要給從機發(fā)一個ACK(輸出一個SDA =0)。注意讀取的時候ACK是由Master發(fā)出的,在寫數據的時候ACK是由slaver發(fā)出的。
? ?可以參考:http://blog.csdn.net/lingfeng5/article/details/73361833
? ?3、寫數據同樣也有一定的write_cycle. 參考datasheet.
? ? ?
example: verilog
View Code // `define SIM //if run modelsim, enable module eeprom_data(input clk,input rst_n,output wr_en,output reg [7:0] wr_addr,output reg [7:0] wr_data,output reg wr_flag,output rd_en,output reg [7:0] rd_addr,input [7:0] rd_data,output reg rd_flag,input rd_wrdata_en, //only one clk cycle high timeinput wr_rddata_en);reg [7:0] wr_cnt;reg [7:0] rd_cnt;reg [31:0] cnt;reg [5:0] rd_wrdata_en_flag;always @(posedge clk or negedge rst_n)begin if(rst_n == 0) rd_wrdata_en_flag <= 6'd0;else rd_wrdata_en_flag <= {rd_wrdata_en_flag[5:0],rd_wrdata_en}; end`ifdef SIMalways @(posedge clk or negedge rst_n)beginif(rst_n == 0) cnt <= 0;else if(cnt == 32'd100_000) cnt <= 0;else cnt <= cnt + 1;endassign wr_en = (cnt == 32'd20_000);assign rd_en = (cnt == 32'd70_000); `else always @(posedge clk or negedge rst_n)beginif(rst_n == 0) cnt <= 0;else if(cnt == 32'd500_000_000) cnt <= 0;else cnt <= cnt + 1;endassign wr_en = (cnt == 32'd200_000_000);assign rd_en = (cnt == 32'd400_000_000); `endifparameter data_num = 8'd16; //the data number of need to be write or read //=========================================//writealways @(posedge clk or negedge rst_n)beginif(rst_n == 0) wr_addr <= 0;else if(rd_wrdata_en_flag[5]) beginif(wr_addr == data_num) wr_addr <= 0; else wr_addr <= wr_addr + 1;end else wr_addr <= wr_addr;endalways @(posedge clk or negedge rst_n)beginif(rst_n == 0) wr_data <= 0;else if(rd_wrdata_en_flag[5]) beginif(wr_data == data_num) wr_data <= 0; else wr_data <= wr_data + 1;end else wr_data <= wr_data;endalways @(posedge clk or negedge rst_n)beginif(rst_n == 0) wr_cnt <= 0;else if(rd_wrdata_en_flag[5]) beginif(wr_cnt == data_num) wr_cnt <= 0; else wr_cnt <= wr_cnt + 1;end else wr_cnt <= wr_cnt;endalways @(posedge clk or negedge rst_n)beginif(rst_n == 0) wr_flag <= 0;else if(wr_en) wr_flag <= 1;else if(rd_wrdata_en_flag[5]) beginif(wr_cnt == data_num) wr_flag <= 0; else wr_flag <= 1;end else wr_flag <= wr_flag;end //====================================//readalways @(posedge clk or negedge rst_n)beginif(rst_n == 0) rd_addr <= 0;else if(wr_rddata_en) beginif(rd_addr == data_num) rd_addr <= 0; else rd_addr <= rd_addr + 1;end else rd_addr <= rd_addr;end// always @(posedge clk or negedge rst_n) // begin // if(rst_n == 0) rd_data <= 0; // else if(wr_rddata_en) begin // if(rd_data == 8'D127) rd_data <= 0; // else rd_data <= rd_data + 1; // end // else rd_data <= rd_data; // end // always @(posedge clk or negedge rst_n)beginif(rst_n == 0) rd_cnt <= 0;else if(wr_rddata_en) beginif(rd_cnt == data_num) rd_cnt <= 0; else rd_cnt <= rd_cnt + 1;end else rd_cnt <= rd_cnt;endalways @(posedge clk or negedge rst_n)beginif(rst_n == 0) rd_flag <= 0;else if(rd_en) rd_flag <= 1;else if(wr_rddata_en) beginif(data_num == 0) rd_flag <= 0;else if(rd_cnt == (data_num-1)) rd_flag <= 0; else rd_flag <= 1;end else rd_flag <= rd_flag;endwire fifo_empty;wire [4:0] cnt_fifo;wire clr_fifo;assign clr_fifo = wr_rddata_en&&(rd_cnt == (data_num-1));RD_DATA_BUF u_rd_data_buf(.aclr(clr_fifo),.clock(clk),.data(rd_data),.rdreq(1'b0), .wrreq(wr_rddata_en),.empty(fifo_empty),.full(),.q(),.usedw(cnt_fifo));endmodule View Code //======================================// I2C.v// //========================== // `define SIM //if run modelsim, enable module I2C( input clk, //sysclk = 50Mhzinput rst_n,input [1:0] wr_rd_en, //wr_rd_en[1] = read, wr_rd_en[0] = writeinput wr_data_flag, //if still have data to write,the flag always is highinput rd_data_flag, //if still have data to read,the flag always is highinput [7:0] wr_addr,input [7:0] wr_data,input [7:0] rd_addr,output [7:0] rd_data,output rd_wrdata_en, //read data from eeprom_data.v to write eepromoutput wr_rddata_en, //write the read data from eeprom to eeprom_data.voutput ee_I2C_CLK,inout ee_I2C_SDA);reg [1:0] wr_rd_en_reg1,wr_rd_en_reg2;reg [4:0] state;parameter IDLE = 5'd0;parameter START_1 = 5'd1;parameter START_2 = 5'd2;parameter START_3 = 5'd3;parameter WR_CTL_1 = 5'd4;parameter WR_CTL_2 = 5'd5;parameter WR_CTL_ACK1 = 5'd6;parameter WR_CTL_ACK2 = 5'd7;parameter WR_ADDR_1 = 5'd8; parameter WR_ADDR_2 = 5'd9; parameter WR_ADDR_ACK1 = 5'd10;parameter WR_ADDR_ACK2 = 5'd11;parameter WR_DATA_1 = 5'd12;parameter WR_DATA_2 = 5'd13; parameter WR_DATA_3 = 5'd14; parameter WR_DATA_ACK1 = 5'd15;parameter WR_DATA_ACK2 = 5'd16;parameter RD_DATA_1 = 5'd17;parameter RD_DATA_2 = 5'd18; parameter RD_DATA_ACK1 = 5'd19; parameter RD_DATA_ACK2 = 5'd20;parameter STOP_1 = 5'd21;parameter STOP_2 = 5'd22;parameter STOP_3 = 5'd23; parameter WRITE_TIME = 5'd24; //delay 10ms parameter CMD_control = 7'b1010000; //eeprom addr = 3'b000;`ifdef SIMparameter delay = 20'd100; parameter delay_10ms = 20'd500; `elseparameter delay = 20'd300; parameter delay_10ms = 20'd500000; `endif always @(posedge clk or negedge rst_n) beginif(rst_n == 0) begin wr_rd_en_reg2 <= 2'd0;wr_rd_en_reg1 <= 2'd0 ;endelse beginwr_rd_en_reg2 <= wr_rd_en_reg1;wr_rd_en_reg1 <= wr_rd_en ;endendreg [4:0] num; //data = 8bitreg [19:0] delay_cnt; reg [7:0] addr_reg; //reg addrreg [7:0] data_reg; //reg datareg wr_flag; //write flagreg rd_flag; //read flagreg rd_restart_flag; // read, the next start flagreg dir_sda_flag; // dir of sda flagreg rd_wrdata_flag; //when write data ,need read data firstreg wr_rddata_flag;reg [7:0] rd_data_reg;reg ee_sclk_reg; reg ee_data_reg;always @(posedge clk or negedge rst_n) beginif(rst_n == 0) begin state <= IDLE;num <= 0;delay_cnt <= 0;addr_reg <= 0;data_reg <= 0;wr_flag <= 0;dir_sda_flag <= 0;rd_flag <= 0;rd_restart_flag <= 0;rd_wrdata_flag <= 0;wr_rddata_flag <= 0;rd_data_reg <= 0;ee_sclk_reg <= 1;ee_data_reg <= 1;endelse begincase(state)IDLE: beginnum <= 0;delay_cnt <= 0;data_reg <= 0;addr_reg <= 0;wr_flag <= 0;dir_sda_flag <= 0;rd_flag <= 0;rd_restart_flag <= 0;rd_wrdata_flag <= 0;wr_rddata_flag <= 0;rd_data_reg <= 0;ee_sclk_reg <= 1;ee_data_reg <= 1;if(wr_rd_en_reg2 == 2'b01) begin //writeaddr_reg <= wr_addr ;wr_flag <= 1;rd_flag <= 0;state <= START_1; dir_sda_flag <= 1; endelse if(wr_rd_en_reg2 == 2'b10) begin //readaddr_reg <= rd_addr ;wr_flag <= 0;rd_flag <= 1;state <= START_1;dir_sda_flag <= 1;rd_data_reg <= 0; endelse beginstate <= state;endendSTART_1: begin //reg ee_sclk_reg <= 1;ee_data_reg <= 1;if(delay_cnt == delay<<1 ) beginstate <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendSTART_2: begin //pull down DATA ee_sclk_reg <= 1;ee_data_reg <= 0;if(delay_cnt == delay ) beginstate <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendSTART_3: begin //pull down SCL ee_sclk_reg <= 0;ee_data_reg <= 0;num <= 7;if(delay_cnt == delay ) begin delay_cnt <= 0;if(rd_restart_flag) begin data_reg <= {CMD_control,1'b1};state <= WR_CTL_1; endelse if((wr_flag ==1)&&(rd_flag == 0)) begindata_reg <= {CMD_control,1'b0};state <= WR_CTL_1;end else if((wr_flag == 0)&&(rd_flag == 1)) begindata_reg <= {CMD_control,1'b0};state <= WR_CTL_1;end else begindata_reg <= 0; state <= IDLE;endendelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendWR_CTL_1 : begin //write CMD,change data at middle of SCL low timeee_sclk_reg <= 0; if(delay_cnt == delay>>1) ee_data_reg <= data_reg[num];else ee_data_reg <= ee_data_reg;if(delay_cnt == delay) begin state <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendWR_CTL_2: begin //write CMD,write dataee_sclk_reg <= 1;ee_data_reg <= ee_data_reg;if(delay_cnt == delay) begin if(num == 0) begin state <= state + 1;delay_cnt <= 0; endelse begin state <= WR_CTL_1;delay_cnt <= 0;num <= num -1;endendelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendWR_CTL_ACK1 : begin //ackee_sclk_reg <= 0;ee_data_reg <= 0;if(delay_cnt == 4) dir_sda_flag <= 0; //delay, make sure SDA change in the SCK Lowelse dir_sda_flag <= dir_sda_flag;if(delay_cnt == delay) beginstate <= state + 1;delay_cnt <= 0;endelse beginstate <= state ;delay_cnt <= delay_cnt + 1;endendWR_CTL_ACK2 : beginee_sclk_reg <= 1;if(delay_cnt == delay) begin delay_cnt <= 0;if(rd_restart_flag) begin state <= RD_DATA_1;delay_cnt <= 0; num <= 7;rd_restart_flag <= 0;endelse beginstate <= WR_ADDR_1; num <= 7;endendelse beginstate <= state ;delay_cnt <= delay_cnt + 1;endendWR_ADDR_1: begin //write addr,change dataee_sclk_reg <= 0; if(delay_cnt == 4) dir_sda_flag <= 1;else dir_sda_flag <= dir_sda_flag;if(delay_cnt == delay>>1) ee_data_reg <= addr_reg[num];else ee_data_reg <= ee_data_reg;if(delay_cnt == delay) begin state <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;end end WR_ADDR_2: begin //write addr,WRITE dataee_sclk_reg <= 1;ee_data_reg <= ee_data_reg;if(delay_cnt == delay) begin if(num == 0) begin state <= WR_ADDR_ACK1;delay_cnt <= 0; endelse begin state <= WR_ADDR_1;delay_cnt <= 0;num <= num -1;endendelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendWR_ADDR_ACK1 : beginee_sclk_reg <= 0;ee_data_reg <= 0;if(delay_cnt == 4) dir_sda_flag <= 0;else dir_sda_flag <= dir_sda_flag;if(delay_cnt == delay) beginstate <= state + 1;delay_cnt <= 0;endelse beginstate <= state ;delay_cnt <= delay_cnt + 1;end endWR_ADDR_ACK2: beginee_sclk_reg <= 1;if(delay_cnt == delay) begindelay_cnt <= 0;if((wr_flag ==1)&&(rd_flag == 0)) beginstate <= WR_DATA_1 ;num <= 7;endelse if((wr_flag ==0)&&(rd_flag == 1)) beginstate <= START_1 ;rd_restart_flag <= 1;dir_sda_flag <= 1;endelse beginstate <= IDLE ;end endelse beginstate <= state ;delay_cnt <= delay_cnt + 1;end endWR_DATA_1 : beginee_sclk_reg <= 0; num <= 7 ;if(delay_cnt == 3) dir_sda_flag <= 1;else dir_sda_flag <= dir_sda_flag;if(delay_cnt == 1) rd_wrdata_flag <= 1;else rd_wrdata_flag <= 0;if(delay_cnt == 5) begindelay_cnt <= 0 ;state <= state + 1;data_reg <= wr_data;endelse begin delay_cnt <= delay_cnt + 1 ;state <= state;end endWR_DATA_2 : beginee_sclk_reg <= 0;if(delay_cnt == delay>>1) ee_data_reg <= data_reg[num];else ee_data_reg <= ee_data_reg;if(delay_cnt == delay) begin state <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;end endWR_DATA_3: begin ee_sclk_reg <= 1;ee_data_reg <= ee_data_reg;if(delay_cnt == delay) begin if(num == 0) beginstate <= WR_DATA_ACK1;delay_cnt <= 0; end else begin state <= WR_DATA_2;delay_cnt <= 0;num <= num -1;endendelse begin state <= state ;delay_cnt <= delay_cnt + 1;end endWR_DATA_ACK1: beginee_sclk_reg <= 0;ee_data_reg <= 0;if(delay_cnt == 4) dir_sda_flag <= 0;else dir_sda_flag <= dir_sda_flag;if(delay_cnt == delay) beginstate <= state + 1;delay_cnt <= 0;endelse beginstate <= state ;delay_cnt <= delay_cnt + 1;end endWR_DATA_ACK2: beginee_sclk_reg <= 1;if(delay_cnt == delay) begindelay_cnt <= 0;dir_sda_flag <= 1;if(wr_data_flag) state <= WR_DATA_1 ;else state <= STOP_1 ; endelse beginstate <= state ;delay_cnt <= delay_cnt + 1;end end RD_DATA_1: begin //readee_sclk_reg <= 0;if(delay_cnt == 4) dir_sda_flag <= 0;else dir_sda_flag <= dir_sda_flag;if(delay_cnt == delay>>1) rd_data_reg[num] <= ee_I2C_SDA;else data_reg <= data_reg;if(delay_cnt == delay) begin state <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendRD_DATA_2: beginee_sclk_reg <= 1; if(delay_cnt == delay) begin if(num == 0) beginstate <= state + 1;delay_cnt <= 0;endelse beginstate <= RD_DATA_1;delay_cnt <= 0;num <= num - 1;endendelse begin state <= state ;delay_cnt <= delay_cnt + 1;endendRD_DATA_ACK1: begin //read data from slave, Notice: the ACK send from Master. ee_sclk_reg <= 0; if(delay_cnt == 4) dir_sda_flag <= 1;else dir_sda_flag <= dir_sda_flag;if(rd_data_flag) ee_data_reg <= 0; //if have data need to read, Master must PULL DOWN the SDA else ee_data_reg <= 1;if(delay_cnt == delay) beginstate <= state + 1;delay_cnt <= 0;endelse beginstate <= state ;delay_cnt <= delay_cnt + 1;end endRD_DATA_ACK2 : begin ee_sclk_reg <= 1;if(delay_cnt == 2) wr_rddata_flag <= 1;else wr_rddata_flag <= 0;if(delay_cnt == delay) begindelay_cnt <= 0;if(rd_data_flag) beginstate <= RD_DATA_1 ;num <= 7;endelse beginstate <= STOP_1 ; num <= 0;endendelse beginstate <= state ;delay_cnt <= delay_cnt + 1;end endSTOP_1: begin ee_sclk_reg <= 0; ee_data_reg <= 0;if(delay_cnt == delay) begin state <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;end end STOP_2: beginee_sclk_reg <= 1; ee_data_reg <= 0;if(delay_cnt == delay) begin state <= state + 1;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;end endSTOP_3: beginee_sclk_reg <= 1; ee_data_reg <= 1;if(delay_cnt == delay) begin if(wr_flag == 1) begin state <= state + 1;delay_cnt <= 0;endelse begin //read,not need wait.rd_flag <= 0;state <= IDLE; delay_cnt <= 0;endendelse begin state <= state ;delay_cnt <= delay_cnt + 1;end endWRITE_TIME: begin //if write, need wait a lot time to re-satrt.if read, not need wait.wr_flag <= 0;if(delay_cnt == delay_10ms) begin state <= IDLE;delay_cnt <= 0;endelse begin state <= state ;delay_cnt <= delay_cnt + 1;end enddefault: state <= IDLE; endcase endend//----------------------------------assign ee_I2C_CLK = ee_sclk_reg;assign ee_I2C_SDA = dir_sda_flag ? ee_data_reg: 1'bz;assign rd_wrdata_en = rd_wrdata_flag;assign wr_rddata_en = wr_rddata_flag;assign rd_data = rd_data_reg;endmodule View Code // megafunction wizard: %FIFO% // GENERATION: STANDARD // VERSION: WM1.0 // MODULE: scfifo // ============================================================ // File Name: RD_DATA_BUF.v // Megafunction Name(s): // scfifo // // Simulation Library Files(s): // altera_mf // ============================================================ // ************************************************************ // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! // // 16.0.0 Build 211 04/27/2016 SJ Standard Edition // ************************************************************//Copyright (C) 1991-2016 Altera Corporation. All rights reserved. //Your use of Altera Corporation's design tools, logic functions //and other software and tools, and its AMPP partner logic //functions, and any output files from any of the foregoing //(including device programming or simulation files), and any //associated documentation or information are expressly subject //to the terms and conditions of the Altera Program License //Subscription Agreement, the Altera Quartus Prime License Agreement, //the Altera MegaCore Function License Agreement, or other //applicable license agreement, including, without limitation, //that your use is for the sole purpose of programming logic //devices manufactured by Altera and sold by Altera or its //authorized distributors. Please refer to the applicable //agreement for further details.// synopsys translate_off `timescale 1 ps / 1 ps // synopsys translate_on module RD_DATA_BUF (aclr,clock,data,rdreq,wrreq,empty,full,q,usedw);input aclr;input clock;input [7:0] data;input rdreq;input wrreq;output empty;output full;output [7:0] q;output [4:0] usedw;wire sub_wire0;wire sub_wire1;wire [7:0] sub_wire2;wire [4:0] sub_wire3;wire empty = sub_wire0;wire full = sub_wire1;wire [7:0] q = sub_wire2[7:0];wire [4:0] usedw = sub_wire3[4:0];scfifo scfifo_component (.aclr (aclr),.clock (clock),.data (data),.rdreq (rdreq),.wrreq (wrreq),.empty (sub_wire0),.full (sub_wire1),.q (sub_wire2),.usedw (sub_wire3),.almost_empty (),.almost_full (),.eccstatus (),.sclr ());defparamscfifo_component.add_ram_output_register = "OFF",scfifo_component.intended_device_family = "Cyclone IV E",scfifo_component.lpm_numwords = 32,scfifo_component.lpm_showahead = "OFF",scfifo_component.lpm_type = "scfifo",scfifo_component.lpm_width = 8,scfifo_component.lpm_widthu = 5,scfifo_component.overflow_checking = "ON",scfifo_component.underflow_checking = "ON",scfifo_component.use_eab = "ON";endmodule// ============================================================ // CNX file retrieval info // ============================================================ // Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0" // Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1" // Retrieval info: PRIVATE: AlmostFull NUMERIC "0" // Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1" // Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "1" // Retrieval info: PRIVATE: Clock NUMERIC "0" // Retrieval info: PRIVATE: Depth NUMERIC "32" // Retrieval info: PRIVATE: Empty NUMERIC "1" // Retrieval info: PRIVATE: Full NUMERIC "1" // Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" // Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0" // Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1" // Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0" // Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0" // Retrieval info: PRIVATE: Optimize NUMERIC "2" // Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" // Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" // Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0" // Retrieval info: PRIVATE: UsedW NUMERIC "1" // Retrieval info: PRIVATE: Width NUMERIC "8" // Retrieval info: PRIVATE: dc_aclr NUMERIC "0" // Retrieval info: PRIVATE: diff_widths NUMERIC "0" // Retrieval info: PRIVATE: msb_usedw NUMERIC "0" // Retrieval info: PRIVATE: output_width NUMERIC "8" // Retrieval info: PRIVATE: rsEmpty NUMERIC "1" // Retrieval info: PRIVATE: rsFull NUMERIC "0" // Retrieval info: PRIVATE: rsUsedW NUMERIC "0" // Retrieval info: PRIVATE: sc_aclr NUMERIC "1" // Retrieval info: PRIVATE: sc_sclr NUMERIC "0" // Retrieval info: PRIVATE: wsEmpty NUMERIC "0" // Retrieval info: PRIVATE: wsFull NUMERIC "1" // Retrieval info: PRIVATE: wsUsedW NUMERIC "0" // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all // Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF" // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" // Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "32" // Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF" // Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo" // Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "8" // Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "5" // Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON" // Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON" // Retrieval info: CONSTANT: USE_EAB STRING "ON" // Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL "aclr" // Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock" // Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]" // Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL "empty" // Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL "full" // Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" // Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq" // Retrieval info: USED_PORT: usedw 0 0 5 0 OUTPUT NODEFVAL "usedw[4..0]" // Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq" // Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0 // Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0 // Retrieval info: CONNECT: @data 0 0 8 0 data 0 0 8 0 // Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0 // Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0 // Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0 // Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0 // Retrieval info: CONNECT: q 0 0 8 0 @q 0 0 8 0 // Retrieval info: CONNECT: usedw 0 0 5 0 @usedw 0 0 5 0 // Retrieval info: GEN_FILE: TYPE_NORMAL RD_DATA_BUF.v TRUE // Retrieval info: GEN_FILE: TYPE_NORMAL RD_DATA_BUF.inc FALSE // Retrieval info: GEN_FILE: TYPE_NORMAL RD_DATA_BUF.cmp FALSE // Retrieval info: GEN_FILE: TYPE_NORMAL RD_DATA_BUF.bsf FALSE // Retrieval info: GEN_FILE: TYPE_NORMAL RD_DATA_BUF_inst.v FALSE // Retrieval info: GEN_FILE: TYPE_NORMAL RD_DATA_BUF_bb.v TRUE // Retrieval info: LIB_FILE: altera_mf View Code TB: `timescale 1 ps/1 psmodule EEPROM_TB;reg clk;reg rst_n;wire ee_I2C_CLK;wire ee_I2C_SDA;EEPROM u_EEPROM(.clk(clk),.rst_n(rst_n),.EEPROM_SCK(ee_I2C_CLK),.EEPROM_SDA(ee_I2C_SDA));parameter T = 20000;always #(T/2) clk = ~clk;initial beginclk = 0;rst_n = 0;$stop;#(500*T) rst_n = 1; endendmodule View Code?
? ??
?
? ? ?
?
轉載于:https://www.cnblogs.com/fhyfhy/p/7878679.html
總結
以上是生活随笔為你收集整理的EEPROM的操作---SPI接口和I2C接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 存储过程Procedure
- 下一篇: vs2010如何安装qt插件