SPI接口的Verilog语言实现 - 图文

更新时间:2024-01-19 22:26:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

电子与电气工程系

课程设计、专题(综合)实验报告

课题名称__串行接口IP核的设计与验证(spi)_

专 业____ 电子信息工程________ 班 级_____ 08电子1班__________ 学 号__0806012103_ 0806012104_ 姓 名___ 高江柯____吴冠雄__ ______ 成 绩________________________ 指导教师_______袁江南____________

2011年 6 月 15 日

串行接口IP核的设计与验证(SPI)

(FPGA作为主机) 一、 实验目的:

通过本实验的学习,使学生掌握使用VHDL 设计一个实用数字系统的能力,以及单片机串行接口编程等知识,训练 VHDL以及单片机的编程与综合使用能力,培养工程设计的基本技能,为今后毕业设计以及实际工作奠定基础。

二、 实验原理

SPI 接口是在 CPU 和外围低速器件之间进行同步串行数据传输,在主器件

的移位脉冲下,数据按位传输,高位在前,地位在后,为全双工通信,数据传输速度总体来说比I2C 总线要快,速度可达到几Mbps。

SPI 接口是以主从方式工作的,这种模式通常有一个主器件和一个或多个从 器件,其接口包括以下四种信号:

(1)MOSI –主器件数据输出,从器件数据输入 (2)MISO –主器件数据输入,从器件数据输出 (3)SCLK – 时钟信号,由主器件产生

(4)/CS –从器件使能信号,由主器件控制

在点对点的通信中,SPI 接口不需要进行寻址操作,且为全双工通信,显得简单高效。

SPI接口在内部硬件实际上是两个简单的移位寄存器,传输的数据为8位,在主器件产生的从器件使能信号和移位脉冲下,按位传输,高位在前,低位在后。下图所示,在 SCLK 的下降沿上数据改变,同时一位数据被存入移位寄存器。

三、 实验步骤:

1、

2、 3、 4、 5、 6、

查找关于SPI的资料,认识理解SPI。

根据SPI传输数据的时序图构建出SPI的框图。

利用自顶向下的方法根据框图分模块进行程序的编写。 把各模块连接构成完整的SPI传输系统。 进行仿真验证。

在康芯开发板上验证此SPI系统收发及中断功能是否正常。(由于时间原因其步未能完成)

四、 设计过程:

模块1:

输入说明:

data7[7..0] : FPGA写数据到RAM的输入口。 enable : 为输入使能。 reset : 复位。 clk : 输入时钟。

contr_addr[5..0]: FPGA写数据到RAM的地址的最大值,即写入RAM

中数据的个数。

feedback : SPI系统发送完数据的反馈,提示FPGA又可以重

新写数据到RAM,然后发送。

输出说明:

wr_en : 控制RAM写使能。

wr_addr : 写数据到RAM的地址控制,写一数据地址加一。 wr_clock : RAM写数据时钟,上升沿有效。 fullflag : RAM写满的标志。 data_out[7..0] : RAM中写入的数据。

模块说明:

FPGA通过SPI发送数据,数据必须要有个缓存阶段。此设计中是利用RAM作为缓存。该模块就是数据写入RAM的控制器,并提示FPGA开始发送数据及发送多少个数据。SPI发送完数据后提示FPGA重新写数据到RAM继续发送。

仿真时序图:

模块2:

输入说明:

data[7..0] :输入RAM的数据。

wraddress[5..0] :RAM写地下输入,写一数据地址加一。 wren :RAM写使能

rdaddress[5..0] :RAM读地址输入,读一数据地址加一。 rden :RAM读使能

wrclock :RAM写数据时钟,上升沿有效。 rdclock :RAM读数据时钟,上升沿有效。

输出说明:

q[7..0] :读RAM数据输出口。

模块说明:

这是双通道的RAM,此设计中需要定制2个容量为64BIT的,能进行数据的读写。需注意的数据的读写不能同时操作。

模块3:

输入说明:

clk :系统时钟。

ramindata[7..0] :输入需要发送的数据。 Cpuwr :

Miso :主机输入从机输出。 Reset :复位。 RFirq :开始发送。

Fullflag :RAM存满,请求开始发送标志。 Addr_num[5..0] :需要发送数据的个数。 输出说明:

feedback :发送完数据后反馈给RAM控制器,请求重新写入RAM数据

发送。

outdata[7..0] :接收到从机发出的数据,用于测试。 mosi :主机发出的移位数据,从机输入。 Irq :发送完中断主求。

CSN :从机选择控制,低电平有效。 SCK :主机从机发送移位数据时钟。

SendAddr[5..0] :RAM读地址控制,读取RAM中的数据进行发送。 SendRDen :RAM读使能。

ReceiveData[7..0] :接收到的数据,用于写入RAM。

ReceiveAddr[5..0] :接收到的数据写入RAM的地址控制。

SendramClk :读取RAM中的数据用于发送的时钟,上升沿有效。 ReceiveClk :接收到的数据写入RAM中的时钟控制,上升沿有效。 ReceiveWen :接收到数据写入RAM使能。 CE:

Sendfinishtest :发送结束标志。

ram_rd :整个数据接收完后,读取RAM中数据使能。

ram_rd_clk :整个数据接收完后,读取RAM中数时钟,上升沿有效。 ram_rd_addr[5..0] :整个数据接收完后,读取RAM中数据的地址控制。

模块说明:

此模块是整个系统的核心部分,控制着SPI的收发。 其整个流程大致如下:

RESE初始化 等待 准备 Y N fullflag=1 N ReadReging=0 Y 开始发送 同时接收 发送接收第一个数据 发送接收中间数据 N sendFinishByte= SendByteNum-1 Y Irq=1 申请中断 sendfilish=1 feedback 读取RAM中收到的数据 ReadReging=1 N ReadReging=0 Y 结束

具体的程序写法:

其收发过程都是通过状态机实现的。状态机容易构成性能良好的同步时序逻辑模块,而且能很大限度的消除毛刺现象。 读取第一个数据(4个状态):

标记,处于发送态 产生读RAM脉冲态 准备发送态 读取第一 个数据态

开始发送接收(17个状态,采用顺序编码): 5'b00000: CSN=1'b0; 片选从机,低电平有效 SCK=1'b0; 拉低SPI时钟线,主机发送数据最高位 mosi=senddata[7]; 读取数据最高位放到数据线MOSI发送 SendRDen=1'b1; 读取发送数据使能 SendramCLK=1'b0; 拉低读RAM时钟线 bitcounter=bitcounter+5'b1; 5'b00001: SCK=1'b1; 拉高SPI时钟线,主机接收从机发出数据最高位 StatusReg0[7]=miso; 存取最高位数据

SendramCLK=1'b1; 拉高读RAM时钟线,产生上升沿读RAM bitcounter=bitcounter+5'b1; 5'b00010: SCK=1'b0; 拉低SPI时钟线,主机发送数据次高位数据 mosi=senddata[6]; 读取数据次高位放到数据线MOSI发送

bitcounter=bitcounter+5'b1;

5'b00011: SCK=1'b1; 拉高SPI时钟线,主机接收从机发出数据次高位 StatusReg0[6]=miso; 存取次高位数据 ramsendtemp=ramindata; 读取RAM中下一个数据 bitcounter=bitcounter+5'b1;

5'b00100:

SCK=1'b0; 拉低SPI时钟线,主机发送数据的第五位 mosi=senddata[5]; 发送数据第五位 SendramCLK=1'b0; 拉低读RAM时钟线 SendRDen=1'b0; 关闭读RAM使能 SendAddr=SendAddr+6'b1; 读RAM地址加一 bitcounter=bitcounter+5'b1; 5'b00101: SCK=1'b1; StatusReg0[5]=miso; bitcounter=bitcounter+5'b1; 5'b00110: SCK=1'b0; mosi=senddata[4]; bitcounter=bitcounter+5'b1; 5'b00111: SCK=1'b1;

StatusReg0[4]=miso; bitcounter=bitcounter+5'b1; 5'b01000: SCK=1'b0; mosi=senddata[3]; bitcounter=bitcounter+5'b1; 5'b01001: SCK=1'b1; StatusReg0[3]=miso; bitcounter=bitcounter+5'b1; 5'b01010: SCK=1'b0;

mosi=senddata[2]; bitcounter=bitcounter+5'b1; 5'b01011: SCK=1'b1; StatusReg0[2]=miso; bitcounter=bitcounter+5'b1; 5'b01100: SCK=1'b0; mosi=senddata[1]; bitcounter=bitcounter+5'b1; 5'b01101: SCK=1'b1;

StatusReg0[1]=miso; bitcounter=bitcounter+5'b1; 5'b01110:

接收从机发出的数据第五位 主机发送数据第四位 接收从机发出的数据第四位

主机发送数据第三位 主机接收从机发出的数据第三位 主机发送数据第二位

主机接收从机发送的数据的第二位 主机发送数据的次低位 主机接收数据的次低位

SCK=1'b0; mosi=senddata[0]; 主机发送数据的最低位 bitcounter=bitcounter+5'b1; 6'b01111: SCK=1'b1;

StatusReg0[0]=miso; 主机接收数据的最低位

bitcounter=bitcounter+5'b1; senddata=ramsendtemp; 6'b10000: SCK=1'b0; bitcounter=5'b0;

发送接收中间数据态(18个状态,采用顺序编码):

5'b00000: SCK=1'b0;

ramdReceivetemp=StatusReg0; 主机存储接收到的第一个数据,并准备

写入RAM

sendFinishByte=sendFinishByte+6'b1; 发送数据个数加一 receiveByte=receiveByte+6'b1; 接收数据个数加一

mosi=senddata[7]; 主机发送中间数据最高位 SendramCLK=1'b0; SendRDen=1'b1; bitcounter=bitcounter+5'b1;

5'b00001: SCK=1'b0; SendramCLK=1'b1;

bitcounter=bitcounter+5'b1;

5'b00010: SCK=1'b1; StatusReg0[7]=miso; 主机接收从机发出的数据的最高位 bitcounter=bitcounter+5'b1;

5'b00011: SCK=1'b0; mosi=senddata[6]; 主机发送中间数据次高位

ramsendtemp=ramindata; bitcounter=bitcounter+5'b1;

读取RAM,作为下一个发送数

5'b00100: SCK=1'b1;

StatusReg0[6]=miso; 主机接收从机发出数据的次高位 SendAddr=SendAddr+6'b1; 读RAM地址加一

SendramCLK=1'b0;

SendRDen=1'b0;

bitcounter=bitcounter+5'b1;

5'b00101: SCK=1'b0;

mosi=senddata[5]; ReceiveCLK=1'b0; ReceiveWen=1'b1; bitcounter=bitcounter+5'b1;

5'b00110: SCK=1'b1;

StatusReg0[5]=miso; bitcounter=bitcounter+5'b1;

5'b00111: SCK=1'b0;

mosi=senddata[4]; ReceiveData=ramdReceivetemp; bitcounter=bitcounter+5'b1;

5'b01000: SCK=1'b1;

StatusReg0[4]=miso; bitcounter=bitcounter+5'b1; ReceiveCLK=1'b1; (为

5'b01001: SCK=1'b0; mosi=senddata[3]; bitcounter=bitcounter+5'b1; ReceiveCLK=1'b0;

主机发送中间数据第五位

拉低写数据到RAM时钟 RAM写数据使能 主机接收从机发出的数据第五位 主机发送中间数据的第四位

准备好写入的数据(在时钟上升沿到来前, 将数据放到总线上) 主机接收从机发出数据的第四位 将拉收到的上一个数据第一次写入RAM 了安全,每个数据写两次) 5'b01010: SCK=1'b1; StatusReg0[3]=miso; bitcounter=bitcounter+5'b1;

ReceiveCLK=1'b1; 第二次写入(为了安全,每个数据写两次)

5'b01011: SCK=1'b0; mosi=senddata[2]; bitcounter=bitcounter+5'b1; ReceiveAddr=ReceiveAddr+6'b1; ReceiveCLK=1'b0; ReceiveWen=1'b0; //取消写ram信号

5'b01100:

SCK=1'b1;

StatusReg0[2]=miso; bitcounter=bitcounter+5'b1;

5'b01101: SCK=1'b0; mosi=senddata[1]; bitcounter=bitcounter+5'b1;

5'b01110: SCK=1'b1; StatusReg0[1]=miso; bitcounter=bitcounter+5'b1;

5'b01111: SCK=1'b0; mosi=senddata[0]; bitcounter=bitcounter+5'b1;

6'b10000: SCK=1'b1; StatusReg0[0]=miso; bitcounter=bitcounter+5'b1;

6'b10001: SCK=1'b0;

bitcounter=5'b0; sendFinishByte=sendFinishByte+6'b1; 接收数据个数加一 ramdReceivetemp=StatusReg0; 主机缓存接收到的数据

senddata=ramsendtemp; 主机把读到的下一个数据拉到发生寄 存器,准备发送 receiveByte=receiveByte+6'b1;

发送最后一个数据(21个状态,采用顺序编码):

前面17个状态与接收发送第一个数据,中间数据基本相同。故不作具体陈述。

6'b10010: CSN=1'b1; bitcounter=bitcounter+5'b1;

ReceiveCLK=1'b0;

6'b10011:

ReceiveCLK=1'b1; bitcounter=bitcounter+5'b1;

6'b10100:

ready=1'b0; feedback=1'b1; senden=1'b0; sendfilish=1; receiveByte=receiveByte+6'b1; ReceiveAddr=6'b0; ReceiveCLK=1'b0; ReceiveWen=1'b0; ReceiveReady=1'b1;

bitcounter=bitcounter+5'b1;

6'b10101: bitcounter=5'b0;

feedback=1'b0;

顶成框图:

取消选择从机使能 接收到数据第二次写入RAM(为了安 全,每个数据写两次) 发送接收完准备取消

反馈给RAM控制器,可以重新写数据 取消发送使能 发送完成标志 接收数据加一 接收地址清0 取消写ram信号

反馈信号清0

仿真时序图:

仿真结果说明:

仿真通过设置contr_addr=4来写五个数据(11,12,7,15,16)到RAM,然后发送。

五、 设计中遇到的问题及解决办法:

1、 控制RAM写数据的时钟时,忽视了Verilog语言的语句执行特 导致RAM中总是写不进去数据。 wr_clock=1'b0;

wr_clock=1'b1; 第一次写入 wr_clock=1'b0;

wr_clock=1'b1; 第二次写入

这样执行后的结果为wr_clock=1'b1,一直为上高平,并不会有两个上升沿。

最好的解决方法就是使用状态机。 2’b00: wr_clock=1'b0;

2’b01: wr_clock=1'b1; 第一次写入 2’b10: wr_clock=1'b0;

2’b11: wr_clock=1'b1; 第二次写入

2、 处理反馈信号feedback与存满信号fullflag的逻辑关系时,遇到 了些麻烦,最终巧妙的运用异或解决了问题。

a=(~feedback)&fullflag0;

b=feedback&(~fullflag0); fullflag=a|b;

3、 在定制FIFO时遇到很大的问题,如数据不能按照严格的时序进出

FIFO,而且有些数据还不能写进FIFO,经过多方面调试改写还是没能解决。最终只能放弃FIFO,改用RAM,外加个控制器就可以了。

六、 设计心得与体会:

1、这次设计花了我四天多时间完成,做之前单纯的以为SPI不过就是写几个简单的移位寄存器外加个时钟就可以了,却完全忽视了SPI具有严格的时序要求及数据发送接收存储问题。SPI不是只发送接收一个八位数据就可以了的,它应该具有强大的信息交换传输功能。

2、仿真时序很不好把握,以后尽量少用Quartus II自带仿真器,要多多学习MODOSIM。 3、Verilog HDL自学了一段时间,第一次用来编写一个完整的系统。和VHDL比起来还是各有各的好处吧。它们描述各层的能力各有千秋。Verilog HDL善于描述更低层设计,比VHDL更灵活,而VHDL善于描述一些高层的设计(主要是一些算法及控制好实现)。Verilog HDL在仿真方面比VHDL也更方便些,如TESTBEN。

4、FPGA方面需学习的还有很多,为了设计SPI借书查了些资料,才发现自己FPGA基本上还没有入门。电子设计做信号题需加倍努力啊。

本文来源:https://www.bwwdw.com/article/xmwo.html

Top