参考:http://blog.csdn.net/yuanlulu/article/details/6163106

 ROM最初不能编程,出厂什么内容就永远什么内容,不灵活。后来出现了PROM,可以自己写入一次,要是写错了,只能换一片,自认倒霉。人类文明不断进步,终于出现了可多次擦除写入的EPROM,每次擦除要把芯片拿到紫外线上照一下,想一下你往单片机上下了一个程序之后发现有个地方需要加一句话,为此你要把单片机放紫外灯下照半小时,然后才能再下一次,这么折腾一天也改不了几次。历史的车轮不断前进,伟大的EEPROM出现了,拯救了一大批程序员,终于可以随意的修改rom中的内容了

  EEPROM的全称是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。是相对于紫外擦除的rom来讲的。但是今天已经存在多种EEPROM的变种,变成了一类存储器的统称.这种rom的特点是可以随机访问和修改任何一个字节,可以往每个bit中写入0或者1。这是最传统的一种EEPROM,掉电后数据不丢失,可以保存100年,可以擦写100w次。具有较高的可靠性,但是电路复杂/成本也高。因此目前的EEPROM都是几十千字节到几百千字节的,绝少有超过512K的。

  EEPROM的接口分为两种:SPI和I2C。

SPI接口为四线,型号如AT25XXX。

    

I2C接口为2线,型号如24CL02/04/XX.

  

    这两种EEPROM的操作主要按SPI 和I2C的协议操作就可以了,不过也有一些需要注意的地方。在这里记录下来,不涉及细节的处理。

对于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数据之后,需要给从机发一个ACK(输出一个SDA =0)。注意读取的时候ACK是由Master发出的,在写数据的时候ACK是由slaver发出的。

可以参考: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接口相关推荐

  1. linux驱动系列学习之OLED(i2c接口)(八)

    一.OLED简介 本次使用的开发板正点原子Linux阿波罗.屏幕是i2c接口的四针.分辨率为128×64的oled液晶屏.通信接口为i2c.具体的i2c框架使用请参考前面的文章.oled的详细简介请参 ...

  2. Arduino驱动I2C接口12864LCD大屏液晶模块方法及库文件

    关键词:Arduino显示,12864液晶模块,中文显示,IIC接口,I2C接口,12864驱动程序 液晶显示模块目前在中国发展已经有30多个年头了,市场上应用最广泛的要属于128*64点阵的显示屏, ...

  3. LCD液晶屏接口和显示器接口介绍

    LCD液晶屏主流显示接口介绍 屏的接口类型种类以及接口定义分析(绝对收藏) I2C.SPI.UART.RGB.LVDS,MIPI,EDP和DP等显示屏接口简要总结 LCD主流显示接口介绍_这个ID洒家 ...

  4. UART SPI I2C 接口介绍 转载

    UART SPI I2C 接口介绍@TOC 做单片机开发时UART,SPI和I2C都是我们最经常使用到的硬件接口,我收集了相关的具体材料对这三种接口进行了详细的解释. UART UART是一种通用串行 ...

  5. linux 扫描i2c端口,s3c2440用I2C接口访问EEPROM

    在前面阅读理解了I2C的官方协议文档后,就拿s3c2440和EEPROM来验证一下. 本来是想用s3c2440的SDA和SCL管脚复用为GPIO来模拟的,但在没有示波器的情况下搞了一周,怎么都出不来, ...

  6. BBB学习(十):操作BBB I2C接口

    一.前言 前文中介绍了普通IO口的使用以及引脚功能互查表的用法,主要想通过简单的IO操作熟悉BBB的使用流程,在BBB的接口中,还在一类功能复用的引脚,如I2C.spi等,本节通过介绍I2C的使用方法 ...

  7. 10.STM32中用I2C接口发送数据到EEPROM寄存器在从此寄存器读数据

    10.STM32中用I2C接口发送数据到EEPROM寄存器在从此寄存器读数据.

  8. STM32CubeMX学习笔记(9)——I2C接口使用(读写EEPROM AT24C02)

    一.I2C简介 I2C(Inter-Integrated Circuit ,内部集成电路) 总线是一种由飞利浦 Philip 公司开发的串行总线.是两条串行的总线,它由一根数据线(SDA)和一根 时钟 ...

  9. CH341的I2C接口编程说明

    CH341的I2C接口特性: 1.支持I2C速度20K/100K/400K/750K: 2.默认不支持设备的ACK应答监测,即忽略ACK状态:强制支持需修改软件: 引脚序号 功能说明 24 SCL 2 ...

最新文章

  1. os.environ[CUDA_DEVICE_ORDER] = PCI_BUS_ID os.environ[CUDA_VISIBLE_DEVICES] = 0
  2. ping: sendto: Network is unreachable
  3. 项目开发环境(h5+pc的开发思路是一样的)
  4. Android RotateAnimation详解
  5. ASIHTTPRequest源码简单分析
  6. 转载 - Linux 磁盘挂载
  7. github git.exe位置
  8. emp和emn是什么文件_emn格式文件
  9. JUnit4教程+实践
  10. TypeScript 获取时间戳
  11. 联想主板9针开关接线图_家庭配电箱总漏电保护,空气开关用63A还是40A好?看完彻底懂了...
  12. 【图片】 3D打印的一些小东西 暗黑
  13. 医疗 PACS 系统的海量影像数据归档实例
  14. HCI_Inquiry
  15. http://blog.csdn.net/pizi0475/article/details/48286579 -------------(Collada 快速入门)
  16. 第05篇:Mybatis的SQL执行流程分析
  17. 股票集合竞价什么意思?集合竞价时间及集合竞价技巧?
  18. 蓝桥云课练习题 用杂志拼接信件
  19. html5卡片平行视差效果,HTML5/jQuery很棒的交互式平行视差皓月当空场景动画
  20. UICollectionView左对齐

热门文章

  1. linux 安装jdk(install jdk)
  2. 【矩阵】概念的理解 —— span、基
  3. 在人山人海里,你不必记得我
  4. Hadoop学习之路一 Single Node Setup
  5. 健身小管家--android app源码
  6. 用饮水机教你什么是RAID [转]
  7. [导入]关于谭浩强[上]
  8. 如何写好一份工程师简历
  9. Tomcat 8 安装和配置、优化
  10. 杭电1860--统计字符