首页 > 技术文章 > SPI总线协议介绍

liantang-blog 2020-09-27 13:37 原文

  一、概述

  SPI = Serial Peripheral Interface,是串行外围接口设备,是一种高速,全双工,同步的通信总线。常规只占用四根线,节约了芯片管脚,PCB的布局省空间。

  • 优点:

    支持全双工,push-pull的驱动性能相比open-drain信号完整性更好。

    支持高速(100MHz以上)。

    协议支持字节长不限于8bits,可根据应用特点灵活选择消息字长

    硬件连接简单。

  • 缺点:

    相比I2C多两根线。

    没有寻址机制,只能靠片选选择不同设备。

    没有从设备接收ACK,主设备对于发送成功与否不得而知。

    典型应用只支持单主控

    相比RS232  RS485和CAN总线,SPI传输距离短

 

  二、硬件结构

  SPI总线定义两个及以上设备间的数据通信,提供时钟的设备为主设备Master,接收时钟的设备为从设备Slave;

  信号定义如下:

    SCK :Serial Clock 串行时钟

    MOSI:Master Ouput,Slave Input 主发从收信号

    MISO:Master Input,Slave Input主收从发信号

    SS/CS:Slave Select片选信号

  电路连接如下:

  单个主设备和单个从设备:

  

  单个主设备和多个从设备:

  

 

  三、寄存器类型

    摩托罗拉定义的SPI寄存器包括:

    SPI Control Register 1 控制寄存器1

    SPI Control Register 2 控制寄存器2

    SPI Baud Rate Register 波特率寄存器

    SPI Status Register(SPISR)   状态寄存器(只读 其余均可读可写)

    SPI Data Register(SPIDR) 数据寄存器

    通过往寄存器中写入不同的值,设置SPI模块的不同属性

  四、SPI传输模式  

    SPI通信有四种模式,简单地讲就是设置SCLK时钟信号线的那种信号为有效信号

    通过设置控制寄存器SPICR1中的CPOL和CPHA位,将SPI可以分成四种传输模式

 

    时钟极性CPOL,即Clock Polarity,决定时钟空闲时状态电平。对于SPI数据传输格式没有显著影响

    CPOL = 0 ,表示当SCLK=0时处于空闲状态,所以有效状态就是SCLK处于高电平状态时

    CPOL = 1, 表示当SCLK=1时处于空闲状态,所以有效状态就是SCLK处于低电平状态时

 

    CPHA,即Clock Phase,定义SPI数据传输的两种基本模式

    CPHA = 0 ,在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。,在第2个边沿发送数据

    CPHA = 1, 在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。,在第1个边沿发送数据

    

 

    四种模式如下图所示:

    先看第一列两张图(CPHA = 0),采样发生在第一个时钟跳变沿,即数据采样发生在SCK奇数边沿;

    再看第二列两张图(CPHA = 1),采样发生在第二个时钟跳变沿,即数据采样发生在SCK偶数边沿。

    

    MODE0:CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第一个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿(准备数据),(发送数据)数据发送是在下沿

    MODE1:CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第一个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿

    MODE2:CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采样是在第一个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿    

    MODE3:CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第一个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿

 

 

    五、读写操作

    标准SPI读写为例

    片选——读指令——地址——数据读出

    

    片选——写指令——地址——数据写入

    

 

    SPI通信协议

    

    

    主从设备必须使用相同的工作模式——SCLK、CPOL 和 CPHA,才能正常工作。如果有多个从设备,并且它们使用了不同的工作模式,那么主设备必须在读写不同从设备时需要重新修改对应从设备的模式。以上SPI总线协议的主要内容。

    是不是感觉,这就完了? SPI就是如此,他没有规定最大传输速率,没有地址方案,也没规定通信应答机制,没有规定流控制规则。

    只要四根信号线连接正确,SPI模式相同,将CS/SS信号线拉低,即可以直接通信,一次一个字节的传输,读写数据同时操作,这就是SPI

    一些通信控制都得通过SPI设备自行实现,SPI并不关心物理接口的电气特性,例如信号的标准电压。

    

   

   STM32中SPI初始化配置

    1.初始化GPIO口,配置相关引脚的复用功能,使能SPIx时钟。调用函数:void GPIO_Init();

    2.使能SPI时钟总线:RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE)

    3.配置SPI初始化的参数,设置SPI工作模式:SPI_Init(SPI1,&SPI_Initstructure)

    4.使能SPI外设:SPI_Cmd(SPI1,ENABLE);

    SPI配置设置

    

  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; /*!< 指定数据传输是从MSB还是LSB位开始的。MSB就是二进制第一位,LSB就是最后一位 */
    uint16_t SPI_CRCPolynomial; /*!< CRC校验 ,设置 CRC 校验多项式,提高通信可靠性,大于 1 即可*/
  }SPI_InitTypeDef;
void SPI2_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;
 
  RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 
  RCC_APB1PeriphClockCmd(    RCC_APB1Periph_SPI2,  ENABLE );//SPI2时钟使能     
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
 
  GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);  //PB13/14/15上拉
 
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;        //设置SPI工作模式:设置为主SPI
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;        //设置SPI的数据大小:SPI发送接收8位帧结构
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;        //串行同步时钟的空闲状态为高电平
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;        //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;        //定义波特率预分频的值:波特率预分频值为256
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;    //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  SPI_InitStructure.SPI_CRCPolynomial = 7;    //CRC值计算的多项式
  SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
  SPI_Cmd(SPI2, ENABLE); //使能SPI外设
    
  SPI2_ReadWriteByte(0xff);//启动传输    
}

 

推荐阅读