STM32F4-SPI接口开发

2022-07-30,,,

SPI 简介
SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32F4 也有 SPI 接口。下面我们看看 SPI 的内部简明图(图 30.1.1).

SPI 接口一般使用 4 条线通信:
MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK 时钟信号,由主设备产生。
CS 从设备片选信号,由主设备控制。

从图中可以看出,主机和从机都有一个串行移位寄存器,主机通过向它的 SPI 串行寄存器写入一个字节来发起一次传输。寄存器通过 MOSI 信号线将字节传送给从机,从机也将自己的移位寄存器中的内容通过 MISO 信号线返回给主机。这样,两个移位寄存器中的内容就被交换。
外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。
SPI 主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。
SPI 总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI 主模块和与之通信的外设备时钟相位和极性应该一致。
不同时钟相位下的总线数据传输时序如图 32.1.1 所示:

STM32F429 的 SPI 功能很强大,SPI 时钟最高可以到 45Mhz,支持 DMA,可以配置为 SPI协议或者 I2S 协议(支持全双工 I2S)。
本章,我们将使用 STM32F429 的 SPI 来读取外部 SPI FLASH 芯片(W25Q256),实现类似上节的功能。这里对 SPI 我们只简单介绍一下 SPI 的使用,STM32F429 的 SPI 详细介绍请参考《STM32F4xx 中文参考手册》第 721 页,27 节。然后我们再介绍下 SPI FLASH 芯片。
这节,我们使用 STM32F429 的 SPI5 的主模式,下面就来看看 SPI5 部分的设置步骤吧。SPI 相关的库函数和定义分布在文件 stm32f4xx_hal_spi.c 以及头文件 stm32f4xx_hal_spi.h 中。STM32 的主模式配置步骤如下:
1)配置相关引脚的复用功能,使能 SPI5 时钟。
我们要用 SPI5,第一步就要使能 SPI5 时钟和响应引脚时钟。其次要设置 SPI5 的相关引脚
为复用(AF5)输出,这样才会连接到 SPI5 上。这里我们使用的是 PF7、8、9 这 3 个(SCK.、
MISO、MOSI,CS 使用软件管理方式)
,所以设置这三个为复用 IO,复用功能为 AF5。
使能 SPI5 时钟的方法为:

__HAL_RCC_SPI5_CLK_ENABLE(); 

//使能 SPI5 时钟
复用 PF7,PF8,PF9 为 SPI5 引脚是通过 HAL_GPIO_Init 函数实现,代码如下:

GPIO_InitTypeDef GPIO_Initure; GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9; GPIO_Initure.Mode=GPIO_MODE_AF_PP;//复用推挽输出
GPIO_Initure.Pull=GPIO_PULLUP;//上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST;//快速
GPIO_Initure.Alternate=GPIO_AF5_SPI5;//复用为 SPI5
HAL_GPIO_Init(GPIOF,&GPIO_Initure); 

2)初始化 SPI5,设置 SPI5 工作模式等。
这一步全部是通过 SPI5_CR1 来设置,我们设置 SPI5 为主机模式,设置数据格式为 8 位,然后通过 CPOL 和 CPHA 位来设置 SCK 时钟极性及采样方式。并设置 SPI5 的时钟频率(最大45Mhz),以及数据的格式(MSB 在前还是 LSB 在前)。在 HAL 库中初始化 SPI 的函数为:

HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi); 

下面我们来看看 SPI_HandleTypeDef 定义:

typedef struct __SPI_HandleTypeDef { SPI_TypeDef     *Instance;//基地址
SPI_InitTypeDef Init;//初始化接哦固体
uint8_t         *pTxBuffPtr;//发送缓存
uint16_t        TxXferSize;//发送数据大小
uint16_t        TxXferCount;//还剩余多少个数据要发送
uint8_t         *pRxBuffPtr;//接收缓存
uint16_t        RxXferSize;//接收数据大小
uint16_t        RxXferCount;//还剩余多少个数据要接收
DMA_HandleTypeDef *hdmatx;//DMA 发送句柄
DMA_HandleTypeDef *hdmarx;//DMA 接收句柄
void (*RxISR)(struct __SPI_HandleTypeDef * hspi); void (*TxISR)(struct __SPI_HandleTypeDef * hspi); HAL_LockTypeDef   Lock; __IO HAL_SPI_StateTypeDef   State; __IO uint32_t               ErrorCode; }SPI_HandleTypeDef; 

该结构体和串口句柄结构体类似,同样有 6 个成员变量和 2 个 DMA_HandleTypeDef 指针类型变量。这几个参数的作用这里我们就不做过多讲解,大家如果对 HAL 库串口通信理解了,那么这些就很好理解。这里我们主要讲解第二个成员变量 Init,它是 SPI_InitTypeDef 结构体类型,该结构体定义如下:

typedef struct { uint32_t Mode;// 模式:主(SPI_MODE_MASTER),从(SPI_MODE_SLAVE) uint32_t Direction; //方式: 只接受模式,单线双向通信数据模式,全双工
	uint32_t DataSize;//8 位还是 16 位帧格式选择项
	uint32_t CLKPolarity; //时钟极性
	uint32_t CLKPhase; //时钟相位
	uint32_t NSS;//SS 信号由硬件(NSS 管脚)还是软件控制
	uint32_t BaudRatePrescaler; //设置 SPI 波特率预分频值
	uint32_t FirstBit;//起始位是 MSB 还是 LSB
	uint32_t TIMode;//帧格式 SPI motorola 模式还是 TI 模式
	uint32_t CRCCalculation; //硬件 CRC 是否使能
	uint32_t CRCPolynomial; //CRC 多项式 }SPI_InitTypeDef; 

该结构体个个成员变量的含义我们已经在成员变量后面注释了,请大家参考学习。SPI 初
始化实例代码如下:

SPI5_Handler.Instance=SPI5;//SP5
SPI5_Handler.Init.Mode=SPI_MODE_MASTER;//模式:主模式
SPI5_Handler.Init.Direction=SPI_DIRECTION_2LINES; //双线模式
SPI5_Handler.Init.DataSize=SPI_DATASIZE_8BIT;//发送接收 8 位帧结构
SPI5_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH; //串行同步时钟空闲状态为高电平
SPI5_Handler.Init.CLKPhase=SPI_PHASE_2EDGE;//第二个跳变沿数据被采样
SPI5_Handler.Init.NSS=SPI_NSS_SOFT;//NSS 信号由硬件管理
SPI5_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256; //定义波特率预分频的值:波特率预分频值为 256
SPI5_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB; //指定数据传输从 MSB 位开始
SPI5_Handler.Init.TIMode=SPI_TIMODE_DISABLE; //关闭 TI 模式
SPI5_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;/关闭硬件 CRC
SPI5_Handler.Init.CRCPolynomial=7; //CRC 值计算的多项式
HAL_SPI_Init(&SPI5_Handler);//初始化 

同样,HAL 库也提供了 SPI 初始化 MSP 回调函数 HAL_SPI_MspInit,定义如下:

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi); 

关于回调函数使用,这里我们就不做过多讲解。
3)使能 SPI1。
这一步通过 SPI5_CR1 的 bit6 来设置,以启动 SPI5,在启动之后,我们就可以开始 SPI 通
讯了。使能 SPI5 的方法为:

__HAL_SPI_ENABLE(&SPI5_Handler);//使能 SPI5 

4)SPI 传输数据
通信接口当然需要有发送数据和接受数据的函数,HAL 库提供的发送数据函数原型为:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size,uint32_t Timeout); 

这个函数很好理解,往 SPIx 数据寄存器写入数据 Data,从而实现发送。
HAL 库提供的接受数据函数原型为:

HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData,
uint16_t Size, uint32_t Timeout); 

这个函数也不难理解,从 SPIx 数据寄存器读出接受到的数据。
前面我们讲解了 SPI 通信的原理,因为 SPI 是全双工,发送一个字节的同时接受一个字节,
发送和接收同时完成,所以 HAL 也提供了一个发送接收统一函数:

HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData,
uint8_t *pRxData, uint16_t Size, uint32_t Timeout); 

该函数发送一个字节的同时负责接收一个字节。
5)设置 SPI 传输速度
SPI 初始化结构体 SPI_InitTypeDef 有一个成员变量是 BaudRatePrescaler,该成员变量用来设置 SPI 的预分频系数,从而决定了 SPI 的传输速度。但是 HAL 库并没有提供单独的 SPI 分频系数修改函数,如果我们需要在程序中不时的修改速度,那么我们就要通过设置 SPI 的 CR1 寄存器来修改,具体实现方法请参考后面软件设计小节相关函数。
SPI5 的使用就介绍到这里,接下来介绍一下 W25Q128。W25Q128 是华邦公司推出的大容量 SPI FLASH 产品, W25Q128 的容量为 128Mb,该系列还有 W25Q80/16/32/64 等。 ALIENTEK所选择的 W25Q128 容量为 128Mb,也就是 16M 字节。
W25Q128 将 16M 的容量分为 256 个块(Block),每个块大小为 64K 字节,每个块又分为16 个扇区(Sector)
,每个扇区 4K 个字节。W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W25Q128 开辟一个至少 4K 的缓存区,这样对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。
W25Q128 的擦写周期多达 10W 次,具有 20 年的数据保存期限,支持电压为 2.7~3.6V,W25Q128 支持标准的 SPI,还支持双输出/四输出的 SPI,最大 SPI 时钟可以到 80Mhz(双输出时相当于 160Mhz,四输出时相当于 320M),更多的 W25Q128 的介绍,请参考 W25Q128 的DATASHEET。
硬件设计
本章实验功能简介:开机的时候先检测 W25Q256 是否存在,然后在主循环里面检测两个
按键,其中 1 个按键(KEY1)用来执行写入 W25Q256 的操作,另外一个按键(KEY0)用来
执行读出操作,在 LCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。
所要用到的硬件资源如下:

  1. 指示灯 DS0
  2. KEY0 和 KEY1 按键
  3. LCD 模块
  4. SPI
  5. W25Q256
    这里只介绍 W25Q256 与 STM32F429 的连接,板上的 W25Q256 是

《STM32F4-SPI接口开发.doc》

下载本文的Word格式文档,以方便收藏与打印。