【IC每日一题:SPI协议】
IC每日一题:SPI协议
【博客首发与微信公众号《漫谈芯片与编程》,欢迎专注一下】
本篇博客继续介绍IC低速串行传输协议–SPI;
SPI是一种同步、全双工、主从式接口;数据传输时高位在前,低位在后(MSB);
1 SPI协议
下面是两个芯片用SPI来进行通信,数据在clk上升沿或下降沿同步,主机和从机可以通过MOSI、MISO线路同时传输数据。
由图片可知有四根信号线,CS是片选信号端–因此支持单master多slave。
1.1 SPI四种传输模式
CPOL(时钟极性)和CPHA(时钟相位)来共同控制SPI的通信方式:
CPOL决定SPI总线空闲时SCLK的电平;(0:空闲状态时SCLK低电平,1:空闲状态时SCLK高电平);
CPHA决定数据是上升沿还是下降沿采样;(0:第一个沿采样,1:第二个沿采样);
具体四种通信模式:(最常用模式是0和3)
mode0:CPOL= 0,CPHA=0。SCLK串行时钟线空闲时为低电平,数据在SCK时钟的上升沿被采样,数据在SCK时钟的下降沿切换
mode1:CPOL= 0,CPHA=1。SCLK串行时钟线空闲时为低电平,数据在SCK时钟的下降沿被采样,数据在SCK时钟的上升沿切换
mode2:CPOL= 1,CPHA=0。SCLK串行时钟线空闲时为高电平,数据在SCK时钟的下降沿被采样,数据在SCK时钟的上升沿切换
mode3:CPOL= 1,CPHA=1。SCLK串行时钟线空闲时为高电平,数据在SCK时钟的上升沿被采样,数据在SCK时钟的下降沿切换
SPI总线在模式0下的时序图:
在空闲状态下,SCK串行时钟线为低电平,当SS被主机拉低以后,数据传输开始;
1时刻:CS由高变低,为SPI通信的起始标志,对应从机被选中;
6时刻:CS由低变高,通信结束标志,对应从机选中取消;
2时刻(偶数时刻):数据在上升沿采样,此时位于数据中间位置,最稳定。
3时刻(奇数时刻):数据在下降沿切换,便于在下一上升沿的时候数据能正确被采集。
2 代码demo
接下来SPI采用模式0,每次传输8bit,MSB现行;
module spi_module
(
input I_clk , // 全局时钟50MHz
input I_rst_n , // 复位信号,低电平有效
input I_rx_en , // 读使能信号
input I_tx_en , // 发送使能信号
input [7:0] I_data_in , // 要发送的数据
output reg [7:0] O_data_out , // 接收到的数据
output reg O_tx_done , // 发送一个字节完毕标志位
output reg O_rx_done , // 接收一个字节完毕标志位
// 四线标准SPI信号定义
input I_spi_miso , // SPI串行输入,用来接收从机的数据
output reg O_spi_sck , // SPI时钟
output reg O_spi_cs , // SPI片选信号
output reg O_spi_mosi // SPI输出,用来给从机发送数据
);
reg [3:0] R_tx_state ;
reg [3:0] R_rx_state ;
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_tx_state <= 4'd0 ;
R_rx_state <= 4'd0 ;
O_spi_cs <= 1'b1 ;
O_spi_sck <= 1'b0 ;
O_spi_mosi <= 1'b0 ;
O_tx_done <= 1'b0 ;
O_rx_done <= 1'b0 ;
O_data_out <= 8'd0 ;
end
else if(I_tx_en) // 发送使能信号打开的情况下
begin
O_spi_cs <= 1'b0 ; // 把片选CS拉低
case(R_tx_state)
4'd1, 4'd3 , 4'd5 , 4'd7 ,
4'd9, 4'd11, 4'd13, 4'd15 : //整合奇数状态
begin
O_spi_sck <= 1'b1 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd0: // 发送第7位
begin
O_spi_mosi <= I_data_in[7] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd2: // 发送第6位
begin
O_spi_mosi <= I_data_in[6] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd4: // 发送第5位
begin
O_spi_mosi <= I_data_in[5] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd6: // 发送第4位
begin
O_spi_mosi <= I_data_in[4] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd8: // 发送第3位
begin
O_spi_mosi <= I_data_in[3] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd10: // 发送第2位
begin
O_spi_mosi <= I_data_in[2] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd12: // 发送第1位
begin
O_spi_mosi <= I_data_in[1] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b0 ;
end
4'd14: // 发送第0位
begin
O_spi_mosi <= I_data_in[0] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state + 1'b1 ;
O_tx_done <= 1'b1 ;
end
default:R_tx_state <= 4'd0 ;
endcase
end
else if(I_rx_en) // 接收使能信号打开的情况下
begin
O_spi_cs <= 1'b0 ; // 拉低片选信号CS
case(R_rx_state)
4'd0, 4'd2 , 4'd4 , 4'd6 ,
4'd8, 4'd10, 4'd12, 4'd14 : //整合偶数状态
begin
O_spi_sck <= 1'b0 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
end
4'd1: // 接收第7位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[7] <= I_spi_miso ;
end
4'd3: // 接收第6位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[6] <= I_spi_miso ;
end
4'd5: // 接收第5位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[5] <= I_spi_miso ;
end
4'd7: // 接收第4位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[4] <= I_spi_miso ;
end
4'd9: // 接收第3位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[3] <= I_spi_miso ;
end
4'd11: // 接收第2位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[2] <= I_spi_miso ;
end
4'd13: // 接收第1位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b0 ;
O_data_out[1] <= I_spi_miso ;
end
4'd15: // 接收第0位
begin
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state + 1'b1 ;
O_rx_done <= 1'b1 ;
O_data_out[0] <= I_spi_miso ;
end
default:R_rx_state <= 4'd0 ;
endcase
end
else
begin
R_tx_state <= 4'd0 ;
R_rx_state <= 4'd0 ;
O_tx_done <= 1'b0 ;
O_rx_done <= 1'b0 ;
O_spi_cs <= 1'b1 ;
O_spi_sck <= 1'b0 ;
O_spi_mosi <= 1'b0 ;
O_data_out <= 8'd0 ;
end
end
endmodule
以上是简单的SPI模式0下的传输8bit时序的demo,没有起始位、校验位和停止位等;
【REF】
1.https://blog.csdn.net/H19981118/article/details/125666438
2.https://www.cnblogs.com/liujinggang/p/9609739.html
原文地址:https://blog.csdn.net/li_kin/article/details/143631812
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!