【精品博文】IIC 通信协议的Verilog实现
刚刚花了几天时间把 IIC 总算搞懂了一些,查了很多资料,也纠结过于很多细节,不过只要耐着性子,一点点的去理解,去尝试,终会得到你想要的结果,人生不也是吗,嘿嘿~
,不闲扯了,下面就写写我的理解以及方法,算是一个总结~
------------------------------------------------------------------------------------------------------------------
IIC 即 Inter-Integrated Circuit (集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。(来源于百度百科)
采用 EEPROM 来验证 IIC 时序,我用的是AT24C02(原理图如下),IIC 时序有单字节写、单字节读,和页写、页读,这次先写单字节写和读,页写和读下次再写。
AT24C02 原理图
首先看一下各引脚定义:
1,A0、A1、A2为 AT24C02 的片选信号,由于 IIC 总线可以挂载多个
IIC 接口器件,所以每个器件都应该有自己的“身份标识” ,通过
对 A0,A1,A2输入不同的高低电平,就可以设置该 EEPROM 的片选
信号。
2,WP 为读写使能信号,当 WP 悬空或者接地,EEPROM 可读可
写,当 WP 接电源,EEPROM 只能读不能写。
3, SCL 为 IIC 接口的时钟线。
4, SDA 为 IIC 接口的数据线。
所以由原理图可以知道,IIC 协议有两条线,一条时钟线SCL,一条双向的数据线SDA,
下面来看一下 IIC 协议的时序图:
写时序:
由时序图可以看出,如果我们要向 EEPROM 写入一个字节,那么必须经过以下步骤:
1. 发送启动信号
2. 发送器件地址 8'b1010_0000
3. 接收并检测 EEPROM 发来的应答信号 ACK
4. 发送字地址
5. 接收并检测 EEPROM 发来的应答信号 ACK
6. 发送 8bit 有效数据
7. 接收并检测 EEPROM 发来的应答信号 ACK
8. 发送停止信号
读时序:
由时序图可以看出,如果我们要从 EEPROM 读出一个字节,那么必须经过以下步骤:
1. 发送启动信号
2. 发送器件地址 8'b1010_0000
3. 接收并检测 EEPROM 发来的应答信号 ACK
4. 发送字地址
5. 接收并检测 EEPROM 发来的应答信号 ACK
6. 发送启动信号
7. 发送器件地址 8'b1010_0001
8. 接收并检测 EEPROM 发来的应答信号 ACK
9. 读取一个字节数据
10. 发送非应答信号 NO ACK
11. 发送停止信号
* 说明及注意事项:
(1) 时钟线 SCL:在3.6V以内的系统中,EEPROM 兼容400kHZ 的通信速率,我用的是100kHZ;
(2) 数据线 SDA:SDA 实现双向串行数据传输,该引脚为开漏输出,可与其它多个开漏输出器件或开集电极器件线或连接;
(3) 启动信号和停止信号:在时钟 SCL 的高电平期间对 SDA 拉低或拉高操作,就分别表示启动和停止;
(4) 器件地址: 器件地址有八位,高四位为 1010,低四位中,第 3~1 位为 A2,A1,A0 这 3 位跟实际电路中的硬件有关,AT24C02 芯片中有 A2,A1,A0 这 3 个引脚,所以这 3 位按照实际的原理图来给的。在实际原理图中我们直接把这 3 个引脚接地,所以第 3~1 位为 0,接下来就是第 0 位,第 0 位是 R/W,第 0 位为 1 表示是读操作,第 0 位为 0 表示为写操作。所以写为: 8’b1010_000读 为: 8’b1010_0001;
(5) 字地址:AT24C02 内部存储空间为 256*8 bit,所以地址位有八位;
(6) 应答信号:应答信号是由接收方发出的,传输完一个字节数据后,主机释放 SDA 控制权, 在 SCL 为高电平期间,如果监测到 SDA 为低电平,说明有应答信号;
(7) 非应答信号:非应答信号是在读完数据后由主机(FPGA)发出的,当 SCL 为高电平期间,如果 SDA 为高电平,说明有非应答信号;
(8) 字节发送:IIC 协议必须要主机取的数据线 SDA 的控制权后,在时钟 SCL 低电平期间一个字节一个字节的传输,高电平期间保持稳定,且先传输最高位(MSB),每一个字节后面都要有一个应答信号(应答信号是由从机发送的,所以需要先释放数据线 SDA 的控制权)
(9) 字节读取:读取数据的时候主机先要释放数据线 SDA 的控制权,读的时候在时钟 SCL 的高电平期间采样读取,读完后再取得数据线 SDA 的控制权,然后拉高 SDA,即发送非应答信号;
(10)数据线 SDA 在 FPGA 为接收方时,要设置为高阻态;
(11)关于控制权:谁发送,谁就先获得控制权;
* 结合写和读时序,发现1~5步骤是一样的,所以可以这样设置 IIC 读写控制器:
* 代码完成后综合得到的RTL视图如下:
可以根据此模块图进行设计,通过两个按键控制 ill_wr_ctrl (协议读写控制模块),先将数据写入EEPROM,再将读出来的数据给到数码管显示模块,以此验证协议的正确性
* 这里我主要写一下协议读写控制模块(ill_wr_ctrl),通过仿真来验证
一定要注意在发送数据前,先打开总线开关,即取得总线控制权,数据发送完毕后关闭总线开关,即释放总线控制权,然后再检测应答信号;读数据的时候要先释放总线控制权,读完后取得总线控制权,拉高SDA,即发送非应答信号,最后在SCL高电平期间拉低SDA,即发送停止信号。
* 测试代码如下:
仿真的时候由于没有EEPROM返回的应答信号,所以可以在源代码上做一点修改,如下所示,略过检测应答信号,直接跳转状态即可
* 仿真图如下:
写时序:
读时序:
说明:蓝线部分为总线释放了控制权之后,所以处于高阻态;数据的改变、数据总线的放开都是在 SCL 低电平的
中间位置实现的。
* IIC 协议的时序非常严密,所以对我们学习时序的实现技巧和方法有很大的帮助,写这篇博客花费了很长时间,一方面,这是我写的第二篇技术博客,不是特别熟练,所以难免会出现一些错误或者不完善的地方,如有发现,还请劳烦留言指正,必定会及时改正,另一方面,虽然花费了很长时间,但是对于此次设计的理解较为深刻,所以欢迎有共同兴趣的朋友留言探讨,一起学习,共同进步!
* 技术只有多交流才能有更大的进步~
* 欢迎留言探讨~