1. SPI

本章参考资料: 《STM32H7xx 参考手册》 、 《STM32H7xx 规格书》 、库帮助文档《stm32h7xx_dsp_stdperiph_lib_um.chm》及《SPI 总线协议介绍》。

1.1. 协议简介

SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface),即串行外围设备接口, 是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率较高的场合。

1.1.1. SPI 物理层

SPI 通讯设备之间的常用连接方式见下图1-1 spi连接方式,

spi连接方式

图1-1 spi连接方式

SPI 通讯使用 3 条总线及片选线,3 条总线分别为 SCK、MOSI、MISO,片选线为 SS ,它们的作用介绍如下: (1) SS*(* Slave Select):从设备选择信号线,常称为片选信号线,也称为 NSS、CS,以下用 NSS表示。 当有多个 SPI 从设备与 SPI 主机相连时,设备的其它信号线 SCK、MOSI 及 MIS O同时并联到相同的 SPI 总线上, 即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线, 本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、 选中总线上的某个设备并与其进行通讯;而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时, 把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。 所以 SPI 通讯以 NSS 线置低电平为开始信号,以NSS 线被拉高作为结束信号。

(2) SCK (Serial Clock):时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率, 不同的设备支持的最高时钟频率不一样,如 STM32 的 SPI 时钟频率最大为 fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。

(3) MOSI (Master Output,Slave Input):主设备输出/从设备输入引脚。主机的数据从这条信号线输出, 从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。

(4) MISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。主机从这条信线读入数据, 从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。

1.1.2. SPI 协议层

与 I2C 的类似,SPI 协议定义了通讯的起始和停止信号、数据有效性、时钟同步等环节。

1.1.2.1. SPI 基本通讯过程

SPI 通讯的通讯时序见下图1-2 spi通信时序,

spi通信时序

图1-2 spi通信时序

这是一个主机的通讯时序。NSS、SCK、MOSI 信号都由主机控制产生,而 MISO 的信号由从机产生, 主机通过该信号线读取从机的数据。MOSI 与 MISO 的信号只在 NSS 为低电平的时候才有效, 在 SCK 的每个时钟周期 MOSI 和 MISO 传输一位数据。以上通讯流程中包含的各个信号分解如下:

1.1.2.2. SPI 通讯的起始和停止信号

在图 24_2 中的标号处,NSS 信号线由高变低,是 SPI 通讯的起始信号。NSS 是每个从机各自独占的信号线, 当从机在自己的 NSS 线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。在图中的标号处, NSS 信号由低变高,是 SPI 通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。

1.1.2.3. SPI 数据有效性

SPI 使用 MOSI 及 MISO 信号线来传输数据,使用 SCK 信号线进行数据同步。MOSI 及 MISO 数据线在 SCK 的每个时钟周期传输一位数据, 且数据输入输出是同时进行的。数据传输时,MSB先行或 LSB 先行并没有作硬性规定,但要保证两个 SPI 通讯设备之间使用同样的协定, 一般都会采用图 24‑2 中的 MSB 先行模式。

观察图中的标号处,MOSI 及 MISO 的数据在 SCK 的上升沿期间变化输出,在 SCK 的下降沿时被采样。 即在 SCK 的下降沿时刻,MOSI 及 MISO 的数据有效,高电平时表示数据“1”,为低电平时表示数据“0”。在其它时刻, 数据无效,MOSI 及 MISO 为下一次表示数据做准备。

SPI 每次数据传输可以 8 位或 16 位为单位,每次传输的单位数不受限制。

1.1.2.4. SPI CPOL/CPHA 及通讯模式

上面讲述的图 24‑2 中的时序只是 SPI 中的其中一种通讯模式,SPI 一共有四种通讯模式,它们的主要区别是总线空闲时 SCK 的时钟状态以及数据采样时刻。 为方便说明,在此引入“时钟极性CPOL”和“时钟相位 CPHA”的概念。

时钟极性 CPOL 是指 SPI 通讯设备处于空闲状态时,SCK 信号线的电平信号 (即 SPI 通讯开始前、 NSS 线为高电平时 SCK 的状态)。CPOL=0 时,SCK 在空闲状态时为低电平,CPOL=1 时,则相反。

时钟相位 CPHA 是指数据的采样的时刻,当 CPHA=0 时,MOSI 或 MISO 数据线上的信号将会在SCK 时钟线的“奇数边沿”被采样。 当 CPHA=1 时,数据线在 SCK 的“偶数边沿”采样,见下图1-3 spi通信时序,

奇数边沿

图1-3 spi通信时序

我们来分析这个 CPHA=0 的时序图。首先,根据 SCK 在空闲状态时的电平,分为两种情况。 SCK信号线在空闲状态为低电平时,CPOL=0;空闲状态为高电平时,CPOL=1。 无论 CPOL=0 还是 =1,因为我们配置的时钟相位 CPHA=0,在图中可以看到,采样时刻都是在SCK 的奇数边沿。 注意当 CPOL=0 的时候,时钟的奇数边沿是上升沿,而 CPOL=1 的时候,时钟的奇数边沿是下降沿。 所以 SPI 的采样时刻不是由上升/下降沿决定的。MOSI 和 MISO 数据线的有效信号在 SCK 的奇数边沿保持不变, 数据信号将在 SCK 奇数边沿时被采样,在非采样时刻,MOSI 和 MISO 的有效信号才发生切换。

类似地,当 CPHA=1 时,不受 CPOL 的影响,数据信号在 SCK 的偶数边沿被采样,见下图1-4 偶数边沿,

偶数边沿

图1-4 偶数边沿

由 CPOL 及 CPHA 的不同状态,SPI 分成了四种模式,

SPI 的四种模式

SPI 模式

CPOL

CPHA

空闲时 SCK 时钟

采样时刻

0

0

0

低电平

奇数边沿

1

0

1

低电平

偶数边沿

2

1

0

高电平

奇数边沿

3

1

1

高电平

偶数边沿

主机与从机需要工作在相同的模式下才可以正常通讯,实际中采用较多的是“模式 0”与“模式 3”。

1.2. STM32 的 SPI 特性及架构

与 I2C 外设一样,STM32 芯片也集成了专门用于 SPI 协议通讯的外设。

1.2.1. STM32 的 SPI 外设简介

STM32 的 SPI 外设可用作通讯的主机及从机,支持最高的 SCK 时钟频率为 fpclk/2 (STM32F103 型号的芯片默认 f:sub:pclk1 为 72MHz,fpclk2 为 36MHz), 完全支持 SPI 协议的 4 种模式,数据帧长度可设置为 8 位或 16 位,可设置数据 MSB 先行或 LSB 先行。 它还支持双线全双工 (前面小节说明的都是这种模式)、双线单向以及单线模式。其中双线单向模式可以同时使用 MOSI 及 MISO 数据线向一个方向传输数据, 可以加快一倍的传输速度。而单线模式则可以减少硬件接线,当然这样速率会受到影响。我们只讲解双线全双工模式。

1.2.2. STM32 的 SPI 架构剖析

spi架构图

图1-5 spi架构图

1.2.2.1. 通讯引脚

SPI 的所有硬件架构都从图 24‑5 中左侧 MOSI、MISO、SCK 及 NSS 线展开的。STM32 芯片有多个 SPI 外设, 它们的 SPI 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚, 关于 GPIO 引脚的复用功能,可查阅与芯片对应的数据手册,以它为准。 (在对应的数据手册中按Ctrl+F,搜索关键字 ”复用功能映射“ 即可查阅 GPIO 相应的引脚复用功能)。

1.2.2.2. 时钟控制逻辑

SCK 线的时钟信号,由波特率发生器根据“控制寄存器 CR1”中的 BR[0:2] 位控制,该位是对 fpclk时钟的分频因子, 对 fpclk 的分频结果就是 SCK 引脚的输出时钟频率,计算方法见表下表。

SPI 分频表

BR[0:2]

分频结果 (SCK 频率)

BR[0:2]

分频结果 (SCK 频率)

000

fpclk/2

100

fpclk/32

001

fpclk/4

101

fpclk/64

010

fpclk/8

110

fpclk/128

011

fpclk/16

111

fpclk/256

其中的 fpclk 频率是指 SPI 所在的 APB 总线频率,APB1 为 fpclk1,APB2 为 fpckl2。

通过配置“控制寄存器 CR”的“CPOL 位”及“CPHA”位可以把 SPI 设置成前面分析的4种SPI模式。

1.2.2.3. 数据控制逻辑

SPI 的 MOSI 及 MISO 都连接到数据移位寄存器上,数据移位寄存器的数据来源及目标接收、发送缓冲区以及 MISO、MOSI 线。 当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位地通过数据线发送出去; 当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到“接收缓冲区”中。 通过写 SPI 的“数据寄存器 DR”把数据填充到发送 F 缓冲区中,通讯读“数据寄存器 DR”,可以获取接收缓冲区中的内容。 其中数据帧长度可以通过“控制寄存器 CR1”的“DFF 位”配置成 8 位及 16 位模式;配置“LSBFIRST位”可选择 MSB 先行还是 LSB 先行。

1.2.2.4. 整体控制逻辑

整体控制逻辑负责协调整个 SPI 外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变, 基本的控制参数包括前面提到的 SPI 模式、波特率、LSB 先行、主从模式、单双向模式等等。在外设工作时, 控制逻辑会根据外设的工作状态修改“状态寄存器(SR)”,我们只要读取状态寄存器相关的寄存器位,就可以了解 SPI 的工作状态了。 除此之外,控制逻辑还根据要求,负责控制产生 SPI 中断信号、DMA 请求及控制 NSS 信号线。

实际应用中,我们一般不使用 STM32 SPI 外设的标准 NSS 信号线,而是更简单地使用普通的GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。

1.2.3. STM32 通讯过程

STM32 使用 SPI 外设通讯时,在通讯的不同阶段它会对“状态寄存器 SR”的不同数据位写入参数,我们通过读取这些寄存器标志来了解通讯状态。

图 1-6 中的是“主模式”流程,即 STM32 作为 SPI 通讯的主机端时的数据收发过程。

spi主模式流程

图1-6 主发送器通讯过程

主模式收发流程及事件说明如下:

  1. 控制 NSS 信号线,产生起始信号 (图中没有画出);

  2. 把要发送的数据写入到“数据寄存器 DR”中,该数据会被存储到发送缓冲区;

  3. 通讯开始,SCK 时钟开始运行。MOSI 把发送缓冲区中的数据一位一位地传输出去;MISO则把数据一位一位地存储进接收缓冲区中;

(4) 当发送完一帧数据的时候,“状态寄存器 SR”中的“TXE 标志位”会被置 1,表示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,“RXNE 标志位”会被置 1, 表示传输完一帧,接收缓冲区非空;

(5) 等待到“TXE 标志位”为 1 时,若还要继续发送数据,则再次往“数据寄存器 DR”写入数据即可;等待到“RXNE 标志位”为 1 时, 通过读取“数据寄存器 DR”可以获取接收缓冲区中的内容。

假如我们使能了 TXE 或 RXNE 中断,TXE 或 RXNE 置 1 时会产生 SPI 中断信号,进入同一个中断服务函数, 到 SPI 中断服务程序后,可通过检查寄存器位来了解是哪一个事件,再分别进行处理。也可以使用 DMA 方式来收发“数据寄存器 DR”中的数据。

1.3. 软件SPI与硬件SPI的区别

1.3.1. 软件SPI

软件SPI需要用IO口模拟时序,这个模拟过程全部由CPU完成,为了能稳定的存入数据,可能插入软件延时,这个时间在读取数据量小的情况下不明显, 但是基本上你在读取过程中其他非中断、非异常程序是无法得到执行的。

1.3.2. 硬件SPI

硬件SPI数据存储过程是不需要CPU参与的,程序中配置好SPI的访问时序,开启中断,CPU就可以在中断函数中搬移数据,省下了软件模拟IO的存取时间。 这一节介绍的内容就是硬件SPI。

当然,不能认为硬件SPI速度快,在做项目时就一定要用它,这需要根据实际情况而定。