欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

STM32F4-SPI接口开发

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

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