I2C总线接口电路设计.docx
《I2C总线接口电路设计.docx》由会员分享,可在线阅读,更多相关《I2C总线接口电路设计.docx(34页珍藏版)》请在冰豆网上搜索。
I2C总线接口电路设计
FPGA与I2C总线器件接口电路设计
利用FPGA模拟I2C总线协议对I2C总线接口器件AT24C256进行读写操作。
利用按键输入读写命令和相应的地址、数据,对芯片进行读写操作,读写的数据用数码管显示。
一、I2C总线接口电路设计分析
1.I2C总线协议
I2C总线的两根通信线,一根是串行数据线SDA,另一根是串行时钟线SCL。
多个符合I2C总线标准的器件都可以通过同一条I2C总线进行通信,而不需要额外的地址译码器。
每个连接到总线上的器件都有一个唯一的地址作为识别的标志,都可以发送或接收数据。
I2C总线通信速率受主机控制,标准模式下可达100kbit/s。
一般具有I2C总线的器件其SDA、SCL引脚都为集电极(或漏极)开路结构。
因此实际使用时,SDA和SCL信号线必须加3~10K的上拉电阻。
总线空闲时均保持高平。
I2C总线接法如图1所示。
图1I2C总线连接示意图
(1)I2C的主机和从机,发送器和接收器
产生I2C总线时钟信号和起始、停止控制信号的器件,称为主机,被主机寻址的器件称为从机。
任何将数据传送到I2C总线的器件称为发送器,任何从I2C总线接收数据的器件称为接收器。
主机和从机都可作为发送数据器件和接收数据器件。
(2)I2C总线上数据的有效性:
时钟线SCL为高电平时,数据线SDA的任何电平变化将被看作总线的起始或停止信号;
在数据传送过程中,当时钟线SCL为高电平时,数据线SDA必须保持稳定状态,不允许有跳变;数据线SDA的状态只能在SCL低电平期间才能改变。
即进行串行传送数据时,在SCL高电平期间传送位数据,低电平期间准备数据。
(3)从机地址
I2C总线不需要额外的片选信号或地址译码。
多个I2C总线接口器件可连接到一条I2C总线上,它们之间通过地址来区分。
主机是主控制器件,只有一个主机的不需要地址。
其它器件均为从机,均有器件地址,但必须保证同一条I2C总线上的器件地址不能重复。
一般从机地址由7位地址位和1位读写位组成,地址位为高7位,读写位为最低位。
读写位为0时,表示主机将向从机写入数据;读写位为1时,表示主机将要从从机读取数据。
(4)I2C总线的通信时序
I2C总线的通信时序如图2所示。
图2I2C总线的通信时序
①首先主机发送一个起始信号。
当时钟线SCL处于高电平期间,数据线SDA电平从高到低的跳变形成I2C总线的起始信号,启动I2C总线。
②主机逐位发送7位(高位在前,低位在后)从机地址和1位读写控制信号,共8位。
需8个时钟。
③与传送地址一致的从机发应答信号(ACK)。
在第9个时钟周期时将SDA线拉低表示其已收到一个8位数据。
若在第9个时钟周期,SDA为高电平时为非应答。
④开始传送数据,传送数据数量不限。
每个字节(8位)后紧跟1个接收器件发出的应答位。
若是主机读取从机数据时,从机发送数据,主机发应答位;若是主机写数据到从机时,主机发送数据,从机发应答位。
⑤数据传输结束时,主机发送1个停止信号,当时钟线SCL为高电平时,数据线SDA由低电平变为高电平时形成终止信号,停止I2C总线通信。
(5)数据传输基本格式如表1。
表1I2C总线数据传输基本格式
S
A7~A1
R/W
ACK
D7~D0
ACK
D7~D0
ASK
P
起始位
7位
地址
0:
写
1:
读
应
答
位
8位
数据
应答位
8位
数据
…
应答位
0:
应答
1:
非应答
停
止
位
其中S、A7~A1、R/W、P总是由主机产生;写数据时,ACK由从机产生,D7~D0由主机产生;读数据时,ACK由主机产生,D7~D0由从机产生。
2.I2C总线器件AT24C256
AT24C256是一个256K位的串行CMOS型E2PROM,可存储32768个字节。
该器件通过I2C总线接口进行操作,其引脚如图3所示,各引脚功能见表2。
图3AT24C256引脚图
表2AT24C256引脚功能说明
管脚名称
功能说明
SCL
AT24C256串行时钟输入管脚。
用于产生器件所有数据发送或接收的时钟,是输入管脚。
SDA
双向串行数据/地址管脚。
用于器件所有数据的发送或接收,SDA是一个开漏输出管脚可与其它开漏输出或集电极开路输出进行线或wire-OR。
WP
写保护。
当WP脚连接到Vcc,所有内存变成写保护只能读;当WP引脚连接到Vss或悬空,允许器件进行读/写操作。
A0A1
器件地址输入。
这些管脚为硬连线或者不连接,对于单总线系统最多可寻址4个AT24C256器件。
当这些引脚没有连接时其默认值为0。
VSS
电源地
VCC
1.8~6V
NC
空脚
作为带有I2C总线接口的器件,每个AT24C256都有一个7位的从机地址,其高5位固定为“10100”,接下来的2位由AT24C256的引脚A1A0硬连线输入决定(A1、A0直接接电源VCC或GND),同一I2C总线上最多可以连接4个AT24C256器件。
AT24C256除了有作为从机的地址,其内部还有作为存储单元的编码子地址,其子地址为双字节(16位),从0000H~7FFFH。
本设计中只有1个AT24C256,可将AT24C256的引脚A1、A0直接接地,其硬件电路如图4所示。
则该AT24C256作为从机的7位地址为“1010000”。
图4单个AT24C256连接电路图
3.对AT24C256的读写过程
(1)向AT24C256某一存储单元写入1个字节数据,过程如下:
①主机(这里为FPGA控制器)发送一个起始信号,启动发送过程;
②主机发送7位从机地址(这里为1010000)和1位写控制位(为0);
③从机(这里为AT24C256)发应答位。
在主机发送起始信号和从机地址字节后,AT24C256监视总线并当其地址与发送的从地址相符时,响应一个应答信号。
在第9个时钟,将SDA线拉为低电平;
④主机接收到应答位后,发从机子地址高8位(为AT24C256某一存储单元地址)。
⑤从机接收完高8位子地址后,发应答位;
⑥主机接收到应答位后,发从机子地址低8位;
⑦从机接收完低8位子地址后,发应答位;
⑧主机接收到应答位后,发送待8位写入数据;
⑨从机接收完8数据后,发应答位,并开始内部数据的擦写;
⑩主机接收到应答位后,发停止位,结束传送,总线挂起。
SDA上数据传输格式见表3,数据传送时序如图5所示。
表3向AT24C256写1个数据时总线SDA上数据传输格式
S
A7~A1
0
0
AD15~AD8
0
AD7~AD0
0
D7~D0
0/1
P
起始位
7位
器件
地址
写
应
答
位
高8位
指针
地址
应
答
位
低8位
指针
地址
应
答
位
写入
8位
数据
应
答
位
停
止
位
主机发送
从机
发送
主机发送
从机发送
主机发送
从机发送
主机发送
从机发送
主机发送
图5向AT24C256写一个数据时序
(2)从AT24C256某一存储单元读出1个字节数据,过程如下:
①主机发送一个起始信号,启动发送过程,接着发送7位从机地址(1010000)和1位写控制位(0);;
②从机检测到起始信号及本身从地址相符时的从机地址后,发应答位。
③主机接收到应答位后,发从机子地址高8位(为AT24C256某一存储单元地址)。
④从机接收完高8位子地址后,发应答位;
⑤主机接收到应答位后,发从机子地址低8位;
⑥从机接收完低8位子地址后,发应答位;
⑦主机接收到应答位后,再发送一个起始信号(称为重复起始信号),接着再发送7位从机地址(1010000)和1位读控制位(为1);
⑧从机检测到重复起始信号及从机地址后,发应答位,并将子地址对应的存储单元数据发送到总线上。
⑨主机接收到应答位后,接着准备从总线接收数据,从总线接收完8数据后。
发非应答位和发停止位,结束传送,总线挂起。
SDA上数据传输格式见表4所示,数据传送时序如图6所示。
表4从AT24C256上读1个数据时总线SDA上数据传输格式
S
A7
~
A1
0
0
AD15
~
AD8
0
AD7
~
AD0
0
Sr
A7
~
A1
1
0
D7
~
D0
0/1
P
起
始
位
7位
器件
地址
写
应
答
位
高8位
指针
地址
应
答
位
低8位
指针
地址
应
答
位
重复
起始
位
7位
器件
地址
读
应
答
位
读出
8位
数据
非
应
答
停
止
位
主机
发送
从
机
发
送
主
机
发
送
从
机
发
送
主
机
发
送
从
机
发
送
主机发送
从
机
发
送
从
机
发
送
主
机
发
送
主
机
发
送
图6从AT24C256读一个数据时序
4.FPGA内部电路
模拟I2C总线对AT24C256的读写控制电路基本结构框图如图7所示。
图7模拟I2C总线对AT24C256的读写控制框图
(1)I2C总线端口
I2C总线端口为三态输出,当使能端有效时,总线输出为低电平;当使能端无效时三态门输出为高阻,但由于I2C总线上有上拉电阻,总线保持在高电平或由总线上从机输出数据决定。
总线数据始终能被读入。
其结构示意图如图8所示。
图8I2C总线端口示意图
(2)位传输控制模块
位传输模块以“位”为单位产生各种I2C协议命令(开始、停止和重复开始)以及进行位数据读写。
为了读写到稳定的“位”数据,读写1位数据分为4到5个阶段完成。
1位数据传输时序要求如图9所示。
这样内部读写时钟频率一般采用5倍于SCL时钟总线频率。
图9I2C协议命令和位数据传输的执行时序
位传输控制电路根据输入的控制命令,将来自字控制模块的一位待写入的数据送到总线上,或从总线上读入一位数据给字控制模块。
当完成1位数据传输时产生读写完成标志,并根据数据传输情况产生忙标志和总线仲裁丢失标志。
(3)字传输控制模块
字节传输模块以字节为单位控制I2C总线的数据传输。
该模块根据输入控制命令,将存放在发送寄存器中的数据加载到一个移位寄存器,然后逐位发送到位传输模块,再控制位传输模块将数据发送到I2C总线上。
或控制位传输模块从总线上逐位接收位数据,暂存到移位寄存器,再转换成字节数据送给数据输出。
同时给出相关传输标志。
(4)AT24C256读写控制
根据输入控制信号和来自位传输模块的反馈标志,将控制信号加到命令寄存器,给字节传输模块提供控制信号;将输入数据或指定单元地址加载到数据传送寄存器;将从字节模块读取的数据回送到数据接收寄存器。
二、FPGA硬件系统电路设计(略)
三、I2C总线接口电路VHDL设计
1.I2C总线端口
(1)名称:
IIC_IO.vhd
(2)功能:
I2C总线双向端口电路描述
(3)端口说明
方向
端口名
宽度
说明
输入
Sda_en
1
数据线三态使能控制端,来自位传输控制模块
Scl_en
1
时钟线三态使能控制端,来自位传输控制模块
输出
Sda_i
1
回送的数据线信号,给位传输控制模块
Scl_i
1
回送的时钟线信号,给位传输控制模块
双向
Sda
1
I2C的数据线,外接I2C器件
Scl
1
I2C的时钟线,外接I2C器件
(4)VHDL描述
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
ENTITYIIC_IOIS
PORT(
Scl_en,sda_en:
INSTD_LOGIC;
Sda,Scl:
INOUTSTD_LOGIC;
Scl_i,sda_i:
OUTSTD_LOGIC);
ENDIIC_IO;
ARCHITECTUREoneOFIIC_IOIS
BEGIN
Sda_i<=sda;
Scl_i<=scl;
Scl<='0'WHENscl_en='0'ELSE'Z';
Sda<='0'WHENsda_en='0'ELSE'Z';
ENDone;
2.位传输控制模块
(1)名称:
bit_txd_rxd.vhd
(2)功能:
实现位数据或协议命令的传输
(3)端口说明
方向
端口名
宽度
说明
输入
Rst
1
复位信号,低电平复位
clk_sys
1
系统时钟
ena
1
系统使能信号,高电平有效
cmd
4
控制命令,由字节传输模块给出
Bit_data_wr
1
待写入总线的1位数据
Scl_i
1
总线时钟输入
Sda_i
1
总线数据输入
输出
Scl_oen
1
总线时钟输出使能
Sda_oen
1
总线数据输出使能
Bit_finish
1
完成1位读写的标志,1为完成,0为未完成
busy
1
总线忙标志,1为忙,0为闲
lose
1
总线仲裁丢失标志,1为出错,0为正确
Bit_data_rd
1
从总线读出的1位数据
(4)VHDL描述
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_Arith.ALL;
USEIEEE.STD_LOGIC_Unsigned.ALL;
ENTITYbit_txd_rxdIS
GENERIC(n:
INTEGER:
=48);--分频系数
PORT(
Clk_sys:
INSTD_LOGIC;
Rst,ena:
INSTD_LOGIC;
cmd:
INSTD_LOGIC_VECTOR(3DOWNTO0);
Bit_data_wr:
INSTD_LOGIC;--
Scl_i,sda_i:
INSTD_LOGIC;
Scl_oen,sda_oen:
OUTSTD_LOGIC;
Busy,Lose:
OUTSTD_LOGIC;
Bit_data_rd,Bit_finish:
OUTSTD_LOGIC);
ENDbit_txd_rxd;
ARCHITECTUREtwoOFbit_txd_rxdIS
Typestate_tIS(bit_idle,start_a,start_b,start_c,start_d,start_e,stop_a,stop_b,stop_c,stop_d,write_a,write_b,write_c,write_d,read_a,read_b,read_c,read_d);
SIGNALsta_p:
state_t;
CONSTANTn:
INTEGER:
=48;--产生500KHz的分频系数
SIGNALen_500k:
STD_LOGIC;--500KHz时钟使能信号
SIGNALScl_a,Sda_a,Scl_b,Sda_b:
STD_LOGIC;--同步SCL和SDA中间信号
SIGNALscl_edg:
STD_LOGIC;--SCL的边沿信号
SIGNALscl_oen_r,sda_oen_r:
STD_LOGIC;--总线使能信号
SIGNALsda_chk:
STD_LOGIC;--写数据时,检查总线信号
SIGNALdscl_oen,slave_wait:
STD_LOGIC;--时钟延迟等待的信号
SIGNALSda_S,Sda_P:
STD_LOGIC;--启动、停止标志位
SIGNALBusy_r,Lose_r:
STD_LOGIC;--忙标志、丢失标志信号
SIGNALstop_cmd,stop_cmd_r:
STD_LOGIC;--停止命令信号
BEGIN
PROCESS(clk_sys,rst)--同步SCL和SDA的输入信号
BEGIN
IFrst='0'THEN
Scl_a<='1';
Sda_a<='1';
Scl_b<='1';
Sda_b<='1';
ELSIFRISING_EDGE(clk_sys)THEN--暂存SCL、SDA的值
Scl_a<=Scl_i;
Sda_a<=Sda_i;
Scl_b<=Scl_a;
Sda_b<=Sda_a;
ENDIF;
ENDPROCESS;
Scl_edg<=scl_aAND(NOTScl_b);--检测时钟SCL上升沿
PROCESS(clk_sys)--产生数据输出信号,在SCL上升沿时锁存SDA上的数据值
BEGIN
IFRISING_EDGE(clk_sys)THEN
IFscl_edg='1'THEN
Bit_data_rd<=Sda_a;
ENDIF;
ENDIF;
ENDPROCESS;
--从节点未准备好时,下拉SCL延迟周期;当给出的SCL使能为1时,检测SCL总线为0时,则节点未准备就绪,产生等待信号。
PROCESS(clk_sys)
BEGIN
IFRISING_EDGE(clk_sys)THEN
dscl_oen<=scl_oen_r;
ENDIF;
ENDPROCESS;
Slave_wait<=dscl_oenAND(NOTscl_a);
PROCESS(clk_sys,rst)--将24M系统时钟分频产生500KHz时钟使能控制信号
VARIABLEcnt:
INTEGERRANGE0TOn-1;--时钟分频计数器
BEGIN
IFrst='0'THEN
cnt:
=0;
en_500k<='1';
ELSIFRISING_EDGE(clk_sys)THEN
IFclk_cntIFena='1'THEN
cnt:
=cnt+1;
en_500k<='0';
ENDIF;
ELSE
IFSlave_wait='0'THEN--从节点准备好,给出时钟使能
cnt:
=0;
en_500k<='1';
ELSE--从节点未准备好,延迟等待
cnt:
=cnt;
en_500k<='0';
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
--生成启动标志和停止标志
--在SCL高电平时,检测SDA的下降沿(起始信号),产生启动标志
--在SCL高电平时,检测SDA的上升沿(停止信号),产生停止标志
PROCESS(clk_sys,rst)
BEGIN
IFrst='0'THEN
Sda_S<='0';--启动标志复位
Sda_P<='0';--停止标志复位
ELSIFRISING_EDGE(clk_sys)THEN
Sda_S<=(NOTSda_a)ANDSda_bANDScl_a;--生成启动标志
Sda_P<=Sda_aAND(NOTSda_b)ANDScl_a;--生成停止标志
ENDIF;
ENDPROCESS;
--生成总线忙标志
--检测到启动信号发生,但无停止信号发生时表示总线处于忙状态
PROCESS(clk_sys,rst)
BEGIN
IFrst='0'THEN
Busy_r<='0';
ELSIFRISING_EDGE(clk_sys)THEN
Busy_r<=(Sda_SORbusy_r)AND(NOTSda_P);
ENDIF;
ENDPROCESS;
Busy<=busy_r;--忙标志输出
--产生仲裁丢失标志,
--当没有停止请求时,检测到停止信号,产生仲裁丢失标志
---当驱动SDA总线为高时,但检测SDA一直为低,产生仲裁丢失标志
PROCESS(clk_sys,rst)
BEGIN
IFrst='0'THEN
stop_cmd<='0';--停止命令信号
stop_cmd_r<='0';
Lose_r<='0';
ELSIFRISING_EDGE(clk_sys)THEN
IFcmd<="0010"THEN--有停止命令
stop_Cmd<='1';
ELSE
stop_Cmd<='0';
ENDIF;
stop_Cmd_r<=stop_Cmd;
Lose_r<=(Sda_PAND(NOTstop_Cmd_r))OR(NOTsda_aANDsda_chkANDsda_oen_r);--丢失标志
ENDIF;
ENDPROCESS;
Lose<=Lose_r;
--位传输状态机
Scl_oen<=scl_oen_r;
Sda_oen<=Sda_oen_r;
PROCESS(clk_sys,rst)
BEGIN
IFrst='0'THEN
Sta_p<=bit_idle;--初始准备状态
bit_finish<='0';--1位信号发送或接收完成标志
Scl_oen_r<='1';--时钟输出使能
Sda_oen_r<='1';--数据输出使能
Sda_chk<='0';--不检查输出
ELSIFRISING_EDGE(clk_sys)THEN
IFLose_r='1'THEN--数据传输信号丢失
Sta_p<=bit_idle;
bit_finish<='0';
Scl_oen_r<='1';
Sda_oen_r<='1';
Sda_chk<='0';
ELSE
bit_finish<='0';
IFclk_en='1'THEN
CASEsta_pIS
WHENbit_idle=>--准备状态
Scl_oen_r<=scl_oen_r;--保持SCL在同一状态
Sda_oen_r<=sda_oen_r;--保持SDA在同一状态
Sda_chk<='0';
CASEcmdIS--状态命令字
WHEN"0001"=>sta_p<=start_a;--发送起始信号状态
WHEN"0010"=>sta_p<=stop_a;--发送停止信号状态
WHEN"0100"=>sta_p<=write_a;--写入1位数据
WHEN"1000"=>sta_p<=read_a;--读出1位数据
WHENOTHERS=>sta_p<=bit_idle;
ENDCASE;
--启动I2C状态,分5个时钟段产生起始信号
WHENstart_a=>
sta_p<=start_b;