RYMCU

STM32篇——SPI 通信

1. 前期准备

安装好 STM32CubeMX

安装好 Clion

2. 创建项目

开启 SPI1,因开发板外部 Flash W25Q64 和单片机之间通过 SPI1 实现通信。如下图所示,SPI1 模式选择 Full-Duplex-Master,4 处分频系数改为 16 将波特率设置为 4.5Mbit/s。如下图所示。

配置 FLASH 片选引脚 PA1 为上拉输出,如下图所示。

3. 编辑代码

main.c 文件中自动生成了 SPI 对象以及初始化代码:

//I2C1对象
 SPI_HandleTypeDef hspi1;
 //根据配置自动生成初始化代码,并在main函数中进行了调用
static void MX_SPI1_Init(void)
{
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
}

main 函数中将调用 MX_SPI1_Init() 完成 SPI 初始化,同时在项目中自动添加了 stm32f1xx_hal_spi.h,stm32f1xx_hal_spi.c 文件,其中 1 个关键函数用来实现读写 W25Q64

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

参数定义如下:

  • hspi :SPI 对象指针
  • pTxData:写数据的 buff 指针
  • pRxData:读出数据存储指针
  • Size :读或写数据大小
  • Timeout :操作超时时间

SPI 底层通信已经准备完毕,单片机对 W25Q64 的读、写操作均在上面函数的基础上完成。

4. 添加 W25Q64 驱动

项目添加驱动文件 bsp_spi_flash.hbsp_spi_flash.c,并修改 main.c 代码如下:

//添加头文件支持
#include "bsp_spi_flash.h"
//增加extern
extern SPI_HandleTypeDef hspi1;

如上代码所示,需要添加 extern 关键字,原因为 hspi1 对象已经在驱动文件 bsp_spi_flash.h 中定义了,防止重定义而添加。驱动文件中关键函数如下所示:

u16  W25QXX_ReadID(void); 
void W25QXX_WAKEUP(void);                
void SPI_FLASH_SectorErase(u32 SectorAddr);
void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);
void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);

包含 ID 读取、FLASH 的擦除、读、写等操作,在 main 函数中调用上述函数实现对 W25Q64 的读写。

5. 读写 W25Q64 示例

mian.c 文件中添加全局变量及测试函数:

#define  FLASHBUFFSIZE 64
void SPI_FLASH_Test(void)
{
    uint16_t FLASH_ID;
    uint8_t Flash_Wr_Buff[FLASHBUFFSIZE],Flash_Rd_Buff[FLASHBUFFSIZE];
    printf("SPI总线通信实验,读写8M外部FLASH W25Q64!rn",FLASH_ID);
    FLASH_ID = W25QXX_ReadID();//读取W25Q64器件ID
    HAL_Delay(100);
    printf("the FLASH Device ID is 0x%X!rn",FLASH_ID);
    //W25Q64 = 8MByte,地址范围:0x000000-0x7FFFFF
    //Sector:每4KB为一个Sector,8M/4K=2048个
    //Block:每64KB为一个Block,8M/64K=128个,每个Block包括16个Sector
    SPI_FLASH_SectorErase(0x00);//擦除第一个Sector
    for (int i = 0; i < FLASHBUFFSIZE; ++i) Flash_Wr_Buff[i] = i;
    SPI_FLASH_BufferWrite(Flash_Wr_Buff,0x00,FLASHBUFFSIZE);
    SPI_FLASH_BufferRead(Flash_Rd_Buff,0x00,FLASHBUFFSIZE);
    printf("Read data form W25Q64: rn");
    for(uint16_t i=0;i<FLASHBUFFSIZE;i++)
    {
        printf("0x%02x ",Flash_Rd_Buff[i]);
    }
    printf("rn");
}

测试函数功能为:读取 WQ2564 器件 ID,擦除扇区,写数据,并将数据读出打印显示。在 main 函数中调用 SPI_FLASH_Test()

6. 编译下载

将程序编译下载至开发板,并将开发板连接至 PC,打开串口调试助手 RYCOM,并设置为:115200+8+N+1,接收结果如下。

7. 小结

本章学习了通过 SPI 总线读写 FLASH 器件 W25Q64,掌握了基本的读写操作。

后发布评论