STM32F4的SPI

SPI协议简介

SPI协议是由摩托罗拉公司提出的通讯协议,即串行外围设备接口。是一种高速全双工的通信总线。

SPI物理层

SPI协议使用3条总线以及片选线。3条总线分别是SCK、MOSI、MISO,片选线为SS(NSS、CS)
在这里插入图片描述

SS:从设备选择信号线,常称为片选信号线。还有NSS、CS标记。当多个SPI从设备与SPI主机相连时,其他信号SCK、MOSI、MISO都是并联到相同的SPI总线上的,所有的从设备都在使用这三条总线。但是每一条设备都有一个独立的SS信号线,该信号线独占主机的一个引脚,由多少个从设备,就有多少条片选信号线。当主机要选择从设备时,就将该设备的SS信号线拉低,表示选中该设备。SPI通讯以SS置低为开始信号,拉高作为结束信号
SCK:时钟信号线、
MOSI:主设备输出/从设备输入引脚
MISO:主设备输入/从设备输出引脚

SPI协议层

SPI基本通讯过程

在这里插入图片描述

NSS、SCK、MOSI信号都由主机控制产生,MISO的信号由从机产生,主机通过该信号线读取从机的数据。MOSI和MISO的信号只在NSS为低电平的时候才有效,在SCK的每个时钟周期MOSI和MISO传输一位数据。

通讯的起始和停止信号

NSS信号线由高变低,是SPI通讯的起始信号。当从机检测到起始信号后,就知道自己被主机选中,开始准备与主机通信。
NSS信号线由低变高,是SPI通讯的停止信号。表示本次通讯结束,从机的选中状态被取消。

数据有效性

SPI使用MOSI和MISO信号线来传输数据,使用SCK信号线进行数据传输。
MOSI和MISO数据线在SCK的每个时钟周期传输一位数据,且数据输入输出是同步进行。
MOSI和MISO的数据在SCK的上升沿期间变化输出,在SCK的下降沿被采样。
SPI每次可以传输8位或16位为单位,不受限制。
MSB先行或LSB先行没有做硬性规定,但要保证两个SPI设备之间使用同样协定。一般采用MSB先行模式。

CPOL/CPHA以及通讯模式

时钟极性CPOL是指SPI通讯设备处于空闲状态时,SCK信号线的电平信号(SPI通讯开始前,NSS线为高电平时SCK的状态)。CPOL=0时,SCK在空闲状态为低电平,CPOL=1则相反。
时钟相位CPHA是指数据的采样时刻,当CPHA=0,MOSI或MISO数据线上的信号将会在SCK时钟线的“奇数边沿”被采样,当CPHA=1时,数据线信号将会在SCK时钟线的“偶数边沿”被采样
在这里插入图片描述

STM32的SPI特性以及架构

SPI外设简介

STM32的SPI外设可用作主机和从机,支持最高的SCK时钟频率f_pclk/2,完全支持SPI协议的四种模式,数据帧长度可设置为8位或16位,可设置MSB或LSB先行。
可以支持双线全双工、双向单线以及单线模式。其中双线单向模式可以同时使用MOSI和MISO数据线向一个方向传输数据。

SPI架构剖析

在这里插入图片描述

通讯引脚

STM32芯片有多个SPI外设,它们SPI通讯信号引到不同的GPIO引脚,使用时必须配置到这些指定的引脚。

时钟控制逻辑

通过控制寄存器CR的BR[0:2]位控制,可以实现2、4、8、16、32、64、128、256分频。

数据控制逻辑

SPI的MOSI以及MISO都连接到数据移位寄存器上,数据移位寄存器的内容来源于接收缓冲区、发送缓冲区以及MOSI、MISO线。
当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位通过数据线发送出去。
当从外部接收数据时,数据移位寄存器把数据线采样到的数据一位一位存储到“接收缓冲区”中。
通过写SPI的数据寄存器DR把数据填充到发送缓冲区中。通过读数据寄存器DR可以获取接收缓冲区中的内容。
数据帧长度->CR1的DFF位配置为8位或16位模式
MSB或LSB先行->LSBFIRST位

整体控制逻辑

控制逻辑负责协调整个SPI外设,控制逻辑的工作模式根据我们配置的”控制寄存器CR1/CR2“的参数而改变,基本的控制参数包括SPI模式、波特率、LSB先行、主从模式等
在SPI外设工作时,控制逻辑会根据外设的工作状态修改”状态寄存器SR“。我们可以通过读取状态寄存器的相关位来了解SPI的工作状态。
控制逻辑还根据要求,负责产生SPI中断信号、DMA请求以及控制NSS信号线
一般实际应用过程中,我们一般不使用SPI外设标准的NSS信号线,而是简单的使用普通的GPIO

通讯过程

主模式收发流程如下
1、控制NSS信号线,产生起始信号
2、把要发送的数据写入”数据寄存器DR“中,该数据会被存储到发送缓冲区
3、通讯开始,SCK时钟运转。MOSI把发送缓冲区里面的数据一位一位的传输出去,MISO把数据一位一位存储进接收缓冲区
4、发送完一帧数据时,“状态寄存去SR”的“TXE标志位”会被置1,表明传输完一帧,发送缓冲区已空。
接收完一帧数据时,“状态寄存去SR”的“RXNE标志位”会被置1,表明传输完一帧,接收缓冲区非空。
5、等待到“TXE标志位”为1时,若还要继续发送数据,则再次往“数据寄存器DR”写入数据即可
等待到“RXNE标志位”为1时,通过读取“数据寄存器”可以获取接收缓冲区中的内容
假如我们使能了TXE或RXNE中断,TXE或RXNE置1时会产生SPI中断信号,进入到同一个中断服务函数中,我们可以在该中断程序中检查寄存器位来了解是哪一个事件,在分别处理。
可以使用DMA方式来收发”数据寄存器DR“中的数据。

SPI结构体以及具体实现代码详解

SPI初始化结构体

typedef struct
{
  uint16_t SPI_Direction;  //设置SPI的单双向模式
  uint16_t SPI_Mode;     //设置SPI的主从模式
  uint16_t SPI_DataSize;   //设置数据帧长度 8/16位
  uint16_t SPI_CPOL;     //设置时钟极性CPOL
  uint16_t SPI_CPHA;     //设置时钟相位CPHA	
  uint16_t SPI_NSS;      //设置NSS引脚是由硬件/软件控制 
  uint16_t SPI_BaudRatePrescaler;   //设置时钟分频因子
  uint16_t SPI_FirstBit;           //设置MSB/LSB先行
  uint16_t SPI_CRCPolynomial;    //设置CRC校验的表达式
}SPI_InitTypeDef;

SPI配置大体逻辑

void SPI_Init(void){
    配置SPI的GPIO初始化;
	SPI_InitStructure SPI_InitStructure;
    配置SPI结构体里面的各个参数;
    SPI_Init(xx,&SPI_InitsStructure);
    SPI_Cmd(xx,ENABLE);
}

SPI接收/发送一个字节的数据

#define Bummy_Byte OXFF
//使用SPI发送一个字节的数据
u8 SPI_XX_SendByte(u8 byte){
    SPITimeout = SPIT_FLAG_TIMEOUT;

    while(SPI_I2S_GetFlagStatus(XX_SPI,SPI_I2S_FLAG_TXE) == RESET){
        if((SPITimeout--) == 0)
            return SPI_TIME_UserCallback(0);
    }
    SPI_I2S_SendData(XX_SPI,byte);
    SPITimeout = SPIT_FLAG_TIMEOUT;
    while(SPI_I2S_GetFlagStatus(XX_SPI,SPI_I2S_FLAG_RXNE) == RESET){
        if((SPITimeout--) == 0)
            return SPI_TIME_UserCallback(1);
    }
    return SPI_I2S_ReceiveData(FLASH_SPI);
}

//使用SPI读取一个字节的数据
//SPI的接收过程和发送过程实质是一样的
//Dummy_Byte 是一个任意值
u8 SPI_XX_ReadByte(void){
    return (SPI_XX_SendByte(Dummy_Byte));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值