STM32SPI通信原理
Posted 想成为大师啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32SPI通信原理相关的知识,希望对你有一定的参考价值。
参考正点原子视频
SPI接口简介
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用于EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议,比如AT91RM9200
SPI内部结构简明图
SPI工作原理总结
- 硬件上为4根线
- 主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输
- 串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换
- 外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。
SPI接口一般使用4条线通信:
- MISO(Master Input Slave Output):主设备数据输入,从设备数据输出
- MOSI(Master Output Slave Input):主设备数据输出,从设备数据输入
- SCLK(Serial Clock):时钟信号,由主设备产生
- CS(Chip Select):从设备片选信号,由主设备控制
其中,CS是从芯片是否被主芯片选中的控制信号,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),主芯片对此从芯片的操作才有效。这就使在同一条总线上连接多个SPI设备成为可能。
接下来就负责通讯的3根线了。通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。这就是SCLK时钟线存在的原因,由SCLK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。数据输出通过 SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。完成一位数据传输,输入也使用同样原理。因此,至少需要8次时钟信号的改变(上沿和下沿为一次),才能完成8位数据的传输。
时钟信号线SCLK只能由主设备控制,从设备不能控制。同样,在一个基于SPI的设备中,至少有一个主设备。这样的传输方式有一个优点,在数据位的传输过程中可以暂停,也就是时钟的周期可以为不等宽,因为时钟线由主设备控制,当没有时钟跳变时,从设备不采集或传送数据。SPI还是一个数据交换协议:因为SPI的数据输入和输出线独立,所以允许同时完成数据的输入和输出。芯片集成的SPI串行同步时钟极性和相位可以通过寄存器配置,IO模拟的SPI串行同步时钟需要根据从设备支持的时钟极性和相位来通讯。
最后,SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。
SPI接口框图
STM32 SPI接口可配置为支持SPI协议或者支持I2S音频协议,默认为SPI模式。可以通过软件切换到I2S方式
SPI特征
- 3线全双工同步传输
- 8或16位传输帧格式选择
- 主或从操作
- 支持多主模式
- 8个主模式波特率预分频系数(最大为fpclk/2)
- 从模式频率(最大为fpclk/2)
- 主模式和从模式的快速通信
- 主模式和从模式下均可以由软件或硬件进行NSS管理,主/从操作模式的动态改变
- 可编程的时钟极性和相位
- 可编程的数据顺序,MSB在前或LSB在前
- 可触发中断的专用发送和接收标志
- SPI总线忙状态标志
- 支持可靠通信的硬件CRC
- ----在发送模式下,CRC值可以被作为最后一个字节发送
- ----在全双工模式中对接收到的最后一个字节自动进行CRC校验
- 可触发中断的主模式故障,过载以及CRC错误标志
- 支持DMA功能的1字节发送和接收缓冲器:产生发送和接收请求
NSS脚
NSS:从器件选择。这是用于选择从器件的可选引脚。此引脚用作“片选”,可让 SPI主器件与从器件进行单独通信,从而并避免数据线上的竞争。从器件的 NSS 输入可由主器件上的标准 IO 端口驱动。 NSS 引脚在使能(SSOE 位)时还可用作输出,并可在SPI 处于主模式配置时驱动为低电平。通过这种方式,只要器件配置成 NSS 硬件管理模式,所有连接到该主器件 NSS 引脚的它器件 NSS 引脚都将呈现低电平,并因此而作为从器件。当配置为主模式,且 NSS 配置为输入(MSTR=1 且 SSOE=0)时,如果NSS 拉至低电平, SPI 将进入主模式故障状态: MSTR 位自动清零,并且器件配置为从模式。
1) NSS管脚为输出时
主模式配置,并且使能(SSOE 位)时可用作输出。对外输出低电平,那么当其他SPI器件的NSS管脚与之相连,并且为硬件从器件管理时,则其他器件会被选定为从器件。另外,还可以把NSS管脚当做片选管脚使用。
2) NSS管脚为输入时
- 软件从器件管理:SSM = 1,从器件选择信息在内部由 SPI_CR1 寄存器中的 SSI
位的值驱动。此时SSI位的值替代了NSS管脚的电平信号 - 硬件从器件管理:SSM = 0,当器件在主模式下工作时才使用此配置。当NSS管脚输入为高电平,芯片会被配置为主器件;反之会被芯片会被配置为从器件。
结论:
-
假如选择硬件从器件管理,则NSS管脚应该接高电平,此时STM32为SPI主机。
-
假如选择软件从器件管理,则SS I位应该配置1,此时STM32为SPI主机。
建议选择软件从器件管理,能省下一个IO口,此时 NSS管脚可以作为普通IO口使用。
时钟信号的相位和极性
- SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0‘,SCK引脚在空闲状态保持低电平;如果CPOL被置’1‘,SCK引脚在空闲状态保持高电平。
- 如果CPHA(时钟相位)位被置’1‘,SCK时钟的第二个边沿(CPOL位为0时就是下降沿,CPOL位为’1‘时就是上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。如果CPHA位被清’0‘,SCK时钟的第一边沿(CPOL位为’0‘时就是下降沿,CPOL位为’1‘时就是上升沿)进行数据位采样,数据在第一个时钟沿被所存。
- CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。
数据帧格式
- 根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以MSB在先也可以LSB在先
- 根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数据帧格式对发送和/或接收都有效
状态标志
- 应用程序通过3个状态标志可以完全监控SPI总线的状态
发送缓冲器空闲标志(TXE)
- 此标志为’1‘时表明发送缓冲器为空,可以写下一个待发送的数据进入缓冲器中。当写入SPI_DR时,TXE标志被清除
接收缓冲器非空(RXNE)
- 此标志为’1‘时表明在接收缓冲器中包含有效的接收数据。读SPI数据寄存器可以清除此标志
忙(Busy)标志
- BSY标志由硬件设置与清除(写入此位无效果),此标志表明SPI通信层的状态
SPI中断
SPI引脚配置
常用寄存器
- SPI控制寄存器1(SPI_CR1)
- SPI控制寄存器2(SPI_CR2)
- SPI状态寄存器(SPI_SR)
- SPI数据寄存器(SPI_DR)
- SPI_I2S配置寄存器(SPI_I2S_CFGR)
- SPI_I2S预分频寄存器(SPI_I2SPR)
SPI相关库函数
初始化函数
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
作用:初始化SPI的相关参数,比如方向(全双工)、主从模式、数据大小、CPOL、CPHA、片选软件模式、预分频系数等。
使能函数
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
作用:使能SPI接口;使能SPI中断;使能SPI的DMA功能。
数据传输函数
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
作用:分别用于SPI传输数据、接收数据。
状态位函数
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
作用:前两者用于获得和清除SPI的各种状态位;后两者则针对SPI的中断标志位。
typedef struct
{
u16 SPI_Direction;//用于设置SPI单向或者双向数据模式。
u16 SPI_Mode;//用于设置SPI的工作模式;
u16 SPI_DataSize;//用于设置SPI数据大小;
u16 SPI_CPOL;//用于选择串行时钟的稳态;
u16 SPI_CPHA;//用于设置位捕捉的时钟活动沿;
u16 SPI_NSS;//用于指定NSS信号由硬件(NSS引脚)还是软件(SSI位)管理
u16 SPI_BaudRatePrescaler;//用于定义比特率预分频的值,该值用于设置发送和接收的SCK时钟
u16 SPI_FirstBit;//用于指定数据传输从MSB位还是LSB位开始
u16 SPI_CRCPolynomial;//定义用于CRC值计算的多项式
}SPI_InitTypeDef;
其中每一个参数初始化可取的值可以查询相关的手册得到,以下用一个例子来说明每一个参数的初始化使用情况。
1.SPI_DeInit函数的功能是将外设SPIx寄存器重设为默认值。输入参数SPIx可以是1和2,是用来选择SPI外设的。
2.SPI_Init函数的功能是根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器。SPI_InitDefType的结构体是定义在文件stm32f10x_spi.h里。
// 依据SPI_InitTsructure中指定的参数初始化SPI1
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI设置双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置为主SPI;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;//SPI发送接收16位帧;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟悬空高;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据捕获于第2个时钟沿;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;//NSS由外部引脚管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//比特率预分频为128;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial =7;//CRC计算的初值为7;
SPI(SPI1,SPI_InitStructure);
3.SPI_Cmd函数的功能是使能或者失能SPI外设。
SPI_Cmd(SPI1,ENABLE);
4.SPI_ITCinfig函数的功能是使能或者失能指定的SPI中断,该函数可取的参数值是SPI_IT_TXE/RXNE/ERR:发送缓存空中断频屏蔽/接受缓存非空中断屏蔽/错误中断屏蔽。
SPI_ITConfig(SPI2,SPI_IT_TXE,ENABLE);
5.SPI_DMACmd函数的功能是使能或者失能指定SPI的DMA请求。该函数可取的值为SPI_DMAReq_Tx/Rx:选择Tx/Rx缓存DMA传输请求。
SPI_DMACmd(SPI2,SPI_CmdRq_Tx,ENABLE);
6.SPI_SendData函数的功能是通过外设SIPx发送一个数据
SPI_SendData(SPI1,0XA5);
7.SPI_ReceiveData函数的功能是返回通过SPIx最近接受的数据,其中接收到的数据是16位的数据。
u16 ReceiveData;
ReceiveData = SPI_ReceiveData(SPI2);
8.SPI_GetFlagStatus函数的功能是检查指定的SPI标志位置位与否。一共有4种可取值:SPI_FLAG_BSY/OVR/MODF/RXNE:忙/超出/模式错误/接收缓存非空标志位。
9.SPI_ClearFlag函数的功能是清楚SPIx的待处理标志位。
SPI_ClearFlag(SPI2,SPI_FLAG_OVER);
10.spi_GetITStatus函数的功能是检查指定的SP中断发生与否。参数可取的值为:SPI_IT_OVR/MODF/CRC/RXNE/TXE.
ITStatus = Status;
Status = SPI_GetITStatus(SPI1,SPI_IT_OVR);
11.SPI_ClearITPendingBit函数的功能是清除SPIx的中断处理位。
SPI_ClearITPendingBit(SPI2,SPI_IT_CRCERR);
程序配置过程
①配置相关引脚的复用功能,使能SPIx时钟
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);
②初始化SPIx,设置SPIx工作模式
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
③使能SPIx
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
④SPI传输数据
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
⑤查看SPI传输状态
SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);
硬件连接
以上是关于STM32SPI通信原理的主要内容,如果未能解决你的问题,请参考以下文章