当前位置:   article > 正文

通过FPGA实现I2C_fpga i2c

fpga i2c

特别说明:以下所涉及代码参考网络、相关开发板厂家。只用于自己学习、理解和感悟。
I2C总线是由Philips公司开发的一种简单、双向二进制串行总线。只需要两根线即可在连接于总线上的器件之间信息传递。
I2C的标准速率为100kbit/s,快速模式时速率为400kbit/s,支持多机通讯,支持多主控模块,但同一时刻只允许有一个主控。由数据线SDA和时钟线SCL构成串行总线。每个电路和模块都有唯一的地址。
以下以AT24C04为例说明I2C的基本读写操作,I2C设备的操作可分为读写单个存储字节和多个存储字节。读写时序示意图如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图所示,I2C通信分为空闲状态、开始态、信息传输态、停止态。传输信息分为:设备地址、读写标志、应答信号、存储地址、数据。
空闲态:
SDA和SCL同时处于高电平(硬件电路中一般SDA和SCL线通过电阻上拉),进行总线释放。
开始态:
开始态时,SDA和SCL处于高电平状,当数据线SDA由高电平跳变到低电平后进入开始态。开始态代表一次数据传输的开始。
信息传输态:
I2C总线上,每一位数据都与一个时钟脉冲对应,即在每个数据位在相对应的时钟沿进行串行传送。在I2C总线上,时钟的高电平时,数据线上的数据保持稳定;时钟的低电平时,才允许电平改变状态。 数据信息传输过程中伴随着应答信号的发生。应答分位ACK和NACK。I2C总线上的数据都是以8位字节传送的。发送器每发送一个字节后,在第9个时钟脉冲期间释放数据线,同时等待接收器所反馈的应答信号。如果应答信号为低电平时,表示为有效应答(ACK);否则为无效应答(NACK)。无应答表示接收失败。如果主控制器在接收到最后一个字节后,发送一个NACK信号通知从设备结束数据发送,并释放SDA线,以便主设备发送一个停止信号。
停止态:
在时钟线保持高电平期间,数据线返回高电平即数据线被释放,称为I2C总线上的停止信号。接收到停止信号后I2C总线进入空闲状态。
读写时序如下所示:
1、写时序:
在这里插入图片描述
2、读时序:
在这里插入图片描述
FPGA中,代码结构如下所示:
在这里插入图片描述

代码如下:
1、timescale.v代码

`timescale 1ns / 10ps
  • 1

2、i2c_master_defines.v代码

`define I2C_CMD_NOP     4'b0000

`define I2C_CMD_START   4'b0001

`define I2C_CMD_STOP    4'b0010

`define I2C_CMD_WRITE   4'b0100

`define I2C_CMD_READ    4'b1000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3、i2c_master_bit_ctrl.v代码

`include "timescale.v"

`include "i2c_master_defines.v"
//位控制部分
//发送简单命令到SCL/SDA转换器
//每个命令有5个状态,A/B/C/D/idle。
module i2c_master_bit_ctrl(
 input   clk,        //系统时钟
 input   rst,        //同步使能高复位
 input   nReset,     //异步使能低复位
 input   ena,        //内核使能信号

 input[15:0] clk_cnt,    //时钟预分频值
	input[3:0]   cmd,       //从控制器来的命令
	output reg  cmd_ack,    //应答命令
	output reg  busy,       //i2c总线忙
	output reg  a1,         //i2c总线仲裁丢失

	input   din,            //数据输入
	output  reg dout,       //数据输出

 input   scl_i,          //i2c时钟线输入
	output  scl_o,          //i2c时钟线输出
	output  reg scl_oen,    //i2c时钟线输出使能(低使能)
	input   sda_i,          //i2c数据线输入
	output  sda_o,          //i2c数据线输出
	output  reg sda_oen     //i2c数据线输出使能(第使能)
);
reg[1:0]    cSCL,cSDA;      //采集SCL,SDA
reg[2:0]    fSCL,fSDA;      //SCL,SDA滤波器输入
reg     sSCL,sSDA;          //滤波和同步后的SCL,SDA输入
reg     dSCL,dSDA;          //延时变化后的dSCL,dSDA
reg     dscl_oen;           //延时变化后的时钟使能信号
reg     sda_chk;            //检查SDA输出(多主机仲裁)
reg     clk_en;             //时钟产生信号
reg     slave_wait;         //从设备就绪等待
reg[15:0]   cnt;            //时钟分频计数器(同步)
reg[13:0]   filter_cnt;     //滤波器时钟分频
//状态机变量
reg [17:0]  c_state;        //逻辑综合枚举状态
//在从设备没有准备好的时候,通过拉低SCL来达到延时的目的
//延时使能SCL
always @(posedge clk)
	dscl_oen <= #1 scl_oen;
// slave_wait is asserted when master wants to drive SCL high, 
//but the slave pulls it low 
// slave_wait remains asserted until the slave releases SCL
always @(posedge clk or negedge nReset)
 if(!nReset) slave_wait <= 1'b0;
	else        slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) 
| (slave_wait & ~sSCL); 
//主设备SCL为高,但另一个主设备为低
//主设备开始倒计时(进行时钟同步)
wire    scl_sync = dSCL & ~sSCL & scl_oen;
//产生时钟使能信号  
always @(posedge clk or negedge nReset)
 if(~nReset)
   	 begin
       	 	cnt <= #1 16'h0;
       	 	clk_en <= 1'b1;
    	end
	else if(rst || ~|cnt || !ena || scl_sync)
    	begin
        	cnt <= #1 clk_cnt;
        	clk_en <= #1 1'b1;
    	end
	else if(slave_wait)
    	begin
        	cnt <= #1 cnt;
        	clk_en <= #1 1'b0;
    	end
	else
    	begin
        	cnt <= #1 cnt - 16'h1;
        	clk_en <= #1 1'b0;
    	end
//信号采集 
//降低亚稳态风险 
always @(posedge clk or negedge nReset)
 if(!nReset)
   		 begin
        		cSCL <= #1 2'b00;
       		 cSDA <= #1 2'b00;
   		 end 
	else if(rst)
    begin
        cSCL <= #1 2'b00;
        cSDA <= #1 2'b00;
    end
else
    begin
        cSCL <= {cSCL[0],scl_i};
        cSDA <= {cSDA[0],sda_i};
    end
//滤波SCL和SDA信号,(尝试)排除故障
always @(posedge clk or negedge nReset)
	 if(!nReset) filter_cnt <= 14'h0;
	else if(rst||!ena)  filter_cnt <= 14'h0;
	else if(~|filter_cnt) filter_cnt <= clk_cnt >> 2;
	else    filter_cnt <= filter_cnt - 1;
//滤波,filter_cnt频率是fSCLK频率的四倍
always @(posedge clk or negedge nReset)
	if(!nReset)
    		begin
        		fSCL <= 3'b111;
        		fSDA <= 3'b111; 
   		 en
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/599784
推荐阅读
相关标签
  

闽ICP备14008679号