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