电子大神的日记本,供应链专家的功夫茶盘,在这里记录、分享与共鸣。

登录以开始

FPGA实现I2C总线模块(转)

摘要:简述了I 2C总线的特点;介绍了开发FPGA时I2C总线模块的设计思想;给出并解释了用VerilogHDL实现部分I2C总线功能的程序,以及I2C总线主从模式下的仿真时序图。sO100

    关键词:I2C总线FPGAVerilogHDL时序

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

    1I2C总线概述

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

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

    2I2C模块的设计与实现

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

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

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

    assignsend_byte_over=tempsend_byte_over;

    assignNO_ACK=tempNO_ACK;

    assignsdao=tempsda;

    assignsclo=tempscl;

    always@(posedgesend_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

    tempsc1=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

    tempsc1=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两根信号线,所以在整个模块设计中,把sdao/sclo和sdai/scli作为两组信号。当需要向外部SDA信号线上输出信息时,sdao连到SDA信号线上;当需要从外部SDA信号线上读入信息时,置sdao成高阻态,sdai连到SDA信号线上。en_sdao信号作为这一过程的切换信号。在程序中定义了一些状态信号:NO_ACK、send_byte_over。其中,NO_ACK信号判断从器件是否对发送的信号给予了应答。send_byte_over信号判断字节是否传输完毕。这些信号可以传递给上一层设计模块,以控制程序的流程。为了使I2C总线能够有效地通讯,必须考虑信号的建立和保持时间,所以程序中设置了相应的延时部分。另外,在以clk为触发信号的过程模块中,定义send_byte_clk信号为时钟信号的两倍频信号,并加入字节发送模块使能信号start_send_byte控制模块工作于篇幅所限,略去该过程模块。

    字节发送模块的仿真测试结果如图1所示。

    根据I2C总线标准,利用VerilogHDL很容易实现字节接收模块、开始条件模块、停止条件模块这三个模块。图2是数据发送过程的仿真测试结果。从器件的7位地址为101011,向从器件发送的数据为00010111。aensclo和aensdao分别是sclo/scli和sdao/sdai的切换信号。

    图3是数据接收过程的仿真测试结果。从器件的7位地址为0011001,从器件发送的数据为11111111。ensclo和ensdao分别是sclo/scli和sdao/sdai的切换信号。

    将图2和图3所模拟的I2C总线时序与I2C总线协议中相关要求进行比较,满足I2C总线的时序要求。

    对各个模块进行多层次处理,形成I2C总线模块。

以该I2C总线模块为基础,编写FPGA与AT24C01A(ATMEL公司生产的E2PROM)的通讯程序。然后把相关程序下载到EPF10Kl0LC84-3中,与AT24C01A进行实际通讯实验,效果良好。ImgLoad(document.getElementById(”BodyLabel”));

 

 

 

// i2c.vhd

//

//这是是能从一个外部NUM(AT24C02A)读数据到一个256x8的外部SRAM块的I2C主接口程序,

//当用于写NUM的外部逻辑寄存器存取时,SRAM就从外部源读数据并且把数据写到特定的I2C地址。

//----------------------------------------------------------------------

//

//               Copyright 2004 Actel corporation

//

//----------------------------------------------------------------------

//

// Version 1.2  06/04/04 J.Vorgert - working file

//

//----------------------------------------------------------------------

 

`timescale 1ns / 1ps

 

module i2c (Reset_n, CLK, INIT, IENB, IADDR, IDATA, ICLK, UPDT,

            UENB, UADDR, UDATA, SDI, SDO, SCK);

 

input Reset_n;  /* active low reset */

input CLK    ;  /* processor clock  */

output INIT   ;  /* high during init */

output IENB   ;  /* low to enable write */

output [7:0] IADDR  ;  /* init address */

output [7:0] IDATA  ;  /* init data */

output ICLK   ;  /* init clock */

 

input UPDT   ;  /* high to trigger mirror image update */

output UENB   ;  /* low to enable fifo */

input [7:0] UADDR; /* write address */

input [7:0] UDATA;  /* write data */

 

input SDI    ;  /* serial input */

output SDO    ; /* active low open-drain drive enable - data */

output SCK    ; /* active low open-drain drive enable - clock */

 

reg IENB;

reg INIT;

reg UENB;

reg BTCK;

wire STEN;    

reg  [3:0] CSTATE;  

reg  [3:0] BCNT  ; 

reg  [7:0] CCNT  ; 

reg DLY     ;

reg D2 ;

wire D2I;

wire NKI     ;

reg NACK    ;

wire WRI     ;

wire RDI     ;

reg [8:0] BYTE   ;

reg [8:0] SDATA  ;

wire LD_BYTE  ;

reg STSP     ;

wire CTL_VAL  ;

 

always @ (posedge CLK or negedge Reset_n)

begin

  if(Reset_n == 1'b0)

     BTCK <= 1'b0;

  else

     BTCK <= #1 !BTCK;

 

end

 

// INIT is set at power-up and cleared when the state machine

// reaches state 0101.

 

always @ (negedge Reset_n or posedge CLK)

begin

  if(Reset_n == 1'b0)

     INIT <= 1'b1;

  else if(CSTATE == 4'b0101)

        INIT <= #1 1'b0 ;

end

 

// This state machine is set-up to read/write data to an AT24C

博主
camfence
camfence's Blog
FPGA设计遇到的困惑:1.FPGA对图像的特征进行提取和识别,目前方法就是通过VGA看实际效果,modelsim只能检测波形,有没有对图像进行仿真的方法?
点击跳转