嵌入式通信协议札记(三):SPI

一.SPI协议简介

SPI协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工通信总线,多应用在通信速率要求较高的场合。另外还支持双线单向以及单线模式。其中双线单向模式可以同时使用MOSI及MISO数据线向一个方向传输数据,可以加快一倍的传输速度。而单线模式则可以减少硬件接线,当然这样速率会受到影响。

1.物理层

在这里插入图片描述
SPI通信使用三条总线SCK、MOSI、MISO,还有片选线SS。

  • SS(Slave Select):从设备选择信号线,常称为片选信号线,亦称NSS、CS。SPI协议中主机选择从设备时,将该从设备SS线置为低电平即可。SPI通信以SS线置低电平为开始信号,以SS线被拉高为结束信号。I2C协议是通过设备地址寻址选中某设备与其建立通信。
  • SCK(Serial Clock):时钟信号线,由通信主机产生,决定了通信速率。STM32的SPI时钟频率最大为fpclk/2 。两个设备通信时通信速率受限于低速设备。
  • MOSI(Master Output,Slave Input):主设备输出/从设备输入引脚,数据方向是从主机到从机。
  • MISO(Master Input,Slave Output):主设备输入/从设备输出引脚,数据方向是从从机到主机。

2.协议层

在这里插入图片描述

  • 起始信号与停止信号
    NSS时钟信号线由高变低是SPI通信的起始信号,从机被选中。
    NSS时钟信号线由低变高是SPI通信的停止信号,从机选中状态被取消。
  • 数据有效性
    MOSI及MISO数据线在SCK每个时钟周期传输一位数据,且输入输出是同时进行的。数据传输时MSB(Most Significant Bit)先行或LSB(Least Significant Bit)先行未作硬性规定但要保证两个SPI通信设备使用相同的协定,通常使用MSB先行模式。
    MOSI及MISO的数据在SCK的上升沿期间变化输出,在SCK的下降沿时被采样。即在SCK的下降沿时刻,MOSI及MISO的数据有效,高电平时表示数据“1”,为低电平时表示数据“0”。在其它时刻,数据无效,MOSI及MISO为下一次表示数据做准备。
    SPI每次数据传输可以8位或16位为单位,每次传输的单位数不受限制。
  • CPOL/CPHA及通讯模式
    上图描述的时序只是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的时序图:首先,根据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的偶数边沿被采样。
    在这里插入图片描述
    由CPOL及CPHA的不同状态,SPI分成了四种模式,主机与从机需要工作在相同的模式下才可以正常通讯,实际中采用较多的是“模式0”与“模式3”。
SPI模式CPOLCPHA空闲时SCK时钟采样时刻
000低电平奇数边沿
101低电平偶数边沿
210高电平奇数边沿
311高电平偶数边沿

二.STM32的SPI特性及架构

在这里插入图片描述
以STM32F4系列为例,SPI1、SPI4、SPI5、SPI6是APB2总线上的外设,最高通信速率为42Mbits/s;SPI2、SPI3是APB1总线上的设备,最高通信速率为21Mbits/s。其他功能上没有差异。

  • 时钟控制逻辑
    SCK线的时钟信号,由波特率发生器根据“控制寄存器CR1”中的BR[0:2]位控制,该位是对fpclk时钟的分频因子,对fpclk的分频结果就是SCK引脚的输出时钟频率。
    在这里插入图片描述
    其中的fpclk频率是指SPI所在的APB总线 频率,APB1为fpclk1,APB2为fpckl2。
    通过配置“控制寄存器CR”的“CPOL位”及“CPHA”位可以把SPI设置成前面分析的4种SPI模式。
  • 数据控制逻辑
    SPI的MOSI及MISO都连接到数据移位寄存器上。
    当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位地通过数据线发送出去;当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到“接收缓冲区”中。通过写SPI的“数据寄存器DR”把数据填充到发送缓冲区中;通过读“数据寄存器DR”,可以获取接收缓冲区中的内容。
    其中数据帧长度可以通过“控制寄存器CR1”的“DFF位”配置成8位及16位模式;配置“LSBFIRST位”可选择MSB先行还是LSB先行。
  • 整体控制逻辑
    整体控制逻辑负责协调整个SPI外设,控制逻辑的工作模式根据配置的“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括SPI模式、波特率、LSB先行、主从模式、单双向模式等等。
    在外设工作时,会对“状态寄存器SR”的不同数据位写入参数,只要读取状态寄存器相关的寄存器位,就可以了解SPI的工作状态了。
    控制逻辑还根据要求,负责控制产生SPI中断信号、DMA请求及控制NSS信号线。
    实际应用中,一般不使用STM32 SPI外设的标准NSS信号线,而是更简单地使用普通的GPIO,软件控制它的电平输出产生通信起始和停止信号。
  • 通信过程
    在这里插入图片描述
    以STM32作为SPI通信的主机端为例,其数据收发过程如下:
    ①控制NSS信号线,产生起始信号(图中没有画出);
    ②把要发送的数据写入到“数据寄存器DR”中,该数据会被存储到发送缓冲区;
    ③通讯开始,SCK时钟开始运行。MOSI把发送缓冲区中的数据一位一位地传输出去;MISO则把数据一位一位地存储进接收缓冲区中;
    ④当发送完一帧数据的时候,“状态寄存器SR”中的“TXE标志位”会被置1,表 示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据 的时候,“RXNE标志位”会被置1,表示传输完一帧,接收缓冲区非空;
    ⑤等待到“TXE标志位”为1时,若还要继续发送数据,则再次 往“数据寄存器DR”写入数据即可;等待到“RXNE标志位”为1时,通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。

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

三.SPI初始化结构体详解

typedef struct {

     uint32_t Mode; /*设置SPI的主/从机端模式 */

     uint32_t Direction; /*设置SPI的单双向模式 */

     uint32_t DataSize; /*设置SPI的数据帧长度,可选8/16位 */

     uint32_t CLKPolarity;/*设置时钟极性CPOL,可选高/低电平*/

     uint32_t CLKPhase; /*设置时钟相位,可选奇/偶数边沿采样 */

     uint32_t NSS; /*设置NSS引脚由SPI硬件控制还是软件控制*/

     uint32_t BaudRatePrescaler; /*设置时钟分频因子,fpclk/分频数=fSCK */

     uint32_t FirstBit; /*设置MSB/LSB先行 */

     uint32_t TIMode; /*指定是否启用TI模式 */

     uint32_t CRCCalculation; /*指定是否启用CRC计算*/

     uint32_t CRCPolynomial; /*设置CRC校验的表达式*/

 } SPI_InitTypeDef;
  • Mode
    SPI_MODE_MASTER或SPI_MODE _SLAVE,
    两者最大区别为SPI的SCK信号线的时序,SCK的时序是由通讯中的主机产生的。 若被配置为从机模式,STM32的SPI外设将接受外来的SCK信号。
  • Direction
    SPI的通讯方向,可设置为双线全双工(SPI_DIRECTION_2LINES), 双线只接收(SPI_DIRECTION_2LINES_RXONLY),单线SPI_DIRECTION_1LINE。
  • DataSize
    SPI通讯的数据帧大小,8位(SPI_DATASIZE_8BIT)或16位(SPI_DATASIZE_16BIT)。
  • CLKPolarity和CLKPhase
    时钟极性CLKPolarity和时钟相位CLKPhase,时钟极性CLKPolarity成员,可设置为高电平(SPI_POLARITY_HIGH)或低电平(SPI_POLARITY_LOW)。时钟相位CPHA 则可以设置为SPI_PHASE_1EDGE(在SCK的奇数边沿采集数据) 或SPI_PHASE_2EDGE ( 在SCK的偶数边沿采集数据) 。
  • NSS
    NSS引脚的使用模式,硬件模式(SPI_NSS_HARD)或软件模式(SPI_NSS_SOFT),在硬件模式中的SPI片选信号由SPI硬件自动产生,而软件模式则需要编写代码把相应的GPIO端口拉高或置低产生非片选和片选信号。实际中软件模式应用比较多。
  • BaudRatePrescaler
    波特率分频因子,分频后的时钟即为SPI的SCK信号线的时钟频率。可设置为fpclk的2、4、6、8、16、32、64、128、256分频。
  • FirstBit
    所有串行的通讯协议都会有MSB先行(高位数据在前)还是LSB先行(低位数据在前)的问题, STM32的SPI模块可以通过该成员对这个特性编程控制。
  • TIMode
    是否启用TI模式。可选择为使能(SPI_TIMO DE_ENABLE)与不使能( SPI_TIMODE_DISABLE )。
  • CRCCalculation
    指定是否启用CRC计算
  • SPI_CRCPolynomial
    SPI的CRC校验中的多项式,若使用CRC校验时,则使用该成员的参数(多项式),来计算CRC的值。

配置完这些结构体成员后,我们要调用HAL_SPI_Init函数把这些参数写入到寄存器中,实现SPI的初始化,然后调用__HAL_SPI_ENABLE来使能SPI外设。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值