模拟I2C协议.docx

上传人:b****3 文档编号:3958706 上传时间:2022-11-26 格式:DOCX 页数:54 大小:94.98KB
下载 相关 举报
模拟I2C协议.docx_第1页
第1页 / 共54页
模拟I2C协议.docx_第2页
第2页 / 共54页
模拟I2C协议.docx_第3页
第3页 / 共54页
模拟I2C协议.docx_第4页
第4页 / 共54页
模拟I2C协议.docx_第5页
第5页 / 共54页
点击查看更多>>
下载资源
资源描述

模拟I2C协议.docx

《模拟I2C协议.docx》由会员分享,可在线阅读,更多相关《模拟I2C协议.docx(54页珍藏版)》请在冰豆网上搜索。

模拟I2C协议.docx

模拟I2C协议

模拟I2C协议

在现代电子系统中,有为数众多的IC需要相互之间以及与外界的通信。

为了简化电路的设计,Philips公司开发了一种用于内部IC控制的简单的双向两线串行总线I2C(Intel-IntegratedCircuitbus)。

1998年当推出I2C总线协议2.0版本时,I2C协议实际上已经成为一个国际标准。

在进行FPGA设计时,经常需要和外围提供I2C接口的芯片通信。

例如低功耗的CMOS实时时钟/日历芯片PCF8563、LCD驱动芯片PCF8574、键盘/LED驱动器ZLG7290等都提供I2C接口。

因此在FPGA中模拟I2C接口已成为FPGA开发必要的步骤。

本章将详细讲解在FPGA芯片中使用VHD/VerilogHDL模拟I2C协议,以及编写TestBench仿真和测试程序的方法。

4.1I2C总线解析

下面先对I2C协议中有关数据格式和时序的内容进行介绍,这里没有涉及的地方请参考THEI2C-SPECIFICATIONVERSION2.1JANUARY2000.

4.1.1I2C总线概述

I2C协议作为一个串行总线标准尽管没有并行总线的数据吞吐能力,但是它的以下特点使其有着广泛的应用。

●只需要两条总线——串行数据线SDA和串行时钟线SCL;

●每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主/从节点关系软件设定地址,主节点可以发送数据或接收数据;

●是真正的多主总线,当两个或更多主节点同时初始化数据传输时,可以通过冲突检测和仲裁防止数据被破坏;

●串行的8位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s;

●片上的滤波器可以滤去总线数据线上的毛刺波,保证数据完整;

●连接到相同总线的IC数量只受到总线的最大电容(400pF)限制。

总线不仅仅是互连的线,还包含系统通信的所有格式和过程。

I2C总线结构上的特点保证了其应用时的简洁,另外其完备的协议避免了所有混乱、数据丢失和妨碍信息的可能性。

4.1.2I2C协议的基本概念

I2C总线支持任何IC生产过程(NMOS、CMOS和双极性)。

串行数据线SDA和串行时钟线SCL在连接到总线的器件间传递信息。

每个器件都有一个唯一的地址作为识别的标志(无论是微控制器、LCD驱动器存储器还是键盘接口),并且都可以发送数据和接收数据。

很明显LCD驱动器只需要接收数据,而存储器需要接收和发送数据。

图4-1所示的是一个高性能集成电视的例子。

 

PLL芯片

TSA5512

颜色解码器

TDA9160A

图像增强器

TDA4670

视频处理器

TDA4685

SCL

SDA

微控制器

PCB83C528

非失效内存

PCF8582E

立体声解码器

TDA9840

HI-FI音频处理器

TDA9860

文本处理芯片

SAA52XX

图4-1高性能集成电视

从图4-1可以看到,应用I2C总线是非常方便的。

用通俗的话讲I2C总线的硬件设计工作就是连接SDA和SCL两条线,依靠I2C协议完成软件工作。

在I2C协议中应理解如下的概念。

1.主/从节点

主节点负责初始化总线的数据传输,并产生允许传输的时钟信号。

此时任何被寻址的器件都被认为是从节点。

当有多个主节点在总线上传输数据时,每个主节点产生自己的时钟信号。

挂接到总线上的所有外围器件、外设接口都是总线上的节点。

2.总线上节点的寻址方式

在任何时刻总线上只有一个主控器件(主节点)实现总线的控制操作,对总线上的其他节点寻址,可分时实现点-点的数据传送。

因此总线上每个节点都有一个固定的节点地址。

I2C总线上主节点的地址由软件给定,此地址存放在I2C总线的地址寄存器中。

I2C总线上所有的外围器件都有规范的器件地址。

器件地址由7位数字组成,它和1位方向位构成了I2C总线器件的寻址字节SLA(Slaveaddress)。

器件地址是I2C总线外围接口器件固有的地址编码,器件出厂时就已给定。

数据方向位规定了总线上主节点对从节点的数据传送方向。

4.1.3I2C协议的时序要求

1.总线上数据传递时序

I2C总线上数据传递时序如图4-2所示,具体步骤如下。

●首先主节点器件发送一个起始信号。

●接下来主节点器件发送从节点地址和读写方式,一共8位。

其中从节点地址7位,读写方式1位。

●与传输地址一致的从节点器件应答(即ACK)。

●开始数据传输,传输数据数量不限。

每个字节(八位)后面跟接收数据方的应答位。

例如主节点器件读取从节点数据,从节点发送数据,主节点应答;主节点器件写数据到从节点,主节点发送数据,从节点应答。

●数据传输结束,主节点器件发送一个终止信号结束整个过程。

采用I2C总线后对传送的字节数没有限制,只要求每传送一个字节后对方回应一个应答位。

在发送时首先发送的是数据的最高位(MSB,MostSingnificantBit)。

每次传送开始有起始信号,结束时有停止信号。

在总线传送完一个字节后,可以通过对时钟线(SCL)的控制使传送暂停。

例如当某个外围器件接收N个字节数据后需要一段处理时间以使继续接收以后的字节数据,这时可在应答信号后使SCL变为低电平控制总线暂停。

如果主节点要求总线暂停也可使时钟线保持低电平控制总线暂停。

2.总线上的时序信号

I2C总线为同步传输总线,总线信号完全与时钟同步。

I2C总线上与数据传送有关的信号有起始信号S、终止信号P、应答信号A以及位传送信号。

下面将对这些信号一一介绍。

(1)起始信号

起始信号(StartCondition)如图4-3所示。

当时钟线SCL为高电平时,数据线SDA从高电平向低电平变化将形成起始信号,启动I2C总线。

(2)终止信号

终止信号(StopCondition)如图4-3所示。

当时钟线SCL为高电平时,数据线SDA从低电平向高电平变化将形成终止信号,停止I2C总线。

(3)应答信号

如图4-3所中ACK第9个时钟脉冲对应应答位,相应数据线上低电平时为应答信号,高电平时为非应答信号。

(4)位传送信号

在I2C总线启动后或应答信号后的第1~8个时钟脉冲对应于一个字节的8位数据传送。

脉冲高电平期间,数据串行传送;低电平期间为数据准备,允许总线上数据电平变换。

4.2模拟I2C接口程序的基本框架

图4-4模拟I2C接口程序的基本框架

1.程序接口

用于和应程序连接的接口,将应用程序的按照I2C协议的方式通过SDA传递给外部器件。

包括下列内容:

●clk_IFPGA外部时钟信号。

●rst_I同步重起信号。

●arst_I异步重起信号。

●adr_I从节点地址。

●dat_I输入数据。

●dat_o输出数据。

●we_I写有效信号。

●stb_I接口有效信号。

●cyc_I有效总线周期输入。

●ack_o应答信号输出。

●inta_o中断信号输出。

2.时钟设置寄存器

I2C协议提供了3种速度模式:

正常速度模式100kbit/s、快速模式400kbit/s、高速模式3.5Mbit/s。

SCL输出的时钟信号频率和速度模式一致。

程序内部使用5倍SCL信号作为时钟,而FPGA外部时钟需要经过分频行到程序内部使用的时钟。

例如:

采用正常速度100kbit/s,FPGA外部时钟为50MHz,则时钟设置寄存器需要设置为(50MHz/5*100kHz=99)。

3.时钟产生模块

时钟产生模块产生4倍SCL频率的时钟信号,它为位传输控制模块中所有同步动作提供触发信号。

4.命令寄存器

倒序寄存器共8位,它决定是否在总线上产生各种时序信号、是否读/写数据,各位表示的含义如表4-1所示。

 

表4-1命令寄存器内容

内容描述

7

STA,产生起始信号

6

STO,产生终止信号

5

RD,从节点读取数据

4

WR,往从节点写数据

3

ACK,应答信号

2:

1

保留位

0

IACK,中断应信号

5.状态寄存器

状态寄存器用来显示当前总线的状态,例如是否接收到从节点的应答信号、是否忙、是否在传递数据等,具体内容如表4-2所示。

 

表4-2状态寄存器内容

内容描述

7

RxACK,获得从节点的应答信号。

“1”代表没有获得应答信号,“0”代表获得应答信号

6

STO,产生终止信号

5

RD,从从节点读取数据

4

WR,往从节点写数据

3

ACK,应答信号

2:

1

保留位

0

IACK,中断应答信号

6.数据传输寄存器

数据传输寄存器用于保存等待传输的数据。

当传递从节点地址信息时,前7位保存从节点地址,最后一位保存读写命令;当传递普通数据时,8位保存一个字节数据。

数据传输寄存器具体内容如表4-3所示。

 

表4-3数据传输寄存器内容

内容描述

7:

1

传输的下一个内容

0

传输地址时是读写位,其他时候是数据

7.数据接收寄存器

数据接收寄存器用于保存通过I2C总线接收到的最后一个字节内容,具体内容如表4-4所示。

表4-4数据接收寄存器内容

内容描述

7:

0

接收到的最后一个字节内容

8.字节传输控制模块

字节传输控制模块以字节为单位控制I2C总线的数据传输。

这个模块按照命令寄存器设置的内容将数据传输寄存器内容传递到I2C总线的接收端,或者从I2C总线发关端接收数据并保存到数据接收寄存器中。

9.位传输控制模块

位传输控制模块以痊为单位I2C总线的数据传输和产生各个I2C协议命令(如开始、停止、重复开始等)。

字节传输控制模块控制位传输控制模块的各种动作。

例如读取一个字节数据,位传输控制模块需要执行8个读的命令。

10.数据移位寄存器

数据移位寄存器保存的数据总是和当前的数据传输相关的。

例如在进行读操作时,主节点通过移位寄存器依次通过SDA获得来自I2C发送端的数据,完成后数据拷贝到数据接收寄存器中。

在写操作时,数据传输寄存器中的数据拷贝到数据移位寄存器中,然后依次通过SDA将数据传输到I2C总线的接收端。

4.3I2C协议的具体实现

FPGA设计一般按照从顶向下的模式进行:

首先设计芯片功能,规划各个模块功能;然后按照规划实现各个模块。

本实例由3个代码文件组成:

i2c_master_bit_ctrl.v完成位传输的功能、i2c_master_byte_ctrl.v完成字节传输的功能、i2c_master_top.v完成整个程序的控制功能,并提供给外部程序的接口。

在ISE中创建一个项目,然后加入上面3个文件。

下面依次介绍3个文件的内容。

4.3.1位传输的实现

i2c_master_bit_ctrl.v完成位传输的功能。

位传输的功能包括数据按位传输的实现和I2C协议各个命令的实现两部分。

如图4-5所示开始和重复开始命令的产生包括5个阶段:

idle和A、B、C、D等。

读、写一个字节通过8次位操作完成,

实现代码如下:

`include"timescale.v"

`include"i2c_master_defines.v"

//模块名称及IO

modulei2c_master_bit_ctrl(

clk,rst,nReset,

clk_cnt,ena,cmd,cmd_ack,busy,al,din,dout,

scl_i,scl_o,sel_oen,sda_i,sda_o,sda_oen

);

 

图4-5位传输完成数据的传输和各个命令的实现

//输入、输出

inputclk;

inputrst;

inputnReset;

inputena;//模块使用信号

input[15:

0]clk_cnt,//时钟分频系数

input[3:

0]cmd;

outputcmd_ack;//命令完成应答

regcmd_ack;

outputbusy;//总线忙

regbusy;

outputal;//总线仲裁丢失

regal;

inputdin;

outputdout;

regdout;

//I2C连线

inputscl_i;//I2C时钟输入

outputscl_o;//I2C时钟输出

outputscl_oen;//I2C时钟输出使能

regscl_oen;

//variabldeclarations

regsSCL,sSDA;//同步后的SCL和SDA输入

tegdscl_oen;//延迟后的scl_oen

regsda_chk;//检查后的SDAoutput(Multi-masterarbitration)

regclk_en;//时钟产生信号

wireslave_wait;

reg[15:

0]ent;//时钟分频计数器

//模块主体

//当从节点没有准备好时,下拉SCL来延迟周期

//延迟scl_oen

always@(posedgeclk)

dscl_oen<=#1scl_oen;

assignslave_wait=dscl_oen&&!

sSCL;

//产生时钟使能信号

always@(posedgeclkornegedgenReset)

if(~nReset)

begin

cnt<=#116`h0;

clk_en<=#11`b1;

end

else

begin

cnt<=#1cnt;

clk_en<=#11`b0;

end

else

begin

cnt<=#1cnt-16`h1;

clk_en<=#11`b0;

end

//产生总线状态控制信号

regdSCL,dSDA;

regsta_condition;

regsto_condition;

//同步SCL和SDA输入信号,减少不稳定风险

always@(posedgeclkornegedgenReset)

if(~nReset)

begin

sSCL<=#11`b1;

sSDA<=#11`b1;

dSCL<=#11`b1;

dSDA<=#11`b1;

end

else

begin

sSCL<=#1scl_i;

sSDA<=#1sda_i;

dSCL<=#1sSCL;

dSDA<=#1sSDA;

end

//SCL处于高时检测到SDA的下降沿,即检测开始状态信号

//SCL处于高时检测到SDA的上升沿,即检测停止状态信号

always@(posedgeclkornegedgenReset)

if(~nReset)

begin

sta_condition<=#11`b0;

sto_condition<=#11`b0;

end

elseif(rst)

begin

sta_condition<=#11`b0;

sto_condition<=#11`b0;

end

else

begin

sta_condition<=#1~sSDA&dSDA&sSCL;

sto_condition<=#1sSDA&~dSDA&sSCL;

end

//产生I2C总线忙信号

always@(posedgeclkornegedgenReset)

if(!

nReset)

busy<=#11`b0;

elseif(rst)

busy<=#11`b0;

else

busy<=#1(sta_condition︱busy)&~sto_condition;

 

//产生仲裁丢失信号generatearbitrationlostsignal

//仲裁丢失发生在:

//1)主节点驱动SDA处于高,但是I2C总线一直处于低

//2)没有请求时却检测到停止状态信号

regcmd_stop,dcmd_stop;

always@(posedgeclkornegedgenReset)

if(~nReset)

begin

cmd_stop<=#11`b0;

dcmd_stop<=#11`b0;

al<=#11`b0;

end

elseif(rst)

begin

cmd_stop<=#11`b0;

dcmd_stop<=#11`b0;

al<=#11`b0;

end

else

begin

cmd_stop<=#1cmd==`12C_CMD_STOP;

dcmd_stop<=#1cmd_stop;

al<=#1(sda_chk&~sSDA&sda_oen)︱(sto_condition&~dcmd_stop

end

//产生数据输出信号,在SCL信号的上升沿保存SDA

always@(posedgeclk)

if(sSCL&~dSCL)

dout<=#1sSDA;

//产生状态机

//状态译码

parameter[16:

0]idle=17`b0_0000_0000_0000_0000;

parameter[16:

0]start_a=17`b0_0000_0000_0000_0001;

parameter[16:

0]start_b=17`b0_0000_0000_0000_0010;

parameter[16:

0]start_c=17`b0_0000_0000_0000_0100;

parameter[16:

0]start_d=17`b0_0000_0000_0000_1000;

parameter[16:

0]start_e=17`b0_0000_0000_0001_0000;

parameter[16:

0]stop_a=17`b0_0000_0000_0010_0000;

parameter[16:

0]stop_b=17`b0_0000_0000_0100_0000;

parameter[16:

0]stop_c=17`b0_0000_0000_1000_0000;

parameter[16:

0]stop_d=17`b0_0000_0001_0000_0000;

parameter[16:

0]rd_a=17`b0_0000_0010_0000_0000;

parameter[16:

0]rd_b=17`b0_0000_0100_0000_0000;

parameter[16:

0]rd_c=17`b0_0000_1000_0000_0000;

parameter[16:

0]rd_a=17`b0_0001_0000_0000_0000;

parameter[16:

0]wr_a=17`b0_0010_0000_0000_0000;

parameter[16:

0]wr_b=17`b0_0100_0000_0000_0000;

parameter[16:

0]wr_c=17`b0_1000_0000_0000_0000;

parameter[16:

0]wr_d=17`b1_0000_0000_0000_0000;

reg[16:

0]c_state;

//状态机

always@(posedgeclkornegedgenReset)

if(!

nReset)

begin

c_state<=#1idle;

cmd_ack<=#11`b0;

scl_oen<=#11`b1;

sda_oen<=#11`b1;

sda_chk<=#11`b0;

end

elseif(rst︱al)

begin

c_state<=#1idle;

cmd_ack<=#11`b0;

scl_oen<=#11`b1;

sda_oen<=#11`b1;

sda_chk<=#11`b0;

end

else

begin

cmd_ack<=#11`b0;

if(clk_en)

case(c_state)

//idle状态

idle:

begin

case(cmd)

`12C_CMD_START:

c_state<=#1start_a;

`12C_CMD_STOP:

c_state<=#1stop_a;

`12C_CMD_WRITE:

c_state<=#1wr_a;

`12C_CMD_READ:

c_state<=#1rd_a;

default:

c_state<=#1idle;

endcase

scl_oen<=#1scl_oen;//保持SCL在同一状态

sda_oen<=#1sda_oen;//保持SDA在同一状态

sda_chk<=#11`b0;//不检查SDA输出

end

//开始状态

start_a:

begin

c_state<=#1start_b;

scl_oen<=#1scl_oen;//保持SCL在同一状态

sda_oen<=#11`b1;//保持SDA处于高

sda_chk<=#11`b0;//不检查SDA的输出

end

start_b:

begin

c_state<=#1start_c;

scl_oen<=#11`b1;

sda_oen<=#11`b1;

sda_chk<=#11`b0;

end

start_c:

begin

c_state<=#1start_d;

scl_oen<=#11`b1;

sda_oen<=#11`b0;

sda_chk<=#11`b0;

end

start_d:

begin

c_state<=#1start_e;

scl_oen<=#11`b1;

sda_oen<=#11`b0;

sda_chk<=#11`b0;

end

start_e:

begin

c_state<=#1idle;

cmd_ack<=#11`b1;

scl_oen<=#11`b0;

sda_oen<=#11`b0;

sda_c

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1