基于VHDL的串行同步通信SPI设计.docx
- 文档编号:13419796
- 上传时间:2023-06-14
- 格式:DOCX
- 页数:13
- 大小:52.84KB
基于VHDL的串行同步通信SPI设计.docx
《基于VHDL的串行同步通信SPI设计.docx》由会员分享,可在线阅读,更多相关《基于VHDL的串行同步通信SPI设计.docx(13页珍藏版)》请在冰点文库上搜索。
基于VHDL的串行同步通信SPI设计
摘要
本设计是用Quartus作为开发环境,以DE2板为硬件平台实现的SPI同步串行通讯。
设计过程方便。
根据接收和发送两个主要部分实现了SPI的基本功能。
此外,该设计还实现了波特率发生器,数码管显示的功能。
用DE2板实现具有电路简洁,开发周期短的优点。
充分利用了EDA设计的优点。
开发过程用了VHDL硬件描述语言进行描述,从底层设计,分模块进行,充分提高了设计者的数字逻辑设计的概念。
关键词:
SPI,同步串行通讯,Quartus,DE2板,VHDL硬件描述语言。
1引言
串行扩展通信接口是器件间进行数据交换的平台和重要渠道。
主控同步串行通信模块主要应用于系统内部近距离的串行通讯,如SPI,I^C等。
SPI是英文SerialPeripheralInterface的缩写,中文意思是串行外围设备接口,SPI是Motorola公司推出的一种同步串行通讯方式,是一种三线同步总线,因其硬件功能很强,与SPI有关的软件就相当简单,使CPU有更多的时间处理其他事务。
2SPI简介
2.1SPI协议和工作原理
顾名思义,串行接口的数据传输方式是串行的,即数据是一位一位地进行传输虽然串行接口的传输方式导致其传输速度会比较慢,但是它却具有较强的抗干扰能力,并能有较长的传输距离,RS232口的最大传输距离为15m。
SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,比如AT91RM9200.
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。
也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。
(1)SDO-主设备数据输出,从设备数据输入
(2)SDI-主设备数据输入,从设备数据输出
(3)SCLK-时钟信号,由主设备产生
(4)CS-从设备使能信号,由主设备控制
其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效。
这就允许在同一总线上连接多个SPI设备成为可能。
接下来就负责通讯的3根线了。
通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。
这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。
数据输出通过SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。
完成一位数据传输,输入也使用同样原理。
这样,在至少8次时钟信号的改变(上沿和下沿为一次),就可以完成8位数据的传输。
SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。
假设下面的8位寄存器装的是待发送的数据10101010,上升沿发送、下降沿接收、高位先发送。
那么第一个上升沿来的时候数据将会是sdo=1;寄存器中的10101010左移一位,后面补入送来的一位未知数x,成了0101010x。
下降沿到来的时候,sdi上的电平将锁存到寄存器中去,那么这时寄存器=0101010sdi,这样在8个时钟脉冲以后,两个寄存器的内容互相交换一次。
这样就完成里一个spi时序。
2.2波特率
这是一个衡量通信速度的参数。
它表示每秒钟传送的bit的个数。
例如300波特表示每秒钟发送300个bit。
当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。
这意味着串口通信在数据线上的采样率为4800Hz。
通常电话线的波特率为14400,28800和36600。
波特率可以远远大于这些值,但是波特率和距离成反比。
串行口每秒发送或接收数据的码元数为传码,单位为波特,也叫波特率。
若发送或接收一位数据所需时间为T,则波特率为1/T,相应的发送或接收时钟为1/THz。
发送和接收设备的波特率应一致。
位同步是实现收发双方的码元同步,由数据传输系统的同步控制电路实现。
发送端由发送时钟的定时脉冲对数据序列取样再生,接收端由接收时
钟的定时脉冲对接收数据序列取样判断,恢复原来的数据序列。
因此,接收时钟和发送时钟必须同频同相,这是由接收端的定时提取和锁相环电路实现的。
传码率与位同步必须同时满足。
否则,接收设备接收不到有效信息。
3模块设计
3.1顶层模块RTL综合
顶层文件设计,将波特率发生模块,数据发送模块,数据接收模块,和数码显示模块通过例化语句组合成总的顶层模块。
其中数据发送模块为并行输入串行输出模块,在时钟的上升沿发送一位数据,共需要8个时钟脉冲即可发送完一字节数据。
数据接收模块为串行输入并行输出模块,串行输入的数据来自数据发送模块,在时钟的上升沿接收数据,即由“自己发送的数据自己同步接收”来模拟主从器件间数据的全双工传输。
数码管显示模块则是循环显示0~8数字,每循环一次代表传输完一字节。
以下是顶层模块VHDL源程序:
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityspiis
port(clk,stop,load:
instd_logic;
data_in:
std_logic_vector(7downto0);
deng_out:
outstd_logic_vector(7downto0);
shuma_out:
outstd_logic_vector(6downto0));
endspi;
architectureoneofspiis
componentsdi
port(clk_sdi:
instd_logic;
sdi_in:
instd_logic;
load:
instd_logic;
shuma:
outintegerrange0to8;
sdi_out:
outstd_logic_vector(7downto0));
endcomponent;
componentsdo
port(clk_sdo,load:
instd_logic;
sdo_in:
instd_logic_vector(7downto0);
sdo_out:
outstd_logic);
endcomponent;
componentSHUMG
port
(
num:
inINTEGERRANGE0TO8;
dout:
outstd_logic_vector(6downto0)
);
endcomponent;
componentfenpin
port(clk,stop:
instd_logic;
clok:
outstd_logic);
endcomponent;
signalA,B:
std_logic;
signalC:
INTEGERrange0to8;
begin
u1:
sdiportmap(sdi_out=>deng_out,clk_sdi=>A,sdi_in=>B,shuma=>C,load=>load);
u2:
sdoportmap(sdo_out=>B,sdo_in=>data_in,load=>load,clk_sdo=>A);
u3:
SHUMGportmap(dout=>shuma_out,num=>C);
u4:
fenpinportmap(clk=>clk,stop=>stop,clok=>A);
endone;
综合后为:
3.2波特率发生器模块
由于SPI同步串行通讯的缺点是波特率不高,通常常用的SPI波特率有2400,4800,9600,19200等比较低的波特率,晶振的频率一般都比较高,需要分频后才能供给SPI使用。
假设采用6MHZ的晶振作为外部时钟,那么要产生9600波特率的时钟信号,则需要对6MHZ的时钟进行625分频。
除此之外,为了提高接收电路接收数据的准确度,采取“过采样法”对发送来的同一个数据进行多次采样,这里对数据进行三次采样取平均值。
输入6MHz的时钟,经过计数分频后得到9600Hz的接收时钟信号和脉冲出现的频率是波特率的3倍的采样时钟信号。
下面是实现该功能的VHDL程序:
libraryieee;
useieee.std_logic_1164.all;
entityfenpinis
port(clk,stop:
instd_logic;clok,clk3:
outstd_logic);
endfenpin;
architectureoneoffenpinis
begin
process(clk)
variablecounter:
integerrange0to625;
begin
ifstop='1'then
ifclk'eventandclk='1'then
ifcounter=625thencounter:
=0;clok<='1';
elsecounter:
=counter+1;clok<='0';
endif;
endif;
if(counter=106orcounter=313orcounter=520)
thenclk3<='1';elseclk3<='0';
endif;
endif;
endprocess;
endone;
其中,clk为6MHz的时钟;clok为9600Hz的接收时钟;clk3为脉冲出现的频率是波特率的3倍的采样时钟。
3.3SDO数据发送模块
发送电路是在时序脉冲的控制下,利用移位寄存器并行输入串行输出的把数据一位一位的送出去。
VHDL源程序如下:
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entitysdois
port(clk_sdo,load:
instd_logic;
sdo_in:
instd_logic_vector(7downto0);
sdo_out:
outstd_logic);
endsdo;
architectureoneofsdois
signalbuff:
std_logic_vector(7downto0);
begin
process(clk_sdo)
begin
ifclk_sdo'eventandclk_sdo='1'then
ifload='1'then
buff<=sdo_in;
elsebuff(7downto1)<=buff(6downto0);
endif;
endif;
sdo_out<=buff(7);
endprocess;
endone;
其中,sdo_in:
instd_logic_vector(7downto0);为并行输入端口8位数据,clk_sdo为输入端口发送时钟;sdo_out:
outstd_logic为输出串行端口;当load=‘1’,则把待发送的数据送入数据缓冲区BUFF,然后根据时钟的上升沿的到来把数据一位一位的从缓冲器送给串行输出。
如图所示,第一次装载待发送数据10101010,第二次装载待发送数据01010101于缓冲区,共2字节数据,从仿真图上可以看到,串行输出分贝输出了2字节数据:
10101010,和01010101
3.4SDI数据接收模块
接收电路的功能是在时钟控制下,采样串行输入端口上的数据,执行采样判断,检测帧同步标志,把后续数据依次送达对应的并行输出端口上。
下面是实现上述功能的VHDL源程序:
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entitysdiis
port(clk_sdi:
instd_logic;
sdi_in:
instd_logic;
shuma:
outintegerrange0to8;
sdi_out:
outstd_logic_vector(7downto0));
endsdi;
architectureoneofsdiis
signalbuff:
std_logic_vector(7downto0);
begin
process(clk_sdi)
variablecout:
integerrange0to8;
begin
ifclk_sdi'eventandclk_sdi='1'then
ifcout=8thencout:
=0;sdi_out<=buff;
elsebuff(7-cout)<=sdi_in;
cout:
=cout+1;
endif;
endif;
shuma<=cout;
endprocess;
endone;
数据一位一位的接收,接收一位就把它存放于接收缓冲寄存器,等待缓冲器满后就并行输出数据由程序读取。
如仿真图所示,串行传来的两字节数据10101010和01010101,数码管循环显示从0~8,当显示8时代表缓冲器满,并串行输出数据,SDI_OUT为串行输出的数据。
3.5数码管显示模块
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_arith.all;
useieee.std_logic_unsigned.all;
entitySHUMGis
port
(num:
inINTEGERRANGE0TO8;
dout:
outstd_logic_vector(6downto0)
);
endSHUMG;
architecturea1ofSHUMGis
begin
withnumselect
dout<="1111110"when0,
"0110000"when1,
"1101101"when2,
"1111001"when3,
"0110011"when4,
"1011011"when5,
"1011111"when6,
"1110000"when7,
"1111111"when8,
"0000000"whenothers;
enda1;
数码管显示模块用来方便表示出数据传输的过程,从0~8循环显示,8代表数据传输完毕准备传送或接收下一字节数据。
4实验验证
4.1实验验证方案选择
由于要在DE2板上验证SPI有一定难度。
我们的方案一
就是利用串口调试助手,PC机作为从器件,目标板做为主器件进行SPI通讯。
我们的方案二
是完全在DE2板上模拟主从同步串行通讯,但是由于考虑到DE2板上可以用的验证设备(开关和LED灯)不够,所以我们决定在DE2版上对所设计的SPI模块进行调整,自己发送的数据自己接收,模拟实现了主从之间通过不串行通讯。
在这里我们采用的是方案2,优点是易于实现。
我们把SDO发送数据模块直接接到了SDI数据接收模块,因此我们只要验证:
通过发送以自己数据,待8个时序脉冲后数据发送完的同时也被接收,则说明我们的思路正确。
4.2实验现象
说明:
开关SW8代表LOAD数据装载。
开关SW9代表时钟时能
SW0~SW7作为发送数据的数据缓冲器,即发送模块数据输入端,存待发送的数据。
LED0~LED7读取数据接收模块的数据接收状态。
数码管循环显示0~8.
当我们拨动开关,准备好待发送数据时,先LOAD把数据送入缓冲区,然后使时钟时能,这是开始发送和接收数据同步。
数码管从0~8显示,当数码管显示8时,灯的状态与开关的状态相对应,灯亮代表数据位1,灯灭为0.然后我们准备第二字节数据。
发送和接收数据区间如果取消时钟时能则可以使数据暂停传输。
5结论与问题讨论
5.1完成设计要求的程度
本设计在完成了基本部分外,还实现了轮流显示每字节数据的传输情况情况的功能。
完成了这次设计的任务。
5.2遇到的问题及解决方法
遇到的问题有数据收发不同步,数据收发不准确,不知道如何验证正确性等问题。
对于数据收发不同步,我们采取了使用同频同相的时钟信号,同在时钟的上升沿接收和发送数据。
对于数据收发不准确,我们经过老师的点拨,采取OVERSAMPLING的方法,即过采样的技术,对发送来的数据进行多次采样取其平均值的方法解决了该问题。
5.3存在的不足及改进思路
1,因为验证环境有限,对于该模块的数据准确度还有待验证。
改进思路:
对于该模块编写一个专门验证的程序,即特色的编辑,以验证其正确性。
5.4心得体会
这次实验对比上学期的实验有了很大的进步,这跟知识的积累和练习是分不开的。
这个设计我采用比较正规的方式,在确定方案前,先去查找相关的资料,从懵懵懂懂的SPI到精确掌握其中的协议规则。
查找到了模块化设计的方法。
确定了从上到下的设计方式。
规划好各个模块及输入输出端后,就开始了各个模块VHDL源程序编写。
最综合处了整个系统。
在这次设计中我积极的向同学,老师请教,比如波特率问题,过采样问题,数据收发不同步问题,验证问题,特色编辑问题等,避免走了弯路。
整个流程下来真的锻炼了我们独立设计的能力和团队协作的能力。
最终看到了预想中的结果。
这是确实令人高兴的。
当然这次设计还存在些不足,就是仿真方面有点问题没有解决就在硬件上验证和修改了。
相对来说,在硬件上验证比较直观的找出问题所在。
还需在软件平台上编写特色的编辑,验证其真正的正确性。
这些都得在以后的学习工作中注意。
参考文献
[1]PIC单片机原理及应用(理解SPI原理)
[2]FPGA与VHDL设计与实践——MAX+plusⅡ与QuartusⅡ双剑合璧
国防工业出版社
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 VHDL 串行 同步 通信 SPI 设计