STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)

STM32使用片内FLASH制作U盘(STM32+FLASH+MSC)

配套代码
https://download.csdn.net/download/qq_40824852/84998391

文章目录

  • STM32使用片内FLASH制作U盘(STM32+FLASH+MSC)
  • 一、设计原因
  • 二、与别人不同的地方
  • 三、硬件原理
  • 四、CubeMx配置
  • 五、U盘识别
  • 六、Fatfs文件系统挂载
  • 七、测试
  • 八、现象

一、设计原因

由于平时使用stm32的板子没有带SD卡,有时候也用不了SD的那么大的容量,stm32内部的flash容量都十分充裕。多以产生了使用stm32的片内flash制作一个USB小U盘的想法。
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第1张图片

二、与别人不同的地方

使用自带的flash加上fatfs文件系统,再使用USB的MSC功能就可以实现,网上也有很多类似的帖子。但是网上的教程都是使用单个扇区512byte大小的,但是stm32片内的flash最小page为2k,不支持最小512byte的扇区读写操作,除非每次对一个flash的page进行写操作时,先将一个page的内容读取出来,在更改其中512byte,整个page擦除,最后将修改后的整个page写回去。这样操作就会减少内部flash的使用寿命,所以我将其单个扇区更改为2k。

三、硬件原理

目前使用芯片为stm32g474vet6,直接将芯片的USB引脚连接到type-c接口即可(从机接法)。

四、CubeMx配置

1.配置烧写口
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第2张图片

2.时钟树
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第3张图片
3.调试串口

STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第4张图片

4.USB配置
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第5张图片
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第6张图片

5.配置fatfs,其中MAX_SS与MIN_SS都配置为2k
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第7张图片
6.修改堆栈大小
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第8张图片
7.生成代码

五、U盘识别

1.修改USB的MSC代码
打开“usbd_storage_if.c”文件
修改宏定义:

#define STORAGE_LUN_NBR                  1
#define STORAGE_BLK_NBR                  192
#define STORAGE_BLK_SIZ                  0x800

修改STORAGE_Read_FSSTORAGE_Write_FS两个函数
代码如下(不同系列的FLash读写结构体有区别):

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : usbd_storage_if.c
  * @version        : v3.0_Cube
  * @brief          : Memory management layer.
  ******************************************************************************
  * @attention
  *
  * 

© Copyright (c) 2022 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "usbd_storage_if.h" /* USER CODE BEGIN INCLUDE */ /* 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. * @{ */ /* USER CODE BEGIN PRIVATE_DEFINES */ #include "usart.h" #include "xl_flash.h" #define STORAGE_LUN_NBR 1 #define STORAGE_BLK_NBR 192 #define STORAGE_BLK_SIZ 0x800 //芯片总共512k,128kram //384k 为USB static uint32_t GetPage(uint32_t Addr) { uint32_t page = 0; if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { /* Bank 1 */ page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE; } else { /* Bank 2 */ page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; } return page; } /* 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 over USB FS IP * @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 */ return (USBD_OK); /* USER CODE END 2 */ } /** * @brief . * @param lun: . * @param block_num: . * @param 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 */ *block_num = STORAGE_BLK_NBR; *block_size = STORAGE_BLK_SIZ; return (USBD_OK); /* USER CODE END 3 */ } /** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_IsReady_FS(uint8_t lun) { /* USER CODE BEGIN 4 */ return (USBD_OK); /* USER CODE END 4 */ } /** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_IsWriteProtected_FS(uint8_t lun) { /* USER CODE BEGIN 5 */ return (USBD_OK); /* USER CODE END 5 */ } /** * @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 */ // XL_Printf("R:lun= %2d,blk_addr =%4d, blk_len= %2d\r\n",lun,blk_addr,blk_len); uint8_t *s = (uint8_t *)(UFlash_Address_Start); s+=(blk_addr*STORAGE_BLK_SIZ); for(int i=0; i<blk_len*STORAGE_BLK_SIZ ;i++) //读取FLash地址中的数据 { *(buf++) = *(s++ ); } 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 */ // XL_Printf("W:lun= %2d,blk_addr =%4d, blk_len= %2d\r\n",lun,blk_addr,blk_len); uint32_t GetPage(uint32_t Addr); uint32_t i; HAL_FLASH_Unlock(); //解锁flash FLASH_EraseInitTypeDef EraseInitStruct; EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = GetPage(UFlash_Address_Start+ blk_addr*STORAGE_BLK_SIZ); if(UFlash_Address_Start+ blk_addr*STORAGE_BLK_SIZ>=0x08040000) EraseInitStruct.Banks = FLASH_BANK_2; else EraseInitStruct.Banks = FLASH_BANK_1; EraseInitStruct.NbPages = blk_len; uint32_t PageError = 0; if( HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) //擦除数据 { return USBD_FAIL; } // XL_Printf("PageError = %x \r\n",PageError); for(i=0;i<blk_len*STORAGE_BLK_SIZ;i+=8) //以四字节写入falsh { HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,UFlash_Address_Start + blk_addr*STORAGE_BLK_SIZ + i , *(uint64_t *)(&buf[i])); } HAL_FLASH_Lock(); return USBD_OK; /* USER CODE END 7 */ } /** * @brief . * @param None * @retval . */ 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 */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

修改完成这部分后,将USB连接电脑
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第9张图片
格式化U盘
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第10张图片
不能正常格式化,需要回去检查“usbd_storage_if.c”中的函数是否错误
这样电脑就能识别并使用该U盘了
在这里插入图片描述

六、Fatfs文件系统挂载

修改“user_diskio.c”中的USER_initializeUSER_readUSER_writeUSER_ioctl四个函数,其中USER_ioctl的参数别填错了。
说明:
fatfs版本为R0.12c,中间对扇区和和总容量大小有要求,如果扇区为2k,那么最小容量为192扇区(也就是384k,否则会报错,f_month不成功)
如果小于384k有两种方式解决:1.使用第五步中的格式化方法,先使用USB进行格式化再在STM32上使用fatfs
2.修改ff.c的5368行、5371行,解除系统的容量限制

在这里插入图片描述

#define SECTOR_COUNT 192
#define SECTOR_SIZE 0x800
#define BLOCK_SIZE 1
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
	BYTE pdrv,      /* Physical drive nmuber (0..) */
	BYTE cmd,       /* Control code */
	void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
  DRESULT res = RES_OK;
  
  switch(cmd)
  {
    case CTRL_SYNC :
			res = RES_OK;
        break;	
 
    case CTRL_TRIM:
			res = RES_OK;
        break;
		
    case GET_BLOCK_SIZE:
	*(DWORD*)buff = BLOCK_SIZE; 
	break;
		
    case GET_SECTOR_SIZE:
	*(DWORD*)buff = SECTOR_SIZE;
        break;
		
    case GET_SECTOR_COUNT:
	*(DWORD*)buff =  SECTOR_COUNT;
	break;
			
    default:
	res = RES_PARERR;
	break;
    }
  

    return res;
  /* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */
/* USER CODE BEGIN Header */
/**
 ******************************************************************************
  * @file    user_diskio.c
  * @brief   This file includes a diskio driver skeleton to be completed by the user.
  ******************************************************************************
  * @attention
  *
  * 

© Copyright (c) 2022 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */
/* USER CODE END Header */ #ifdef USE_OBSOLETE_USER_CODE_SECTION_0 /* * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0) * To be suppressed in the future. * Kept to ensure backward compatibility with previous CubeMx versions when * migrating projects. * User code previously added there should be copied in the new user sections before * the section contents can be deleted. */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ #endif /* USER CODE BEGIN DECL */ /* Includes ------------------------------------------------------------------*/ #include #include "ff_gen_drv.h" #include #include #include #include #include #include "usart.h" extern void XL_Printf(const char *format, ...); #define SECTOR_COUNT 192 #define SECTOR_SIZE 0x800 #define BLOCK_SIZE 1 /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ static uint32_t GetPage(uint32_t Addr) { uint32_t page = 0; if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { /* Bank 1 */ page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE; } else { /* Bank 2 */ page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; } return page; } /* Private variables ---------------------------------------------------------*/ /* Disk status */ static volatile DSTATUS Stat = STA_NOINIT; /* USER CODE END DECL */ /* Private function prototypes -----------------------------------------------*/ DSTATUS USER_initialize (BYTE pdrv); DSTATUS USER_status (BYTE pdrv); DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count); #if _USE_WRITE == 1 DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count); #endif /* _USE_WRITE == 1 */ #if _USE_IOCTL == 1 DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff); #endif /* _USE_IOCTL == 1 */ Diskio_drvTypeDef USER_Driver = { USER_initialize, USER_status, USER_read, #if _USE_WRITE USER_write, #endif /* _USE_WRITE == 1 */ #if _USE_IOCTL == 1 USER_ioctl, #endif /* _USE_IOCTL == 1 */ }; /* Private functions ---------------------------------------------------------*/ /** * @brief Initializes a Drive * @param pdrv: Physical drive number (0..) * @retval DSTATUS: Operation status */ DSTATUS USER_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { /* USER CODE BEGIN INIT */ Stat = FLASH_If_Init(); return Stat; /* USER CODE END INIT */ } /** * @brief Gets Disk Status * @param pdrv: Physical drive number (0..) * @retval DSTATUS: Operation status */ DSTATUS USER_status ( BYTE pdrv /* Physical drive number to identify the drive */ ) { /* USER CODE BEGIN STATUS */ Stat = FLASH_If_Init(); return Stat; /* USER CODE END STATUS */ } /** * @brief Reads Sector(s) * @param pdrv: Physical drive number (0..) * @param *buff: Data buffer to store read data * @param sector: Sector address (LBA) * @param count: Number of sectors to read (1..128) * @retval DRESULT: Operation result */ DRESULT USER_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) { /* USER CODE BEGIN READ */ uint8_t *s = (uint8_t *)(UFlash_Address_Start); XL_Printf("fR:pdrv= %2d,sector =%4d, count= %2d\r\n",pdrv,sector,count); s+=(sector*SECTOR_SIZE); for(int i=0; i<count*SECTOR_SIZE ;i++) //读取FLash地址中的数据 { *(buff++) = *(s++ ); } return RES_OK; /* USER CODE END READ */ } /** * @brief Writes Sector(s) * @param pdrv: Physical drive number (0..) * @param *buff: Data to be written * @param sector: Sector address (LBA) * @param count: Number of sectors to write (1..128) * @retval DRESULT: Operation result */ #if _USE_WRITE == 1 DRESULT USER_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to write */ ) { /* USER CODE BEGIN WRITE */ /* USER CODE HERE */ XL_Printf("fW:pdrv= %2d,sector =%4d, count= %2d\r\n",pdrv,sector,count); uint32_t GetPage(uint32_t Addr); uint32_t i; HAL_FLASH_Unlock(); //解锁flash FLASH_EraseInitTypeDef EraseInitStruct; EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = GetPage(UFlash_Address_Start+ sector*SECTOR_SIZE); if(UFlash_Address_Start+ sector*SECTOR_SIZE>=0x08040000) EraseInitStruct.Banks = FLASH_BANK_2; else EraseInitStruct.Banks = FLASH_BANK_1; EraseInitStruct.NbPages = count; uint32_t PageError = 0; if( HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) //擦除数据 { return RES_ERROR; } // XL_Printf("PageError = %x \r\n",PageError); for(i=0;i<count*SECTOR_SIZE;i+=8) //以四字节写入falsh { HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,UFlash_Address_Start + sector*SECTOR_SIZE + i , *(uint64_t *)(&buff[i])); } HAL_FLASH_Lock(); return RES_OK; /* USER CODE END WRITE */ } #endif /* _USE_WRITE == 1 */ /** * @brief I/O control operation * @param pdrv: Physical drive number (0..) * @param cmd: Control code * @param *buff: Buffer to send/receive control data * @retval DRESULT: Operation result */ #if _USE_IOCTL == 1 DRESULT USER_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { /* USER CODE BEGIN IOCTL */ DRESULT res = RES_OK; switch(cmd) { case CTRL_SYNC : res = RES_OK; break; case CTRL_TRIM: res = RES_OK; break; case GET_BLOCK_SIZE: *(DWORD*)buff = BLOCK_SIZE; break; case GET_SECTOR_SIZE: *(DWORD*)buff = SECTOR_SIZE; break; case GET_SECTOR_COUNT: *(DWORD*)buff = SECTOR_COUNT; break; default: res = RES_PARERR; break; } return res; /* USER CODE END IOCTL */ } #endif /* _USE_IOCTL == 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

七、测试

在main.c中添加以下的测试代码。

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * 

© Copyright (c) 2022 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "app_fatfs.h" #include "usart.h" #include "usb_device.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "xl_flash.h" uint16_t BackFlag = 0x55; uint16_t BackFlag1 = 0x55; /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); if (MX_FATFS_Init() != APP_OK) { Error_Handler(); } MX_USB_Device_Init(); MX_LPUART1_UART_Init(); /* USER CODE BEGIN 2 */ BackFlag = FLASH_If_Init(); // // FLASH_If_Erase(0,192); // XL_Printf("FLASH_If_Erase = %d",FLASH_If_Erase); FRESULT retUSER; FATFS USERFatFS; BYTE ReadBuffer[2048]; UINT fnum; /* 文件成功读写数量 */ BYTE WriteBuffer[]= "Hello World89898!\n"; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ char nUSERPath[4]= {"0:"}; *USERPath = *nUSERPath; while (1) { // 在外部SPI Flash挂载文件系统,文件系统挂载时会对SPI设备初始化 retUSER = f_mount(&USERFatFS, USERPath, 1); XL_Printf("f_mount= %d\r\n",retUSER); /*----------------------- 格式化测试 -----------------*/ /* 如果没有文件系统就格式化创建创建文件系统 */ if(retUSER == FR_NO_FILESYSTEM) { XL_Printf("no filesystem\r\n"); /* 格式化 */ retUSER = f_mkfs(USERPath, FM_FAT, 0,ReadBuffer ,2048); XL_Printf("f_mkfs= %d\r\n",retUSER); if(retUSER == FR_OK) { XL_Printf("f_mkfs OK\r\n"); /* 格式化后,先取消挂载 */ retUSER = f_mount(NULL, USERPath, 1); /* 重新挂载 */ retUSER = f_mount(&USERFatFS, USERPath, 1); } else { XL_Printf("f_mkfs ERROR\r\n"); while(1); } } else if(retUSER != FR_OK) { while(1); } else { } /*----------------------- 文件系统测试:写测试 -------------------*/ /* 打开文件,每次都以新建的形式打开,属性为可写 */ XL_Printf("\r\n****** STARTW ******\r\n"); retUSER = f_open(&USERFile, "test.txt", FA_CREATE_ALWAYS | FA_WRITE); if(retUSER == FR_OK) { XL_Printf("OPEN\r\n"); /* 将指定存储区内容写入到文件内 */ retUSER = f_write(&USERFile, WriteBuffer, sizeof(WriteBuffer), &fnum); if(retUSER == FR_OK) { XL_Printf("WLEN:%d\n", fnum); XL_Printf("WDATA", WriteBuffer); } else { XL_Printf("WERR", retUSER); } /* 不再读写,关闭文件 */ f_close(&USERFile); } else { XL_Printf("OPENERR\r\n"); } /*------------------- 文件系统测试:读测试 --------------------------*/ XL_Printf("****** START ******\r\n"); retUSER = f_open(&USERFile, "test.txt",FA_OPEN_EXISTING | FA_READ); if(retUSER == FR_OK) { XL_Printf("OPENOK\r\n"); retUSER = f_read(&USERFile, ReadBuffer, sizeof(ReadBuffer), &fnum); if(retUSER==FR_OK) { XL_Printf("FILELEM:%d\r\n",fnum); XL_Printf("FILEDATA:\r\n%s \r\n", ReadBuffer); } else { XL_Printf("READ ERR(%d)\n",retUSER); } } else { XL_Printf("open ERR\r\n"); } /* 不再读写,关闭文件 */ f_close(&USERFile); /* 不再使用文件系统,取消挂载文件系统 */ f_mount(NULL,"1:",1); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ while(1); } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Configure the main internal regulator output voltage */ HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV6; RCC_OscInitStruct.PLL.PLLN = 108; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV6; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } /** Initializes the peripherals clocks */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1|RCC_PERIPHCLK_USB; PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1; PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

八、现象

使用fatfs格式化的U盘,容量变小。想容量不变小,就使用USB在电脑上进行格式化。
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第11张图片
文件读写成功:
STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)_第12张图片

你可能感兴趣的:(CubeMX,stm32,单片机,arm)