关于IIC通信用一个具体实例来进行说明(含设计代码)
几个重要的信号
空闲状态:SDA,SCL均处于高电平状态。
起始信号:SCL为高电平时SDA由高到低跳变
停止信号:SCL为高电平时SDA由低到高跳变
数据有效性:在SCL为高期间,SDA信号必须保持稳定不能发生变化,只有在SCL为低电平时SDA信号才能发生变化。
应答信号ACK:要求在发送或者接受时候每第8个周期下降沿后的低低电平将SDA释放同时拉低SDA,在SCL在第9个时钟周期高电平时SDA为低电平说明主机或者从机接受到数据,为高说明未接受或者不想接受了。
下面以EEPROM为例型号为AT24C64A这是一个存储容量为65536bit的存储芯片,地址为8192个地址位是13位,每位一个字节。
共有8个引脚其中在控制器设计时候只需要操控SDA和SCL这两根线,A0-A2是它的地址位低三位,可以扩展8片,高四位是固定的为:1010。WP是写保护位,此位置高则写无效。
时序参数如图:
总线时序图:
SDA在SCL为低的时候才可以变化,且在SCL为高时禁止变化。在eeprom工作之前SCL和SDA必须为高,当SDA由高到底后才标志着器件可以工作,而结束位是在SCL为高时SDA由低变高。在传入地址或者数据时接收方在地址或者数据接收到后必须发送应答位,应答位为低,如果是高说明没有正确接收或者不想接受了。我一开始不解为什么在从机发送数据时主机释放总线SDA,那接收的数据由谁判断呢?最后才明白,这个“释放”是从主机给输出一端的信号是高阻态,这时sda_out并不输出到sda总线,sda_en让sda为高阻了,这个高阻一般是OC门或者集电极开路状态。这时总线的状态就不由sda_out来控制了,此时eeprom是发送设备,而控制器也就是FPGA这时是接收器,可以接收此时sda上的电平高低来判断是ACK(低)还是NO ACK(高),由sda_in接收。可见数电(模电)学好很有必要,阎石老师的数字电路基础第五版的第三章有详细讲OC门和各种CMOS组成的基本电路。
系统框架:
状态转移图
在设计中代码已经给了比较详细的注释,其中分频时钟为了仿真分析方便没有按照芯片要求的范围进行设计,如有需要可以自行修改。注意下面这种scl时钟一定是像I2C这种在低速(不是I2C传输模式中的低速,而是I2C所有模式相对来说都是低速)传输的条件下才能以这种形式产生!
/*--------------------------------------------
description: AT24C64 65532bit/32byte x 256
addr:0 —— 8192 13bit
one page 32byte
---------------------------------------------*/
module iic_driver(
input sclk,//系统时钟50MHz
input rst_n,//复位信号低有效
input dri_en,//驱动器使能信号
input wr,//读写信号
input [15:0] addr,//输入的地址
input [7:0] w_data,//写入的数据
output reg [7:0] rd_data,//读出的数据
output i2c_done,//完成标志
output scl_o,//输出的时钟
inout sda//总线
);
reg [15:0] addr_r; //输入地址寄存器,用于并转串
reg [7:0] w_data_r; //写数据寄存器
reg st_done; //一次操作完标志
reg d_clk; //驱动器的时钟
reg wr_flag; //读写标志,低表示写,高表示读
reg sda_en; //控制总线的三态输出
reg [6:0] cnt; //每一个状态进度计数
reg [9:0] clk_cnt; //分频计数
reg sda_out; //总线数据输出:控制器到eeprom
reg [3:0] state; //状态
reg [7:0] rd_data_r; //读取数据寄存器
reg scl; //用于生成eep