<返回更多

SPI协议并没有我想的那么简单

2022-09-05  今日头条  嵌入式胖胖
加入收藏

先说串口

之前写过一篇UART,通用串行异步通讯协议,感兴趣可以参考一下《 我打赌!你还不会UART 》; 因为UART没有时钟信号,无法控制何时发送数据,也无法保证双发按照完全相同的速度接收数据。因此,双方以不同的速度进行数据接收和发送,就会出现问题。

如果要解决这个问题,UART为每个字节添加额外的 起始位和 停止位,以帮助接收器在数据到达时进行同步;

双方还必须事先就 传输速度达成共识(设置相同的波特率,例如每秒9600位)。

传输速率如果有微小差异不是问题,因为接收器会在每个字节的开头重新同步。相应的协议如下图所示;

串口传输的过程

异步串行工作得很好,但是在每个字节发送的时候都需要额外的 起始位和 停止位以及在发送和接收数据所需的复杂硬件方面都有很多开销。

不难发现,如果接收端和发送端设置的速度都不一致,那么接收到的数据将是 垃圾(乱码)。

下面开始讲一下SPI协议,会有哪些优点。

SPI通讯协议

于是我们想有没有更好一点的串行通讯方式;相比较于 UART , SPI 的工作方式略有不同。

SPI 是一个同步的数据总线,也就是说它是用 单独的数据线和 一个单独的时钟信号来保证 发送端和接收端的完美同步

时钟是一个振荡信号,它告诉接收端在确切的时机对数据线上的信号进行采样。

产生时钟的一侧称为 主机,另一侧称为 从机。总是 只有一个主机(一般来说可以是 微控制器/MCU),但是可以有多个 从机(后面详细介绍);

数据的采集时机可能是 时钟信号的 上升沿(从低到高)或 下降沿(从高到低)。

 

具体要看对SPI的配置;

 

整体的传输大概可以分为以下几个过程:

 

 

具体如下图所示;

SPI的时序

 

注意,SPI是“全双工”(具有单独的发送和接收线路),因此可以在同一时间发送和接收数据,另外SPI的接收硬件可以是一个简单的移位寄存器。这比异步串行通信所需的完整UART要简单得多,并且更加便宜;
SPI特性

 

SPI总线包括4条逻辑线,定义如下:

 

 

其他制造商可能会遵循其他命名规则,但是最终他们指的相同的含义。以下是一些常用术语;

 

 

本文将按照以下命名进行讲解 [MISO, MOSI, SCK,NSS]

下图显示了单个主机和单个从机之间的典型SPI连接。

主从连接 时钟频率

SPI总线上的主机必须在通信开始时候配置并生成相应的时钟信号。在每个SPI时钟周期内,都会发生 全双工数据传输

主机在 MOSI 线上发送一位数据,从机读取它,而从机在 MISO 线上发送一位数据,主机读取它。

就算只进行单向的数据传输,也要保持这样的顺序。这就意味着无论接收任何数据,必须实际发送一些东西!在这种情况下,我们称其为虚拟数据;

从理论上讲,只要实际可行,时钟速率就可以是您想要的任何速率,当然这个速率受限于每个系统能提供多大的系统时钟频率,以及最大的SPI传输速率。

时钟极性 CKP/Clock Polarity

除了配置串行时钟速率(频率)外,SPI主设备还需要配置 时钟极性

根据硬件制造商的命名规则不同,时钟极性通常写为 CKP或 CPOL。时钟极性和相位共同决定读取数据的方式,比如信号上升沿读取数据还是信号下降沿读取数据;

CKP可以配置为1或0。这意味着您可以根据需要将时钟的默认状态(IDLE)设置为高或低。极性反转可以通过简单的逻辑逆变器实现。您必须参考设备的数据手册才能正确设置CKP和CKE。

 

时钟相位 CKE /Clock Phase (Edge)

 

除配置串行时钟速率和极性外,SPI主设备还应配置时钟相位(或边沿)。根据硬件制造商的不同,时钟相位通常写为 CKE或 CPHA

顾名思义,时钟相位/边沿,也就是采集数据时是在时钟信号的具体相位或者边沿;

 

时钟配置总结

 

综上几种情况,下图总结了所有时钟配置组合,并突出显示了实际采样数据的时刻;

 

其中黑色线为采样数据的时刻;
蓝色线为SCK时钟信号;

 

具体如下图所示;

模式编号

SPI的时钟极性和相位的配置通常称为 SPI模式,所有可能的模式都遵循以下约定;具体如下表所示;

SPI Mode CPOL CPHA 0 [00] 0 0 1 [01] 0 1 2 [10] 1 0 3 [11] 1 1

除此之外,我们还应该仔细检查微控制器数据手册中包含的模式表,以确保一切正常。

多从机模式

前面说到SPI总线必须有一个主机,可以有多个从机,那么具体连接到SPI总线的方法有以下两种:

第一种方法:多NSS

 

  1.  

    通常,每个从机都需要一条单独的SS线。

     

  2.  

    如果要和特定的从机进行通讯,可以将相应的 NSS 信号线拉低,并保持其他 NSS 信号线的状态为高电平;如果同时将两个 NSS 信号线拉低,则可能会出现乱码,因为从机可能都试图在同一条 MISO 线上传输数据,最终导致接收数据乱码。

     

 

具体连接方式如下图所示;

多NSS连接

第二种方法:菊花链

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

 

  1.  

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

     

  2.  

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

     

 

具体的连接如下图所示;

菊花链连接

 

其中红线加粗为数据的流向;

 

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

数据流图

 

SCK为时钟信号,8clks表示8个边沿信号;
其中D为数据,X为无效数据;

 

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

优缺点SPI通讯的优势

使SPI作为串行通信接口脱颖而出的原因很多;

 

SPI的缺点 编程实现

 

下面是通过STM32的cubemx自动生成的HAL库代码,比较简单,截取了其中一部分,具体如下;

staticvoidMX_SPI1_Init( void)

{

hspi1.Instance = SPI1;

hspi1.Init.Mode = SPI_MODE_MASTER; //主机模式

hspi1.Init.Direction = SPI_DIRECTION_2LINES; //全双工

hspi1.Init.DataSize = SPI_DATASIZE_8BIT; //数据位为8位

hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; //CPOL=0

hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; //CPHA为数据线的第一个变化沿

hspi1.Init.NSS = SPI_NSS_SOFT; //软件控制NSS

hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; //2分频,32M/2=16MHz

hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; //最高位先发送

hspi1.Init.TIMode = SPI_TIMODE_DISABLE; //TIMODE模式关闭

hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; //CRC关闭

hspi1.Init.CRCPolynomial = 10; //默认值,无效

if(HAL_SPI_Init(&hspi1) != HAL_OK) //初始化

{

_Error_Handler(__FILE__, __LINE__);

}

}

//发送数据

HAL_StatusTypeDef

HAL_SPI_Transmit(SPI_HandleTypeDef *hspi,

uint8_t*pData,

uint16_tSize,

uint32_tTimeout) ;

//接收数据

HAL_StatusTypeDef

HAL_SPI_Receive(SPI_HandleTypeDef *hspi,

uint8_t*pData,

uint16_tSize,

uint32_tTimeout) ;

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>