微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 基于Verilog HDL的I2C总线功能的实现

基于Verilog HDL的I2C总线功能的实现

时间:06-05 来源:互联网 点击:

开发FPGA时,利用EDA工具设计芯片实现系统功能已经成为支撑电子设计的通用平台,并逐步向支持系统级的设计方向发展。在软件设计过程中,越来越强调模块化设计。I2C总线是Philips公司推出的双向两线串行通讯标准,具有接口线少?通讯效率高等特点。把I2C总线设计成相应的模块,有利于相关FPGA的开发。目前有一些介绍相关开发的资料[1],但都是利用VHDL语言或AHDL语言实现的。本文给出利用Verilog HDL语言设计的I2C总线模块。

1 I2C总线概述

I2C总线系统由两根总线即SCL(串行时钟)线和SDA(串行数据)线构成。这种总线可以设计成很多种通讯配置,但本文只讨论主从系统的应用。主器件控制总线通讯,开始/结束传送?发送信息并产生I2C系统时钟。在写操作过程中,从器件一旦被主控器件寻址,就执行特定的相应功能。在读操作过程中,主控器件从从器件那里获得数据。在整个主从传送过程中,所有的事件都通过主控器件的SCL时钟线达到同步。连到总线上的器件的接口形式必须是漏极开路或集电极开路输出状态。通过上拉电阻,使得两根总线在空闲的状态下都为高电平状态。因此I2C总线上具有线与功能,即总线上的所有器件都达到高电平状态时,I2C总线才能达到高电平状态,从而使总线上的高速器件和慢速器件工作同步。

在I2C协议中,从器件地址是一个唯一的7位地址。接下来是一个读写方向标志位,读状态是高电平?写状态是低电平。

2 I2C模块的设计与实现

根据I2C协议中传输过程的特点,I2C模块可以划分为字节发送模块、字节接收模块、开始条件模块、停止条件模块。其中,字节发送模块、字节接收模块和停止条件模块为基本模块。在开始条件模块中,因为需要发送从器件地址,所以要调用字节发送模块。

下面给出用Verilog HDL语言[3]实现字节发送模块的关键程序。相关变量的声明在此略去。程序在Max+PlusII环境下编译?调试?仿真。

assign en_sdao=tempen_sdao; //设置SDA三态输出使能

assign send_byte_over=tempsend_byte_over;

assign NO_ACK=tempNO_ACK;

assign sdao=tempsda;

assign sclo=tempscl;

always@(posedge send_byte_clk)

begin

case(send_byte_zt)

sendbit1:

begin

if(send_byte_num==0)

begin

shiftdata[7:0]=indata[7:0];

end

shiftdata=shiftdata 1;

tempsda=shiftdata[8];

tempscl=1; //置SCL为高电平

send_byte_zt= delay_1;

send_byte_num=send_byte_num+1;

end

delay_1: //延时三个周期

begin

if(delay_counter>=2)

begin

send_byte_zt = sendbit2;

delay_counter=0;

end

else

begin

delay_counter=delay_counter+1;

send_byte_zt = send_byte_zt;

end

end

sendbit2:

begin

tempscl=0; //SCL置零

send_byte_zt = delay_2;

end

delay_2: //延时三个周期

begin

if(delay_counter>=2)

begin

send_byte_zt = sendbit3;

delay_counter=0;

end

else

begin

delay_counter=delay_counter+1;

send_byte_zt = send_byte_zt;

end

end

sendbit3: //判断是否字节中所有位都发送完毕

begin

if(send_byte_num=8)

begin

send_byte_zt=sendbit1;

end

else

begin

send_byte_zt=ForACK1;

send_byte_num=0;

end

end

ForACK1:

begin

tempsda=1; //释放数据线,等待应答信号

send_byte_zt=delay_ACK;

end

delay_ACK: //延时

begin

if(delay_counter>=3)

begin

send_byte_zt = ForACK2;

delay_counter=0;

end

else

begin

delay_counter=delay_counter+1;

send_byte_zt = send_byte_zt;

tempscl=1;

end

end

ForACK2:

begin

send_byte_zt=AckYESNO;

tempen_sdao=0; //输出SDA使能信号,控制sdao和sdai

end

AckYESNO:

begin

if(sdai) //如果应答信号sdai为1,NO_ACK置1

begin

tempNO_ACK=1; //设置未应答标志信号

end

tempscl=0; //终止应答位

send_byte_zt=Finish_delay;

end

Finish_delay: //延时

begin

if(delay_counter>=2)

begin

tempsend_byte_over=1;

send_byte_zt = FinishACK1;

delay_counter=0;

end

else

begin

delay_counter=delay_counter+1;

send_byte_zt = send_byte_zt;

end

end

FinishACK1:

begin

send_byte_zt=sendbit1;

send_byte_num=0;

end

default:

begin

send_byte_zt=sendbit1;

send_byte_num=0;

end

endcase

end

程序中sdao、sclo为输出信号,sdai为应答信号,en_sdao是对sdao和sdai进行切换的信号。I2C总线具有SDA和SCL两根信号线,所以在整个模块设计中

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top