16 玩转STM32之SPI通信

15.1 SPI协议概述

由于时间的原因物理特性之类的这里不在过多的说,如果你是做软件的,这篇是完全没有问题的,因为作为程序开发者,只需要知道他的数据的发送以及时钟特性,其他的并不是很重要,如果你是做硬件开发的话,我认为你只需要参考芯片官方的数据手册就可以了,并不需要你做什么,这方面的电路设计网上也挺多。

SPI是Motorola首先提出的全双工四线同步串行外围接口,采用主从模式(Master-Slave)架构。支持单主多从模式应用,时钟由Master控制,在时钟移位脉冲下,数据按位传输,高位在前,低位在后(MSB first)。
**4线SPI器件有四个信号:时钟(SPI CLK, SCLK)、主机输出从机输入(MOSI)、主机输入从机输出(MISO)、片选(CS/NSS)。**为全双工通信,如图是SPI与从机连接示意图:

SPI通信什么时候是主机呢?
产生时钟信号的器件称作主机。主机和从机之间传输的数据与主机产生的时钟同步。
SPI只有一个主机,但是可以有多个从机。
SPI通信示意图:

主机的片选信号用于选择从机,一般是一个低电平有效,拉高时从机与SPI总线断开连接。
MOSI是主机发送从机接収,MISO主机接収从机发送。

15.1.1 SPI数据传输

1、在MOSI、MISO和SPI主从机内部的数据寄存器构成一个数据串行传输的环路,在时钟SCLK的控制下实现数据的环形传输。
要开始SPI通信,主机必须发送时钟信号,并通过使能NSS信号选择从机。
在看一下这个图:

15.1.2 时钟极性和时钟相位

1、CPOL极性(Clock Polarity ,CPOL)

SPI的CPOL,表示当总线空闲时,SCLK的极性,其电平的值是低电平0还是高电平1:
CPOL=0,时钟空闲时候的电平是低电平,所以当SCLK有效的时候,就是高电平;
CPOL=1,时钟空闲时候的电平是高电平,所以当SCLK有效的时候,就是低电平。

2、CPHA相位(Clock Phase ,CPHA)

CPHA相位对应着数据采样是在第一个边沿(空闲态转电平切换到相反电平)还是第二个边沿,0对应着第一个边沿,1对应着第二个边沿。

15.1.3 四种SPI模式

主机必须根据从机的要求选择时钟极性和时钟相位。
下图是SPI的四种模式:

下面咱们来说说这几种模式:

1、模式0:

在此模式下,时钟极性CPOL=0,表示时钟信号的空闲状态为低电平。时钟相位CPHA=0,数据在第一个边沿(上升沿)采样,并且数据在时钟信号接下来的下降沿移出。

2、模式1:

在此模式下,时钟极性CPOL=0,表示时钟信号的空闲状态为低电平。时钟相位CPHA=1,数据在第二个边沿(下降沿)采样,并且数据在时钟信号接下来的上升沿移出。

3、模式2:

在此模式下,时钟极性CPOL=1,表示时钟信号的空闲状态为高电平。时钟相位CPHA=0,数据在第一个边沿(下降沿)采样,并且数据在时钟信号接下来的上升沿移出。

4、模式3:

在此模式下,时钟极性CPOL=1,表示时钟信号的空闲状态为高电平。时钟相位CPHA=1,数据在第二个边沿(上升沿)采样,并且数据在时钟信号接下来的下降沿移出。

15.2 STM32上的SPI

STM32F429内部有6个SPI控制器,可与外部器件进行半双工/全双工的同步串行通信。
SPI控制器主要有以下特性:
全双工同步传输;
8位或 16 位传输帧格式选择;
支持最高的SCK时钟频率为 fpclk/2
主模式或从模式操作、多主模式功能;
可编程的时钟极性和相位;
可编程的数据顺序,先移位 MSB 或 LSB;
可触发中断的专用发送和接收标志;
具有 DMA 功能。

15.2.1 结构

SPI结构图:

STM32 芯片有多个 SPI 外设,它们的 SPI 通讯引脚(MOSI、MISO、SCLK 及 NSS)通过 GPIO 引脚复用映射实现。
SPI引脚图:

6个SPI控制器中SPI1、SPI4、SPI5、SPI6 挂载在 APB2总线上,最高通信速率达45Mbtis/s,SPI2、SPI3挂载在 APB1 总线上,最高通信速率为 22.5Mbits/s。

15.2.2 SPI主机配置

在此配置中,MOSI 引脚为数据输出,MISO 引脚为数据输入。

1、发送数据:在发送缓冲区中写入字节时,SPI控制器开始发送数据。当移位寄存器中的数据都串行输出之后,数据从发送缓冲区传输到移位寄存器,并将TXE 标志置 1,并且在 SPI_CR2寄存器中的 TXEIE 位置 1 时将生成中断。仅当 TXE 标志为 1 时,才可以对发送缓冲区执行写操作。

2、接收数据:对于接收器,在数据传输完成时:移位寄存器中的数据将传输到接收缓冲区,并且 RXNE 标志置 1。如果 SPI_CR2 寄存器中的 RXNEIE 位置 1,则生成中断。在出现最后一个采样时钟边沿时,RXNE 位置 1,移位寄存器中接收的数据字节被拷贝到接收缓冲区中。通过读取 SPI_DR 寄存器获取接收到的数据,并将 RXNE 位清零。

15.2.3 SPI从机配置

在此配置中,从 SCK 引脚上接收主器件的串行时钟。

1、发送数据:数据字节在写周期内被并行加载到发送缓冲区中,当从器件收到时钟信号和数据的高有效位时,开始发送数据。SPI_SR 寄存器中的TXE 标志在数据从发送缓冲区传输到移位寄存器时置 1,并且在SPI_CR2 寄存器中的 TXEIE 位置 1 时将生成中断。

2、接收数据:对于接收器,在数据传输完成时:移位寄存器中的数据将传输到接收缓冲区,并且 RXNE 标志(SPI_SR 寄存器)置 1。如果 SPI_CR2 寄存器中的 RXNEIE 位置 1,则生成中断。通过读取SPI_DR寄存器获取接收到的数据,并将 RXNE 位清零。

15.2.4 主模式的全双工收发过程

通过SPE位置1使能SPI
把第一个数据写入SPI_DR(这种操作会把TXE标志清零)
等到TXE=1,然后写入要发送的第二个数据项。然后等待RXNE=1,读取SPI_DR获取接収第一个数据(RXNE会清零)。然后重复此操作,直到数据接収为止。
等待RXNE=1,读取最后的接収数据
等待TXE=1,然后等待BSY=0,载关闭SPI。

15.2.5 SPI状态标志

软件可通过三种状态标志监视 SPI 总线的状态。
1、发送缓冲区为空 (TXE):此标志置1时,表示发送缓冲区为空,可以将待发送的下一个数据加载到缓冲区中。对SPI_DR 寄存器执行写操作时,将清零 TXE 标志。

2、接收缓冲区非空 (RXNE):此标志置 1 时,表示接收缓冲区中存在有效的已接收数据。读取 SPI_DR 时,将清零该标志。

3、BUSY:BSY 标志由硬件置 1 和清零(对此标志执行写操作没有任何作用)。BSY 标志用于指示SPI 通信的状态。BSY 置 1 时,表示 SPI 正忙于通信。在主模式下的双向通信接收模式(MSTR=1 且 BDM=1且 BDOE=0)有一个例外情况,BSY 标志在接收过程中保持低电平。

15.2.6 SPI中断

15.3 SPI应用步骤及常用库函数

15.3.1 SPI典型应用步骤

以SPI5工作在全双工主模式为例,使用PF6、PF7、PF8、PF9分别作为作为SPI1的NSS、SCLK、MISO和MOSI的复用引脚。

1、开启SPI5控制器时钟和通信线复用引脚端口GPIOF的时钟。

使能SPI5时钟:
RCC_APB2PeriphClockCmd (RCC_APB2Periph_SPI5, ENABLE);  
使能GPIOA时钟:
         RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);

2、初始化引脚

复用PF6~PF9到SPI5:
  GPIO_PinAFConfig(GPIOF,GPIO_PinSource7,GPIO_AF_SPI5); 
  GPIO_PinAFConfig(GPIOF,GPIO_PinSource8,GPIO_AF_SPI5); 
  GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_SPI5);
将引脚设置为复用模式,并初始化:
  GPIO_Init(GPIOF, &GPIO_InitStructure);

3、初始化SPI5控制器工作模式。

 SPI_Init(SPI5, &SPI_InitStructure);

4、使能SPI5控制器

  SPI_Cmd(SPI5, ENABLE);

5、中断使能

如果需要使用中断,需要配置NVIC和使能相应的SPI5中断事件。

15.3.2 常用库函数

头文件:stm32f4xx_spi.h
源文件:stm32f4xx_spi.c

1、SPI初始化函数

void   void SPI_Init(SPI_TypeDef*  SPIx, SPI_InitTypeDef*  SPI_InitStruct)
1)、参数1:SPI_TypeDef*  SPIx ,SPI应用对象,是一个结构体指针
#define SPI1   ((SPI_TypeDef *) SPI1_BASE)
2)、参数2:SPI_InitTypeDef*  SPI_InitStruct,是SPI应用对象初始化结构体指针
typedef struct
{
  uint16_t  SPI_Direction;	 //定义SPI单向还是双向传输
  uint16_t  SPI_Mode;   	 //定义SPI的主从模式
  uint16_t  SPI_DataSize;      //定义SPI传输数据宽度
  uint16_t  SPI_CPOL;       // SPI的CPOL极性,定义当SPI空闲时,SCLK的极性
  uint16_t  SPI_CPHA;       // SPI的CPHA 相位
  uint16_t  SPI_NSS;      	//NSS引脚管理方式
  uint16_t  SPI_BaudRatePrescaler;   //时钟频率
  uint16_t  SPI_FirstBit;        //最先输出的数据位
  uint16_t  SPI_CRCPolynomial;  //CRC多项式
}SPI_InitTypeDef;
SPI_InitTypeDef  SPI_InitStructure;
  

/* FLASH_SPI 模式配置 */
// FLASH芯片 支持SPI模式0及模式3,据此设置CPOL CPHA
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主机模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//数据位=8bit
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//SCK 引脚在 空闲状态处于高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//SCK第二个边沿采样数据线
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//内部 从器件管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//波特率预分频器
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//先发送数据高位
SPI_InitStructure.SPI_CRCPolynomial = 7;//
SPI_Init(SPI5, &SPI_InitStructure);

2、SPI使能函数

void  SPI_Cmd(SPI_TypeDef*  SPIx, FunctionalState  NewState);

3、SPI发送数据函数

void  SPI_I2S_SendData(SPI_TypeDef*  SPIx, uint16_t  Data);

4、SPI接收数据函数

uint16_t  SPI_I2S_ReceiveData(SPI_TypeDef*  SPIx);

5、SPI检测状态标志函数

FlagStatus  SPI_I2S_GetFlagStatus(SPI_TypeDef*  SPIx, uint16_t  SPI_I2S_FLAG);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南山府嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值