STM32F405外部FLASH模拟U盘HAL CubeMx

硬件

单片机:STM32F405RGT6
外部Flash芯片:W25Q128

引脚说明

在这里插入图片描述
设置好RCC和SYS后接下来配置:

SPI设置
在这里插入图片描述
CS引脚配置
在这里插入图片描述

USB设置
在这里插入图片描述
USB驱动设置
在这里插入图片描述
这里是时钟配置
在这里插入图片描述
设置堆栈大小
在这里插入图片描述
然后生成代码

外部FLASH驱动文件

新建一个 W25qxx.h 头文件

// W25qxx.h 
#ifndef __SPI_FLASH_H
#define __SPI_FLASH_H

#include "stm32f4xx.h"
#include "stm32f4xx_hal_spi.h"
#include "stm32f4xx_hal.h"

/* ----------------------------------------------------------------*/

#define SPI_FLASH_REBUILD 0            // 
#define SPI_FLASH_SECTOR_SIZE 4096     // 
#define SPI_FLASH_START_SECTOR 256 * 4 // 
#define SPI_FLASH_SECTOR_COUNT 256     //

// 使用SPI3
#define FLASH_SPI_Handle hspi3

// W25Qxx系列芯片的ID
// W25Q80  ID  0xEF13
// W25Q16  ID  0xEF14
// W25Q32  ID  0xEF15
// W25Q64  ID  0xEF16
// W25Q128 ID  0xEF17
// W25Q256 ID  0xEF18

// #define W25Q80 	0xEF13
#define W25Q16 0xEF14
#define W25Q32 0xEF15
#define W25Q64 0xEF16
#define W25Q128 0xEF17
// #define W25Q256 0xEF18

#define FLASH_ID W25Q128

// SPI字段
extern SPI_HandleTypeDef FLASH_SPI_Handle;
extern uint16_t W25qxx_TYPE;

// 设置CS引脚 高低电平 宏定义
#define W25QXX_CS_1 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET)
#define W25QXX_CS_0 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET)

/* ----------------------------------------------------------------*/

//
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg1 0x05
#define W25X_ReadStatusReg2 0x35
#define W25X_ReadStatusReg3 0x15
#define W25X_WriteStatusReg1 0x01
#define W25X_WriteStatusReg2 0x31
#define W25X_WriteStatusReg3 0x11
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define W25X_Enable4ByteAddr 0xB7
#define W25X_Exit4ByteAddr 0xE9

void W25qxx_Init(void);
uint16_t W25qxx_ReadID(void);
void W25qxx_WAKEUP(void);
void SPI_FLASH_SectorErase(uint32_t SectorAddr);
void SPI_FLASH_BufferWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void SPI_FLASH_BufferRead(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
void SPI_FLASH_PageWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);

#endif /* __SPI_FLASH_H */

新建一个 W25qxx.c 文件

#include "./W25qxx/W25qxx.h"
#include "stm32f4xx_hal_gpio.h"
#include "stdio.h"
// #include "board.h"
uint16_t W25qxx_TYPE = FLASH_ID;
extern SPI_HandleTypeDef FLASH_SPI_Handle;

uint8_t W25qxx_ReadSR(uint8_t regno);            //
void W25qxx_4ByteAddr_Enable(void);              //
void W25qxx_Write_SR(uint8_t regno, uint8_t sr); //
void W25qxx_Write_Enable(void);                  //
void W25qxx_Write_Disable(void);                 //
void W25qxx_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void W25qxx_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);    //
void W25qxx_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); //
void W25qxx_Erase_Chip(void);                                                     //
void W25qxx_Erase_Sector(uint32_t Dst_Addr);                                      //
void W25qxx_Wait_Busy(void);                                                      //
void W25qxx_PowerDown(void);                                                      //

// SPI 读写字节
uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&FLASH_SPI_Handle, &TxData, &Rxdata, 1, 1000);
    return Rxdata;
}
// SPI设置速度
void SPI2_SetSpeed(uint8_t SPI_BaudRatePrescaler)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
    __HAL_SPI_DISABLE(&FLASH_SPI_Handle);
    FLASH_SPI_Handle.Instance->CR1 &= 0xFFC7;
    FLASH_SPI_Handle.Instance->CR1 |= SPI_BaudRatePrescaler;
    __HAL_SPI_ENABLE(&FLASH_SPI_Handle);
}

// 初始化引脚
void W25qxx_Init(void)
{
    uint8_t temp;
    GPIO_InitTypeDef GPIO_Initure;

    __HAL_RCC_GPIOD_CLK_ENABLE(); //
    // PD2
    GPIO_Initure.Pin = GPIO_PIN_2;             // PD2
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;   // 设置推挽
    GPIO_Initure.Pull = GPIO_PULLUP;           // 设置上拉
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; // 设置高速
    W25QXX_CS_1;                               // 默认高电平
    SPI2_SetSpeed(SPI_BAUDRATEPRESCALER_2);    //
    W25qxx_TYPE = W25qxx_ReadID();             // 读取FLASH芯片的ID
    if (W25qxx_TYPE == FLASH_ID)               //
    {
        temp = W25qxx_ReadSR(3);
        if ((temp & 0x01) == 0)
        {
            W25QXX_CS_0;
            SPI_ReadWriteByte(W25X_Enable4ByteAddr);
            W25QXX_CS_1;
        }
    }
}
//
uint8_t W25qxx_ReadSR(uint8_t regno)
{
    uint8_t byte = 0, command = 0;
    switch (regno)
    {
    case 1:
        command = W25X_ReadStatusReg1;
        break;
    case 2:
        command = W25X_ReadStatusReg2;
        break;
    case 3:
        command = W25X_ReadStatusReg3;
        break;
    default:
        command = W25X_ReadStatusReg1;
        break;
    }
    W25QXX_CS_0;                    //
    SPI_ReadWriteByte(command);     //
    byte = SPI_ReadWriteByte(0xff); //
    W25QXX_CS_1;                    //
    return byte;
}
//
void W25qxx_Write_SR(uint8_t regno, uint8_t sr)
{
    uint8_t command = 0;
    switch (regno)
    {
    case 1:
        command = W25X_WriteStatusReg1; //
        break;
    case 2:
        command = W25X_WriteStatusReg2; //
        break;
    case 3:
        command = W25X_WriteStatusReg3; //
        break;
    default:
        command = W25X_WriteStatusReg1;
        break;
    }
    W25QXX_CS_0;                //
    SPI_ReadWriteByte(command); //
    SPI_ReadWriteByte(sr);      //
    W25QXX_CS_1;                //
}
// W25QXX
void W25qxx_Write_Enable(void)
{
    W25QXX_CS_0;                         //
    SPI_ReadWriteByte(W25X_WriteEnable); //
    W25QXX_CS_1;                         //
}
// W25QXX
void W25qxx_Write_Disable(void)
{
    W25QXX_CS_0;                          //
    SPI_ReadWriteByte(W25X_WriteDisable); //
    W25QXX_CS_1;                          //
}

// 读取 W25Qxx系列芯片的ID
// W25Q80  ID  0xEF13
// W25Q16  ID  0xEF14
// W25Q32  ID  0xEF15
// W25Q64  ID  0xEF16
// W25Q128 ID  0xEF17
// W25Q256 ID  0xEF18
uint16_t W25qxx_ReadID(void)
{
    uint16_t Temp = 0;
    W25QXX_CS_0;
    SPI_ReadWriteByte(0x90);
    SPI_ReadWriteByte(0x00);
    SPI_ReadWriteByte(0x00);
    SPI_ReadWriteByte(0x00);
    Temp |= SPI_ReadWriteByte(0xFF) << 8;
    Temp |= SPI_ReadWriteByte(0xFF);
    W25QXX_CS_1;
    return Temp;
}
//
void W25qxx_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    uint16_t i;
    W25QXX_CS_0;                      //
    SPI_ReadWriteByte(W25X_ReadData); //
    //    if(W25qxx_TYPE==FLASH_ID)                //W25Q256ĻַΪ4ֽڵģҪ8λ
    //    {
    //        SPI_ReadWriteByte((uint8_t)((ReadAddr)>>24));
    //    }
    SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 16)); // 24bitַ
    SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
    SPI_ReadWriteByte((uint8_t)ReadAddr);
    for (i = 0; i < NumByteToRead; i++)
    {
        pBuffer[i] = SPI_ReadWriteByte(0xFF); // ѭ
    }
    W25QXX_CS_1;
}
/**
 * @brief   FLASH
 * @param 	pBuffer洢ݵָ
 * @param   ReadAddrȡַ
 * @param   NumByteToReadȡݳ
 * @retval
 */
void SPI_FLASH_BufferRead(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    W25QXX_CS_0;
    SPI_ReadWriteByte(W25X_ReadData);
    SPI_ReadWriteByte((ReadAddr & 0xFF0000) >> 16);
    SPI_ReadWriteByte((ReadAddr & 0xFF00) >> 8);
    SPI_ReadWriteByte(ReadAddr & 0xFF);
    while (NumByteToRead--)
    {
        *pBuffer = SPI_ReadWriteByte(0xFF);
        pBuffer++;
    }
    W25QXX_CS_1;
}

#define WIP_Flag 0x01

/**
 * @brief  ȴWIP(BUSY)־0ȴFLASHڲд
 * @param  none
 * @retval none
 */
void SPI_FLASH_WaitForWriteEnd(void)
{
    uint8_t FLASH_Status = 0;
    W25QXX_CS_0;
    SPI_ReadWriteByte(W25X_ReadStatusReg1);
    do
    {
        FLASH_Status = SPI_ReadWriteByte(0xFF);
    } while ((FLASH_Status & WIP_Flag) == SET);
    W25QXX_CS_1;
}

/**
 * @brief  FLASH
 * @param  SectorAddrҪַ
 * @retval
 */
void SPI_FLASH_SectorErase(uint32_t SectorAddr)
{
    W25qxx_Write_Enable();
    SPI_FLASH_WaitForWriteEnd();
    W25QXX_CS_0;
    SPI_ReadWriteByte(W25X_SectorErase);
    SPI_ReadWriteByte((uint8_t)((SectorAddr) >> 16)); // 24bitַ
    SPI_ReadWriteByte((uint8_t)((SectorAddr) >> 8));
    SPI_ReadWriteByte(SectorAddr & 0xFF);
    W25QXX_CS_1;
    SPI_FLASH_WaitForWriteEnd();
}

#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256
/**
 * @brief  FLASHҳдݣñдǰҪȲ
 * @param	pBufferҪдݵָ
 * @param WriteAddrдַ
 * @param  NumByteToWriteдݳȣСڵSPI_FLASH_PerWritePageSize
 * @retval
 */
void SPI_FLASH_PageWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    W25qxx_Write_Enable();
    W25QXX_CS_0;
    SPI_ReadWriteByte(W25X_PageProgram);
    SPI_ReadWriteByte((WriteAddr & 0xFF0000) >> 16);
    SPI_ReadWriteByte((WriteAddr & 0xFF00) >> 8);
    SPI_ReadWriteByte(WriteAddr & 0xFF);
    if (NumByteToWrite > SPI_FLASH_PageSize)
    {
        NumByteToWrite = SPI_FLASH_PerWritePageSize;
    }
    while (NumByteToWrite--)
    {
        SPI_ReadWriteByte(*pBuffer);
        pBuffer++;
    }
    W25QXX_CS_1;
    SPI_FLASH_WaitForWriteEnd();
}

//
void W25qxx_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t i;
    W25qxx_Write_Enable();
    W25QXX_CS_0;
    SPI_ReadWriteByte(W25X_PageProgram);
    //    if(W25qxx_TYPE==FLASH_ID)
    //    {
    //        SPI_ReadWriteByte((uint8_t)((WriteAddr)>>24));
    //    }
    SPI_ReadWriteByte((uint8_t)((WriteAddr) >> 16)); // 24bitַ
    SPI_ReadWriteByte((uint8_t)((WriteAddr) >> 8));
    SPI_ReadWriteByte((uint8_t)WriteAddr);
    for (i = 0; i < NumByteToWrite; i++)
        SPI_ReadWriteByte(pBuffer[i]); //
    W25QXX_CS_1;                       //
    SPI_FLASH_WaitForWriteEnd();       //
}

/**
 * @brief  FLASHдݣñдǰҪȲ
 * @param	pBufferҪдݵָ
 * @param  WriteAddrдַ
 * @param  NumByteToWriteдݳ
 * @retval
 */
void SPI_FLASH_BufferWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
    Addr = WriteAddr % SPI_FLASH_PageSize;
    count = SPI_FLASH_PageSize - Addr;
    NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
    NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
    if (Addr == 0)
    {
        if (NumOfPage == 0)
        {
            SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
        }
        else
        {
            while (NumOfPage--)
            {
                SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
                WriteAddr += SPI_FLASH_PageSize;
                pBuffer += SPI_FLASH_PageSize;
            }
            SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        }
    }
    else
    {
        if (NumOfPage == 0)
        {
            if (NumOfSingle > count)
            {
                temp = NumOfSingle - count;
                SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
                WriteAddr += count;
                pBuffer += count;
                SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
            }
            else
            {
                SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
            }
        }
        else
        {
            NumByteToWrite -= count;
            NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
            NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
            SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
            WriteAddr += count;
            pBuffer += count;
            while (NumOfPage--)
            {
                SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
                WriteAddr += SPI_FLASH_PageSize;
                pBuffer += SPI_FLASH_PageSize;
            }
            if (NumOfSingle != 0)
            {
                SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
            }
        }
    }
}

//
void W25qxx_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t pageremain;
    pageremain = 256 - WriteAddr % 256; // ҳʣֽ
    if (NumByteToWrite <= pageremain)
        pageremain = NumByteToWrite; // 256ֽ
    while (1)
    {
        W25qxx_Write_Page(pBuffer, WriteAddr, pageremain);
        if (NumByteToWrite == pageremain)
            break;
        else
        {
            pBuffer += pageremain;
            WriteAddr += pageremain;

            NumByteToWrite -= pageremain;
            if (NumByteToWrite > 256)
                pageremain = 256;
            else
                pageremain = NumByteToWrite;
        }
    };
}
//
uint8_t W25qxx_BUFFER[4096];
void W25qxx_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t *W25qxx_BUF;
    W25qxx_BUF = W25qxx_BUFFER;
    secpos = WriteAddr / 4096; //
    secoff = WriteAddr % 4096; //
    secremain = 4096 - secoff; //
    if (NumByteToWrite <= secremain)
        secremain = NumByteToWrite; //
    while (1)
    {
        W25qxx_Read(W25qxx_BUF, secpos * 4096, 4096); //
        for (i = 0; i < secremain; i++)               //
        {
            if (W25qxx_BUF[secoff + i] != 0xFF)
                break; //
        }
        if (i < secremain) //
        {
            W25qxx_Erase_Sector(secpos);    //
            for (i = 0; i < secremain; i++) //
            {
                W25qxx_BUF[i + secoff] = pBuffer[i];
            }
            W25qxx_Write_NoCheck(W25qxx_BUF, secpos * 4096, 4096); //
        }
        else
            W25qxx_Write_NoCheck(pBuffer, WriteAddr, secremain); //
        if (NumByteToWrite == secremain)
            break; //
        else       //
        {
            secpos++;   //
            secoff = 0; //

            pBuffer += secremain;        //
            WriteAddr += secremain;      //
            NumByteToWrite -= secremain; //
            if (NumByteToWrite > 4096)
                secremain = 4096; //
            else
                secremain = NumByteToWrite; //
        }
    };
}
//
void W25qxx_Erase_Chip(void)
{
    W25qxx_Write_Enable(); // SET WEL
    W25qxx_Wait_Busy();
    W25QXX_CS_0;                       //
    SPI_ReadWriteByte(W25X_ChipErase); //
    W25QXX_CS_1;                       //
    W25qxx_Wait_Busy();                //
}
//
void W25qxx_Erase_Sector(uint32_t Dst_Addr)
{
    Dst_Addr *= 4096;
    W25qxx_Write_Enable(); // SET WEL
    W25qxx_Wait_Busy();
    W25QXX_CS_0;                         //
    SPI_ReadWriteByte(W25X_SectorErase); //
    if (W25qxx_TYPE == FLASH_ID)         //
    {
        SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 24));
    }
    SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 16)); // 24bitַ
    SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 8));
    SPI_ReadWriteByte((uint8_t)Dst_Addr);
    W25QXX_CS_1;        //
    W25qxx_Wait_Busy(); //
}
// ȴ
void W25qxx_Wait_Busy(void)
{
    while ((W25qxx_ReadSR(1) & 0x01) == 0x01)
        ; // BUSY
}
// ģʽ
void W25qxx_PowerDown(void)
{
    W25QXX_CS_0;                       //
    SPI_ReadWriteByte(W25X_PowerDown); //
    W25QXX_CS_1;                       //
    // delay_us(3);                            //
}
//
void W25qxx_WAKEUP(void)
{
    W25QXX_CS_0;                              //
    SPI_ReadWriteByte(W25X_ReleasePowerDown); //
    W25QXX_CS_1;                              //
    // delay_us(3);                            //
}

将以上俩文件都放在一个文件里(W25qxx)
在这里插入图片描述
然后引入到项目中
在这里插入图片描述
打开 usbd_storage_if.c 文件
在这里插入图片描述
引入外部FLASH驱动头文件

#include "./W25qxx/W25qxx.h"

修改这里的宏定义(每次使用CubeMx生成代码后,这里都需要再重新设置一次)

#define STORAGE_LUN_NBR                  1
#define STORAGE_BLK_NBR                  4096  // 256*16扇区=16MByte   更改FLASH大小更改这里就可以
#define STORAGE_BLK_SIZ                  4096  // 每个扇区4096Byte

修改以下函数内的内容

int8_t STORAGE_Init_FS(uint8_t lun)
{
    /* USER CODE BEGIN 2 */
    // UNUSED(lun);
    W25qxx_Init();
    return (USBD_OK);
    /* USER CODE END 2 */
}
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
    /* USER CODE BEGIN 3 */
    UNUSED(lun);
    *block_num = STORAGE_BLK_NBR;
    *block_size = STORAGE_BLK_SIZ;
    return (USBD_OK);
    /* USER CODE END 3 */
}
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    /* USER CODE BEGIN 6 */
    // UNUSED(lun);
    // UNUSED(buf);
    // UNUSED(blk_addr);
    // UNUSED(blk_len);
    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 */
}
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    /* USER CODE BEGIN 7 */
    // UNUSED(lun);
    // UNUSED(buf);
    // UNUSED(blk_addr);
    // UNUSED(blk_len);
    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 */
}

修改后完整的代码(usbd_storage_if.c)


/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : usbd_storage_if.c
 * @version        : v1.0_Cube
 * @brief          : Memory management layer.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"

/* USER CODE BEGIN INCLUDE */
#include "./W25qxx/W25qxx.h"
/* USER CODE END INCLUDE */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
 * @brief Usb device.
 * @{
 */

/** @defgroup USBD_STORAGE
 * @brief Usb mass storage device module
 * @{
 */

/** @defgroup USBD_STORAGE_Private_TypesDefinitions
 * @brief Private types.
 * @{
 */

/* USER CODE BEGIN PRIVATE_TYPES */

/* USER CODE END PRIVATE_TYPES */

/**
 * @}
 */

/** @defgroup USBD_STORAGE_Private_Defines
 * @brief Private defines.
 * @{
 */

// #define STORAGE_LUN_NBR 1
// #define STORAGE_BLK_NBR 0x10000
// #define STORAGE_BLK_SIZ 0x200

/* USER CODE BEGIN PRIVATE_DEFINES */
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 4096
#define STORAGE_BLK_SIZ 4096
/* USER CODE END PRIVATE_DEFINES */

/**
 * @}
 */

/** @defgroup USBD_STORAGE_Private_Macros
 * @brief Private macros.
 * @{
 */

/* USER CODE BEGIN PRIVATE_MACRO */

/* USER CODE END PRIVATE_MACRO */

/**
 * @}
 */

/** @defgroup USBD_STORAGE_Private_Variables
 * @brief Private variables.
 * @{
 */

/* USER CODE BEGIN INQUIRY_DATA_FS */
/** USB Mass storage Standard Inquiry Data. */
const int8_t STORAGE_Inquirydata_FS[] = {
    /* 36 */

    /* LUN 0 */
    0x00,
    0x80,
    0x02,
    0x02,
    (STANDARD_INQUIRY_DATA_LEN - 5),
    0x00,
    0x00,
    0x00,
    'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
    'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product      : 16 Bytes */
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
    '0', '.', '0', '1' /* Version      : 4 Bytes */
};
/* USER CODE END INQUIRY_DATA_FS */

/* USER CODE BEGIN PRIVATE_VARIABLES */

/* USER CODE END PRIVATE_VARIABLES */

/**
 * @}
 */

/** @defgroup USBD_STORAGE_Exported_Variables
 * @brief Public variables.
 * @{
 */

extern USBD_HandleTypeDef hUsbDeviceFS;

/* USER CODE BEGIN EXPORTED_VARIABLES */

/* USER CODE END EXPORTED_VARIABLES */

/**
 * @}
 */

/** @defgroup USBD_STORAGE_Private_FunctionPrototypes
 * @brief Private functions declaration.
 * @{
 */

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);

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

/**
 * @}
 */

USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
    {
        STORAGE_Init_FS,
        STORAGE_GetCapacity_FS,
        STORAGE_IsReady_FS,
        STORAGE_IsWriteProtected_FS,
        STORAGE_Read_FS,
        STORAGE_Write_FS,
        STORAGE_GetMaxLun_FS,
        (int8_t *)STORAGE_Inquirydata_FS};

/* Private functions ---------------------------------------------------------*/
/**
 * @brief  Initializes the storage unit (medium) over USB FS IP
 * @param  lun: Logical unit number.
 * @retval USBD_OK if all operations are OK else USBD_FAIL
 */
int8_t STORAGE_Init_FS(uint8_t lun)
{
    /* USER CODE BEGIN 2 */
    // UNUSED(lun);

    W25qxx_Init();

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

/**
 * @brief  Returns the medium capacity.
 * @param  lun: Logical unit number.
 * @param  block_num: Number of total block number.
 * @param  block_size: Block size.
 * @retval USBD_OK if all operations are OK else USBD_FAIL
 */
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
    /* USER CODE BEGIN 3 */
    UNUSED(lun);
    *block_num = STORAGE_BLK_NBR;
    *block_size = STORAGE_BLK_SIZ;
    return (USBD_OK);
    /* USER CODE END 3 */
}

/**
 * @brief   Checks whether the medium is ready.
 * @param  lun:  Logical unit number.
 * @retval USBD_OK if all operations are OK else USBD_FAIL
 */
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
    /* USER CODE BEGIN 4 */
    // uint16_t flash_ID;
    // flash_ID = W25QXX_ReadID();

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

/**
 * @brief  Checks whether the medium is write protected.
 * @param  lun: Logical unit number.
 * @retval USBD_OK if all operations are OK else USBD_FAIL
 */
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
    /* USER CODE BEGIN 5 */
    UNUSED(lun);

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

/**
 * @brief  Reads data from the medium.
 * @param  lun: Logical unit number.
 * @param  buf: data buffer.
 * @param  blk_addr: Logical block address.
 * @param  blk_len: Blocks number.
 * @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 */
    // UNUSED(lun);
    // UNUSED(buf);
    // UNUSED(blk_addr);
    // UNUSED(blk_len);
    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  Writes data into the medium.
 * @param  lun: Logical unit number.
 * @param  buf: data buffer.
 * @param  blk_addr: Logical block address.
 * @param  blk_len: Blocks number.
 * @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 */
    // UNUSED(lun);
    // UNUSED(buf);
    // UNUSED(blk_addr);
    // UNUSED(blk_len);
    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 */
}

/**
 * @brief  Returns the Max Supported LUNs.
 * @param  None
 * @retval Lun(s) number.
 */
int8_t STORAGE_GetMaxLun_FS(void)
{
    /* USER CODE BEGIN 8 */
    return (STORAGE_LUN_NBR - 1);
    /* USER CODE END 8 */
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/**
 * @}
 */

/**
 * @}
 */

最后编译烧录

测试

第一次插入电脑会提示格式化,格式化以后就会变成U盘了,往里边丢文件测试完成
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值