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 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM