浅谈 SPI 总线协议

简介

SPI总线是Motorola公司推出的三线同步接口,同步串行三线方式进行通信:一条时钟线SCK,一条数据输出线MOSI(Master Output Slave Input),一条数据输入线MISO(Master Input Slave Output)。SPI是Serial Peripheral Interface的缩写。

SPI是全双工的,一般用于单主机(Master)的场合。SPI总线上的从机(Slave)没有地址的概念,主机只能通过与从机连接的片选线(CS/SS)**一个从机,进行数据传输。所以从机越多,带来的不便就是片选线相应增多。

SPI一般用于片间传输,不适合用于设备间数据传输,Motorola白皮书没有明确规定SPI的传输距离。但是根据经验,考虑干扰和高速带来的不可靠性,最好保持在50CM内。传输速率上,已知的有的器件SPI已达到50Mbps,一般也能达到5Mbps左右,总体来说比IIC要快。在无人机应用上,SPI一般用于云台的IMU与MCU的数据传输,因为云台尤其是搭载高倍变焦的相机的云台需要更高的实时性,而飞控的IMU用IIC总线或者CAN总线就能满足要求。


硬件连接

浅谈 SPI 总线协议

主机和从机通过上图的方式接入总线,前面说到,每个从机都有一条片选线与主机相连,就是上图的CS线。其中SCK的时钟信号由主机产生。


通讯过程

1)预设置

主机通过把对应的片选线置低来选择对应的从机,如把与一号从机连接的片选线置低表示与一号从机通信。发送接收的过程按照SCK时钟线的节奏进行。

初始化时需要先设置时钟相位(CPHA)和时钟极性(CPOL):

  1. CPHA:时钟相位,表示SPI设备是在SCK的时钟信号变为上升沿时触发数据采样,还是在下降沿时触发数据采样。若CPHA被设置为1,数据发送发生在时钟从有效状态转到空闲状态的那一时刻,数据接收发生在时钟从空闲状态转到有效状态的那一时刻。这里空闲和有效对应是高电平或低电平与CPOL的设置有关。
  2. CPOL:时钟极性,表示SPI在空闲时,时钟信号是高电平还是低电平。若CPOL被设为1,那么该设备在空闲时SCK的时钟信号为高电平。

浅谈 SPI 总线协议

2)数据交换

下图中的SSPBUF(Synchronous Serial Port Buffer)指SPI设备里面的内部缓冲区,一般在物理上是以FIFO的形式,保存传输过程中的临时数据。SSPSR是SPI设备内部的移位寄存器(Shift Register),它的主要作用是根据SPI时钟信号状态,往SSPBUF里移入或者移出数据,每次移动的数据大小由Bus-Width以及Channel-Width所决定。

Bus-Width的作用是指定地址总线到Master之间数据传输的单位。
Channel-Width的作用是指定Master与Slave之间数据传输的单位。与Bus-Width相似,Master内部的移位寄存器会依据Channel-Width自动地把数据从SSPBUF里通过SDO搬运到Slave里的SDI,Slave的SSPSR再把每次接收的数据移入SSPBUF里。

浅谈 SPI 总线协议

通常情况下,Bus-Width总是会大于或等于 Channel-Width,这样能保证不会出现因Master与Slave之间数据交换的频率比地址总线与Master之间的数据交换频率要快,导致SSPBUF里面存放的数据为无效数据这样的情况。

我们知道,在每个时钟周期内,Master与Slave之间交换的数据其实都是SPI内部移位寄存器从SSPBUF里面拷贝的。我们可以通过往SSPBUF对应的寄存器(Tx-Data/Rx-Data Register)里读写数据,间接地操控SPI设备内部的SSPBUF。

举个例子,在发送数据之前,我们应该先往Master的Tx-Data寄存器写入将要发送出去的数据,这些数据会被SSPSR移位寄存器根据Bus-Width自动移入SSPBUF里,然后这些数据又会被SSPSR根据Channel-Width从SSPBUF中移出,通过Master的SDO管脚传给Slave的SDI管脚,Slave的SSPSR则把从SDI接收到的数据移入SSPBUF里。
与此同时,Slave的SSPBUF里面的数据根据每次接收数据的大小(Channel-Width),通过Slave的SDO发往Master的SDI,Master的SSPSR再把从SDI接收的数据移入SSPBUF。在单次数据传输完成之后,用户程序可以通过从Master设备的Rx-Data寄存器读取Master设备数据交换得到的数据。