1、概述
SPI是Serial Perripheral Interface的简称,是由Motorola公司推出的一种高速、全双工的总线协议。
SPI也是采用主从方式工作,一般由**SCLK(时钟线)、CS(片选信号)、MOSI(主机输出,从机输入),MISO(主机输入,从机输出)**四根线组成,当有多个从机存在时,主机就需要多个CS信号引脚,每个CS引脚信号对应一个从机,主机可以通过相应的CS来选择要控制的从机设备。
如下图所示,SCLK、MOSI,MISO这三根线都是公用的,唯有片选信号线(CS)是和从机一一对应的。
2、四种工作模式
根据SPI时钟极性(CPOL)和时钟相位(CPHA)配置的不同可分为4种模式。
1、CPOL = 1:表示SCLK时钟信号空闲时是高电平;CPHA = 0:表示从第一个跳变沿开始采样;
2、CPOL = 1:表示SCLK时钟信号空闲时是高电平;CPHA = 1:表示从第二个跳变沿开始采样;
3、CPOL = 0:表示SCLK时钟信号空闲时是低电平;CPHA = 0:表示从第一个跳变沿开始采样;
4、CPOL = 0:表示SCLK时钟信号空闲时是低电平;CPHA = 1:表示从第二个跳变沿开始采样;
3、数据交换
SPI 设备间的数据传输之所以又被称为数据交换,是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 “发送者(Transmitter)” 或者 “接收者(Receiver)”。SPI是全双工通信,所以发送和接收是同时进行的。在每个 Clock 周期内,SPI 设备都会发送并接收一个 bit 大小的数据(不管主设备还是从设备),相当于该设备有一个 bit 大小的数据被交换了。一个 Slave 设备要想能够接收到 Master 发过来的控制信号,必须在此之前能够被 Master 设备进行访问 (Access)。所以,Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上。 在数据传输的过程中,每次接收到的数据必须在下一次数据传输之前被采样。如果之前接收到的数据没有被读取,那么这些已经接收完成的数据将有可能会被丢弃,导致 SPI 物理模块最终失效。因此,在程序中一般都会在 SPI 传输完数据后,去读取 SPI 设备里的数据, 即使这些数据(Dummy Data)在我们的程序里是无用的(虽然发送后紧接着的读取是无意义的,但仍然需要从寄存器中读出来)。
所以一般在SPI通信中,写数据的时候从机一般会返回一个无效数据。读数据的时候,主机也需要向从机发送一个无效数据。
uint8_t SPI_ReadWrite_Byte(uint8_t TxData,uint8_t *RcvMsg)
{
uint8_t uState = BSP_OK;
uint16_t i=0;
while( !LL_SPI_IsActiveFlag_TXE(SPI1) ) //判断发送缓存器里是否为空。空返回1.
{
if(++i>=500)
{
uState = BSP_ERR;
break;
}
}
LL_SPI_TransmitData8(SPI1, TxData);
i= 0;
while(!LL_SPI_IsActiveFlag_RXNE(SPI1)) //判断接收寄存器里是否有数据,有数据返回1
{
if(++i>=500)
{
uState = BSP_ERR;
break;
}
}
*RcvMsg = LL_SPI_ReceiveData8(SPI1);
return uState;
}
写地址调用函数:SPI_ReadWrite_Byte( addrTemp, &date ); //其中返回的data无意义
读数据调用函数:SPI_ReadWrite_Byte( 0xFF, &date ); //其中0xFF为无效数据