一、SPI接口简介
SPI是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口,是Motoroal首先在其MC68HCXX系列处理器上定义的。
SPI是一种高速的、全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省了空间,提供方便,主要应用在EEPROM、FLASH、实时时钟、AD转换器还有数字信号处理器和数字信号解码器之间
SPI接口框图
SPI内部结构简明图
SPI接口一般使用4条线通信:
MISO主设备数据输入,从设备数据输出;MOSI主设备数据输出,从设备数据输入;
SCLK时钟信号,由主设备产生。CS从设备片选信号,由主设备控制。
SPI工作原理总结:
1、硬件上为4根线。
2、主机和从机都有一个串移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。
3、串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。
4、外设的写操作和读操作是同步完成的。如果只进行写操作,主机只忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。
二、SPI特征
1、3线全双工同步传输。
2、8位或16位传输帧格式选择。
3、主或从操作。
4、支持多主模式。
5、8个主模式波特率预分频系数(最大为Fpclk/2)
6、从模式频率(最大为Fpclk/2)
7、主模式和从模式的快速通信。
8、主模式和从模式下均可由软件或硬件进行NSS管理:主/从操作模式的动态改变。
9、可编程的时钟极性和相位。
10、可编程的数据顺序,MSB在前或LSB在前。
11、可触发中断的专用发送和接收标志。
12、SPI总线忙状态标志。
13、支持可通信的硬件CRC:——在发送模式下,CRC值可以被作为最后一个字节发送。
——在全双工模式中对接收到的最后一个字节自动进行CRC校验。
14、可触发中断的主模式故障、过载以及CRC错误标志。
15、支持DMA功能的1字节发送和接收缓冲器:产生发送和接收请求。
(STM32 SPI接口可配置为支持SPI协议或者支持I2C音频协议,默认是SPI模式。可以通过软件切换到I2C方式)
从器件选择(NSS)引脚管理
时钟信号的相位和极性
CPHA=1(采集数据的时间)
CPHA=0(采集数据的时间)
数据帧格式
根据SPI_CR1寄存器中的LSBFISRST位,输出数据位时可以MSB在先也可以LSB在先。
根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位,所选择的数据帧格式对发送和/或接收都有效
状态标志:应用程序通过3个状态标志位可以完全监控SPI总线的状态。
发送缓冲器空闲标志(TXE):此标志为‘1’表明发送缓冲器为空,可以写下一个待发送的数据进入缓冲器中。当写入SPI_DR时,TXE标志被清除。
接收缓冲器非空(RXNE):此标志为‘1’时表明在接收缓冲器中包含有效的接收数据。读SPI数据寄存器可以清除该标志位。
忙(Busy)标志:BSY标志由硬件设置与清除(写入此位无效果),此标志表明SPI通信层的状态。
SPI中断:
SPI引脚配置(3个SPI)
三、SPI常用寄存器和相关库函数
SPI常用寄存器
SPI控制寄存器1(SPI_CR1)
SPI控制寄存器2(SPI_CR2)
SPI状态寄存器(SPI_SR)
SPI数据寄存器(SPI_DR)
SPI_I2S配置寄存器(SPI_I2C_CFGR)
SPI_I2S预分频寄存器(SPI_I2CSPR)
SPI相关库函数
void SPI_I2C_DeInit(SPI_TypeDef* SPIx);
void SPI_Init(SPI_TypeDef* SPIx,SPI_InitTypeDef* SPI_InitStruct);//SPI初始化函数
void SPI_Cmd(SPI_TypeDef* SPIx,FunctionalState NewState);//SPI使能函数
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);//DMA函数
void SPI_I2S_SendData(SPI_TypeDef* SPIx,uint16_t Data);//SPI发送数据函数
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);//SPI接收数据函数
void SPI_DataSizeConfig(SPI_TypeDef* SPIx,uint16_t SPI_DataSize);//确定数据是8位还是16位
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_Init()
typedef struct
{
uint16_t SPI_Direction;方向:支持两线双通或者一线之类的
uint16_t SPI_Mode;模式
uint16_t SPI_DataSize;确定位数:8位或16位
uint16_t SPI_CPOL;
uint16_t SPI_CPHA;
uint16_t SPI_NSS;确定是硬件还是软件
uint16_t SPI_BaudRatePrescaler;波特率预分频系数
uint16_t SPI_FirstBit;第一位:LSB在前还是MSB在前
uint16_t SPI_CrCPolynomial;CRC的校验
}SPI_InitTypeDef;
程序配置过程:
1、使能SPIx和IO口时钟
RCC_AHBxPeriphClockCmd()/RCC_APBxPeriphClockCmd();
2、初始化IO口为复用功能
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);
3、 设置引脚复用映射
GPIO_PinAFConifg();
4、初始化SPIx,设置SPIx工作模式
void SPI_Init(SPI_TypeDef* SPIx,SPI_InitTypeDef* SPI_InitStruct);
5、使能SPIx
void SPI_Cmd(SPI_TypeDef* SPIx,FunctionalState NewState);
6、SPI传输数据
void SPI_I2S_SendData(SPI_TypeDef* SPIx,uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
7、查看SPI传输状态
SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE);
四、SPI FLASH的相关硬件