基于fpga的eeprom设计.docx

上传人:b****6 文档编号:3382618 上传时间:2022-11-22 格式:DOCX 页数:37 大小:580.04KB
下载 相关 举报
基于fpga的eeprom设计.docx_第1页
第1页 / 共37页
基于fpga的eeprom设计.docx_第2页
第2页 / 共37页
基于fpga的eeprom设计.docx_第3页
第3页 / 共37页
基于fpga的eeprom设计.docx_第4页
第4页 / 共37页
基于fpga的eeprom设计.docx_第5页
第5页 / 共37页
点击查看更多>>
下载资源
资源描述

基于fpga的eeprom设计.docx

《基于fpga的eeprom设计.docx》由会员分享,可在线阅读,更多相关《基于fpga的eeprom设计.docx(37页珍藏版)》请在冰豆网上搜索。

基于fpga的eeprom设计.docx

基于fpga的eeprom设计

二线制I2CCMOS串行EEPROM的FPGA设计

姓名:

钱大成

学号:

080230114

院系:

物理院电子系

 

2011年1月1日

一、课程设计摘要:

(1)背景知识:

A、基本介绍:

二线制I2CCMOS串行EEPROMAT24C02/4/8/16是一种采用CMOS工艺制成的串行可用电擦除可编程只读存储器。

B、I2C(InterIntegratedCircuit)总线特征介绍:

I2C双向二线制串行总线协议定义如下:

只有在总线处于“非忙”状态时,数据传输才能被初始化。

在数据传输期间,只要时钟线为高电平,数据线都必须保持稳定,否则数据线上的任何变化都被当作“启动”或“停止”信号。

图1是被定义的总线状态。

①总线非忙状态(A段)

数据线SDA和时钟线SCL都保持高电平。

②启动数据传输(B段)

当时钟线(SCL)为高电平状态时,数据线(SDA)由高电平变为低电平的下降沿被认为是“启动”信号。

只有出现“启动”信号后,其它的命令才有效。

③停止数据传输(C段)

当时钟线(SCL)为高电平状态时,数据线(SDA)由低电平变为高电平的上升沿被认为是“停止”信号。

随着“停在”信号出现,所有的外部操作都结束。

④数据有效(D段)

在出现“启动”信号以后,在时钟线(SCL)为高电平状态时数据线是稳定的,这时数据线的状态就要传送的数据。

数据线(SDA)上的数据的改变必须在时钟线为低电平期间完成,每位数据占用一个时钟脉冲。

每个数传输都是由“启动”信号开始,结束于“停止”信号。

⑤应答信号

每个正在接收数据的EEPROM在接到一个字节的数据后,通常需要发出一个应答信号。

而每个正在发送数据的EEPROM在发出一个字节的数据后,通常需要接收一个应答信号。

EEPROM读写控制器必须产生一个与这个应答位相联系的额外的时钟脉冲。

在EEPROM的读操作中,EEPROM读写控制器对EEPROM完成的最后一个字节不产生应答位,但是应该给EEPROM一个结束信号。

C、3.二线制I2CCMOS串行EEPROM读写操作

①EEPROM的写操作(字节编程方式)

所谓EEPROM的写操作(字节编程方式)就是通过读写控制器把一个字节数据发送到EEPROM中指定地址的存储单元。

其过程如下:

EEPROM读写控制器发出“启动”信号后,紧跟着送4位I2C总线器件特征编码1010和3位EEPROM芯片地址/页地址XXX以及写状态的R/W位(=0),到总线上。

这一字节表示在接收到被寻址的EEPROM产生的一个应答位后,读写控制器将跟着发送1个字节的EEPROM存储单元地址和要写入的1个字节数据。

EEPROM在接收到存储单元地址后又一次产生应答位以后,读写控制器才发送数据字节,并把数据写入被寻址的存储单元。

EEPROM再一次发出应答信号,读写控制器收到此应答信号后,便产生“停止”信号。

字节写入帧格式如图2所示:

 

②二线制I2CCMOS串行EEPROM的读操作

所谓EEPROM的读操作即通过读写控制器读取EEPROM中指定地址的存储单元中的一个字节数据。

串行EEPROM的读操作分两步进行:

读写器首先发送一个“启动”信号和控制字节(包括页面地址和写控制位)到EEPROM,再通过写操作设置EEPROM存储单元地址(注意:

虽然这是读操作,但需要先写入地址指针的值),在此期间EEPROM会产生必要的应答位。

接着读写器重新发送另一个“启动”信号和控制字节(包括页面地址和读控制位R/W=1),EEPROM收到后发出应答信号,然后,要寻址存储单元的数据就从SDA线上输出。

读操作有三种:

读当前地址存储单元的数据、读指定地址存储单元的数据、读连续存储单元的数据。

在这里只介绍读指定地址存储单元数据的操作。

读指定地址存储单元数据的帧格式如图3:

 

 

(2)实现功能及设计思路:

EEPROM是要实现接收来自信号源模型产生的读信号、写信号、并行地址信号、并行数据信号,并把它们转换为相应的串行信号发送到串行EEPROM(AT24C02/4/8/16)的行为模型中去的功能,同时它还发送应答信号(ACK)到信号源模型,以便让信号源来调节发送或接收数据的速度以配合EEPROM模型的接收(写)和发送(读)数据。

其基本设计思路是利用同步有限状态机的设计方法实现,根据串行EEPROM的读写特性,用五个状态时钟完成写操作,用七个状态时钟完成读操作,通过编写EEPROM读写器的模块以及随机读写数据模块,再加上信号产生模块,最终封装在一块完成初步的设计。

 

二、系统设计部分

(1)整体设计的组织结构

(2)子单元设计结构:

①EEPROM的行为模型

为了设计这样一个电路我们首先要设计一个EEPROM的VerilogHDL模型,而设计这样一个模型我们需要仔细地阅读和分析EEPROM器件的说明书,因为EEPROM不是我们要设计的对象,而是我们验证设计对象所需要的器件,所以只需设计一个EEPROM的行为模型,而不需要可综合风格的模型,这就大大简化了设计过程。

下面的VerilogHDL程序就是这个EEPROM(AT24C02/4/8/16)能完成一个字节数据读写的部分行为模型。

这里只对在操作中用到的信号线进行模拟,对于没有用到的信号线就略去了。

对EEPROM用于基本总线操作的引脚SCL和SDA说明如下:

SCL,串行时钟端,这个信号用于对输入和输出数据的同步,写入串行EEPROM的数据用其上升沿同步,输出数据用其下降沿同步;SDA,串行数据(/地址)输入/输出端。

EEPROM的行为模型如下:

//---------------eeprom.v文件开始-----------------

`definetimeslice100

moduleEEPROM(scl,sda);

inputscl;

inoutsda;

regout_flag;

reg[7:

0]memory[2047:

0];

reg[10:

0]address;

reg[7:

0]memory_buf;

reg[7:

0]sda_buf;

reg[7:

0]shift;

reg[7:

0]addr_byte;

reg[7:

0]ctrl_byte;

reg[7:

0]State;

integeri;

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

parameterr7=8'b10101111,w7=8'b10101110,//main7

r6=8'b10101101,w6=8'b10101100,//main6

r5=8'b10101011,w5=8'b10101010,//main5

r4=8'b10101001,w4=8'b10101000,//main4

r3=8'b10100111,w3=8'b10100110,//main3

r2=8'b10100101,w2=8'b10100100,//main2

r1=8'b10100011,w1=8'b10100010,//main1

r0=8'b10100001,w0=8'b10100000;//main0

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

assignsda=(out_flag==1)?

sda_buf[7]:

1'bz;

//---------------------寄存器和存储器初始化--------

initial

begin

addr_byte=0;

ctrl_byte=0;

out_flag=0;

sda_buf=0;

State=2'b00;

memory_buf=0;

address=0;

shift=0;

for(i=0;i<2047;i=i+1)

memory[i]=0;

end

//--------------启动信号-----------------------

always@(negedgesda)

if(scl==1)

begin

State=State+1;

if(State==2'b11)

disablewrite_to_eeprm;

end

//----------------主状态机----------------------

always@(posedgesda)

if(scl==1)

stop_W_R;

else

begin

casex(State)

2'b01:

/***************************************************

***************************************************/

Begin

read_in;

if(ctrl_byte==w7||ctrl_byte==w6||ctrl_byte==w5

||ctrl_byte==w4||ctrl_byte==w3||ctrl_byte==w2

||ctrl_byte==w1||ctrl_byte==w0)

begin

State=2'b10;

write_to_eeprm;

end

else

State=2'b00;

end

2'b11:

read_from_eeprm;

default:

State=2'b00;

endcase

end

//------------------------操作停止----------------------

taskstop_W_R;

begin

State=2'b00;

addr_byte=0;

ctrl_byte=0;

out_flag=0;

sda_buf=0;

end

endtask

//--------------------读进控制字和存储单元地址--------------

taskread_in;

begin

shift_in(ctrl_byte);

shift_in(addr_byte);

end

endtask

//--------------------EEPROM的写操作-----------------------

taskwrite_to_eeprm;

begin

shift_in(memory_buf);

address={ctrl_byte[3:

1],addr_byte};

memory[address]=memory_buf;

$display("eeprm-----memory[%0h]=%0h",address,memory[address]);

State=2'b00;

end

endtask

//----------------------EEPROM的读操作--------------------

taskread_from_eeprm;

begin

shift_in(ctrl_byte);

if(ctrl_byte==r7||ctrl_byte==r6||ctrl_byte==r5

||ctrl_byte==r4||ctrl_byte==r3||ctrl_byte==r2

||ctrl_byte==r1||ctrl_byte==r0)

begin

address={ctrl_byte[3:

1],addr_byte};

sda_buf=memory[address];

shift_out;

State=2'b00;

end

end

endtask

//---SDA数据线上的数据存入寄存器,数据在SCL的高电平有效----------

taskshift_in;

output[7:

0]shift;

begin

@(posedgescl)shift[7]=sda;

@(posedgescl)shift[6]=sda;

@(posedgescl)shift[5]=sda;

@(posedgescl)shift[4]=sda;

@(posedgescl)shift[3]=sda;

@(posedgescl)shift[2]=sda;

@(posedgescl)shift[1]=sda;

@(posedgescl)shift[0]=sda;

@(negedgescl)

begin

#`timeslice;

out_flag=1;

sda_buf=0;

end

@(negedgescl)

#`timesliceout_flag=0;

end

endtask

//---EEPROM存储器中的数据通过SDA数据线输出,数据在SCL低电平时变化-------

taskshift_out;

begin

out_flag=1;

for(i=6;i>=0;i=i-1)

begin

@(negedgescl);

#`timeslice;

sda_buf=sda_buf<<1;

end

@(negedgescl)#`timeslicesda_buf[7]=1;

@(negedgescl)#`timesliceout_flag=0;

end

endtask

endmodule

//-----------------eeprom.v文件结束----------------------------

②EEPROM读写器的可综合的VerilogHDL模型

下面的程序是一个串行EEPROM读写器的可综合的VerilogHDL模型,它接收来自信号源模型产生的读信号、写信号、并行地址信号、并行数据信号,并把它们转换为相应的串行信号发送到串行EEPROM(AT24C02/4/8/16)的行为模型中去;它还发送应答信号(ACK)到信号源模型,以便让信号源来调节发送或接收数据的速度以配合EEPROM模型的接收(写)和发送(读)数据。

因为它是我们的设计对象,所以它不但要仿真正确无误,还需要可综合。

这个程序基本上由两部分组成:

开关组合电路和控制时序电路,见图5。

开关电路在控制时序电路的控制下按照设计的要求有节奏的打开或闭合,这样SDA可以按I2C数据总线的格式输出或输入,SDA和SCL一起完成EEPROM的读写操作。

电路最终用同步有限状态机(FSM)的设计方法实现。

程序实则上是一个嵌套的状态机,由主状态机和从状态机通过由控制线启动的总线在不同的输入信号的情况下构成不同功能的较复杂的有限状态机,这个有限状态机只有唯一的驱动时钟CLK。

根据串行EEPROM的读写操作时序可知,用5个状态时钟可以完成写操作,用7个状态时钟可以完成读操作,由于读写操作的状态中有几个状态是一致的,用一个嵌套的状态机即可。

状态转移如图6,程序由一个读写大任务和若干个较小的任务所组成,其状态机采用独热编码,若需改变状态编码,只需改变程序中的parameter定义即可。

读者可以通过模仿这一程序来编写较复杂的可综合VerilogHDL模块程序。

这个设计已通过后仿真,并可在FPGA上实现布局布线。

完成串行EEPROM读写器件的设计后,我们还需要做的重要一步是EEPROM读写器件的仿真。

仿真可以分为前仿真和后仿真,前仿真是VerilogHDL的功能仿真,后仿真是VerilogHDL代码经过综合、布局布线后的时序仿真。

为此,我们还要编写了用于EEPROM读写器件的仿真测试的信号源程序。

这个信号源能产生相应的读信号、写信号、并行地址信号、并行数据信号,并能接收串行EEPROM读写器件的应答信号(ACK),来调节发送或接收数据的速度。

在这个程序中,我们为了保证串行EEPROM读写器件的正确性,可以进行完整的测试,写操作时输入的地址信号和数据信号的数据通过系统命令$readmemh从addr.dat和data.dat文件中取得,而在addr.dat和data.dat文件中可以存放任意数据。

读操作时从EEPROM读出的数据存入文件eeprom.dat,对比三个文件的数据就可以验证程序的正确性。

$readmemh和$fopen等系统命令读者可以参考VerilogHDL的语法部分。

最后我们把信号源、EEPROM和EEPROM读写器用顶层模块连接在一起。

在下面的程序就是这个信号源的VerilogHDL模型和顶层模块。

EEPROM读写器模型如下:

//--------------------eeprom_wr.v文件开始-------------------

ModuleEEPROM_WR(sda,scl,ack,reset,clk,wr,rd,addr,data,main_state,sh8out_buf,head_state,sh8in_state);

outputscl,ack;

inputreset,clk,wr,rd;

input[10:

0]addr;

inoutsda;

inout[7:

0]data;

output[10:

0]main_state;

output[7:

0]sh8out_buf;

output[2:

0]head_state;

output[9:

0]sh8in_state;

regack,scl,wf,rf,ff;

reg[1:

0]head_buf,stop_buf;

reg[7:

0]sh8out_buf;

reg[8:

0]sh8out_state;

reg[9:

0]sh8in_state;

reg[2:

0]head_state,stop_state;

reg[10:

0]main_state;

reg[7:

0]data_from_rm;

reglink_sda,link_read,link_head,link_write,link_stop;

wiresda1,sda2,sda3,sda4;

assignsda1=(link_head)?

head_buf[1]:

1'b0;

assignsda2=(link_write)?

sh8out_buf[7]:

1'b0;

assignsda3=(link_stop)?

stop_buf[1]:

1'b0;

assignsda4=(sda1|sda2|sda3);

assignsda=(link_sda)?

sda4:

1'bz;

assigndata=(link_read)?

data_from_rm:

8'hzz;

parameter

idle=11'b00000000001,

ready=11'b00000000010,

write_start=11'b00000000100,

ctrl_write=11'b00000001000,

addr_write=11'b00000010000,

data_write=11'b00000100000,

read_start=11'b00001000000,

ctrl_read=11'b00010000000,

data_read=11'b00100000000,

stop=11'b01000000000,

ackn=11'b10000000000,

sh8out_bit7=9'b000000001,

sh8out_bit6=9'b000000010,

sh8out_bit5=9'b000000100,

sh8out_bit4=9'b000001000,

sh8out_bit3=9'b000010000,

sh8out_bit2=9'b000100000,

sh8out_bit1=9'b001000000,

sh8out_bit0=9'b010000000,

sh8out_end=9'b100000000;

parameter

sh8in_begin=10'b0000000001,

sh8in_bit7=10'b0000000010,

sh8in_bit6=10'b0000000100,

sh8in_bit5=10'b0000001000,

sh8in_bit4=10'b0000010000,

sh8in_bit3=10'b0000100000,

sh8in_bit2=10'b0001000000,

sh8in_bit1=10'b0010000000,

sh8in_bit0=10'b0100000000,

sh8in_end=10'b1000000000;

parameter

head_begin=3'b001,

head_bit=3'b010,

head_end=3'b100,

stop_begin=3'b001,

stop_bit=3'b010,

stop_end=3'b100,

yes=1'b1,no=1'b0;

always@(negedgeclk)

if(reset)

scl<=1'b0;

else

scl<=~scl;

always@(posedgeclk)

if(reset)

begin

link_read<=no;link_write<=no;

link_head<=no;link_stop<=no;

link_sda<=no;ack<=1'b0;rf<=1'b0;wf<=1'b0;ff<=1'b0;

main_state<=idle;

end

else

begin

casex(main_state)

idle:

begin

link_read<=no;link_write<=no;

link_head<=no;link_stop<=no;

link_sda<=no;

if(wr)

begin

wf<=1'b1;

main_state<=ready;

end

elseif(rd)

begin

rf<=1'b1;

main_state<=ready;

end

else

begin

wf<=1'b0;rf<=1'b0;

main_state<=idle;

end

end

ready:

begin

link_read<=no;link_write<=no;

link_head<=no;link_stop<=yes;

link_sda<=yes;

head_buf<=2'b10;stop_buf<=1'b01;

head_state<=head_begin;

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

当前位置:首页 > 小学教育 > 小升初

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

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