zoukankan      html  css  js  c++  java
  • SPI总线协议及SPI时序图详解

     SPI,是英语Serial Peripheral Interface的缩写,是串行外围设备接口,高速的,全双工,同步的通信总线,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。

    上升沿发送、下降沿接收、高位先发送。

    上升沿到来的时候,sdo上的电平将被发送到从设备的寄存器中。

    下降沿到来的时候,sdi上的电平将被接收到主设备的寄存器中。

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

    SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。

    时钟极性(CPOL)

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

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

             时钟相位(CPHA)

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

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

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

     

    CPOL是用来决定SCK时钟信号空闲时的电平,

             CPOL=0,空闲电平为低电平,

             CPOL=1时,空闲电平为高电平。

    CPHA是用来决定采样时刻的,

             CPHA=0,在每个周期的第一个时钟沿采样,

             CPHA=1,在每个周期的第二个时钟沿采样。

    工作在模式0这种时序(CPOL=0,CPHA=0),只关注模式0的时序。

      

    /*********************************************************************************
    * Company                    : 
    * Engineer                    :     空气微凉
    * 
    * Create Date                :     00:00:00 22/03/2013 
    * Design Name                : 
    * Module Name                :         
    * Project Name                :  
    * Target Devices            : 
    * Tool versions            : 
    * Description                :  
    *                                   http://www.cnblogs.com/kongqiweiliang/             
    * Dependencies                : 
    *
    * Revision                    : 
    * Revision                    :     0.01 - File Created
    * Additional Comments    : 
    ********************************************************************************/
    `timescale 1ns/100ps
    `define    UD  #1
    /*******************************************************************************/
    module SPI    
    ( 
        //system interface
        input                                             iCLK                ,/* 50MHz */
        input                                             iRST                 ,/* system interface */
        //Interface package
        input                                             iSPI_TX_EN        ,/* SPI数据发送使能信号,高有效 */
        input                                             iSPI_RX_EN        ,/* SPI数据接收使能信号,高有效 */
        output                                        oSPI_TX_RDY        ,/* SPI数据发送完成标志位,高有效 */
        output                                        oSPI_RX_RDY        ,/* SPI数据接收完成标志位,高有效 */
        input                                [7:0]        iSPI_TX_DAT        ,/* SPI数据发送寄存器 */
        output    reg                    [7:0]        oSPI_RX_DAT        ,/* SPI数据接收寄存器 */
        //hardware interface
        input                                            iSPI_MISO        ,/* SPI主机输入从机输出数据信号 */
        output    reg                                oSPI_MOSI        ,/* SPI主机输出从机输入数据信号 */
        output    reg                                oSPI_CLK             /* SPI时钟信号,由主机产生 */
    );  
    //-------------------------------------------------------------------------------
    //        SPI主机接收发送模块,模拟SPI的时序模式为CPOL=1, CPHA=1,模拟速率为25Mbit
    //            时钟极性(CPOL) 
    //               如果CPOL=0,串行同步时钟的空闲状态为低电平;
    //               如果CPOL=1,串行同步时钟的空闲状态为高电平。
    //            时钟相位(CPHA)
    //                如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;
    //                如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。 
    //-------------------------------------------------------------------------------
    /* SPI时序控制计数器,所有SPI时序由该计数器值控制 */
    reg    [4:0]        timer0_count;
    
    /* SPI时序控制计数器 */
    always@(posedge iCLK or negedge iRST)begin
        if(!iRST)
            timer0_count <= 0;
        else if(timer0_count == 5'd18)
            timer0_count <= 0;
        else if((iSPI_TX_EN == 1'b1) || (iSPI_RX_EN == 1'b1))
            timer0_count <= timer0_count + 1'b1;
    end
    
    /* SPI时钟信号,由主机产生 */
    always@(posedge iCLK or negedge iRST)begin
        if(!iRST)
            oSPI_CLK <= 1'b1;
        else begin
            case(timer0_count)
                    5'd2    : oSPI_CLK <= 1'b0;/* 第1个周期 */
                    5'd3    : oSPI_CLK <= 1'b1;
                    5'd4    : oSPI_CLK <= 1'b0;/* 第2个周期 */
                    5'd5    : oSPI_CLK <= 1'b1;
                    5'd6    : oSPI_CLK <= 1'b0;/* 第3个周期 */
                    5'd7    : oSPI_CLK <= 1'b1;  
                    5'd8    : oSPI_CLK <= 1'b0;/* 第4个周期 */
                    5'd9    : oSPI_CLK <= 1'b1;
                    5'd10    : oSPI_CLK <= 1'b0;/* 第5个周期 */
                    5'd11    : oSPI_CLK <= 1'b1;
                    5'd12    : oSPI_CLK <= 1'b0;/* 第6个周期 */
                    5'd13    : oSPI_CLK <= 1'b1;
                    5'd14    : oSPI_CLK <= 1'b1;/* 第7个周期 */
                    5'd15    : oSPI_CLK <= 1'b1;
                    5'd16    : oSPI_CLK <= 1'b0;/* 第8个周期 */
                    5'd17    : oSPI_CLK <= 1'b1;
                default    : oSPI_CLK <= 1'b1;
            endcase
        end
    end
    
    /* SPI主机输出数据控制 */
    always@(posedge iCLK or negedge iRST)begin
        if(!iRST)
            oSPI_MOSI <= 1'b1;
        else if(iSPI_TX_EN == 1'b1)
            case(timer0_count[4:1])
                5'd1        : oSPI_MOSI <= iSPI_TX_DAT[7]; /* bit7 */
                5'd2        : oSPI_MOSI <= iSPI_TX_DAT[6]; /* bit6 */
                5'd3        : oSPI_MOSI <= iSPI_TX_DAT[5]; /* bit5 */
                5'd4        : oSPI_MOSI <= iSPI_TX_DAT[4]; /* bit4 */
                5'd5        : oSPI_MOSI <= iSPI_TX_DAT[3]; /* bit3 */
                5'd6        : oSPI_MOSI <= iSPI_TX_DAT[2]; /* bit2 */
                5'd7        : oSPI_MOSI <= iSPI_TX_DAT[1]; /* bit1 */
                5'd8        : oSPI_MOSI <= iSPI_TX_DAT[0]; /* bit0 */
                default    : oSPI_MOSI <= 1'b1;
            endcase
        else
            oSPI_MOSI <= 1'b1;
    end
    
    /* SPI数据发送完成标志位,高有效 */
    assign oSPI_TX_RDY = (timer0_count == 5'd18) ? 1'b1 : 1'b0;
    
    /* SPI主机输入数据控制 */
    always@(posedge iCLK or negedge iRST)begin
        if(!iRST)
            oSPI_RX_DAT <= 0;
        else if(iSPI_RX_EN == 1'b1)
            case(timer0_count)
                5'd3        : oSPI_RX_DAT[0] <= iSPI_MISO; /* bit0 */ 
                5'd5        : oSPI_RX_DAT[1] <= iSPI_MISO; /* bit1 */ 
                5'd7        : oSPI_RX_DAT[2] <= iSPI_MISO; /* bit2 */ 
                5'd9        : oSPI_RX_DAT[3] <= iSPI_MISO; /* bit3 */ 
                5'd11        : oSPI_RX_DAT[4] <= iSPI_MISO; /* bit4 */ 
                5'd13        : oSPI_RX_DAT[5] <= iSPI_MISO; /* bit5 */ 
                5'd15        : oSPI_RX_DAT[6] <= iSPI_MISO; /* bit6 */ 
                5'd17        : oSPI_RX_DAT[7] <= iSPI_MISO; /* bit7 */ 
                default    : oSPI_RX_DAT    <= 8'hff;
            endcase
    end
    /* SPI数据接收完成标志位,高有效 */
    assign oSPI_RX_RDY = (timer0_count == 5'd18) ? 1'b1 : 1'b0;
    //-------------------------------------------------------------------------------
    endmodule 

     

     

  • 相关阅读:
    list去重
    安装go与nebula-importer遇见的问题
    2.安装docker后运行其他镜像
    2.绝对路径Linux和Windows上的写法
    1.SpringBoot 读取配置文件的值 赋给静态变量
    04747JAVA语言程序设计练习题(第一章)
    Revit文件加载到arcgis pro中调整位置并生成slpk包
    新部署arcgis javascript api 服务器添加的两个mime
    转发博客园中的文章
    【转】使用ArcGIS Pro编辑在线三维服务图层
  • 原文地址:https://www.cnblogs.com/kongqiweiliang/p/3484379.html
Copyright © 2011-2022 走看看