目录
[STM32F1 SPI串行总线的工作原理](#STM32F1 SPI串行总线的工作原理)
[SPI的HAL 驱动函数](#SPI的HAL 驱动函数)
STM32的SPI通信原理
实际生产生活当中,有些系统的功能无法完全通过STM32的片上外设实现,例如,16位及以上的A/D转换器、温/湿度传感器、大容量EEPROM或Flash、大功率电机驱动芯片、无线通信控制芯片等。此时,只能通过扩展特定功能的芯片实现这些功能。另外,有的系统需要两个或者两个以上的主控器(STM32或FPGA),而这些主控器之间也需要通过适当的芯片间通信方式实现通信。
(1)SPI模式。 (2)I2C模式。 全系列的STM32F1系列嵌入式处理器上都集成了硬件的SPI。除小容量STM32外,集成的SPI可以配置为支持SPI协议或者支持I2S协议。在小容量和中容量产品上,不支持I2S音频协议。 下面介绍和解释一下STM32F1上的SPI不同于常见SPI的功能特点。 (1)SPI1 连接到 Cortex-M3的高速外设总线APB2上,其他SPI连接到低速外设总线APB1上。 (2)除支持常见的全双工主从式双机方式外,STM32F1上的SPI还支持只使用一条数据线的半双工同步通信方式以及多主机通信模式。
(3)可作为DMA数据传输中的外设侧设备,实现内存和SPI之间的快速数据交换,而无须担心频繁地打断Cortex-M3内核的工作。 (4)可配置为8位或16位传输的帧格式。虽然在实用当中可以由两次8位传输"拼"成一次16位传输,但单独使用一次16位传输可以提高通信的平均速率,并降低软件的复杂度。 (5)无论工作在SPI的主模式还是从模式下,STM32F1 系列都可以配置成硬件或软件控制片选线SS。 (6)能够对SPI通信数据进行硬件的CRC校验,即由片上集成的硬件实现计算产生通信数据的CRC结果,并与对方发送的循环校验结果进行比对。 (7)可配置SPI通信的数据顺序,实现MSB或LSB在前的通信方式。
SPI串行总线概述
串行外设接口(Serial Peripheral Interface,SPI)是由美国摩托罗拉(Motorola)公司提出的一种高速全双工串行同步通信接口,首先出现在M68HC系列处理器中,由于其简单方便,成本低廉,传输速度快,因此被其他半导体厂商广泛使用,从而成为事实上的标准。 SPI与USART相比,其数据传输速度要快得多,因此它被广泛地应用于微控制器与ADC、LCD等设备的通信,尤其是高速通信的场合。微控制器还可以通过SPI组成一个小型同步网络进行高速数据交换,完成较复杂的工作。
SPI是同步全双工串行通信接口。由于同步,SPI有一条公共的时钟线;由于全双工,SPI至少有两条数据线实现数据的双向同时传输;由于串行,SPI收发数据只能一位一位地在各自的数据线上传输,因此最多只有两条数据线:一条发送数据线和一条接收数据线。由此可见,SPI在物理层体现为4条信号线,分别是SCK、MOSI、MISO和SS。 (1)SCK(Serial Clock),即时钟线,由主设备产生。不同的设备支持的时钟频率不同。 但每个时钟周期可以传输一位数据,经过8个时钟周期,一个完整的字节数据就传输完成了。
(2)MOSI(Master Output Slave Input),即主设备数据输出/从设备数据输入线。这条信号线上的方向是从主设备到从设备,即主设备从这条信号线发送数据,从设备从这条信号线上接收数据。有的半导体厂商(如Microchip公司),站在从设备的角度,将其命名为SDI。 (3) MISO(Master Input Slave Output),即主设备数据输入/从设备数据输出线。这条信号线上的方向是由从设备到主设备,即从设备从这条信号线发送数据,主设备从这条信号线上接收数据。有的半导体厂商(如Microchip公司),站在从设备的角度,将其命名为SDO。
(4)SS(Slave Select),有时候也叫CS(Chip Select),SPI从设备选择信号线,当有多个SPI从设备与SPI主设备相连(即一主多从)时,SS用来选择激活指定的从设备,由SPI主设备(通常是微控制器)驱动,低电平有效。当只有一个SPI从设备与SPI主设备相连(即一主一从)时,SS并不是必需的。因此,SPI也被称为三线同步通信接口。 除了SCK、MOSI、MISO和SS这4条信号线外,SPI接口还包含一个串行移位寄存器
SPI串行总线互连方式
SPI互连主要有一主一从和一主多从两种互连方式。
- 一主一从 在一主一从的SPI互连方式下,只有一个SPI主设备和一个SPI从设备进行通信。这种情况下,只需要分别将主设备的SCK、MOSI、MISO和从设备的SCK、MOSI、MISO直接相连,并将主设备的SS置为高电平,从设备的SS接地(置为低电平,片选有效,选中该从设备)
值得注意的是:USART互连时,通信双方USART的两条数据线必须交叉连接,即一端的TxD必须与另一端的RxD相连,对应地,一端的RxD必须与另一端的TxD相连。而当SPI互连时,主设备和从设备的两根数据线必须直接相连,即主设备的MISO与从设备的MISO相连,主设备的MOSI与从设备的MOSI相连。 2. 一主多从 在一主多从的SPI互连方式下,一个SPI主设备可以和多个SPI从设备相互通信。这种情况下,所有的SPI设备(包括主设备和从设备)共享时钟线和数据线,即SCK、MOSI、MISO这3条线,并在主设备端使用多个GPIO引脚选择不同的SPI从设备
STM32F1 SPI串行总线的工作原理
串行外设接口(SPI)允许芯片与外部设备以半/全双工、同步、串行方式通信。此接口可以被配置成主模式,并为外部从设备提供通信时钟(SCK),接口还能以多主的配置方式工作。它可用于多种用途,包括使用一条双向数据线的双线单工同步传输,还可使用CRC校验的可靠通信。
SPI串行总线的特征
STM32F103微控制器的小容量产品有1个SPI接口,中等容量产品有2个SPI,大容量产品则有3个SPI。 STM32F103微控制器SPI主要具有以下特征:
(1)3线全双工同步传输。
(2)带或不带第三根双向数据线的双线单工同步传输。
(3)8或16位传输帧格式选择。
(4)主或从操作。
(5)支持多主模式。
(6)8个主模式波特率预分频系数(最大为fPCLK/2)。
(7)从模式频率(最大为fPCLK/2)。
(8)主模式和从模式的快速通信。
(9)主模式和从模式下均可以由软件或硬件进行NSS管理:主/从操作模式的动态改变。
(10)可编程的时钟极性和相位。
(11)可编程的数据顺序,MSB在前或LSB在前。
(12)可触发中断的专用发送和接收标志。
(13)SPI总线忙状态标志。
(14)支持可靠通信的硬件CRC。在发送模式下,CRC值可以被作为最后一个字节发送;在全双工模式下,对接收到的最后一个字节自动进行CRC校验。
(15)可触发中断的主模式故障、过载以及CRC错误标志。
(16)支持DMA功能的1字节发送和接收缓冲器,产生发送和接受请求。
SPI串行总线的内部结构
STM32F103微控制器SPI主要由波特率发生器、收发控制和数据存储转移三部分组成。波特率发生器用来产生SPI的SCK时钟信号,收发控制主要由控制寄存器组成,数据存储转移主要由移位寄存器、接收缓冲区和发送缓冲区等构成。
通常SPI通过4个引脚与外部器件相连:
① MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
② MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
③ SCK:串口时钟,作为主设备的输出,从设备的输入。
④ NSS:从设备选择。这是一个可选的引脚,用来选择主/从设备。它的功能是用来作为片选引脚,让主设备可以单独地与特定从设备通信,避免数据线上的冲突。 STM32系列微控制器SPI的功能主要由波特率控制、收发控制和数据存储转移3部分构成。
-
波特率控制 波特率发生器可产生SPI的SCK时钟信号。波特率预分频系数为2、4、8、16、32、64、128或256。通过设置波特率控制位(BR)可以控制SCK的输出频率,从而控制SPI的传输速率。
-
收发控制 收发控制由若干个控制寄存器组成,如SPI控制寄存器SPI_CR1、SPI_CR2和SPI状态 寄存器SPI_SR等。 SPI_CR1 寄存器主控收发电路,用于设置SPI的协议,如时钟极性、相位和数据格式等。 SPI_CR2 寄存器用于设置各种SPI中断使能,如使能TXE的TXEIE和RXNE的RXNEIE等。通过SPI_SR寄存器中的各个标志位可以查询SPI当前的状态。 SPI的控制和状态查询可以通过库函数实现。
-
数据存储转移 数据存储转移如图,主要由移位寄存器、接收缓冲区和发送缓冲区等构成。 移位寄存器与SPI的数据引脚MISO和MOSI连接,一方面将从MISO收到的数据位根据数据格式及顺序经串/并转换后转发到接收缓冲区,另一方面将从发送缓冲区收到的数据根据数据格式及顺序经并/串转换后逐位从MOSI上发送出去。
SPI串行总线时钟信号的相位和极性
SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清0,SCK引脚在空闲状态保持低电平;如果CPOL被置1,SCK引脚在空闲状态保持高电平。 如果CPHA(时钟相位)位被清0,数据在SCK时钟的奇数(第1、3、5个···)跳变沿(CPOL位为0时就是上升沿,CPOL位为1时就是下降沿)进行数据位的存取,数据在SCK时钟偶数(第2、4、6个···)跳变沿(CPOL位为0时就是下降沿,CPOL位为1时就是上升沿)准备就绪。
如果CPHA(时钟相位)位被置1,数据在SCK时钟的偶数(第2、4、6个···)跳变沿(CPOL位为0时就是下降沿,CPOL位为1时就是上升沿)进行数据位的存取,数据在SCK时钟奇数(第1、3、5个···)跳变沿(CPOL位为0时就是上升沿,CPOL位为1时就是下降沿)准备就绪。
CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。SPI传输的4种CPHA和CPOL位组合。此图可以解释为主设备和从设备的SCK、MISO、MOSI引脚直接连接的主或从时序图。 根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以MSB在先也可以LSB 在先。 根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数据帧格式决定发送/接收的数据长度。
STM32的SPI接口配置
- 配置SPI为从模式 在从模式下,SCK引脚用于接收从主设备来的串行时钟。SPI_CR1寄存器中 BR[2:0]的设置不影响数据传输速率。 SPI从模式的配置步骤如下,
(1)设置DFF位以定义数据帧格式为8位或16位。
(2)选择CPOL和CPHA位定义数据传输和串行时钟之间的相位关系。为保证正确的数据传输,从设备和主设备的CPOL和CPHA位必须配置成相同的方式。
(3)帧格式(SPI_CR1寄存器中的LSBFIRST位定义的"最高位在前"还是"最低位在前")必须与主设备相同。
(4)在NSS引脚管理硬件模式下,在数据帧传输过程中,NSS引脚必须为低电平。在NSS软件模式下,设置SPI_CR1寄存器中的SSM位并清除SSI位。
(5)在SPI_CR1寄存器中,清除MSTR位,设置SPE位,使相应引脚工作于SPI模 式下。 在这个配置中,MOSI引脚是数据输入,MISO引脚是数据输出。
(1)数据发送过程 在写操作中,数据字被并行地写入发送缓冲器。当从设备收到时钟信号,并且在MOSI引脚上出现第一个数据位时,发送过程开始,此时第一个位被发送出去,余下的位被装进移位寄存器。当发送缓冲器中的数据传输到移位寄存器时,SPI_SR寄存器的TXE标志被置位,如果设置了SPI_CR2寄存器的TXEIE位,将会产生中断。
(2)数据接收过程 对于接收器,当数据接收完成时,在最后一个采样时钟边沿后,移位寄存器中的数据传送到接收缓冲器,SPI_SR寄存器中的RXNE标志被置位。
- 配置SPI为主模式 在主模式时,MOSI引脚是数据输出,而MISO引脚是数据输入,在SCK引脚产生串行时钟。SPI主模式的配置步骤如下:
(1)通过SPI_CR1寄存器的BR[2:0]位定义串行时钟波特率。
(2)选择CPOL和CPHA位,定义数据传输和串行时钟间的相位关系。
(3)设置DFF位定义8位或16位数据帧格式。
(4)配置SPI_CR1寄存器的LSBFIRST位定义帧格式。
(5)如果需要NSS引脚工作在输入模式,在硬件模式下,在整个数据帧传输期间应把NSS引脚连接到高电平;在软件模式下,需设置SPI_CR1寄存器的SSM位和SSI位。如果NSS引脚工作在输出模式,则只需设置SSOE位。
(6)必须设置MSTR位和SPE位(只当NSS引脚被连到高电平,这些位才能保持置位)。 ① 数据发送过程 当写入数据到发送缓冲器时,发送过程开始。在发送第一个数据位时,数据字通过内部总线被并行地传入移位寄存器,然后串行地移出到MOSI脚上;先输出最高位还是最低位,取决于SPLCR1寄存器中的LSBFIRST位的设置。数据从发送缓冲器传输到移位寄存器时 TXE标志将被置位,如果设置了SPI_CR1寄存器中的TXEIE位,将产生中断。
② 数据接收过程 对于接收器来说,当数据传输完成时,在最后的采样时钟沿,移位寄存器中接收到的数据字被传送到接收缓冲器,并且RXNE标志被置位。 一旦传输开始,如果下一个将发送的数据被放进了发送缓冲器,就可以维持一个连续的传输流。在试图写发送缓冲器之前,需确认TXE标志应该为1。 在NSS硬件模式下,从设备的NSS输入由NSS引脚控制或另一个由软件驱动的GPIO引脚控制。
- 配置SPI为单工通信 SPI模块能够以两种配置工作于单工方式: 1条时钟线和1条双向数据线;1条时钟线和1条数据线(只接收或只发送)。
(1)1条时钟线和1条双向单向数据线(BIDIMODE=1) 通过设置SPI_CR1寄存器中的BIDIMODE位启用此模式。在这个模式下,SCK引脚作为时钟,主设备使用MOSI引脚而从设备使用MISO引脚作为数据通信。传输的方向由SPI_CR1寄存器里的BIDIOE控制,当这个位是1的时候,数据线是输出,否则是输入。
(2)1条时钟和1条单向数据线(BIDIDIMODE=0) 在这个模式下,SPI模块可以或者作为只发送,或者作为只接收。
STM32的SPI接口数据发送与接收过程
-
接收与发送缓冲器 接收时,接收到的数据被存放在接收缓冲器中;发送时,在数据被发送之前,首先被存放在发送缓冲器中。 读SPI DR寄存器将返回接收缓冲器的内容;写入SPI_DR寄存器的数据将被写入发送缓冲器中。
-
主模式下的数据传输
(1)全双工模式(BIDIMODEE=0并且RXONLY=0)
(2)单向的只接收模式(BIDIMODE并且RRXONLY=1)
(3)双向模式,发送时(BIDIMODE并且BIIDIOE=1)
(4)双向模式,接收时(BIDIMODE=1并且BIDIOE=0)
- 从模式下的数据传输
(1)全双工模式(BIDIMODE并且RXONLY=0)
(2)单向的只接收模式(BIDIMODE=0并且RXONLY=1)
(3)双向模式发送时(BIDIMODE=1并且BIDIOE=1)
(4)双向模式接收时(BIDIMODE=并且BIDIOE=0)
- 处理数据的发送与接收 当数据从发送缓冲器传送到移位寄存器时,TXE标志置位(发送缓冲器空),表示发送缓冲器可以接收下一个数据;如果在SPI_CR2寄存器中设置了TXEIE位,则此时会产生中断;写入数据到SPI_DR寄存器即可清除TXE位。
在写入发送缓冲器之前,软件必须确认TXE标志为1,否则新的数据会覆盖已经在发送缓冲器中的数据。 在采样时钟的最后一个边沿,当数据被从移位寄存器传送到接收缓冲器时,设置RXNE标志(接收缓冲器非空),表示数据已经就绪,可以从SPI_DR寄存器读出;如果在SPI_CR2寄存器中设置了RXNEIE位,则此时会产生一个中断;读SPI_DR寄存器即可清除RXNIE标志位。
SPI的HAL 驱动函数
SPI的驱动程序头文件是stm32f1xx_hal_spi.h。SPI寄存器操作的宏函数如表所示。宏函数中的参数_HANDLE是具体某个SPI接口的对象指针,参数_INTERRUPT 是SPI的中断事件类型,参数_FLAG_是事件中断标志。
STM32CubeMX自动生成的文件spi.c会定义表示具体SPI接口的外设对象变量。例如,使用SPI1时,会定义如下的外设对象变量hspil,宏函数中的参数_HANDLE_就可以使用&hspil。 SPI_HandleTypeDef hspil; //表示SPI1的外设对象变量 SPI的中断事件和宏定义如表所示。这是比较特殊的一种情况,对于一般的外设,1个中断事件就有1个使能控制位和1个中断标志位。 在SPI的HAL驱动程序中,定义了6个表示事件中断标志位的宏,可作为宏函数中参数FLAG_的取值;定义了3个表示中断事件类型的宏,可作为宏函数中参数_INTERRUPT的取值。这些宏定义符号如表所示。
- SPI接口初始化
函数HAL_SPI_Init()用于具体某个SPI接口的初始化,其原型定义如下: HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi) 其中,参数hspi是SPI外设对象指针。hspi->Init是SPI_InitTypeDef结构体类型,存储了SPI接口的通信参数。这两个结构体主要成员变量的意义在示例里结合代码具体解释。
函数HAL_SPI_Transmit()用于发送数据,其原型定义如下: HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t*pData,uint16_t size, uint32_t Timeout); 其中,参数hspi是SPI外设对象指针;pData是输出数据缓冲区指针;Size是缓冲区数据的字节数;Timeout是超时等待时间,单位是系统嘀嗒信号节拍数,默认情况下就是ms。 函数HAL_SPI_Transmit()是阻塞式执行的,也就直到数据发送完成或超过等待时间后才返回。函数返回HAL_OK表示发送成功,返回HAL_TIMEOUT表示发送超时。
函数HAL_SPI_Receive()用于从SPI接口接收数据,其原型定义如下: HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi,uint8_t *pData,uint16_tSize,uint32_t Timeout); 其中,参数pData是接收数据缓冲区,Size是要接收的数据字节数,Timeout是超时等待时间。
-
阻塞式数据发送和接收 SPI是一种主/从通信方式,通信完全由SPI主机控制,因为SPI主机控制了时钟信号SCK。SPI主机和从机之间一般是应答式通信,主机先用函数HAL_SPI_Transmit()在MOSI线上发送指令或数据,忽略MISO线上传入的数据;从机接收指令或数据后会返回响应数据,主机通过函数HAL_SPI_Receive()在MISO线上接收响应数据,接收时不会在MOSI线上发送有效数据。
-
阻塞式同时发送与接收数据 虽然SPI通信一般采用应答式,MISO和MOSI两根线不同时传输有效数据,但是在原理上,它们是可以在SCK时钟信号作用下同时传输有效数据的。函数HAL_SPI_TransmitReceive()就实现了接收和发送同时操作的功能,其原型定义如下: HAL_StatusTypeDef HAL_SPI_TransmitReceive (SPI_HandleTypeDef *hspi, uint8_t *pTxData,uint8_t *pRxData,uint16_t Size,uint32_t Timeout) 其中,pTxData是发送数据缓冲区,pRxData是接收数据缓冲区,Size是数据字节数,Timeout是超时等待时间。这种情况下,发送和接收到的数据字节数是相同的。
函数HAL_SPI_Transmit_IT()用于发送一个缓冲区的数据,发送完成后,会产生发送完成中断事件(SPI_IT_TXE),对应的回调函数是HAL_SPI_TxCpltCallback()。 函数HAL_SPI_Receive_IT()用于接收指定长度的数据保存到缓冲区,接收完成后,会产生接收完成中断事件(SPI_IT_RXNE),对应的回调函数是HAL_SPI_RxCpltCallback()。 函数 HAL_SPI_TransmitReceive_IT()是发送和接收同时进行,由它启动的数据传输会产生SPI_IT_TXE和SPI_IT_RXNE中断事件,但是有专门的回调函数HAL_SPI_TxRxCpltCallback()。