SPI,是英語Serial Peripheral Interface的縮寫,是串行外圍設備接口,高速的,全雙工,同步的通訊總線,由ss(cs)、sck、sdi、sdo構成,其時序其實很簡單,主要是在sck的控制下,兩個雙向移位寄存器進行數據交換。編程
上升沿發送、降低沿接收、高位先發送。spa
上升沿到來的時候,sdo上的電平將被髮送到從設備的寄存器中。code
降低沿到來的時候,sdi上的電平將被接收到主設備的寄存器中。blog
SPI主要特色有:能夠同時發出和接收串行數據;能夠看成主機或從機工做;提供頻率可編程時鐘;發送結束中斷標誌;寫衝突保護;總線競爭保護等。接口
SPI總線有四種工做方式(SP0, SP1, SP2, SP3),其中使用的最爲普遍的是SPI0和SPI3方式。ip
時鐘極性(CPOL)ci
若是CPOL=0,串行同步時鐘的空閒狀態爲低電平;get
若是CPOL=1,串行同步時鐘的空閒狀態爲高電平。input
時鐘相位(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