Lecture 10 : Serial Peripheral Interface (SPI)
什么是通讯协议
当我们连接一个微处理器和外设(比如传感器,屏幕等设备)的时候,微处理器需要通过特定的方式与外设模块进行通信。传感器可能通过私有的编码方式将数据传输给微处理器,可能返回模拟信号,也可能通过这一章将要讲的这些通讯协议的方式进行通信。
在单片机上,常用的通讯协议有 UART(串口),SPI,I2C,CAN(这里不考这个)
需要注意的是,这些常用的通讯协议往往慢于我们现在常用的协议,比如 USB(通用串行总线),Ethernet(以太网),Bluetooth(蓝牙)以及 Wi-Fi。他们的主要特点是简单,易于实现,并且不需要很多的外设来实现这些协议的功能。准确的说,你甚至可以只使用 GPIO 来软件模拟这些通讯协议。
因此,SPI,I2C 和 UART 时多个微控制器以及控制器与传感器之间高速传输信息的通讯协议的理想选择
为什么选择串行总线
并行总线的速度更快,同一时间可以发送的数据更多,但是需要更多的线的数量和引脚的数量,并且有比较严格的时序要求,也需要严密的解码逻辑。也是因为这一点,并行总线往往并不能做到较长距离的信号传输。
串行总线虽然牺牲了传输的效率,但是节省了连接所需要的线数,降低了成本。如果要连接两个设备,使用 SPI 只用链接四根线进行信号传输,而 I2C 只需要两根即可。
什么是 SPI
SPI,即 大豆分离蛋白(Soy Protein Isolate) 串行外设接口(Serial Peripheral Interface),是一种常用的通讯协议。它是一种同步的串行通讯协议,以全双工模式运行(如果 MISO 和 MOSI 线都进行连接)
对于典型的 SPI 连接,其整体由一个主机(Master)和一个乃至若干个从机(Slave)组成。主机和从机的 MOSI 线、MISO 线和 SCLK 线分别相连,形成三条总线,而 CS 线则在需要的时候依照目标设备调节电平高低。

SPI 的参数规格
| Data Type | Data | Description |
|---|---|---|
| Wires Used | 4 | 根据你设备数的上升,主设备可能需要更多的 SS/CS 线,但是对于每个从设备来说,与主设备连接的线数还是 4 |
| Maximum Speed | Up to 10 Mbps | 注意这里的速度指的是 SCLK 线的时钟速率 |
| Synchronous or Asynchronous? | Synchronous | 正如前文所说,SPI 是同步通讯协议。从主机提供 SCLK 线也可以看出来 |
| Serial of Parallel? | Serial | 正如前文所说,SPI 是串行的通讯协议 |
| Max # of Masters | 1 | 只有一台主机 |
| Max # of Slaves | Theoretically unlimited | 理论上无限制,但实际数量受限于主机的 SS/CS 引脚数量、总线驱动能力以及信号完整性等因素 |
引脚介绍
SCLK(Serial Clock)
SCLK,即为时钟线,由主机发出,给整个总线提供时钟信号。所有的设备通过主机提供的时钟信号进行运行。
在典型的 SPI 传输场景中,SCLK 时钟线只有在数据传输的时候才向外发送时钟信号,而在总线空闲的时候处于不工作状态。
在工作状态中,时钟信号会以周期的形式向外发送,一个时钟周期向外传输或者向内接受一位的信息。
时钟信号的参数可以根据设备类型调整,如 CPOL(Clock Polarity,时钟极性)和 CPHA(Clock Phase,时钟相位)两个参数,其中 CPOL 决定了时钟线在空闲的情况下的电平高低,CPHA 决定了设备在时钟的上升沿韩式下降沿进行数据读取以及发送。
你在实际使用中使用什么样的参数,往往由你选择的设备的数据手册决定。

简单来说,CPHA 为 0 则在第一个上升/下降沿进行采样,为 1 则在第二个上升/下降沿进行采样。
需要注意的是,SCLK 信号虽然是时钟信号,但是并没有要求 SCLK 的周期是均匀的,也没有要求 SCLK 的信号的占空比。数据的传输只和 SCLK 的上升沿和下降沿相关。
MOSI(Master Out Slave In)
MOSI 线,即为主机向从机输出信息的线。MOSI 可以和 MISO 同时工作,也就是可以一边输入一边输出,也就是全双工。
当 MOSI 为高电平的时候,数据为 1;MOSI 为低电平的时候,数据为 0。
如同他的名字,MOSI 对于主机是输出线,而对于从机是需要读取的输入。
MISO(Master In Slave Out)
MISO 线,即从机向主机输出信息的线。MOSI 可以和 MISO 同时工作,也就是可以一边输入一边输出,也就是全双工。
如同他的名字,MOSI 对于从机是输出线,而对于主机是需要读取的输入。
在从机通过 MISO 传输数据的时候,主机仍然要提供 SCLK 的信号。
SS/CS(Slave Select / Chip Select)
SS/CS 线,一般被成为片选线,默认为高电平。从机没有被主机选中的时候,从机的 CS 被置为高电平,从机不响应总线上的信号;从机被选中后,CS 被置为低电平,告知从机被选中。之后,主机开始发送或者接收数据。在交互完成后,CS 被重新置为高电平。
因为所有设备都挂在在一条总线上,在主机开始数据传输时,应当先通过片选确定需要交互的设备。

对于一些设备(比如 MAX7219),可以多个设备只使用一个 CS 引脚,并通过菊花链的方式连接。

怎么使用 SPI 传输
图解
步骤 1:主机向从机发送时钟信号
时钟信号的频率需要不大于从机支持的最大频率,常用的是 1~10MHz

步骤 2:主机下拉 SS/CS,使从机开始运作
需要提及的是,实际上更常见的做法是先拉低 SS/CS 线,然后再开始发送 SCLK 信号

步骤 3:主机在每个时钟信号通过 MOSI 总线输出数据

步骤 4:主机在每个时钟信号通过 MISO 总线读取数据

在实际使用中,更常用的是在 SS/CS 拉低后再开始同时在总线上输出 MOSI 和 SCLK 的信号。
同时,SPI 并不是一定要同时收发的,可以只收不发,也可以只发不收。
并且,MOSI 和 MISO 的读写过程可以同时进行,因为 SPI 是一个全双工的通讯协议。
传输往往涉及两个移位寄存器,常见的为 8 位大小,一个在主机中,另一个在从机中
SPI 的数据帧
SPI 的数据帧由 SS/CS 的信号来定义它的开始与结束。数据帧由片选信号的拉低开始,回到高电平结束。
对于常见的 SPI 通讯,往往是主机先向从机发送一个信号,之后从机向主机发送回一个信号。这两个信号往往都是 8 位长的。
大多数的 SPI 数据帧使用 8 位的长度,但是实际上 SPI 并没有定义数据帧的长度,想发多长只取决于你的想法。

简单分析
优点
- 全双工设计,可以同时收发信息
- 传续速度远高于 I2C,可以达到 10Mbps
- 电路较少,功耗要求较低
- 灵活的数据帧长度
- 同步信号传输设计,从设备不用精密的振荡器
缺点
- 使用的线材较多,对于每个从设备需要 4 根线进行连接
- 无法得知数据有没有被成功接受,在这方面差于 I2C
- 与串口相比,没有数据的纠错设计
- 最多只能存在一个主设备
应用
- 传感器:温度传感器,压力传感器,ADC 等
- 需要控制的设备:音频编解码器,数字电位器,DAC 等
- 实时时钟
- LCD 显示器
- SD 卡
例程
/**
* Program: Sets up the mbed as SPI master, and continuously sends a single byte
*/
#include "mbed.h"
SPI ser_port(D11, D12, D13); // mosi, miso, sclk
char switch_word ; //word we will send
int main() {
ser_port.format(8,0); // Setup the SPI for 8 bit data, Mode 0 operation
ser_port.frequency(1000000); // Clock frequency is 1MHz
while (1) {
switch_word=0xA1; //set up word to be transmitted
switch_word=switch_word & 0x01;
ser_port.write(switch_word); //send switch_word
ThisThread::sleep_for(10ms);
}
}