FPGA实现iic通信(读写EEPROM)
实验平台:正点原子ALIENTEK开拓者FPGA开发板
目录
- FPGA实现iic通信(读写EEPROM)
-
- 1. IIC协议简介
-
- 1.1 什么是IIC协议
- 1.2 硬件结构
- 1.3 为什么要使用IIC协议
- 1.4 IIC协议的时序特点
-
- 1.4.1 传输特点
- 1.4.2 时序特点
- 1.4.3 完整时序
- 2. IIC协议实践
-
- 2.1 设计思想
- 2.2 RTL代码重要部分
- 2.3 开发过程遇到的问题
- 3. 代码下载
1. IIC协议简介
1.1 什么是IIC协议
IIC即为Inter-Inegrated Circuit(集成电路总线),在上世纪八十年代左右由Philips公司(即现做的NXP半导体公司)设计出来的一种简单、双向、二进制总线标准。其只需要两根线(SDA数据线和SCL时钟线)即可实现总线连接的器件间的通信。SDA和SCL都是双向I/O线,所以主要适用于数据量小,距离短的主从通信,数据的传输速率在标准模式下可达100kbit/s,在快速模式下可达400kbit/s,在高速模式下可达3.4Mbit/s。
当两个器件通信时,用于启动总线并产生时钟的为主器件,此时总线上所有可被寻址的都为从器件。所有的从器件都有其第一无二的设备地址,主机发送想要通信的从机的设备地址,所有的从器件将此地址与自身的设备地址对照,对应的从器件则发出应答信号,二者即开始通信。这也意味着主机与从机不是固定的,而是取决于数据的传输方向。
1.2 硬件结构
SDA(串行数据线)和SCL(串行时钟线)都是双向I/O线,接口电路为开漏输出,需通过上拉电阻接电源VCC,因此当总线空闲时两根线都是高电平。
1.3 为什么要使用IIC协议
通过上文可知IIC可以挂载多个设备,这也是其最大的优点。在工业中有时我们并不需要读出所有设备的数据,这时就可以使用IIC总线,将多个传感器挂载在其上,只需要在需要的时候读出对应设备的数据。虽然其与其他的串行外设接口相比,通信速度较慢,但是其大大节约了I/O资源;而且在传输过程中可以通过应答位来判断是否成功通信;这些优点导致IIC大面积应用。
1.4 IIC协议的时序特点
1.4.1 传输特点
由于IIC是由数据线和时钟线所组成的,因此二者相互配合完成数据的传输。当时钟线(SCL)为高电平时要求数据线(SDA)的数据稳定,此时从机开始接收主机数据或者主机接收从机的应答;当时钟线(SCL)为低电平时数据线(SDA)的数据可变化,即更新数据以备下一次的接收。
1.4.2 时序特点
IIC传输主要由开始信号、停止信号、应答/非应答、读、写信号五部分组成:
开始信号
当时钟线(SCL)为高电平期间,数据线(SDA)由高电平变为低电平即为起始信号,时序图如下图所示:
终止信号
当时钟线(SCL)为高电平期间数据线(SDA)由低电平变为高电平即为终止信号,时序图如下图所示:
应答/非应答
应答信号与非应答都由接收方发出(需要注意在读数据时,主机为接收方,因此要由主机发送应答/非应答信号),在时钟线(SCL)为高电平期间,检测数据线(SDA)的值,如果数据线(SDA)为低电平则为应答信号,数据线(SDA)为高电平则为非应答信号。
读数据
读数据的时序与应答/非应答的相同,都是在时钟线(SCL)为高电平期间读取数据线(SDA)的值,数据线(SDA)的高低电平即代表“1”或“0”,读数据的时序如下图所示:![在这里插入图片描述](https://img-blog.csdnimg.cn/20210308164815695.png #pic_center =750x)
写数据
通过上面的分析可知,从机在时钟线(SCL)高电平期间读取数据线(SDA)的数据,因此写数据时需要在时钟线(SCL)低电平期间改变数据线(SDA)的值来传输数据,时序图如下:
1.4.3 完整时序
IIC写时序
IIC写时序变化
IIC读时序
2. IIC协议实践
2.1 设计思想
通过对读写过程分析可知,无论是读或者写过程都由开始信号、发送设备地址(最后一位读或者写)、发送存储单元地址、发送数据/读数据、结束几部分组成。因此用状态机来完成此代码。
在此我将读写操作写在了一个驱动文件里,是考虑到如果读写分别写在两个文件里的话,在例化时对inout端口的例化会有困难(因为其还需要一个控制信号),因此我写在了一个文件里,由一个读写控制信号来判断是执行读操作还是写操作;在此次设计中我将开始信号放在了发送设备地址里,以便减少状态。
2.2 RTL代码重要部分
驱动时钟
由于IIC需要满足不同的通信速率,因此在此将其设置为参数,为了在时钟线(SCL)的不同时刻对数据线(SDA)进行处理,因此将其进行四分频,这样驱动时钟的4个周期就是时钟线(SCL)的一个周期。
parameter CLK_FREQ = 26'd50_000_000, //模块输入的时钟频率
parameter I2C_FREQ = 18'd250_000 //IIC_SCL的时钟频率
assign clk_divide = (CLK_FREQ/I2C_FREQ) >> 2'd2;
时钟计数器
由于驱动时钟是与时钟线(SCL)相互对应的,因此驱动一个计数器来作为其他信号的判断依据。由于不同的状态持续的时间不同,因此将计数器的自加放在状态机的case语句中,这样不同状态可直接判断计数器来判断其他信号的状态。
数据线(SDA)数据的变化
通过驱动时钟来驱动一个计数器,由于驱动时钟的四个周期对应时钟线(SCL)的一个周期,因此通过计数器的数值即可判断时钟线(SCL)是处于什么位置,并根据此来判断时钟线(SCL)的上升沿和下降沿。
inout端口输入输出方向变化
在状态机内部通过计数器来判断时钟线(SCL)的不同状态,当其计数到相应时刻时将控制inout端口的 信号更新到对应的状态。
2.3 开发过程遇到的问题
从机无应答
在测试过程中出现了从机应答错误的情况,用SignalTap抓取波形图发现起始信号并没有问题,通过上网查询发现EEPROM在写之间需要时间间隔,由于不知道需要等待多长时间,因此在状态机中持续等待应答,等到应答正确后再状态跳转。
应答正常但读出数据不对
更改后发现读写时序都正确,应答也正确但是读出的数据不正确,通过查询资料怀疑是EEPROM出问题,所以将设备断电使EEPROM进行上电,上电后恢复正常。
时钟问题
将IIC和串口模块相连接,实现数据的回环,将IIC模块的完成信号作为串口的发送使能信号,由于IIC的完成信号保持的时钟是远远长于一个时钟的,因此会造成串口持续发送。所以在IIC模块中加了一个边沿检测程序,将电平信号变为脉冲信号后再将其输出。
3. 代码下载
链接: IIC通信源码.