基于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
                s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值