一 SPI介绍
SPI(Serial Peripheral Interface,串行外围设备接口)通讯协议,是Motorola公司提出的一种同步串 行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,广 泛用于 EEPROM、Flash、RTC(实时时钟)、ADC(数模转换 器)、DSP(数字信号处理器)以及数字信号解码器上,是常用的、重要的低速通讯协议之一。
二 SPI四线
1:CS/SS(Slave Select/Chip Select),这个是片选信号线,用于选择需要进行通信的从设备。I2C通信时通过主机发送从机设备地址来选择需要进行通信的从机设备,而 SPI 主机不需要发送从机设备,直接将相应的从机设备片选信号拉低即可。(片选信号是低电平有效)
2:SCK(Serial Clock),串行时钟,和 I2C 的 SCL 一样,为 SPI 通信提供时钟。
3:MOSI/SDO(Master Out Slave In/Serial Data Output)简称主出从入信号线,这根数据线只能用于主机向从机发送数据,也就是主机输出,从机输入。
4:MISO/SDI(Master In Slave Out/Serial Data Input)简称主入从出信号线,这根数据线只能用户从机向主机发送数据,也就是主机输入,从机输出。
三 SPI特点
SPI 作为一种经典的同步串行通信协议,具有以下几个显著特点:
1. 高速传输:SPI 没有像 I2C 那样的应答机制和地址帧开销,通信速率仅受限于从设备的最高工作频率和主设备的时钟产生能力,因此可以达到很高的数据传输速率,通常远高于 I2C 和 UART。
2. 全双工通信:SPI 采用主出从入(MOSI)和主入从出(MISO)两根独立的数据线,主机发送数据的同时可以接收从机返回的数据,实现真正的全双工同步传输,收发互不干扰。
3. 同步串行通信:SPI 依靠串行时钟线(SCK)来同步数据的发送与接收,所有数据位都在时钟沿的驱动下逐位传输,不需要额外的起始位、停止位和校验位,协议开销小、时序清晰。
4. 主从结构,一主多从:SPI 总线采用主从架构,由主机产生时钟并控制整个通信过程。主机通过独立的片选信号(CS/SS)来选择目标从设备,可以挂接多个从设备,且从设备之间互不干扰。
5. 接口简单,占用管脚少:SPI 通信仅需 SCK、MOSI、MISO、CS 四根信号线即可完成数据交互(若只做单向传输还可进一步减少),相比并行总线大大节省了芯片管脚资源。
6. 无设备地址,片选寻址:与 I2C 通过发送从机地址寻址不同,SPI 直接通过拉低对应从机的片选信号来选择通信对象,寻址方式简单直接,无需在数据帧中携带地址信息。
7. 协议灵活,模式可配置:通过配置时钟极性(CPOL)和时钟相位(CPHA),SPI 可以组合出四种工作模式,能够灵活适配不同从设备的时序要求,兼容性强。
8. 无应答机制,可靠性依赖约定:SPI 本身不包含应答和错误检测机制,通信是否成功需要由主从双方通过协议约定或软件方式(如 CRC 校验、超时判断)来保证,这是其与 I2C 的一个重要区别。
四时钟极性和时钟相位
五 工作模式
根据时钟的极性以及相位可以分为4种工作模式:
六 代码编写
6.1接口分析
默认4线:SCK,MOSI,MISO,CS_n.
发送或者接受完成,以及SPI完成后产生的done信号:done_r,done_w,done_spi;
总数据量,发送数据量:data_len,wr_len;
输入数据,输出数据:data_i_spi,data_o_spi,(分别是需要发送的数据,以及接受到的数据)
工作开始信号:start_spi
6.2状态分析:
根据时序图:可以分为4种状态:空闲态,START,DATA,STOP。
空闲态:用来检测开始信号,检测到开始信号上升沿跳转到START
STATR:(拉低片选)。
,DATA:(发送数据与接受数据)。
STOP:将片选拉高。
6.3部分代码分析:
6.3.1 bit计数器与分频计数器;
分频计数器:选择6分频,
bit计数器最大值:data_len*8-1;
6.3.2开始信号寄存
通过寄存开始信号,可以选择在上升沿触发开始(start_reg==01),或者下降沿触发开始(start_reg==10),亦或是高电平(11)或者低电平00作为开始信号。
6.3.3发送数据与接收数据的时序分析
根据模式选择的不同,采样数据与接收数据需要根据模式来调整时序,
七 仿真结果
7.1仿真代码
`timescale 1ns/1ps module test(); reg clk ; reg rst_n ; reg start_spi ; reg [7:0] data_i_spi ; wire [7:0] data_o_spi ; wire done_r ; wire done_w ; wire done_spi ; wire SCK ; wire MOSI ; wire CS_n ; always #10 clk=~clk; initial begin clk=0; rst_n=1; start_spi=0; #20 rst_n=0; #20 rst_n=1; #20 start_spi=1; #20 start_spi=0; #20000 $stop; end always @(posedge clk or negedge rst_n) begin if(!rst_n) data_i_spi<=8'haa; else if(done_w||done_r) data_i_spi<=data_i_spi+8'h11; end SPI_master SPI_master_tb( .clk (clk ), .rst_n (rst_n ), .start_spi (start_spi ), .data_i_spi (data_i_spi ), .data_o_spi (data_o_spi ), .data_len (5 ), .wr_lenth (3 ), .done_r (done_r ), .done_w (done_w ), .done_spi (done_spi ), .SCK (SCK ), .MOSI (MOSI ), .CS_n (CS_n ), .MISO (MOSI ) ); endmodule7.2结果
与预想结果一致