基于FPGA的SPI控制器.docx

上传人:b****5 文档编号:4045430 上传时间:2022-11-27 格式:DOCX 页数:10 大小:188.11KB
下载 相关 举报
基于FPGA的SPI控制器.docx_第1页
第1页 / 共10页
基于FPGA的SPI控制器.docx_第2页
第2页 / 共10页
基于FPGA的SPI控制器.docx_第3页
第3页 / 共10页
基于FPGA的SPI控制器.docx_第4页
第4页 / 共10页
基于FPGA的SPI控制器.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

基于FPGA的SPI控制器.docx

《基于FPGA的SPI控制器.docx》由会员分享,可在线阅读,更多相关《基于FPGA的SPI控制器.docx(10页珍藏版)》请在冰豆网上搜索。

基于FPGA的SPI控制器.docx

基于FPGA的SPI控制器

基于FPGA的SPI控制器

一 SPI协议概括

SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。

是Motorola首先在其MC68HCXX系列处理器上定义的。

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位数据的传输。

 

要注意的是,SCK信号线只由主设备控制,从设备不能控制信号线。

同样,在一个基于SPI的设备中,至少有一个主控设备。

这样传输的特点:

这样的传输方式有一个优点,与普通的串行通讯不同,普通的串行通讯一次连续传送至少8位数据,而SPI允许数据一位一位的传送,甚至允许暂停,因为SCK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据。

也就是说,主设备通过对SCK时钟线的控制可以完成对通讯的控制。

SPI还是一个数据交换协议:

因为SPI的数据输入和输出线独立,所以允许同时完成数据的输入和输出。

不同的SPI设备的实现方式不尽相同,主要是数据改变和采集的时间不同,在时钟信号上沿或下沿采集有不同定义,具体请参考相关器件的文档。

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

在多个从设备的系统中,每个从设备需要独立的使能信号,硬件上比I2C系统要稍微复杂一些。

最后,SPI接口的一个缺点:

没有指定的流控制,没有应答机制确认是否接收到数据。

AT91RM9200的SPI接口主要由4个引脚构成:

SPICLK、MOSI、MISO及 /SS,其中SPICLK是整个SPI总线的公用时钟,MOSI、MISO作为主机,从机的输入输出的标志,MOSI是主机的输出,从机的输入,MISO 是主机的输入,从机的输出。

/SS是从机的标志管脚,在互相通信的两个SPI总线的器件,/SS管脚的电平低的是从机,相反/SS管脚的电平高的是主机。

在一个SPI通信系统中,必须有主机。

SPI总线可以配置成单主单从,单主多从,互为主从。

SPI的片选可以扩充选择16个外设,这时PCS输出=NPCS,说NPCS0~3接4-16译码器,这个译码器是需要外接4-16译码器,译码器的输入为NPCS0~3,输出用于16个外设的选择。

二 SPI协议举例

SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。

       假设下面的8位寄存器装的是待发送的数据10101010,上升沿发送、下降沿接收、高位先发送。

       那么第一个上升沿来的时候 数据将会是sdo=1;寄存器=0101010x。

下降沿到来的时候,sdi上的电平将所存到寄存器中去,那么这时寄存器=0101010sdi,这样在 8个时钟脉冲以后,两个寄存器的内容互相交换一次。

这样就完成里一个spi时序。

举例:

      假设主机和从机初始化就绪:

并且主机的sbuff=0xaa,从机的sbuff=0x55,下面将分步对spi的8个时钟周期的数据情况演示一遍:

假设上升沿发送数据 

这样就完成了两个寄存器8位的交换,上面的上表示上升沿、下表示下降沿,sdi、sdo相对于主机而言的。

其中ss引脚作为主机的时候,从机可以把它拉底被动选为从机,作为从机的是时候,可以作为片选脚用。

根据以上分析,一个完整的传送周期是16位,即两个字节,因为,首先主机要发送命令过去,然后从机根据主机的命令准备数据,主机在下一个8位时钟周期才把数据读回来。

      SPI 总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:

一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于CPU与各种外围器件进行全双工、同步串行通讯。

SPI主要特点有:

可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束 中断标志;写冲突保护;总线竞争保护等。

下图示出SPI总线工作的四种方式,其中使用的最为广泛的是SPI0和SPI3方式 (实线表示):

                    

                            

                                                    

                                                                                               SPI总线四种工作方式 

SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。

如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。

时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。

如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

SPI主模块和与之通信的外设备时钟相位和极性应该一致。

SPI总线包括1根串行同步时钟信号线以及2根数据线。

       SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。

如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。

时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。

如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

SPI主模块和与之通信的外设音时钟相位和极性应该一致。

SPI接口时序如图3、图4所示。

补充:

 

上文中最后一句话:

SPI主模块和与之通信的外设备时钟相位和极性应该一致。

个人理解这句话有2层意思:

其一,主设备SPI时钟和极性的配置应该由外设来决定;其二,二者的配置应该保持一致,即主设备的SDO同从设备的SDO配置一致,主设备的SDI同从设备的SDI配置一致。

因为主从设备是在SCLK的控制下,同时发送和接收数据,并通过2个双向移位寄存器来交换数据。

工作原理演示如下图:

上升沿主机SDO发送数据1,同时从设备SDO发送数据0;紧接着在SCLK的下降沿的时候从设备的SDI接收到了主机发送过来的数据1,同时主机也接收到了从设备发送过来的数据0.

三 FPGA实现源码

LIBRARYieee;

USEieee.std_logic_1164.ALL;

USEieee.std_logic_arith.ALL;

USEieee.std_logic_unsigned.ALL;

ENTITYspiIS

 PORT

 (

  --全局信号

  NReset   :

IN  STD_LOGIC;        --全局复位信号

  Clk    :

IN  STD_LOGIC;        --全局时钟

--  ResetWdi  :

BUFFER STD_LOGIC;        --看门狗的喂狗信号

  --SPI通讯端口

  SPINcs   :

INOUT  STD_LOGIC;        --SPI片选(低有效)

  SPIClk   :

INOUT  STD_LOGIC;        --SPI时钟

  SPIMOSI   :

INOUT  STD_LOGIC;        --SPI的主出从入

  SPIMISO   :

INOUT  STD_LOGIC;        --SPI的主入从出

  --SPI数据寄存器

  SPITxdata  :

IN  STD_LOGIC_VECTOR(15DOWNTO0);   --待发送数据

  SPIRxdata  :

BUFFER STD_LOGIC_VECTOR(15DOWNTO0);   --接收数据

  --SPI状态寄存器

  SPIStatus  :

BUFFER STD_LOGIC_VECTOR(7DOWNTO0);   --第5位为trdy(发送器准备好),第6位rrdy(接收器准备好)

  --SPI控制寄存器

  SPIControl  :

IN  STD_LOGIC_VECTOR(7DOWNTO0);   --第0位为mode(模式设置,0为主模式,1为从模式),

                   --第1位为clkpolarity(时钟极性,0时为空闲是低,1为空闲是高),

                   --第2位为clkphasic(时钟相位,0时为前沿检测,1为后沿检测),

                   --第3位为datapriority(数据先后,0时为MSB在前,1为LSB在前),

                   --第4位为start(上升沿开始发送数据),

                   --第7位sso(1时始终置cs为1(无效))

  SPILength  :

IN  STD_LOGIC_VECTOR(7DOWNTO0);   --数据位数寄存器

  --SPI频率设置寄存器

  SPISetClk  :

IN  STD_LOGIC_VECTOR(31DOWNTO0)   --SPIClk为Clk的SPISetClk分频

 );

ENDspi;

ARCHITECTURErtlOFspiIS

 TYPEStateTypeIS(S0_Wait,S1_Data,S2_Stop);       --状态机定义

 SIGNAL StateIndex  :

 StateType;         --状态机

 SIGNAL CntCycle  :

 integerRANGE0TO16383;     --位周期计数器

 SIGNAL CntBit   :

 integerRANGE0TO15;      --位数计数器

 SIGNAL SPITxdataTmp :

 STD_LOGIC_VECTOR(15DOWNTO0);    --数据锁存

 SIGNAL CycleBit  :

 integerRANGE0TO16383;     --位周期

 

 SIGNAL SPIClkCut  :

 STD_LOGIC_VECTOR(31DOWNTO0);   --生成SPIClk计数器

 SIGNAL SPIBitCut  :

 integerRANGE0TO15;     --SPI的数据位数计数

 --看门狗计数

-- SIGNAL CntWdi   :

 STD_LOGIC_VECTOR(9DOWNTO0);

BEGIN

--看门狗的喂狗信号的产生

--CntWdi<=CntWdi+1WHEN(Clk'EVENTANDClk='1');

--ResetWdi<=CntWdi(9);

--设置SPI的主从模式,若为主模式则设置SPINcs和SPIClk

PROCESS(NReset,Clk)

BEGIN

 IF(NReset='0')THEN     --复位状态

  SPINcs<='Z';

  SPIClk<='Z';

  SPIMOSI<='Z';

  SPIMISO<='Z';

  SPIStatus<="01100000";

  SPIRxdata<=X"0000";

  StateIndex<=S0_Wait;

  SPIClkCut<=X"00000000";

  SPIBitCut<=0;

 ELSIF(Clk'EVENTANDClk='1')THEN

  IF(SPIControl(0)='0')THEN   --主模式状态

   SPIMISO<='Z';

   CASEStateIndexIS

    WHENS0_Wait=>

     SPIClk<=SPIControl

(1);

     IF(SPIControl(4)='1') THEN --判断起始标志

      SPINcs<=SPIControl(7);

      IF(SPIControl(3)='0')THEN  --判断数据MSB还是LSB在前

       SPIMOSI<=SPITxdata(CONV_INTEGER(SPILength)-1);

      ELSE

       SPIMOSI<=SPITxdata(0);

      ENDIF;

      SPIRxdata<=X"0000";

      StateIndex<=S1_Data;

      SPIStatus<="00000000";

     ELSE

      SPINcs<='1';

      SPIMOSI<='0';

      StateIndex<=StateIndex;

      SPIStatus<="01100000";

     ENDIF;

     SPIBitCut<=0;

     SPIClkCut<=X"00000000";     

    WHENS1_Data=>

     SPINcs<=SPIControl(7);

     IF(SPIClkCut =('0'&SPISetClk(31DOWNTO1)-'1'))THEN --SPIClk前沿

      SPIClk<=NOTSPIClk;

      SPIClkCut<=SPIClkCut+1;

      IF(SPIControl

(2)='0')THEN   --前沿检测

       SPIMOSI<=SPIMOSI;

       IF(SPIControl(3)='0')THEN  --判断数据MSB还是LSB在前

        SPIRxdata<=SPIRxdata;

        SPIRxdata(CONV_INTEGER(SPILength)-SPIBitCut-1)<=SPIMISO;

       ELSE

        SPIRxdata<=SPIRxdata;

        SPIRxdata(SPIBitCut)<=SPIMISO;

       ENDIF;

      ELSE         --后沿检测

       IF(SPIControl(3)='0')THEN  --判断数据MSB还是LSB在前

        SPIMOSI<=SPITxdata(CONV_INTEGER(SPILength)-SPIBitCut-1);

       ELSE

        SPIMOSI<=SPITxdata(SPIBitCut);

       ENDIF;

       SPIRxdata<=SPIRxdata;

      ENDIF;

      StateIndex<=StateIndex;

      SPIBitCut<=SPIBitCut;

     ELSIF(SPIClkCut>=(SPISetClk(31DOWNTO0)-'1'))THEN  --SPIClk后沿

      SPIClk<=NOTSPIClk;

      SPIClkCut<=X"00000000";

      IF(SPIControl

(2)='0')THEN   --前沿检测

       IF(SPIControl(3)='0')THEN  --判断数据MSB还是LSB在前

        SPIMOSI<=SPITxdata(CONV_INTEGER(SPILength)-SPIBitCut-2);

       ELSE

        SPIMOSI<=SPITxdata(SPIBitCut);

       ENDIF;

       SPIRxdata<=SPIRxdata;       

      ELSE         --后沿检测

       SPIMOSI<=SPIMOSI;

       IF(SPIControl(3)='0')THEN  --判断数据MSB还是LSB在前

        SPIRxdata<=SPIRxdata;

        SPIRxdata(CONV_INTEGER(SPILength)-SPIBitCut-1)<=SPIMISO;

       ELSE

        SPIRxdata<=SPIRxdata;

        SPIRxdata(SPIBitCut)<=SPIMISO;

       ENDIF;

      ENDIF;

      IF(SPIBitCut>=CONV_INTEGER(SPILength)-1)THEN

       SPIBitCut<=0;

       SPIMOSI<=SPIMOSI;

       StateIndex<=S2_Stop;

      ELSE

       SPIBitCut<=SPIBitCut+1;

       StateIndex<=StateIndex;

      ENDIF;

     ELSE

      SPIClk<=SPIClk;

      SPIMOSI<=SPIMOSI;

      StateIndex<=StateIndex;

      SPIClkCut<=SPIClkCut+1;

      SPIBitCut<=SPIBitCut;

      SPIRxdata<=SPIRxdata;

     ENDIF;

     SPIStatus<="00000000";

    WHENS2_Stop=>

     IF(SPIClkCut =('0'&SPISetClk(31DOWNTO1)-'1'))THEN

      StateIndex<=S0_Wait;

      SPIClkCut<=X"00000000";

     ELSE

      StateIndex<=StateIndex;

      SPIClkCut<=SPIClkCut+1;

     ENDIF;

     SPINcs<=SPINcs;

     SPIClk<=SPIClk;

     SPIMOSI<=SPIMOSI;

     SPIStatus<=SPIStatus;

     SPIRxdata<=SPIRxdata;

     SPIBitCut<=0;

    WHENOTHERS=>

     SPINcs<='Z';

     SPIClk<='Z';

     SPIMOSI<='Z';

     SPIStatus<="01100000";

     SPIRxdata<=X"0000";

     StateIndex<=S0_Wait;

     SPIClkCut<=X"00000000";

     SPIBitCut<=0;

   ENDCASE;

  ELSE         --从模式状态

   SPINcs<='Z';

   SPIClk<='Z';

   SPIMOSI<='Z';

  ENDIF; 

 ENDIF;

ENDPROCESS;

ENDrtl;

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

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

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

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