08-Verilog学习-S_I2C总线协议

IIC协议

首先是比较好的博客与资料:

  1. https://www.cnblogs.com/xiaomeige/p/6509414.html
  2. https://www.cnblogs.com/microxiami/p/8527464.html
  3. I2C总线协议(中文版).pdf
    https://download.csdn.net/download/weixin_43499278/12275402
  4. I2C协议的实现(判断SCL).pdf
    https://download.csdn.net/download/weixin_43499278/12275402
  5. 夏宇闻《Verilog数字系统设计教程》——第16章

本次实践是I2C总线协议的硬件实现,其中本次实践只能用于<I2C单字节的读写功能,不支持主机仲裁>,这些功能可以后续加入。本次实践I2C总线设计可具体分为以下部分(下述按此框架讲述):

  • 产生SCL
  • 构建输入/输出性SDA
  • 确定I2C总线协议的基础状态,以设计状态机跳转方式
  • 编写I2C单字节读/写状态机,以控制SDA产生相应时序

其核心思想:利用状态机的跳转来控制SDA、SCL产生符合I2C协议的时序,属于时序电路控制组合电路输出。

1、产生SCL

从参考资料2中,可知I2C总线工作的速度分为标准模式(100kbit/s)、快速模式(400kbit/s),因此SCL的速度受到限制。本次实践中,我采用了比I2C工作速度高2倍的时钟作为时钟输入,并且经过时钟二分频后,即可得到满足要求的SCL,具体实现如下(相当于时钟分频器):

/*产生SCL时钟:二分频*/

//下降沿时钟跳转:SCL中点检测SDA的电平
always@(negedge clk or negedge rst_n)
begin
	if(!rst_n)
		SCL <= 1;
	else
		SCL <= ~SCL;
end

重点: 采用clk下降沿进行时钟分频,由此后面模块使用clk上升沿判断时,可达到在SCL电平中点检测SDA的电平状态。

2.构建输入/输出性SDA

SDA是一个可输入/输出类型引脚,因此使用三态门的结构进行构建,同时硬件外部是将SDA线上拉的,所以具体实现方式如下:

/*组合逻辑控制产生电路*/
assign SDA = (Link_SDA)? SDA_reg:1'bz;

3.确定IIC总线协议的基础状态,设计状态机跳转方式

由参考资料1,可以得到I2C总线协议的基础状态为:起始信号、传输数据(控制字节/数据字节)、应答、停止信号。

以下是I2C单字节的读写操作顺序:

  • I2C写操作:

    起始信号->传输写控制字节->从机应答->传输数据字节->从机应答->停止信号

  • I2C读操作:

    起始信号->传输写控制字节->从机应答->传输器件存储字节->从机应答->起始信号->传输读控制字节->读数据->主机非应答->停止信号

由以上的读写顺序,结合I2C总线协议的基础状态,可得到如下的状态机跳转图:
在这里插入图片描述
其中ack状态内包含了判断I2C总线协议读/写的跳转,为此状态机的要点。

4.编写IIC单字节读/写状态机,以控制SDA产生相应时序

此处的状态机,采用三段式状态机书写。其中重点是:

  1. 在trans_data状态中,判断读写,并将wr_flag/rd_flag赋值,用于ack状态内的判断和状态机的跳转判断。
  2. 应I2C的时序要求,在例如起始信号后必须传数据等,代码注释中有标注。
  3. 写/读数据都只能在SCL为低电平时,才能够变化。
  4. 使用任务task完成起始信号、串转并、并转串、停止信号。注意:使用task时须将从状态机复位。

<task中串转并、并转串不懂得可以参考我之前的博客>

具体硬件代码如下:

module I2C_Timing(
	input clk,		//时钟、复位
	input rst_n,
	
	input I2C_en,	//I2C使能
	
	input wr_en,	//写使能
	input rd_en,	//读使能
	
	inout SDA,
	output reg SCL,
	
	input  [7:0] ctrl_in,		//I2C控制字节输入
	input  [7:0] data_in,		//I2C数据字节输入
	output reg   done,			//测试信号输出
	output reg [7:0] data_out	//I2C数据输出
);

/*信号及寄存器定义*/
reg Link_SDA;				//Link_SDA=1时,SDA为输出;Link_SDA=0时,SDA为输入

reg SDA_reg;				//I2C的SDA输出寄存器

reg Finish;					//从状态机完成标志位

reg wr_falg;				//写标志位

reg [1:0]rd_falg;			//读标志位

reg [7:0] write_buf;		//数据写入缓冲寄存器

reg [7:0] read_buf;			//数据读出缓冲寄存器

reg [4:0] current_state;	//主状态机当前状态寄存器

reg [4:0] 
  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值