细说STM32单片机USBD_MSC_FlashInChip虚拟U盘接口项目创建及编程方法
目录
在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盘里的文件一样。

更多推荐

所有评论(0)