1.SPI简介
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。**SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,**节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
SPI 是一种用于在数字设备之间进行通信的串行通信协议。与UART和I2C相比,SPI 在一些方面具有独特的优势:
SPI 的主要特点包括:
-
高速传输:SPI 通常可以实现更高的传输速率,因为它是同步的,且没有像 UART 那样的起始位和停止位,也没有像 I2C 那样的地址字节。这使得 SPI 在需要快速数据传输的应用中非常有用。
-
全双工通信:SPI 支持全双工通信,这意味着数据可以在同一时刻在两个方向上传输。这种特性对于需要同时进行数据读取和写入的应用非常有用。
-
硬件依赖性:SPI 在一些硬件上实现简单且成本较低。SPI 总线通常只需要3+n根线(如时钟线、数据线和选择线),因此在硬件资源有限的情况下,SPI 可能是更好的选择。
-
多主设备支持:SPI 支持多主设备的通信,这意味着多个设备可以同时连接到同一个 SPI 总线上,并能够协调使用总线进行通信。
-
应用广泛:SPI 在许多领域得到广泛应用,包括嵌入式系统、传感器、存储器等等。由于其高速和灵活性,SPI 是许多数字系统中的首选通信协议之一。
2.物理层
-
MOSI(主机输出/从机输入)------主机向从机发送数据的线 master slave
-
MISO(主机输入/从机输出)------从机向主机发送数据的线
-
SCLK(时钟)------时钟信号线
-
SS/CS(从机选择/芯片选择)------用于主机选择给哪个从机发送数据的线 把这个线置位就可以选择主机跟哪个从机通信
SPI 通讯使用3 条总线及片选线,3 条总线分别为SCK、MOSI、MISO,片选线为SS/CS,SPI可以一个主机连接单个或多个从机,每个从机都使用一个引脚进行片选。
一主一从
一主多从
片选线SS( Slave Select):
从设备选择信号线,常称为片选信号线,也称为NSS、CS、SS,以下用SS 表示。
当有多个SPI 从设备与SPI 主机相连时,设备的其它信号线SCK、MOSI 及MISO 同时并联到相同的SPI 总线上,即无论有多少个从设备,都共同只使用这3 条总线。而每个从设备都有独立的这一条SS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯。
而SPI 协议中没有设备地址,而是使用SS 信号线来寻址,当主机要选择从设备时,把该从设备的SS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行SPI 通讯。所以SPI 通讯以SS 线置低电平为开始信号,以SS 线被拉高作为结束信号。
SCK (Serial Clock):
时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,**不同的设备支持的最高时钟频率不一样,如STM32 的SPI 时钟频率最大为fpclk/2,**两个设备之间通讯时,通讯速率受限于低速设备。
MOSI (Master Output,Slave Input):
主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。
MISO(Master Input,,Slave Output):
主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。
3.协议层
与I2C 的类似,SPI 协议定义了通讯的起始和停止信号、数据有效性、时钟同步等环节。
3.1 SPI基本通讯过程
这是一个主机的通讯时序。NSS、SCK、MOSI 信号都由主机控制产生,而MISO 的信号由从机产生,主机通过该信号线读取从机的数据。MOSI 与MISO 的信号只在NSS 为低电平的时候才有效,在SCK 的每个时钟周期MOSI 和MISO 传输一位数据。
3.2 起始和停止信号
NSS 信号线由高变低,是SPI 通讯的起始信号 。NSS 是每个从机各自独占的信号线,当从机在自己的NSS 线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。如图,NSS 信号由低变高,是SPI 通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。
3.3数据有效性
SPI 使用MOSI 及MISO 信号线来传输数据,使用SCK 信号线进行数据同步。MOSI 及MISO 数据线在SCK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。
观察下图,MOSI 及MISO 的数据在SCK 的上升沿期间变化(红色框图),在SCK 的下降沿时被采样(绿色框图)。即在SCK 的下降沿时刻,MOSI 及MISO 的数据有效,高电平时表示数据"1",为低电平时表示数据"0"。
在其它时刻,数据无效,MOSI 及MISO 为下一次表示数据做准备。SPI 每次数据传输可以8 位或16 位为单位,每次传输的单位数不受限制。
MSB:高位在前
LSB:低位在前
3.4 CPOL/CPHA 及通讯模式
上文讲的例程只是SPI 中的其中一种通讯模式,SPI 一共有四种通讯模式,它们的主要区别是总线空闲时SCK 的时钟状态以及数据采样时刻。在此引入"时钟极性CPOL"和"时钟相位CPHA"的概念。
CPOL和CPHA,分别都可以是0或时1,对应的四种组合就是:
-
时钟极性CPOL 是指SPI 通讯设备处于空闲状态时,SCK 信号线的电平信号(即SPI 通讯开始前、NSS 线为高电平时SCK 的状态)。CPOL=0 时,SCK 在空闲状态时为低电平,CPOL=1 时,则相反。
-
时钟相位CPHA 是指数据的采样的时刻,当CPHA=0 时,MOSI 或MISO 数据线上的信号将会在SCK 时钟线的"奇数边沿"被采样。当CPHA=1 时,数据线在SCK 的"偶数边沿"采样。
时钟和相位会决定你发过来的数据怎么解析
拿《STM32F4xx参考手册》举例:
分析上图:
CPHA=1时,说明是在SCK偶数边沿采样
CPOL=1时,SCK在空闲状态为高电平,也就是说开始信号有效后,SCK肯定是高电平到低电平的跳变。
在这个搭配下,有效数据如上图所示,其他三种模式也是类似,可查看《STM32F4xx参考手册》图 273. 数据时钟时序图
下面列举了四种情况:
CPOL=0,CPHA=0
CPOL=0,CPHA=1
CPOL=1,CPHA=0
CPOL=1,CPHA=1
在实际操作过程中,我们怎么设置SPI的极性和相位呢?
- 由SPI从设备硬件决定
SPI从设备,具体是什么模式,需要查看对应的模块手册
SPI从设备,在空闲的时候,是高电平还是低电平,即决定了CPOL是0还是1;
然后再找到关于设备是在上升沿还是下降沿去采样数据,对应着可以推算出CPHA是0还是1了。
- 由软件自己设定
如果四种模式都支持,那就随便。
4.STM32 的SPI外设
STM32 的SPI 外设可用作通讯的主机及从机,支持最高的SCK 时钟频率为fpclk/2 (STM32F407 型 号的芯片默认fpclk1(APB1)42MHz,fpclk2(APB2) 为84MHz),完全支持SPI 协议的4 种模式,数据帧长度可设置 为8 位或16 位,可设置数据MSB 先行或LSB 先行
它还支持双线全双工(前面小节说明的都是这种模式)、双线单向以及单线模式。其中双线单向模式可以同时使用MOSI 及MISO 数据线向一个方向传输数据,可以加快一倍的传输速度。而单线模式则可以减少硬件接线,当然这样速率会受到影响。不过这些模式用的比较少,还是双线全双工模式最常用。
4.1 通讯引脚
STM32 芯 片有多个SPI 外设,它们的SPI 通讯信号引出到不同的GPIO 引脚上,使用时必须配置到这些指 定的引脚
STM32F4xx 的SPI 引脚
其中SPI1、SPI4、SPI5、SPI6 是挂在APB2 上的设备,最高通信速率达42Mbtis/s
SPI2、SPI3 是挂在APB1 上的设备,最高通信速率为21Mbits/s。其它功能上没有差异。
4.2 时钟
SCK 线的时钟信号,由波特率发生器根据"控制寄存器CR1"中的BR[0:2] 位控制,该位是对fpclk时钟的分频因子,对fpclk 的分频结果就是SCK 引脚的输出时钟频率。
4.3 数据逻辑控制
SPI 的MOSI 及MISO 都连接到数据移位寄存器上,数据移位寄存器的内容来源于接收缓冲区及发送缓冲区以及MISO、MOSI 线。
当向外发送数据的时候,数据移位寄存器以"发送缓冲区"为数据源,把数据一位一位地通过数据线发送出去;
当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到"接收缓冲区"中。
其中数据帧长度可以通过"控制寄存器CR1"的"DFF 位"配置成8 位及16 位模式;配置"LSBFIRST 位"可选择MSB 先行还是LSB 先行。
4.4 状态和控制部分
SR是通信过程中的寄存器
基本的控制参数包括前面提到的SPI 模式、波特率、LSB 先行、主从模式、单双向模式等等。在外设工作时,控制逻辑会根据外设的工作状态修改"状态寄存器(SR)",我们只要读取状态寄存器相关的寄存器位,就可以了解SPI 的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生SPI 中断信号、DMA 请求及控制NSS 信号线。
实际应用中,我们一般不使用STM32 SPI 外设的标准NSS 信号线,而是更简单地使用普通的GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。
4.5 通讯过程
STM32 使用SPI 外设通讯时,在通讯的不同阶段它会对"状态寄存器SR"的不同数据位写入参数,我们通过读取这些寄存器标志来了解通讯状态。
(1) 控制NSS 信号线,产生起始信号(图中没有画出);
(2) 把要发送的数据写入到"数据寄存器DR"中,该数据会被存储到发送缓冲区(此操作会将 TXE 标志清零)。
(3) 通讯开始,SCK 时钟开始运行。MOSI 把发送缓冲区中的数据一位一位地传输出去;MISO 则把数据一位一位地存储进接收缓冲区中;
(4) 当发送完一帧数据的时候,"状态寄存器SR"中的"TXE 标志位"会被置1,表示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,"RXNE 标志位"会被置1,表示传输完一帧,接收缓冲区非空;
(5) 等待到"TXE 标志位"为1 时,若还要继续发送数据,则再次往"数据寄存器DR"写入数据即可;等待到"RXNE 标志位"为1 时,通过读取"数据寄存器DR"可以获取接收缓冲区中的内容。假如我们使能了TXE 或RXNE 中断,TXE 或RXNE 置1 时会产生SPI 中断信号,进入同一个中断服务函数。
5.SPI初始化结构体
cs
typedef struct
{
uint16_t SPI_Direction; /* 设置SPI 的单双向模式*/
uint16_t SPI_Mode; /* 设置SPI 的主/从机端模式*/
uint16_t SPI_DataSize; /* 设置SPI 的数据帧长度,可选8/16 位*/
uint16_t SPI_CPOL; /* 设置时钟极性CPOL,可选高/低电平*/
uint16_t SPI_CPHA; /* 设置时钟相位,可选奇/偶数边沿采样*/
uint16_t SPI_NSS; /* 设置NSS 引脚由SPI 硬件控制还是软件控制
*/
uint16_t SPI_BaudRatePrescaler; /* 设置时钟分频因子,fpclk/分频数=fSCK */
uint16_t SPI_FirstBit; /* 设置MSB/LSB 先行*/
uint16_t SPI_CRCPolynomial; /* 设置CRC 校验的表达式*/
} SPI_InitTypeDef;6