RYMCU

stm32使用外部SPI FLASH模拟U盘(大容量存储设备MSC)

Hugh 4 年前
# STM32 # SPIFLASH # MSC # 模拟U盘 # W25Q64

前言

单片机和PC直接如何通信?最常见接口为串口以及USB。本章详细讲解如何配置STM32单片机USB功能。

1.前期准备

1.运行环境windows10;
2.stm32f103x开发板一套;
3.安装好STM32CubeMX;

其中,需配置Clion满足嵌入式开发要求,如果没有安装可以参考《使用 CLion 进行嵌入式开发》

2.预期结果

开发板通过USB插入PC,PC可成功识别到一个U盘并可在U盘中新建、删除文件等。

3.使用CubeMX生成工程

step1:运行 CubeMX ,新建工程并选择芯片 STM32F103RCTx,如下图。

芯片选型.png
step2:系统时钟配置为外部时钟,如下图。

时钟选择.png
step3:使能下载调试接口 SWD,如下图,后续需要通过该接口下载程序至单片机。

SWD.png
step4:使能 USB,如下图所示,③处参数保持默认值。

usb1.png
step5:USB配置选择 Mass Storage Class,并将③处改为 4096,原因为我们开发板采用外部 Flash W25Q64模拟U盘存储数据, W25Q64一个扇区大小为 4096 Byte,配置如下图所示。

usb2.png
step6: USB时钟配置为 48MHz

usb48mhz.png

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

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

CS.png

step9:USB初始化等需要使用堆栈,将堆栈空间改稍大些,并点击右上角 GENERATE CODE生成工程,如下图。

stack.png

4.修改工程中USB读写函数代码

step1:将SPI FLASH 驱动文件bps_spi_flash.h,bps_spi_flash.c添加至工程中。

step2:main.c文件函数static void MX_SPI1_Init(void)添加SPI使能代码:

/* USER CODE BEGIN SPI1_Init 2 */
    __HAL_SPI_ENABLE(&hspi1);//使能SPI1
  /* USER CODE END SPI1_Init 2 */

sep3:修改USB初始化函数int8_t STORAGE_Init_FS(uint8_t lun) 修改读函数:int8_tSTORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len),修改写函数:int8_tSTORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len),代码如下所示。

#include "bsp_spi_flash.h"

#define STORAGE_LUN_NBR                  1
#define STORAGE_BLK_NBR                  256*4 //256*4扇区=4MByte
#define STORAGE_BLK_SIZ                  4096  //每个扇区4096Byte


static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Init_FS(uint8_t lun)
{
    /* USER CODE BEGIN 2 */
    W25QXX_Init();
    return (USBD_OK);
    /* USER CODE END 2 */
}
/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    /* USER CODE BEGIN 6 */
    blk_addr+=SPI_FLASH_START_SECTOR;
    SPI_FLASH_BufferRead(buf, blk_addr*SPI_FLASH_SECTOR_SIZE, blk_len*SPI_FLASH_SECTOR_SIZE);

    return (USBD_OK);
    /* USER CODE END 6 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    /* USER CODE BEGIN 7 */
    uint32_t write_addr;
    blk_addr+=SPI_FLASH_START_SECTOR;
    write_addr = blk_addr*SPI_FLASH_SECTOR_SIZE;
    SPI_FLASH_SectorErase(write_addr);
    SPI_FLASH_BufferWrite((uint8_t *)buf,write_addr,blk_len*SPI_FLASH_SECTOR_SIZE);

    return (USBD_OK);
    /* USER CODE END 7 */
}

step4:main()函数中语句SPI_HandleTypeDef hspi1;前增加extern关键字,因该变量在bps_spi_flash.h中已经定义过,引用即可。

extern  SPI_HandleTypeDef hspi1;

至此,已完成代码修改。

4.程序下载验证

编译代码,将程序下载至开发板,并通过USB连接至电脑,格式化后,如下图所示显示容量为4MB的U盘。

4MU盘.png

后续即可当普通U盘使用。FLASH驱动文件及工程完整代码:github完整代码

后发布评论