• 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 

     

     

  • 相关阅读:
    Zabbix5 Frame 嵌套
    Zabbix5 对接 SAML 协议 SSO
    CentOS7 安装 Nexus
    CentOS7 安装 SonarQube
    GitLab 后台修改用户密码
    GitLab 查看版本号
    GitLab Admin Area 500 Error
    Linux 安装 PostgreSQL
    Liger ui grid 参数
    vue.js 是一个怪东西
  • 原文地址:https://www.cnblogs.com/kongqiweiliang/p/3484379.html
Copyright © 2020-2023  润新知