【STM32 学习笔记】SPI通信协议

SPI通信协议

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

学习本章时,可与I2C章节对比阅读,体会两种通讯总线的差异以及EEPROM存储器与FLASH存储器的区别。下面我们分别对SPI协议的物理层及协议层进行讲解。

SPI物理层

SPI通讯设备之间的常用连接方式见图

SPI通讯使用3条总线及片选线,3条总线分别为SCK、MOSI、MISO,片选线为SS,它们的作用介绍如下:

(1) SS ( Slave Select):从设备选择信号线,常称为片选信号线,也称为NSS、CS ,以下用NSS表示。当有多个SPI从设备与SPI主机相连时, 设备的其它信号线SCK、MOSI及MISO同时并联到相同的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):主设备输入/从设备输出引脚。主机从这条信号线读入数据, 从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。

SPI协议层

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

SPI基本通讯过程

先看看SPI通讯的通讯时序,

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

以上通讯流程中包含的各个信号分解如下:

1.通讯的起始和停止信号

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

2.数据有效性

MSB高位先行,LSB低位先行

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

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

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

3.CPOL/CPHA及通讯模式

上面讲述的图 SPI通讯时序 中的时序只是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的"偶数边沿"采样。见图 CPHA = 0时的SPI通讯模式 及图 CPHA = 1时的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的偶数边沿被采样,见图 CPHA=1时的SPI通讯模式_ 。

由CPOL及CPHA的不同状态,SPI分成了四种模式,见表 SPI的四种模式 , 主机与从机需要工作在相同的模式下才可以正常通讯,实际中采用较多的是"模式0"与"模式3"。

STM32的SPI特性及架构

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

1.STM32的SPI外设简介

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

2. STM32的SPI架构剖析

1.通讯引脚

SPI的所有硬件架构都从图 SPI架构图 中左侧MOSI、MISO、SCK及NSS线展开的。STM32芯片有多个SPI外设, 它们的SPI通讯信号引出到不同的GPIO引脚上,使用时必须配置到这些指定的引脚,见表 STM32F10x的SPI引脚 。 关于GPIO引脚的复用功能,可查阅《STM32F10x规格书》,以它为准。

其中SPI1是APB2上的设备,最高通信速率达36Mbtis/s,SPI2、SPI3是APB1上的设备,最高通信速率为18Mbits/s。除了通讯速率, 在其它功能上没有差异。其中SPI3用到了下载接口的引脚,这几个引脚默认功能是下载,第二功能才是IO口,如果想使用SPI3接口, 则程序上必须先禁用掉这几个IO口的下载功能。一般在资源不是十分紧张的情况下,这几个IO口是专门用于下载和调试程序,不会复用为SPI3。

2. 时钟控制逻辑

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

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

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

3. 数据控制逻辑

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

4. 整体控制逻辑

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

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

3.通讯过程

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

图 主发送器通讯过程 中的是"主模式"流程,即STM32作为SPI通讯的主机端时的数据收发过程。

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

(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"中的数据。

4.实战------读写串行FLASH

1.硬件连接

注意:

如果SPI通讯中的三个从机都是推挽输出(Push-Pull Output),那么在没有适当管理的情况下,当多个从设备同时驱动MISO线时,就会发生线路冲突,这可能导致数据错误和通信故障。为了解决这个问题,【从机】一般采用下面的处理方式:

片选(Chip Select):每个从设备都有一个独立的片选线,用于启用或禁用该设备的输出。当主设备想要与某个从设备通信时,它会通过激活相应的片选线来选择该从设备。++未被选中的从设备会将其MISO输出设置为高阻态(High-Impedance),从而不会对MISO线产生影响。++

2.软件设计



编程要点:

  1. 初始化通讯使用的目标引脚及端口时钟;
  2. 使能SPI外设的时钟;
  3. 配置SPI外设的模式、地址、速率等参数并使能SPI外设;
  4. 编写基本SPI按字节收发的函数;
  5. 编写对FLASH擦除及读写操作的的函数;
  6. 编写测试程序,对读写数据进行校验。

扩展1:SPI物理层第二种连接方式:菊花链

在数字通信世界中,在设备信号(总线信号或中断信号)以串行的方式从一 个设备依次传到下一个设备,不断循环直到数据到达目标设备的方式被称为菊花链

菊花链的最大缺点是因为是信号串行传输,所以一旦数据链路中的某设备发生故障的时候,它下面优先级较低的设备就不可能得到服务了;

另一方面,距离主机越远的从机,获得服务的优先级越低,所以需要安排好从机的优先级,并且设置总线检测器,如果某个从机超时,则对该从机进行短路,防止单个从机损坏造成整个链路崩溃的情况

具体的连接如下图所示:

采用一个/SS (或者/CS) 信号控制所有从器件的/CS 输入; 所有从器件接收同一个时钟信号。只有链上的第一个从器件(SLAVE 1) 从微控制器直接接收命令。 其他所有从器件都从链上前一个器件的 DOUT 输出获得其 DIN 数据。要保证菊链正常工作, 每一个从器件就必须能在给定的命令周期内(定义为每一个命令所需的时钟数) 从 DIN 引脚读入命令, 而在下一个命令周期从 DOUT 引脚输出同样的命令。 显然,从 DIN 到 DOUT 会有一个命令周期的延迟。 另外, 各个从器件只能在/CS 的上升沿执行写入的命令。 这意味着只要/CS 保持低电平, 从器件将不会执行命令, 并且会在下一个命令周期将命令通过 DOUT 引脚输出。 如果在给定命令周期之后/CS 变高, 所有从器件将立即执行写入 DIN 引脚的命令。 如果/CS 变高, 数据将不会从 DOUT 输出, 这就使得链上每个从器件可以执行不同的命令。只要菊链的这些要求能够满足, 微控制器只需三个信号(/SS、SCK 和 MOSI)就能控制网络上的所有从器件。

所以最终的数据流向图可以表示为:

SCK为时钟信号,8clks表示8个边沿信号;

其中D为数据,X为无效数据

所以不难发现,菊花链模式充分使用了SPI其移位寄存器的功能,整个链充当通信移位寄存器,每个从机在下一个时钟周期将输入数据复制到输出。

详细原理请看:SPI菊花链原理和配置

扩展2:关于stm32硬件spi的MISO口配置

在我们刚使用spi时,对于spi的io口配置可能会有一些疑惑吧,miso明明是一个输入口却配置成了复用推挽输出,是不是会有一点疑惑呢?

复制代码
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     // 复用的推挽输出

MISO不是应该设置成为输入端口(GPIO_Mode_IN_FLOATING)才行的吗?其实可以设置成为输入模式,也可以设置成为复用的推挽输出。其工作都是正常的,不过建议大家还是设置成为输入端口的好,容易理解。

具体产生这一问题的原因是:从功能上来说,MISO应该配置为输入模式才对,但为什么也可以配置为GPIO_Mode_AF_PP?请看下面的GPIO复用功能配置框图。当一个GPIO端口配置为GPIO_Mode_AF_PP是,这个端口的内部结构框图如下:图中可以看到,片上外设的复用功能输出信号会连接到输出控制电路,然后在端口上产生输出信号。但是在芯片内部,MISO是SPI模块的输入引脚,而不是输出引脚,也就是说图中的"复用功能输出信号"根本不存在,因此"输出控制电路"不能对外产生输出信号。而另一方面看,即使在GPIO_Mode_AF_PP模式下,复用功能输入信号却与外部引脚之间相互连接,既MISO得到了外部信号的电平,实现了输入的功能。


SPI协议详解(图文并茂+超详细)
关于stm32硬件spi的miso口配置

相关推荐
数字芯片实验室2 小时前
分享一个可以学习正则表达式的网址:Pythex.org
学习·正则表达式
陈洪奇2 小时前
注册中心学习笔记整理
笔记·学习
光影少年2 小时前
从前端转go开发的学习路线
前端·学习·golang
兴趣使然_5 小时前
【笔记】使用 html 创建网址快捷方式
笔记·html·js
aramae7 小时前
C++ -- STL -- vector
开发语言·c++·笔记·后端·visual studio
fen_fen7 小时前
学习笔记(32):matplotlib绘制简单图表-数据分布图
笔记·学习·matplotlib
编程墨客8 小时前
STM32F103C8T6单片机内部执行原理及启动流程详解
stm32·单片机·嵌入式硬件
Wangshanjie_989 小时前
【STM32】-SPI通讯
stm32
饕餮争锋11 小时前
设计模式笔记_创建型_建造者模式
笔记·设计模式·建造者模式
萝卜青今天也要开心11 小时前
2025年上半年软件设计师考后分享
笔记·学习