基于I2C协议的EEPROM驱动控制

1.原理

IIC(Inter-Integrated Circuit)协议是一种串行通信协议,它具有以下特点:

  1. 双线通信:IIC协议使用两根信号线进行通信,分别是串行数据线SDA和串行时钟线SCL。
  2. 多主从架构:IIC支持多主多从的通信方式,允许多个设备连接到同一总线上,并且每个设备都有唯一的地址。
  3. 开漏输出:所有设备的SDA和SCL引脚都采用开漏输出结构,通过外接上拉电阻实现线与逻辑关系,防止数据冲突。
  4. 自动寻址:总线上的所有设备都可以通过软件寻址,具有唯一的7位或10位地址。
  5. 支持仲裁机制:在多主机系统中,通过冲突检测和仲裁机制防止多个主机同时发起数据传输时存在的冲突。
  6. 自动应答:IIC总线上所有器件都具有自动应答功能,保证数据传输的正确性。
  7. 传输速率:IIC支持不同的传输速率,包括标准模式(100kb/s)、快速模式(400kb/s)、增强快速模式(1Mb/s)、高速模式(3.4Mb/s)和极速模式(5Mb/s。
  8. 总线电容限制:IIC总线允许挂载的设备数量取决于总线上最大电容值,一般为400pf(高速模式100pf。
  9. 简单可靠:IIC协议结构简单,可靠性高,适用于低速外围设备的数据传输。
  10. 广泛应用:由于其简单性和可靠性,IIC协议被广泛应用于各种嵌入式系统中,如存储器、LED及LCD驱动器、A/D及D/A转换器等。

IIC协议的这些特点使其在嵌入式系统和集成电路间的通信中非常流行,特别是在对硬件资源要求较低、需要连接多个低速设备的应用场景中。

A2A1A3地址表示可以连接8个EEPROM设备,当读写控制位为0表示主机要对从机进行数据写入操作,1表示主机要对从机进行数据读出操作。当主机把器件地址发送到总线上,所有的从机都会收到,然后和自身的器件地址做对比,如果和总线上的地址相同,那么从机设备就会给主机发送一个应答信号。

内存地址只是一个编号,代表一个内存空间;内存地址所执行的内存单元大小就是1字节,跟内存地址位数无关

1.写操作

以上是单字节写

以上是页写

所有的i2c设备都支持单字节写入,但只有一部分I2C设备支持页写操作。并且支持页写操作的设备一次性写入的数据量不能超过这个设备单页所包含的存储单元数。而24c64单页的存储单元个数是32,也就是一次页写操作最多写入32个字节的数据。

2.读操作

以上是随机读操作

以上是顺序读

2.实践

任务

使用写控制按键向EEPROM写入1-10共10个字节的数据,再使用读控制按键读出数据并在数码管上显示出来。

64Kbit=8KB,EEPROM每个存储空间只能存储1字节的数据,24C64需要13位宽的地址。

以上是数据写的状态转移图

以上是读和写的状态转移图

系统时钟是50MHZ,i2c_clk是1mhz,所以i2c_clk信号经过系统时钟50分频。

时钟分频的时序图

i2c_scl的时钟频率是250K,250K相当于i2c_clk的4分频

以上是写操作的时序图

以上是读操作的时序图

2.1 i2c_ctrl.v

module  i2c_ctrl
#(
    parameter   DEVICE_ADDR     =   7'b1010_011,
    parameter   SYS_CLK_FREQ    =   'd50_000_000,
    parameter   SCL_FREQ        =   'd250_000
)
(
    input   wire            sys_clk     ,
    input   wire            sys_rst_n   ,
    input   wire            i2c_start   ,
    input   wire            wr_en       ,
    input   wire    [15:0]  byte_addr   ,
    input   wire    [7:0]   wr_data     ,
    input   wire            rd_en       ,
    input   wire            addr_num    ,

    output  reg             i2c_scl     ,
    inout   wire            i2c_sda     ,
    output  reg     [7:0]   rd_data     ,
    output  reg             i2c_end     ,
    output  reg             i2c_clk
);

parameter   CNT_CLK_MAX = (SYS_CLK_FREQ / SCL_FREQ) >> 3 ;

parameter   IDLE        =    4'd00,
            START       =    4'd01,
            SEND_D_A    =    4'd02,
            ACK_1       =    4'd03,
            SEND_B_H    =    4'd04,
            ACK_2       =    4'd05,
            SEND_B_L    =    4'd06,
            ACK_3       =    4'd07,
            WR_DATA     =    4'd08,
            ACK_4       =    4'd09,
            START_2     =    4'd10,
            SEND_R_A    =    4'd11,
            ACK_5       =    4'd12,
            RD_DATA     =    4'd13,
            N_ACK       =    4'd14,
            STOP        =    4'd15;

wire            sda_en          ;
wire            sda_in          ;

reg     [7:0]   cnt_clk         ;
reg     [3:0]   state           ;
reg     [1:0]   cnt_i2c_clk     ;
reg             cnt_i2c_clk_en  ;
reg     [2:0]   cnt_bit         ;
reg             sda_out         ;
reg             ack             ;
reg     [7:0]   rd_data_reg     ;


always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk <=  8'd0;
    else    if(cnt_clk == CNT_CLK_MAX - 1)
        cnt_clk <=  8'd0;
    else
        cnt_clk <=  cnt_clk + 1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        i2c_clk <=  1'b1;
    else    if(cnt_clk == CNT_CLK_MAX - 1)
        i2c_clk <=  ~i2c_clk;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state   <=  IDLE;
    else    case(state)
        IDLE:
            if(i2c_start == 1'b1)
                state   <=  START;
            else
                state   <=  state;
        START:
            if(cnt_i2c_clk == 2'd3)
                state   <=  SEND_D_A;
            else
                state   <=  state;
        SEND_D_A:
            if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
                state   <=  ACK_1;
            else
                state   <=  state;
        ACK_1:
            if((cnt_i2c_clk == 2'd3) && (ack == 1'b0))
                begin
                    if(addr_num == 1'b1)
                        state   <=  SEND_B_H;
                    else
                        state   <=  SEND_B_L;
                end
            else
                state   <=  state;
        SEND_B_H:
            if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
                state   <=  ACK_2;
            else
                state   <=  state;
        ACK_2:
            if((cnt_i2c_clk == 2'd3) && (ack == 1'b0))
                state   <=  SEND_B_L;
            else
                state   <=  state;
        SEND_B_L:
            if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
                state   <=  ACK_3;
            else
                state   <=  state;
        ACK_3:
            if((cnt_i2c_clk == 2'd3) && (ack == 1'b0))
                begin
                    if(wr_en == 1'b1)
                        state   <=  WR_DATA;
                    else    if(rd_en == 1'b1)
                        state   <=  START_2;
                    else
                        state   <=  state;
                end
            else
                state   <=  state;
        WR_DATA:
            if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
                state   <=  ACK_4;
            else
                state   <=  state;
        ACK_4:
            if((cnt_i2c_clk == 2'd3) && (ack == 1'b0))
                state   <=  STOP;
            else
                state   <=  state;
        START_2:
            if(cnt_i2c_clk == 2'd3)
                state   <=  SEND_R_A;
            else
                state   <=  state;
        SEND_R_A:
            if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
                state   <=  ACK_5;
            else
                state   <=  state;
        ACK_5:
            if((cnt_i2c_clk == 2'd3) && (ack == 1'b0))
                state   <=  RD_DATA;
            else
                state   <=  state;
        RD_DATA:
            if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
                state   <=  N_ACK;
            else
                state   <=  state;
        N_ACK:
            if(cnt_i2c_clk == 2'd3)
                state   <=  STOP;
            else
                state   <=  state;
        STOP:
            if((cnt_bit == 3'd3) && (cnt_i2c_clk == 2'd3))
                state   <=  IDLE;
            else
                state   <=  state;
        default:state   <=  IDLE;
    endcase

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_i2c_clk <=  2'd0;
    else    if(cnt_i2c_clk_en == 1'b1)
        cnt_i2c_clk <=  cnt_i2c_clk + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_i2c_clk_en  <=  1'b0;
    else    if((state == STOP) && (cnt_bit == 3'd3) && (cnt_i2c_clk == 2'd3))
        cnt_i2c_clk_en  <=  1'b0;
    else    if(i2c_start == 1'b1)
        cnt_i2c_clk_en  <=  1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_bit <=  3'd0;
    else    if((state == IDLE) || (state == START) || (state == ACK_1)
                ||(state == ACK_2) || (state == ACK_3) ||(state == ACK_4)
                || (state == ACK_5) ||(state == START_2) || (state == N_ACK))
        cnt_bit <=  3'd0;
    else    if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
        cnt_bit <=  3'd0;
    else    if((cnt_i2c_clk == 2'd3)&& (state != IDLE))
        cnt_bit <=  cnt_bit + 1'b1;

always@(*)
    case(state)
        IDLE:
            sda_out <=  1'b1;
        START:
            if(cnt_i2c_clk == 2'd0)
                sda_out <=  1'b1;
            else
                sda_out <=  1'b0;
        SEND_D_A:
            if(cnt_bit <= 3'd6)
                sda_out <=  DEVICE_ADDR[6 - cnt_bit];
            else
                sda_out <=  1'b0;
        ACK_1:
            sda_out <=  1'b1;
        SEND_B_H:
            sda_out <=  byte_addr[15 - cnt_bit];
        ACK_2:
            sda_out <=  1'b1;
        SEND_B_L:
            sda_out <=  byte_addr[7 - cnt_bit];
        ACK_3:
            sda_out <=  1'b1;
        WR_DATA:
            sda_out <=  wr_data[7 - cnt_bit];
        ACK_4:
            sda_out <=  1'b1;
        START_2:
            if(cnt_i2c_clk <= 2'd1)
                sda_out <=  1'b1;
            else
                sda_out <=  1'b0;
        SEND_R_A:
            if(cnt_bit <= 3'd6)
                sda_out <=  DEVICE_ADDR[6 - cnt_bit];
            else
                sda_out <=  1'b1;
        ACK_5:
            sda_out <=  1'b1;
        RD_DATA:
            sda_out <=  1'b1;
        N_ACK:
            sda_out <=  1'b1;
        STOP:
            if((cnt_bit == 3'd0) && (cnt_i2c_clk < 2'd3))
                sda_out <=  1'b0;
            else
                sda_out <=  1'b1;
        default:sda_out <=  1'b1;
    endcase

assign  sda_en = ((state == RD_DATA) || (state == ACK_1) || (state == ACK_2) || (state == ACK_3) || (state == ACK_4) || (state == ACK_5)) ? 1'b0 : 1'b1;

always@(*)
    case(state)
        ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:
            if(cnt_i2c_clk == 2'd0)
                ack <=  sda_in;//1'b0;//
            else
                ack <=  ack;
        default:ack <=  1'b1;
    endcase

assign  sda_in = i2c_sda;

always@(*)
    case(state)
        IDLE:
            rd_data_reg <=  8'd0;
        RD_DATA:
            if(cnt_i2c_clk == 2'd2)
                rd_data_reg[7-cnt_bit]  <=  sda_in;
            else
                rd_data_reg <=  rd_data_reg;
        default:rd_data_reg <=  rd_data_reg;
    endcase

always@(*)
    case(state)
        IDLE:
            i2c_scl <=  1'b1;
        START:
            if(cnt_i2c_clk == 2'd3)
                i2c_scl <=  1'b0;
            else
                i2c_scl <=  1'b1;
        SEND_D_A,ACK_1,SEND_B_H,ACK_2,SEND_B_L,ACK_3,
        WR_DATA,ACK_4,START_2,SEND_R_A,ACK_5,RD_DATA,N_ACK:
            if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2))
                i2c_scl <=  1'b1;
            else
                i2c_scl <=  1'b0;
        STOP:
            if((cnt_bit == 3'd0) && (cnt_i2c_clk == 2'd0))
                i2c_scl <=  1'b0;
            else
                i2c_scl <=  1'b1;
        default:i2c_scl <=  1'b1;
    endcase

assign  i2c_sda = (sda_en == 1'b1) ? sda_out : 1'bz;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        i2c_end <=  1'b0;
    else    if((state == STOP) && (cnt_bit == 3'd3) && (cnt_i2c_clk == 2'd3))
        i2c_end <=  1'b1;
    else
        i2c_end <=  1'b0;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_data <=  8'd0;
    else    if((state == RD_DATA) && (cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
        rd_data <=  rd_data_reg;

endmodule

2.2 i2c_rw_data.v

module  i2c_rw_data
(
    input   wire            sys_clk     ,
    input   wire            sys_rst_n   ,
    input   wire            write       ,
    input   wire            read        ,
    input   wire    [7:0]   rd_data     ,
    input   wire            i2c_end     ,
    input   wire            i2c_clk     ,

    output  reg             i2c_start   ,
    output  reg             wr_en       ,
    output  reg     [15:0]  byte_addr   ,
    output  reg     [7:0]   wr_data     ,
    output  reg             rd_en       ,
    output  wire    [7:0]   fifo_data
);

parameter   CNT_WR_RD_MAX   =   8'd200;
parameter   CNT_START_MAX   =   16'd50_000;
parameter   CNT_DATA_NUM    =   8'd10;
parameter   CNT_WAIT_MAX    =   20'd500_000;

wire    [7:0]   data_num    ;

reg             wr_valid    ;
reg     [7:0]   cnt_wr      ;
reg             rd_valid    ;
reg     [7:0]   cnt_rd      ;
reg     [15:0]  cnt_start   ;
reg     [7:0]   cnt_wr_num  ;
reg     [7:0]   cnt_rd_num  ;
reg             fifo_rd_valid;
reg             fifo_rd_en  ;
reg     [19:0]  cnt_wait    ;
reg     [7:0]   cnt_rd_fifo_num  ;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_valid    <=  1'b0;
    else    if(cnt_wr == CNT_WR_RD_MAX - 1)
        wr_valid    <=  1'b0;
    else    if(write == 1'b1)
        wr_valid    <=  1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_wr  <=  8'd0;
    else    if(wr_valid == 1'b0)
        cnt_wr  <=  8'd0;
    else    if(wr_valid == 1'b1)
        cnt_wr  <=  cnt_wr + 1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_valid    <=  1'b0;
    else    if(cnt_rd == CNT_WR_RD_MAX - 1)
        rd_valid    <=  1'b0;
    else    if(read == 1'b1)
        rd_valid    <=  1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_rd  <=  8'd0;
    else    if(rd_valid == 1'b0)
        cnt_rd  <=  8'd0;
    else    if(rd_valid == 1'b1)
        cnt_rd  <=  cnt_rd + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_start   <=  16'd0;
    else    if((wr_en == 1'b0) && (rd_en == 1'b0))
        cnt_start   <=  16'd0;
    else    if(cnt_start == CNT_START_MAX - 1'b1)
        cnt_start   <=  16'd0;
    else    if((wr_en == 1'b1) || (rd_en == 1'b1))
        cnt_start   <=  cnt_start + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_wr_num  <=  8'd0;
    else    if(wr_en == 1'b0)
        cnt_wr_num  <=  8'd0;
    else    if((wr_en == 1'b1) && (i2c_end == 1'b1))
        cnt_wr_num  <=  cnt_wr_num + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_rd_num  <=  8'd0;
    else    if(rd_en == 1'b0)
        cnt_rd_num  <=  8'd0;
    else    if((rd_en == 1'b1) && (i2c_end == 1'b1))
        cnt_rd_num  <=  cnt_rd_num + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        fifo_rd_valid   <=  1'b0;
    else    if((cnt_rd_fifo_num == CNT_DATA_NUM) 
            && (cnt_wait == CNT_WAIT_MAX - 1'b1))
        fifo_rd_valid   <=  1'b0;
    else    if(data_num == CNT_DATA_NUM)
        fifo_rd_valid   <=  1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        fifo_rd_en  <=  1'b0;
    else    if((cnt_rd_fifo_num < CNT_DATA_NUM) 
            && (cnt_wait == CNT_WAIT_MAX - 1'b1))
        fifo_rd_en  <=  1'b1;
    else
        fifo_rd_en  <=  1'b0;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_wait    <=  20'd0;
    else    if(fifo_rd_valid == 1'b0)
        cnt_wait    <=  20'd0;
    else    if(cnt_wait == CNT_WAIT_MAX - 1'b1)
        cnt_wait    <=  20'd0;
    else    if(fifo_rd_valid == 1'b1)
        cnt_wait    <=  cnt_wait + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_rd_fifo_num <=  8'd0;
    else    if(fifo_rd_valid == 1'b0)
        cnt_rd_fifo_num <=  8'd0;
    else    if(fifo_rd_en == 1'b1)
        cnt_rd_fifo_num <=  cnt_rd_fifo_num + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_en   <=  1'b0;
    else    if((cnt_wr_num == CNT_DATA_NUM - 1'b1) 
                && (i2c_end == 1'b1) && (wr_en == 1'b1))
        wr_en   <=  1'b0;
    else    if(wr_valid == 1'b1)
        wr_en   <=  1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en   <=  1'b0;
    else    if((cnt_rd_num == CNT_DATA_NUM - 1'b1) 
                && (i2c_end == 1'b1) && (rd_en == 1'b1))
        rd_en   <=  1'b0;
    else    if(rd_valid == 1'b1)
        rd_en   <=  1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        i2c_start   <=  1'b0;
    else    if(cnt_start == CNT_START_MAX - 1'b1)
        i2c_start   <=  1'b1;
    else
        i2c_start   <=  1'b0;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        byte_addr   <=  16'h00_99;
    else    if((wr_en == 1'b0) && (rd_en == 1'b0))
        byte_addr   <=  16'h00_99;
    else    if(((wr_en == 1'b1) || (rd_en == 1'b1)) && (i2c_end == 1'b1))
        byte_addr   <=  byte_addr + 1'b1;

always@(posedge i2c_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_data <=  8'h01;
    else    if(wr_en == 1'b0)
        wr_data <=  8'h01;
    else    if((wr_en == 1'b1) && (i2c_end == 1'b1))
        wr_data <=  wr_data + 1'b1;


fifo_data   fifo_data_inst
(
    .clock (i2c_clk),
    .data (rd_data),
    .rdreq (fifo_rd_en),
    .wrreq (i2c_end && rd_en),
    .q (fifo_data),
    .usedw (data_num)
);

endmodule

i2c_clk的频率是1mhz,去采集sys_clk的50mhz,会出现问题采集不正确的情况,所以就要做一个跨时钟域的处理。需要将读写使能信号同步到i2c_clk时钟下。要保证在i2c_clk信号下,能正确采集到读写使能信号。

跨时钟域处理

多比特数据:fifo,ram IP核,写入数据缓存一下,写入时钟和读出时钟使用不同的时钟就可以实现跨时钟域的处理。

单比特数据:如果两个时钟信号同频不同相,采用打拍的方式处理。但是在此处,两个时钟不同频,而且是从高速时钟域到低俗时钟域,我们要延长触发信号的保持时间来处理跨时钟域信号。

增加有效信号大于i2c_clk两个时钟周期的长度。50mhz和1mhz存在50倍的关系,也就是1个i2c_clk时钟的时钟周期等于50个sys_clk的时钟周期,因此有效信号的高电平保持时间至少要大于100个sys_clk的时钟周期,为了保险起见这里选择200个sys_clk的时钟周期。

两个字节的写入,中间的间隔要大于5ms。以上是24c64的数据手册。i2c_clk是1mhz,1mhz=1000_00hz=1/1000_000s=0.000_001s=1us。5ms=5000us。5000us/1us=5000也就是至少要间隔5000个i2c_clk时钟周期。

2.3  i2c_eeprom.v

module  i2c_eeprom
(
    input   wire            sys_clk     ,
    input   wire            sys_rst_n   ,
    input   wire            key_wr      ,
    input   wire            key_rd      ,

    output  wire            ds          ,
    output  wire            oe          ,
    output  wire            shcp        ,
    output  wire            stcp        ,
    output  wire            i2c_scl     ,
    inout   wire            i2c_sda
);

parameter   CNT_MAX = 20'd999_999;


wire            write   ;
wire            read    ;
wire            i2c_start;
wire            wr_en    ;
wire    [15:0]  byte_addr;
wire    [7:0]   wr_data  ;
wire            rd_en    ;
wire    [7:0]   fifo_data;
wire    [7:0]   rd_data ;
wire            i2c_end;
wire            i2c_clk;

key_filter
#(
    .CNT_MAX (CNT_MAX)
)
key_filter_wr
(
    .sys_clk    (sys_clk),
    .sys_rst_n  (sys_rst_n),
    .key_in     (key_wr),

    .key_flag   (write)
);

key_filter
#(
    .CNT_MAX (CNT_MAX)
)
key_filter_rd
(
    .sys_clk    (sys_clk),
    .sys_rst_n  (sys_rst_n),
    .key_in     (key_rd),

    .key_flag   (read)
);

i2c_rw_data i2c_rw_data_inst
(
    .sys_clk     (sys_clk),
    .sys_rst_n   (sys_rst_n),
    .write       (write),
    .read        (read),
    .rd_data     (rd_data),
    .i2c_end     (i2c_end),
    .i2c_clk     (i2c_clk),

    .i2c_start   (i2c_start),
    .wr_en       (wr_en),
    .byte_addr   (byte_addr),
    .wr_data     (wr_data),
    .rd_en       (rd_en),
    .fifo_data   (fifo_data)
);

i2c_ctrl
#(
    .DEVICE_ADDR     (7'b1010_011),
    .SYS_CLK_FREQ    ('d50_000_000),
    .SCL_FREQ        ('d250_000)
)
i2c_ctrl_inst
(
    .sys_clk     (sys_clk),
    .sys_rst_n   (sys_rst_n),
    .i2c_start   (i2c_start),
    .wr_en       (wr_en),
    .byte_addr   (byte_addr),
    .wr_data     (wr_data),
    .rd_en       (rd_en),
    .addr_num    (1'b1),

    .i2c_scl     (i2c_scl),
    .i2c_sda     (i2c_sda),
    .rd_data     (rd_data),
    .i2c_end     (i2c_end),
    .i2c_clk     (i2c_clk)
);



seg_595_dynamic seg_595_dynamic_inst
(
    .sys_clk     (sys_clk),
    .sys_rst_n   (sys_rst_n),
    .data        (fifo_data  ),
    .point       (  ),
    .sign        (  ),
    .seg_en      (1'b1),

    .ds          (ds  ),
    .oe          (oe  ),
    .shcp        (shcp),
    .stcp        (stcp)
);




endmodule

2.4  tb_i2c_eeprom.v

`timescale  1ns/1ns
module  tb_i2c_eeprom();

wire            ds     ;
wire            oe     ;
wire            shcp   ;
wire            stcp   ;
wire            i2c_scl;
wire            i2c_sda;

reg             sys_clk     ;
reg             sys_rst_n   ;
reg             key_wr      ;
reg             key_rd      ;

initial
    begin
        sys_clk     =   1'b1;
        sys_rst_n   <=  1'b0;
        key_wr      <=  1'b1;
        key_rd      <=  1'b1;
        #200
        sys_rst_n   <=  1'b1;
        #1000
        key_wr      <=  1'b0;
        key_rd      <=  1'b1;
        #400
        key_wr      <=  1'b1;
        key_rd      <=  1'b1;
        #55_000_0000
        key_wr      <=  1'b1;
        key_rd      <=  1'b0;
        #400
        key_wr      <=  1'b1;
        key_rd      <=  1'b1;
    end
always #10 sys_clk = ~sys_clk;

defparam    i2c_eeprom_inst.CNT_MAX = 5;
defparam    i2c_eeprom_inst.i2c_rw_data_inst.CNT_WAIT_MAX = 1000;

i2c_eeprom  i2c_eeprom_inst
(
    .sys_clk     (sys_clk),
    .sys_rst_n   (sys_rst_n),
    .key_wr      (key_wr),
    .key_rd      (key_rd),

    .ds          (ds     ),
    .oe          (oe     ),
    .shcp        (shcp   ),
    .stcp        (stcp   ),
    .i2c_scl     (i2c_scl),
    .i2c_sda     (i2c_sda)
);

M24LC64 M24LC64_inst
(
    .A0      (1'b0),
    .A1      (1'b0),
    .A2      (1'b0),
    .WP      (1'b0),
    .SDA     (i2c_sda),
    .SCL     (i2c_scl),
    .RESET   (~sys_rst_n)
);

endmodule

2.5  M24LC64.v (从官网上下载的仿真文件)

// *******************************************************************************************************
// **                                                                                                   **
// **   24LC64.v - Microchip 24LC64 64K-BIT I2C SERIAL EEPROM (VCC = +2.5V TO +5.5V)                    **
// **                                                                                                   **
// *******************************************************************************************************
// **                                                                                                   **
// **                   This information is distributed under license from Young Engineering.           **
// **                              COPYRIGHT (c) 2009 YOUNG ENGINEERING                                 **
// **                                      ALL RIGHTS RESERVED                                          **
// **                                                                                                   **
// **                                                                                                   **
// **   Young Engineering provides design expertise for the digital world                               **
// **   Started in 1990, Young Engineering offers products and services for your electronic design      **
// **   project.  We have the expertise in PCB, FPGA, ASIC, firmware, and software design.              **
// **   From concept to prototype to production, we can help you.                                       **
// **                                                                                                   **
// **   http://www.young-engineering.com/                                                               **
// **                                                                                                   **
// *******************************************************************************************************
// **   This information is provided to you for your convenience and use with Microchip products only.  **
// **   Microchip disclaims all liability arising from this information and its use.                    **
// **                                                                                                   **
// **   THIS INFORMATION IS PROVIDED "AS IS." MICROCHIP MAKES NO REPRESENTATION OR WARRANTIES OF        **
// **   ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO        **
// **   THE INFORMATION PROVIDED TO YOU, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY,           **
// **   PERFORMANCE, MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR PURPOSE.                         **
// **   MICROCHIP IS NOT LIABLE, UNDER ANY CIRCUMSTANCES, FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL      **
// **   DAMAGES, FOR ANY REASON WHATSOEVER.                                                             **
// **                                                                                                   **
// **   It is your responsibility to ensure that your application meets with your specifications.       **
// **                                                                                                   **
// *******************************************************************************************************
// **   Revision       : 1.4                                                                            **
// **   Modified Date  : 02/04/2009                                                                     **
// **   Revision History:                                                                               **
// **                                                                                                   **
// **   10/01/2003:  Initial design                                                                     **
// **   07/19/2004:  Fixed the timing checks and the open-drain modeling for SDA.                       **
// **   01/06/2006:  Changed the legal information in the header                                        **
// **   12/04/2006:  Corrected timing checks to reference proper clock edges                            **
// **                Added timing check for Tbuf (bus free time)                                        **
// **                Reduced memory blocks to single, monolithic array                                  **
// **   02/04/2009:  Added timing checks for tSU_WP and tHD_WP                                          **
// **                                                                                                   **
// *******************************************************************************************************
// **                                       TABLE OF CONTENTS                                           **
// *******************************************************************************************************
// **---------------------------------------------------------------------------------------------------**
// **   DECLARATIONS                                                                                    **
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// **   INITIALIZATION                                                                                  **
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// **   CORE LOGIC                                                                                      **
// **---------------------------------------------------------------------------------------------------**
// **   1.01:  START Bit Detection                                                                      **
// **   1.02:  STOP Bit Detection                                                                       **
// **   1.03:  Input Shift Register                                                                     **
// **   1.04:  Input Bit Counter                                                                        **
// **   1.05:  Control Byte Register                                                                    **
// **   1.06:  Byte Address Register                                                                    **
// **   1.07:  Write Data Buffer                                                                        **
// **   1.08:  Acknowledge Generator                                                                    **
// **   1.09:  Acknowledge Detect                                                                       **
// **   1.10:  Write Cycle Timer                                                                        **
// **   1.11:  Write Cycle Processor                                                                    **
// **   1.12:  Read Data Multiplexor                                                                    **
// **   1.13:  Read Data Processor                                                                      **
// **   1.14:  SDA Data I/O Buffer                                                                      **
// **                                                                                                   **
// **---------------------------------------------------------------------------------------------------**
// **   DEBUG LOGIC                                                                                     **
// **---------------------------------------------------------------------------------------------------**
// **   2.01:  Memory Data Bytes                                                                        **
// **   2.02:  Write Data Buffer                                                                        **
// **                                                                                                   **
// **---------------------------------------------------------------------------------------------------**
// **   TIMING CHECKS                                                                                   **
// **---------------------------------------------------------------------------------------------------**
// **                                                                                                   **
// *******************************************************************************************************


`timescale 1ns/10ps

module M24LC64 (A0, A1, A2, WP, SDA, SCL, RESET);

   input                A0;                             // chip select bit
   input                A1;                             // chip select bit
   input                A2;                             // chip select bit

   input                WP;                             // write protect pin

   inout                SDA;                            // serial data I/O
   input                SCL;                            // serial data clock

   input                RESET;                          // system reset


// *******************************************************************************************************
// **   DECLARATIONS                                                                                    **
// *******************************************************************************************************

   reg                  SDA_DO;                         // serial data - output
   reg                  SDA_OE;                         // serial data - output enable

   wire                 SDA_DriveEnable;                // serial data output enable
   reg                  SDA_DriveEnableDlyd;            // serial data output enable - delayed

   wire [02:00]         ChipAddress;                    // hardwired chip address

   reg  [03:00]         BitCounter;                     // serial bit counter

   reg                  START_Rcvd;                     // START bit received flag
   reg                  STOP_Rcvd;                      // STOP bit received flag
   reg                  CTRL_Rcvd;                      // control byte received flag
   reg                  ADHI_Rcvd;                      // byte address hi received flag
   reg                  ADLO_Rcvd;                      // byte address lo received flag
   reg                  MACK_Rcvd;                      // master acknowledge received flag

   reg                  WrCycle;                        // memory write cycle
   reg                  RdCycle;                        // memory read cycle

   reg  [07:00]         ShiftRegister;                  // input data shift register

   reg  [07:00]         ControlByte;                    // control byte register
   wire                 RdWrBit;                        // read/write control bit

   reg  [12:00]         StartAddress;                   // memory access starting address
   reg  [04:00]         PageAddress;                    // memory page address

   reg  [07:00]         WrDataByte [0:31];              // memory write data buffer
   wire [07:00]         RdDataByte;                     // memory read data

   reg  [15:00]         WrCounter;                      // write buffer counter

   reg  [04:00]         WrPointer;                      // write buffer pointer
   reg  [12:00]         RdPointer;                      // read address pointer

   reg                  WriteActive;                    // memory write cycle active

   reg  [07:00]         MemoryBlock [0:8191];           // EEPROM data memory array

   integer              LoopIndex;                      // iterative loop index

   integer              tAA;                            // timing parameter
   integer              tWC;                            // timing parameter


// *******************************************************************************************************
// **   INITIALIZATION                                                                                  **
// *******************************************************************************************************

//----------------------------
//------写数据间隔改动----------
   initial tAA = 900;                                   // SCL to SDA output delay
   initial tWC = 500;                                   // memory write cycle time

//   initial tAA = 900;                                   // SCL to SDA output delay
//   initial tWC = 5000000;                               // memory write cycle time
	
	
   initial begin
      SDA_DO = 0;
      SDA_OE = 0;
   end

   initial begin
      START_Rcvd = 0;
      STOP_Rcvd  = 0;
      CTRL_Rcvd  = 0;
      ADHI_Rcvd  = 0;
      ADLO_Rcvd  = 0;
      MACK_Rcvd  = 0;
   end

   initial begin
      BitCounter  = 0;
      ControlByte = 0;
   end

   initial begin
      WrCycle = 0;
      RdCycle = 0;

      WriteActive = 0;
   end

   assign ChipAddress = {A2,A1,A0};


// *******************************************************************************************************
// **   CORE LOGIC                                                                                      **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
//      1.01:  START Bit Detection
// -------------------------------------------------------------------------------------------------------

   always @(negedge SDA) begin
      if (SCL == 1) begin
         START_Rcvd <= 1;
         STOP_Rcvd  <= 0;
         CTRL_Rcvd  <= 0;
         ADHI_Rcvd  <= 0;
         ADLO_Rcvd  <= 0;
         MACK_Rcvd  <= 0;

         WrCycle <= #1 0;
         RdCycle <= #1 0;

         BitCounter <= 0;
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.02:  STOP Bit Detection
// -------------------------------------------------------------------------------------------------------

   always @(posedge SDA) begin
      if (SCL == 1) begin
         START_Rcvd <= 0;
         STOP_Rcvd  <= 1;
         CTRL_Rcvd  <= 0;
         ADHI_Rcvd  <= 0;
         ADLO_Rcvd  <= 0;
         MACK_Rcvd  <= 0;

         WrCycle <= #1 0;
         RdCycle <= #1 0;

         BitCounter <= 10;
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.03:  Input Shift Register
// -------------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      ShiftRegister[00] <= SDA;
      ShiftRegister[01] <= ShiftRegister[00];
      ShiftRegister[02] <= ShiftRegister[01];
      ShiftRegister[03] <= ShiftRegister[02];
      ShiftRegister[04] <= ShiftRegister[03];
      ShiftRegister[05] <= ShiftRegister[04];
      ShiftRegister[06] <= ShiftRegister[05];
      ShiftRegister[07] <= ShiftRegister[06];
   end

// -------------------------------------------------------------------------------------------------------
//      1.04:  Input Bit Counter
// -------------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      if (BitCounter < 10) BitCounter <= BitCounter + 1;
   end

// -------------------------------------------------------------------------------------------------------
//      1.05:  Control Byte Register
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (START_Rcvd & (BitCounter == 8)) begin
         if (!WriteActive & (ShiftRegister[07:01] == {4'b1010,ChipAddress[02:00]})) begin
            if (ShiftRegister[00] == 0) WrCycle <= 1;
            if (ShiftRegister[00] == 1) RdCycle <= 1;

            ControlByte <= ShiftRegister[07:00];

            CTRL_Rcvd <= 1;
         end

         START_Rcvd <= 0;
      end
   end

   assign RdWrBit = ControlByte[00];

// -------------------------------------------------------------------------------------------------------
//      1.06:  Byte Address Register
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (CTRL_Rcvd & (BitCounter == 8)) begin
         if (RdWrBit == 0) begin
            StartAddress[12:08] <= ShiftRegister[04:00];
            RdPointer[12:08]    <= ShiftRegister[04:00];

            ADHI_Rcvd <= 1;
         end

         WrCounter <= 0;
         WrPointer <= 0;

         CTRL_Rcvd <= 0;
      end
   end

   always @(negedge SCL) begin
      if (ADHI_Rcvd & (BitCounter == 8)) begin
         if (RdWrBit == 0) begin
            StartAddress[07:00] <= ShiftRegister[07:00];
            RdPointer[07:00]    <= ShiftRegister[07:00];

            ADLO_Rcvd <= 1;
         end

         WrCounter <= 0;
         WrPointer <= 0;

         ADHI_Rcvd <= 0;
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.07:  Write Data Buffer
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (ADLO_Rcvd & (BitCounter == 8)) begin
         if (RdWrBit == 0) begin
            WrDataByte[WrPointer] <= ShiftRegister[07:00];

            WrCounter <= WrCounter + 1;
            WrPointer <= WrPointer + 1;
         end
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.08:  Acknowledge Generator
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (!WriteActive) begin
         if (BitCounter == 8) begin
            if (WrCycle | (START_Rcvd & (ShiftRegister[07:01] == {4'b1010,ChipAddress[02:00]}))) begin
               SDA_DO <= 0;
               SDA_OE <= 1;
            end 
         end
         if (BitCounter == 9) begin
            BitCounter <= 0;

            if (!RdCycle) begin
               SDA_DO <= 0;
               SDA_OE <= 0;
            end
         end
      end
   end 

// -------------------------------------------------------------------------------------------------------
//      1.09:  Acknowledge Detect
// -------------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      if (RdCycle & (BitCounter == 8)) begin
         if ((SDA == 0) & (SDA_OE == 0)) MACK_Rcvd <= 1;
      end
   end

   always @(negedge SCL) MACK_Rcvd <= 0;

// -------------------------------------------------------------------------------------------------------
//      1.10:  Write Cycle Timer
// -------------------------------------------------------------------------------------------------------

   always @(posedge STOP_Rcvd) begin
      if (WrCycle & (WP == 0) & (WrCounter > 0)) begin
         WriteActive = 1;
         #(tWC);
         WriteActive = 0;
      end
   end

   always @(posedge STOP_Rcvd) begin
      #(1.0);
      STOP_Rcvd = 0;
   end

// -------------------------------------------------------------------------------------------------------
//      1.11:  Write Cycle Processor
// -------------------------------------------------------------------------------------------------------

   always @(negedge WriteActive) begin
      for (LoopIndex = 0; LoopIndex < WrCounter; LoopIndex = LoopIndex + 1) begin
         PageAddress = StartAddress[04:00] + LoopIndex;

         MemoryBlock[{StartAddress[12:05],PageAddress[04:00]}] = WrDataByte[LoopIndex[04:00]];
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.12:  Read Data Multiplexor
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (BitCounter == 8) begin
         if (WrCycle & ADLO_Rcvd) begin
            RdPointer <= StartAddress + WrPointer + 1;
         end
         if (RdCycle) begin
            RdPointer <= RdPointer + 1;
         end
      end
   end

   assign RdDataByte = MemoryBlock[RdPointer[12:00]];

// -------------------------------------------------------------------------------------------------------
//      1.13:  Read Data Processor
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (RdCycle) begin
         if (BitCounter == 8) begin
            SDA_DO <= 0;
            SDA_OE <= 0;
         end
         else if (BitCounter == 9) begin
            SDA_DO <= RdDataByte[07];

            if (MACK_Rcvd) SDA_OE <= 1;
         end
         else begin
            SDA_DO <= RdDataByte[7-BitCounter];
         end
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.14:  SDA Data I/O Buffer
// -------------------------------------------------------------------------------------------------------

   bufif1 (SDA, 1'b0, SDA_DriveEnableDlyd);

   assign SDA_DriveEnable = !SDA_DO & SDA_OE;
   always @(SDA_DriveEnable) SDA_DriveEnableDlyd <= #(tAA) SDA_DriveEnable;


// *******************************************************************************************************
// **   DEBUG LOGIC                                                                                     **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
//      2.01:  Memory Data Bytes
// -------------------------------------------------------------------------------------------------------

   wire [07:00] MemoryByte_000 = MemoryBlock[00];
   wire [07:00] MemoryByte_001 = MemoryBlock[01];
   wire [07:00] MemoryByte_002 = MemoryBlock[02];
   wire [07:00] MemoryByte_003 = MemoryBlock[03];
   wire [07:00] MemoryByte_004 = MemoryBlock[04];
   wire [07:00] MemoryByte_005 = MemoryBlock[05];
   wire [07:00] MemoryByte_006 = MemoryBlock[06];
   wire [07:00] MemoryByte_007 = MemoryBlock[07];
   wire [07:00] MemoryByte_008 = MemoryBlock[08];
   wire [07:00] MemoryByte_009 = MemoryBlock[09];
   wire [07:00] MemoryByte_00A = MemoryBlock[10];
   wire [07:00] MemoryByte_00B = MemoryBlock[11];
   wire [07:00] MemoryByte_00C = MemoryBlock[12];
   wire [07:00] MemoryByte_00D = MemoryBlock[13];
   wire [07:00] MemoryByte_00E = MemoryBlock[14];
   wire [07:00] MemoryByte_00F = MemoryBlock[15];

// -------------------------------------------------------------------------------------------------------
//      2.02:  Write Data Buffer
// -------------------------------------------------------------------------------------------------------

   wire [07:00] WriteData_00 = WrDataByte[00];
   wire [07:00] WriteData_01 = WrDataByte[01];
   wire [07:00] WriteData_02 = WrDataByte[02];
   wire [07:00] WriteData_03 = WrDataByte[03];
   wire [07:00] WriteData_04 = WrDataByte[04];
   wire [07:00] WriteData_05 = WrDataByte[05];
   wire [07:00] WriteData_06 = WrDataByte[06];
   wire [07:00] WriteData_07 = WrDataByte[07];
   wire [07:00] WriteData_08 = WrDataByte[08];
   wire [07:00] WriteData_09 = WrDataByte[09];
   wire [07:00] WriteData_0A = WrDataByte[10];
   wire [07:00] WriteData_0B = WrDataByte[11];
   wire [07:00] WriteData_0C = WrDataByte[12];
   wire [07:00] WriteData_0D = WrDataByte[13];
   wire [07:00] WriteData_0E = WrDataByte[14];
   wire [07:00] WriteData_0F = WrDataByte[15];

   wire [07:00] WriteData_10 = WrDataByte[16];
   wire [07:00] WriteData_11 = WrDataByte[17];
   wire [07:00] WriteData_12 = WrDataByte[18];
   wire [07:00] WriteData_13 = WrDataByte[19];
   wire [07:00] WriteData_14 = WrDataByte[20];
   wire [07:00] WriteData_15 = WrDataByte[21];
   wire [07:00] WriteData_16 = WrDataByte[22];
   wire [07:00] WriteData_17 = WrDataByte[23];
   wire [07:00] WriteData_18 = WrDataByte[24];
   wire [07:00] WriteData_19 = WrDataByte[25];
   wire [07:00] WriteData_1A = WrDataByte[26];
   wire [07:00] WriteData_1B = WrDataByte[27];
   wire [07:00] WriteData_1C = WrDataByte[28];
   wire [07:00] WriteData_1D = WrDataByte[29];
   wire [07:00] WriteData_1E = WrDataByte[30];
   wire [07:00] WriteData_1F = WrDataByte[31];


// *******************************************************************************************************
// **   TIMING CHECKS                                                                                   **
// *******************************************************************************************************

   wire TimingCheckEnable = (RESET == 0) & (SDA_OE == 0);
   wire StopTimingCheckEnable = TimingCheckEnable && SCL;
	
//--------------------------------
//-------仿真时时序约束需改动--------
//--------------------------------
   specify
      specparam
         tHI = 600,                                     // SCL pulse width - high
//         tLO = 1300,                                    // SCL pulse width - low
         tLO = 600, 
			tSU_STA = 600,                                 // SCL to SDA setup time
         tHD_STA = 600,                                 // SCL to SDA hold time
         tSU_DAT = 100,                                 // SDA to SCL setup time
         tSU_STO = 600,                                 // SCL to SDA setup time
         tSU_WP = 600,                                  // WP to SDA setup time
         tHD_WP = 1300,                                 // WP to SDA hold time
//         tBUF = 1300;                                   // Bus free time
         tBUF = 600; 
			
      $width (posedge SCL, tHI);
      $width (negedge SCL, tLO);

      $width (posedge SDA &&& SCL, tBUF);

      $setup (posedge SCL, negedge SDA &&& TimingCheckEnable, tSU_STA);
      $setup (SDA, posedge SCL &&& TimingCheckEnable, tSU_DAT);
      $setup (posedge SCL, posedge SDA &&& TimingCheckEnable, tSU_STO);
      $setup (WP, posedge SDA &&& StopTimingCheckEnable, tSU_WP);

      $hold  (negedge SDA &&& TimingCheckEnable, negedge SCL, tHD_STA);
      $hold  (posedge SDA &&& StopTimingCheckEnable, WP, tHD_WP);
   endspecify

endmodule

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值