使用STM32制作U盘(device)

1 篇文章 0 订阅
1 篇文章 0 订阅
本文详细介绍了如何使用STM32CubeMX配置MCU,结合外部SPIFlash(W25Q64)实现USB设备作为大容量存储。涉及时钟配置、USB中断、串口输出、SPI接口配置以及中间件USB_DEVICE的设置。通过修改存储介质驱动代码,实现了数据的读写功能,最终使USB设备在电脑上显示为可格式化的磁盘。经过格式化后,设备能够稳定读写,达到较高的传输速度。
摘要由CSDN通过智能技术生成

硬件环境

  • STM32(支持USB)
  • 存储介质(SPI FLASH、E2P、甚至是片内FLASH均可),本实验使用外部SPI flash(W25Q64)。

使用STM32CubeMX进行配置初始化信息

  1. 配置MCU的时钟,外设等信息,可以使用一路串口进行输出Log信息,串口波特率越高越好

  2. MCU管脚配置
    在这里插入图片描述4. 时钟配置
    我这里的硬件中有8M的HSE,然后需要注意的是,USB时钟需要配置到48M在这里插入图片描述

  3. USB配置,记得打开中断在这里插入图片描述

  4. 串口 在这里插入图片描述

  5. 存储介质的通信接口,如使用内部flash,则不需要配置
    W25Q64 是SPI FLASH,配置SPI接口,这个配置可能需要根据芯片手册进行调整
    在这里插入图片描述

  6. 中间件 USB_DEVICE
    Class for FS IP选择大容量存储,其他可以默认,USB_DEBUG_LEVEL改不改都一样,做USB device时没看到打印出log来。如果配置了非0,那么需要重定向printf,并且勾选USE Micro LIB,否则可能会出现问题。
    在这里插入图片描述

  7. 将堆栈空间改大之后就可以生成代码了

修改程序

生成完程序后,直接编译烧录,然后将USB连接到电脑上,就可以看到已经多出来一个盘符,但是看不到容量和大小,也不能成功格式化磁盘,那是因为我们还没有完成数据的读取和写入

修改添加存储介质的驱动代码

这个步骤很关键,如果你的驱动有问题,那么就会导致格式化失败,也就没办法使用。

W25Q64

必要的函数
W25Q64.h

typedef struct
{
    void (*init) (void);
    void (*read_sector) (uint32_t addr, uint8_t *pData, uint32_t length);
    void (*write_sector) (uint32_t addr, uint8_t *pData, uint32_t length);
    uint8_t (*get_status) (void);
}W25Q64_Dev_T;
extern W25Q64_Dev_T w25q64_drv;

W25Q64.c

static void w25q64_write_enable(void);
static void w25q64_write_disable(void);
static void w25q64_chip_init(void);
static void w25q64_page_write(uint32_t addr, uint8_t *pData, uint32_t length);  //256byte max
static void w25q64_sector_write(uint32_t addr, uint8_t *pData, uint32_t length);//4kbyte max
static void w25q64_sector_read(uint32_t addr, uint8_t *pData, uint32_t length);
static void w25q64_erase_sector(uint32_t addr);
static uint8_t w25q64_read_satatus(void);

static uint8_t data_padding = 0xff;

W25Q64_Dev_T w25q64_drv = 
{
    w25q64_chip_init,
    w25q64_sector_read,
    w25q64_sector_write,
    w25q64_read_satatus,
};

数据读写函数添加到USB驱动中

我们要修改的文件是 usbd_storage_if.c

#define STORAGE_LUN_NBR                  1
#define STORAGE_BLK_NBR                  W25Q64_SECTOR_NBR//改为flash介质的sector 数量
#define STORAGE_BLK_SIZ                  W25Q64_SECTOR_SIZE//改为flash介质的sector 大小
  • int8_t STORAGE_Init_FS(uint8_t lun)

    我们可以添加我们刚刚写的存储介质初始化,如果正常,则返回 USBD_OK

  • int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)

    获取存储介质的大小,函数已经填充好,我们可以不动

  • int8_t STORAGE_IsReady_FS(uint8_t lun)

    获取介质状态,我们要对存储介质的状态进行判断,这里我们要判断两点,一个是是否正在读写状态中,另外一个就是存储介质是否是不可工作状态

  • int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)

    判断是否是写保护,我们可以直接返回USBD_OK

  • int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

    读取一个扇区,我们将准备好的读取一个扇区的代码填充进来就好

    例上述W25Q64的驱动代码:

    /**
      * @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 */
      while(STORAGE_IsReady_FS(1) != 0);
      storage_status = 1;
      w25q64_drv.read_sector(blk_addr*W25Q64_SECTOR_SIZE, buf, blk_len*W25Q64_SECTOR_SIZE);
      storage_status = 0;
      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)

    写入一个扇区,我们将准备好的读取一个扇区的代码填充进来就好

    例上述W25Q64的驱动代码:

    /**
      * @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 */
      while(STORAGE_IsReady_FS(1) != 0);
      storage_status = 1;
      w25q64_drv.write_sector(blk_addr*W25Q64_SECTOR_SIZE, buf, blk_len*W25Q64_SECTOR_SIZE);
      storage_status = 0;
        
      return (USBD_OK);
      /* USER CODE END 7 */
    }
    
  • int8_t STORAGE_GetMaxLun_FS(void)

    读取磁盘介质的个数,一般我们只虚拟出一个来,不用管就行

我们使用的spi flash的sector大小为4k,也就是4096,USB这边是520,所以我们需要将其修改一致

  • 修改usbd_msc.h

    /** @defgroup USBD_BOT_Exported_Defines
      * @{
      */
    /* MSC Class Config */
    #ifndef MSC_MEDIA_PACKET
    #define MSC_MEDIA_PACKET             4096U //512U
    #endif /* MSC_MEDIA_PACKET */
    
    #define MSC_MAX_FS_PACKET            0x40U  //0x40
    #define MSC_MAX_HS_PACKET            0x1000U //0x200
    
    #define BOT_GET_MAX_LUN              0xFE
    #define BOT_RESET                    0xFF
    #define USB_MSC_CONFIG_DESC_SIZ      32
    
    #define MSC_EPIN_ADDR                0x81U
    #define MSC_EPOUT_ADDR               0x01U
    
  • 修改usbd_conf.h

    /** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
      * @brief Defines for configuration of the Usb device.
      * @{
      */
    
    /*---------- -----------*/
    #define USBD_MAX_NUM_INTERFACES     1
    /*---------- -----------*/
    #define USBD_MAX_NUM_CONFIGURATION     1
    /*---------- -----------*/
    #define USBD_MAX_STR_DESC_SIZ     4096 //512
    /*---------- -----------*/
    #define USBD_DEBUG_LEVEL     3
    /*---------- -----------*/
    #define USBD_SELF_POWERED     1
    /*---------- -----------*/
    #define MSC_MEDIA_PACKET     4096 //512
    

    至此,我们的U盘就做好了

格式化U盘

做好之后,首次插入到电脑上会比较慢,然后就可以对其进行格式化,格式化完成之后就可以进行使用了。格式化设置。分配单元大小即为4096bytes
在这里插入图片描述
格式化完成
在这里插入图片描述
传个文件试试,达到了惊人的177KB/s
在这里插入图片描述
传输完成
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值