设备间数据通信 —— 串行外设接口(SPI)协议
设备间通信
两个设备或者多个设备之间通信时,需要有一份共同遵守的协议,避免鸡同鸭讲。
常见的通信协议有:SPI、USB、UART、I2C、CAN[1][2]。
图 1:不同的设备间通信协议
不同的协议是为了满足特定场景的要求而制定的,而不是为了好玩。因此应该分析特定应用的要求,并选择合适的协议。
SPI 协议
使用 SPI 协议的场景是全双工、同步传输、一主多从、线少、高速率。
以下是使用 SPI 协议通信的设备群:
图 2:SPI 一主多从
从图中可以看出一对设备通过 SPI 协议进行通信需要四条线。SPI 四条线分别是:
- 片选信号线(CS,Chip Select):选设备
- 主->从 数据线(MOSI, Master Out / Slave In):传数据
- 从->主 数据线(MISO, Master In / Slave Out):传数据
- 时钟信号线(SCK,Serial Clock):提供采集数据的时机
数据传输线
由于使用同步传输,所以传输一个字节的 8 位二进制不需要八条导线,只需要一条线分 8 个时钟发送就行了。下文的时钟信号线部分会再次提到。
另外由于要支持全双工,即一次传输过程中主设备传输数据到从设备的同时,从设备也可以传输数据到主设备,因此需要两条传输方向不同的线 MOSI(Master Out/Slave In) 和 MISO(Master In/Slave Out)。如下图:
图 3:全双工。蓝色线表示主设备输出,红色线表示从设备输出。
从图 3 可以看出,单向传输的线连接了多个从设备。
注意这里的接线方式:主设备的 MOSI 接从设备的 MOSI,主设备的 MISO 接从设备的 MISO。
此时我们有了疑问:这些从设备都会同时接收数据吗?多个从设备同时发送数据给主设备岂不是冲突了?
片选信号线
主设备会通过控制从设备的 CS 引脚来激活从设备。上面说过从设备的 CS 引脚为低电平的时候,从设备被激活。
图 4:片选信号线
下图表示从设备被激活后传输数据(NSS 是 CS 引脚的另一个称呼):
图 5:拉低片选线后才开始传输数据
红框部分表示持续激活从设备,以及采集数据。
注意,主设备用 I/O 线连接到从设备的片选信号线上。
时钟信号线
时钟信号线提供读取数据信号的时机。时钟信号由主设备提供给从设备。
图 6: 时钟信号(中间波浪线表示省略 N 个信号)
时钟线的作用是提供高低电平的变化作为数据采样的信号。根据不同的模式,可以是从高到低的时候采样,也可以是从低到高的时候采样。
SPI 协议有四种通信模式,分别由 CPOL(时钟极性)和 CPHA(时钟相位)来控制。也就是选择采样的时机。
CPOL(Clock POLarity) 表示时钟空闲时的电平。0 为低电平,1 为高电平。如下图表示 CPOL = 0。
图 7:空闲的 SCK 为低电平,即 CPOL 为 0 的情况
CHPA(Clock PHAse) 表示数据有效的时刻的相位,或者说边沿(Edge)。边沿指的是电平变化的时刻,有两种类型:上升沿(Rising Edge)和下降沿(Falling Edge)。0 表示处于第一个边沿类型的时刻数据有效(进行采样),1 表示处于第二个边沿类型的时刻数据有效(进行采样)。
图 8:上升沿和下降沿
下图标出了采样的时机:
图 9:工作在(0,1)模式的数据采样
四种模式用下表列出:
SPI 通信模式 | CPOL | CPHA | 特点 |
---|---|---|---|
0 | 0 | 0 | 时钟空闲时保持低电平,工作时在上升沿从输入引脚采样,在下降沿改变输出引脚的数据 |
1 | 0 | 1 | 时钟空闲时保持低电平,工作时在下降沿从输入引脚采样,在上升沿改变输出引脚的数据 |
2 | 1 | 0 | 时钟空闲时保持高电平,工作时在下降沿从输入引脚采样,在上升沿改变输出引脚的数据 |
3 | 1 | 1 | 时钟空闲时保持高电平,工作时在上升沿从输入引脚采样,在下降沿改变输出引脚的数据 |
注:两个通信的设备要配置为同一个模式才能正常通信。
通信双方采样的时机是一致的,改变输出的时机也是一致的。不然 A 在采样的时候,B 把输出改了,那 A 得到的数据可能是修改前的数据也可能是修改后的数据,就乱了。
如何确保主从处于同一模式?应该以从设备的模式为准,再配置主设备的模式。从设备的模式有两种情况[3]:
- 从设备的 SPI 模式由硬件决定,已经被固定
- 从设备有 SPI 控制器,则 SPI 模式由软件决定,可配置
在模式相同且片选信号线拉低时,开始通信。通常芯片内部的 SPI 控制器会自动控制在 8 次取样后停止通信,也就是一次传输 8 bit,即一个字节。但也可以使用 I/O 线模拟片选信号,这样一次可以传送多个字节[4]。
图 10:工作在(0,1)模式的数据采样
图 10 中的 MSB 和 LSB 表示最高权重位(Most Significant Bit)和最低权重位(Least Significant Bit)[5]。权重指的是对这个数值影响程度高,例如十进制的万比千的权重高。
一个字节,即 8 位二进制数据可以从最高位开始发送,也可以从最低为开始发送。
举个例子:
一个字节的数据:1000 0000
MSB | - | - | - | - | - | - | LSB |
---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
从最高位开始发送就是先发 1。
如果通信双方没有达成一致,则接收者得到的数据和发送者的数据的含义不一致。不过这个通常不需要我们配置。
总结
如果要用到 SPI 协议,需要接四条线。
- 主设备的 MISO 接从设备的 MISO
- 主设备的 MOSI 接从设备的 MOSI
- 主设备的 SCK 接从设备的 SCK
- 主设备任选一个 I/O 接从设备的 CS
主设备在编程的时候需要配置与从设备相同的 SPI 模式。
主设备在编程的时候需要配置第一位(First Bit)[6]先从 MSB 开始发还是 LSB 开始发。从设备会规定第一位是 MSB 还是 LSB。
参考:
[1]: https://zhuanlan.zhihu.com/p/47925844 (常见硬件通信协议介绍)
[2]: https://blog.csdn.net/heda3/article/details/89053635 (IIC、SPI、UART、USART、USB、CAN等通讯协议原理及区别)
[3]: https://blog.csdn.net/u013165704/article/details/81076890 (SPI 接口配置)
[4]: https://blog.csdn.net/qq_25814297/article/details/86190106 (SPI通讯有单字节模式和多字节连续模式)
[5]: https://www.cnblogs.com/shuaifeng/archive/2009/12/23/1630195.html (MSB与LSB)
[6]: https://www.stmcu.org.cn/module/forum/thread-627137-1-1.html ([分享] SPI原理超详细讲解---值得一看)