目录

一、项目配置

1、RCC、SYS、CodeGenerator、NVIC

2、USB_OTG_FS

3、中间件USB_DEVICE

二、软件设计

三、运行并测试


        在USBD中间件众多的IP类中,可以把MCU中片内的FLASH的一部分空间创建成虚拟的U盘,并在电脑端自动识别、驱动U盘,然后通过接口操作U盘。

        本文旨在演示如何把MCU片内FLASH创建成一个虚拟U盘,然后通过U盘接口创建文件、读写文件。

        继续使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0,使用STM32CubeIDE 1.19.0。

一、项目配置

1、RCC、SYS、CodeGenerator、NVIC

  • RCC:外部晶振25MHz,HCLK=168MHz;
  • SYS:serial wire;
  • CodeGenerator:选择;
  • 在启用USB后,再来选择48MHz;
  • NVIC:默认。时基中断优先级可以修改为0;

2、USB_OTG_FS

        选择Device_Only,参数默认;

3、中间件USB_DEVICE

        模式类选择:MSC,参数设置如下:

二、软件设计

        本例只是实现虚拟U盘接口,因此只需要重写USBD_MSC的接口文件usbd_storage_if.c里的函数。

/**
  ******************************************************************************
  * @file           : usbd_storage_if.c
  * @version        : v1.0_Cube
  * @brief          : Memory management layer.
  ******************************************************************************
  */

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

/* USER CODE BEGIN PRIVATE_TYPES */
uint8_t usb_buffer[104 * 1024];		//开辟一个104K的存储区
/* 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 */
#ifdef STORAGE_BLK_NBR
	#undef STORAGE_BLK_NBR
	#define STORAGE_BLK_NBR				104	//页数
#endif

#ifdef STORAGE_BLK_SIZ
	#undef STORAGE_BLK_SIZ
	#define STORAGE_BLK_SIZ				1024 //页大小为1KB,这里应该用页表达,手册里并没有说页,但说到了扇区,扇区的大小大于1页,各个扇区还不相等
#endif

#define FLASH_START_ADDR                usb_buffer  //(FLASH_BASE+(800*1024))    //U盘存储区的起始位置
/* USER CODE END PRIVATE_DEFINES */

/**
  * @}
  */

//省略此处IDE自动生成的代码

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

  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 */
//  UNUSED(lun);

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

  //读U盘函数
  //将(FLASH_START_ADDR + blk_addr * FLASH_PAGE_SIZE)起始地址处的blk_len * FLASH_PAGE_SIZE大小的数据拷贝到buf里面
  memcpy(buf, (uint8_t*)(FLASH_START_ADDR + blk_addr * STORAGE_BLK_SIZ), blk_len * STORAGE_BLK_SIZ);
  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);

  memcpy((uint8_t*)(FLASH_START_ADDR + blk_addr * STORAGE_BLK_SIZ), buf,  blk_len * STORAGE_BLK_SIZ);
  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 */
}

        在这里,把STORAGE_BLK_SIZ解释为FLASH页更好,F407的手册里并没有FLASH页的说法,但有扇区的说法,并且各个扇区的大小还不相等,区分为16K、64K、128K。在本例中,把FLASH(STM32F407ZGT6的FLASH大小为1MB)理想化为最小存储单位为1KB的页,连续相等,一共1024个页,合计1MB的大小。而且,在配置界面,最好把参数MSC_MEDIA_PACKET的设置得与STORAGE_BLK_SIZ一致。

        在创建U盘接口时,不能把全部的页用于创建U盘,到底需要把到少数量的页用于创建U盘,需要尝试,编译一次,就会知道是否超过了存储空间的允许。如果创建的U盘所需页分区大小超过了RAM空间允许,编译器会提出错误警告,并提出超过了多大的空间:

        通过几次测试,在没有其他程序的情况下,用于创建U盘的FLASH页数STORAGE_BLK_NBR设置为104K,基本上是最大的选择了。

        实际,创建U盘大小=STORAGE_BLK_SIZ * STORAGE_BLK_NBR。

        创建的U盘,WIN系统会恒用掉20K,剩下的空间才是U盘的容量;

三、运行并测试

        下载后,在电脑端生成一个新的U盘,首次使用需要格式化。

        可以进行如下类似的操作:打开U盘,在其内创建一个123.txt的文件,打开此文件,在文件内写上一些文字,保存。再次打开文件,查看刚刚写过的文字,可以编辑此文字,再保存。这些操作很流利、很丝滑,就好像操作市售的U盘里的文件一样。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐