I2C通信模块的设计和“AT24C64 型号的EEPROM 芯片通信”实践

# 期望通过本文掌握I2C模块的FPGA和软件设计和实践 #

1 I2C(InterIntegrated Circuit)通信协议及FPGA模块设计

I2C 是很常见的一种总线协议,使用两条线在主控制器和从机之间进行数据通信。一 条是 SCL( 串行时钟线 ) ,另外一条是 SDA( 串行数据线 ) 。这两条线都需要接上拉电 阻。因为仅有一根数据线,所以I2C 通信是半双工的。
I2C 总线有标准模式 (100kb/s) 和快速模式 (400kb/s) 两种。“总线 指多个设备共用的信号线。在一个 I2C 总线中,支持多个从设备。不同的从设备有不同的器件地址,这样 I2C 主控制器就可以通过 I2C 设备的器件地址访问指定的I2C 设备了,一个 I2C 总线连接多个 I2C 设备,如下所示,
I2C 协议基本术语
起始信号: I2C 通信起始标志。主机告诉从机,要开始进行 I2C 通信了。在SCL 为高电平期间, SDA 出现下降沿就表示产生起始信号。起始信号产生后总线处于占用状态。
停止信号: I2C 停止通信的标志。在 SCL 为高电平期间, SDA 出现上升沿就表
示为停止信号。停止信号产生后总线被释放,处于空闲状态。
数据传输: I2C 总线在进行数据传输时要保证在 SCL 高电平期间, SDA 上的数据稳定,因此 SDA 上的数据变化只能在 SCL 低电平期间发生。数据传送时,先传送最高位,后传送低位。
应答信号:当 I2C 主机发送完 8bit 数据后会将 SDA 设置为输入状态,等待 I2C从机应答,也就是等到 I2C 从机告诉主机它接收到 8bit 数据了。
应答信号是由从机发出的,主机需要提供应答信号所需的时钟。主机发送完数据以后的下一个时钟信号就是给应答信号使用的。从机通过将 SDA 拉低来表示发出应答信号(ACK ,低有效 ) ,表示通信成功,否则表示通信失败 (NACK)
设计一个 I2C 模块,要求如下所示,
        支持总线仲裁丢失检测;
        支持总线忙状态检测;
        支持不同的 I2C 通信模式:
                标准模式(100kHz);        
                快速模式(400kHz);
        支持产生起始、终止、重复起始和应答信息;
        支持起始、终止和重复起始检测;
        支持 7 位寻址模式;
        支持中断;
主要包括 8 8 位宽的寄存器,如下所示
        I2C 分频值低字节寄存器
        I2C 分频值高字节寄存器
        I2C 控制寄存器
        I2C 发送数据寄存器
        I2C 接受数据寄存器 I2C 命令寄存器
        I2C 状态寄存器
        I2C 总线死锁时间寄存器
根据 I2C 协议,我们需要设计一个状态机,对应 I2C 的通信过程,各个状态如下所
示,
根据 I2C 寄存器的配置以及状态完成标志进行上述状态的切换,如下所示 ( 仅展示部
分代码 )
每个状态都需要持续多个周期,所以针对每个状态细分了几个子状态,如下所示,
I2C 2 个外部接口,分别是 I2C_SCL I2C_SDA 。对于 I2C_SCL ,这里我们只设计 I2C 主模式,所以对于 FPGA 来说, I2C_SCL 始终是输出。对于 I2C_SDA ,在主模式下,在接收响应的状态下是输入,其他情况下为输出。为了便于接口管理,我们将 I2C_SCL I2C_SDA 都设计为 IOBUF 。如下所示,
主机读写数据的时序操作如下所示,
主机写数据
1. 主机操作命令寄存器,使能开始命令,使 I2C 总线发送开始信号。
2. 主机操作发送数据寄存器,写入从机地址 + 读写位,决定访问哪个从机。这是
        一个8 位的数据,其中高 7 位是从机地址,最后 1 位是读写位。 1 表示读操作,
        0 表示写操作(对主机而言)。这里读写位为 0
3. 主机操作命令寄存器,使能写命令,使 I2C 总线开始传输数据。
4. 主机读取状态寄存器的 TIP 位,以确保命令执行完毕。
5. 主机操作发送数据寄存器,写入从机存储地址,决定待发送数据存储在从机哪
    里。
6. 主机操作命令寄存器,使能写命令,使 I2C 总线开始传输数据。
7. 主机读取状态寄存器的 TIP 位,以确保命令执行完毕。
8. 主机操作发送数据寄存器,写入 8 bit 的待发送数据。
9. 主机操作命令寄存器,使能写命令,使 I2C 总线开始传输数据。
10. 主机读取状态寄存器的 TIP 位,以确保命令执行完毕。
11. 重复步骤 8 10 ,不断向从机写数据;
12. 主机操作命令寄存器,使能结束命令,使 I2C 总线结束传输数据。
13. 每次传输结束后需要延时,保证下次能正常开始传输。
主机读数据
1. 主机操作命令寄存器,使能开始命令,使 I2C 总线发送开始信号。
2. 主机操作发送数据寄存器,写入从机地址 + 读写位,决定访问哪个从机。这是一个8 位的数据,其中高 7 位是从机地址,最后 1 位是读写位。 1 表示读操作,
        0 表示写操作(对主机而言)。这里读写位为 0
        3. 主机操作命令寄存器,使能写命令,使 I2C 总线开始传输数据。
4. 主机读取状态寄存器的 TIP 位,以确保命令执行完毕。
5. 主机操作发送数据寄存器,写入从机存储地址,主机将会从该地址读取数据。
6. 主机操作命令寄存器,使能写命令,使 I2C 总线开始传输数据。
7. 主机读取状态寄存器的 TIP 位,以确保命令执行完毕。
8. 主机操作命令寄存器,使能开始命令(这种情况是重复起始),使 I2C 总线发送开始信号。
9. 主机操作发送数据寄存器,写入从机地址 + 读写位。这里读写位为 1
10. 主机操作命令寄存器,使能写命令,使 I2C 总线开始传输数据。
11. 主机读取状态寄存器的 TIP 位,以确保命令执行完毕。 12. 主机操作命令寄存器,使能读命令和应答命令,使 I2C 总线开始接收数据。
13. 主机操作接收数据寄存器,读取接收到的 8 bit 的数据。
14. 重复步骤 12 13 ,不断从从机读数据;
15. 当主机需要停止从从机读数据时,操作命令寄存器,使能读命令,但不使能应答命令,读取最后一个字节的数据。
我们可以将 I2C 模块作为一个 APB 外设,挂在 APB 总线上。那么就需要设计一个APB 接口来对寄存器进行读写操作。我们需要对每个 APB 接口分配一个地址,这样才能通过译码电路区分开来不同的 APB 。在 config.h 文件中定了 9 APB 地址,默认使用 APB0 作为 GPIO ,现在我们为 I2C 模块分配 APB5 ,对应地址为
0xbfe90000 ,如下所示
最后实现的结构框图如下所示,
在顶层文件 godson_mcu_top.v 中例化我们设计的模块,如下所示,
在约束文件中,将例化好的 I2C 的输出引脚与原理图上的合适引脚进行连接即可,如
下所示,

2. 软件设计,基于软 I2C 模块与模 AT24C64型号的EEPROM芯片通信

既然已经设计好了硬件电路,我们就可以进行软件程序的编写了。在硬件 I2C 模块设
计过程中我们为 APB 分配的地址是 0xbfe90000 ,并且 I2C 相关寄存器的偏移地址
0x00 0x01 0x02 0x03 0x04 ,所以软件上需要对应好。一个不错的方法是用结构体
指针来访问寄存器。由于这个结构体指针使用频率很高,所以通过宏定义进行重命名
(I2C) ,如下所示,
编写的函数声明如下所示,
然后可以基于 I2C 相函数编写 I2C 读写 AT24C64 的函数,如下所示,
/****************************************************************
* 函数名: AT24CXX_WriteByte
* 功 能:写一个字节
* 参 数: u16Addr 要写入的地址
u8Data 要写入的数据 * 返回值:无
* 说 明:无
****************************************************************/
/****************************************************************
* 函数名: x24Cxx_ReadByte
* 功 能:读一个字节
* 参 数: u16Addr 要读取的地址
* 返回值: u8Data 读出的数据
* 说 明:无
****************************************************************/
这里需要注意的是,对芯片完成单字节写入或者页面写入命令后需要延时 10ms 。因为设备在此期间将不会对新的命令作出响应。延时之后再进行读命令才可以读到刚写入的数据。
我们可以在 main.c 中调用相应函数验证 I2C 通信,如下所示,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值