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

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

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

一、设计原因

由于平时使用stm32的板子没有带SD卡,有时候也用不了SD的那么大的容量,stm32内部的flash容量都十分充裕。多以产生了使用stm32的片内flash制作一个USB小U盘的想法。
在这里插入图片描述

二、与别人不同的地方

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

三、硬件原理

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

四、CubeMx配置

1.配置烧写口
在这里插入图片描述

2.时钟树
在这里插入图片描述
3.调试串口

在这里插入图片描述

4.USB配置
在这里插入图片描述
在这里插入图片描述

5.配置fatfs,其中MAX_SS与MIN_SS都配置为2k
在这里插入图片描述
6.修改堆栈大小
在这里插入图片描述
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
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * 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连接电脑
在这里插入图片描述
格式化U盘
在这里插入图片描述
不能正常格式化,需要回去检查“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
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * 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 <string.h>
#include "ff_gen_drv.h"
#include <xl_flash.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#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
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * 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在电脑上进行格式化。
在这里插入图片描述
文件读写成功:
在这里插入图片描述

  • 8
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: STM32 Flash MSC是指STM32单片机通过MSC(Mass Storage Class)协议对Flash进行读写操作的功能。MSC是一种通用的USB存储设备类协议,可以使STM32单片机被电脑识别为一个USB存储设备。通过MSC协议,可以在STM32单片机上通过USB接口直接读写Flash,实现向Flash写入数据或从Flash读取数据的操作。 STM32 Flash MSC的优点是方便、快捷,无需专门的烧录器或工具,只需一个USB线即可连接STM32单片机和电脑,就可以对Flash进行读写操作。这对于开发者来说是非常便利的,可以方便地调试代码、更新固件或者进行数据的存储与读取。 具体使用步骤如下: 1. 在STM32单片机中实现MSC功能,并配置相关的寄存器和中断。 2. 将STM32单片机通过USB接口连接到电脑。 3. 电脑会自动识别STM32单片机为一个USB存储设备。 4. 在电脑的文件管理器中可以看到STM32单片机的存储设备,可以像操作普通的U盘一样对其进行文件的读写操作。 5. 在STM32单片机的代码中,可以通过读写Flash的接口对Flash进行数据的读写操作。 需要注意的是,使用Flash MSC功能时需要对Flash进行合理的分区,以保证数据的存储和读取的稳定性。同时,要遵循MSC协议的规范,避免产生数据冲突或损坏Flash等问题。 总之,STM32 Flash MSC功能可以方便地实现对Flash的读写操作,为开发者提供了更便捷的开发和调试方式,极大地提高了开发效率。 ### 回答2: STM32 Flash MSC是指STM32系列微控制器中使用的闪存存储器(Flash Memory)和质量服务分类(MSC)模块。该模块在STM32芯片中集成,提供了高效、可靠的闪存存储和管理功能。 闪存存储器是STM32微控制器的一部分,用于存储程序代码和数据。它具有非易失性存储特性,即在芯片断电后仍能保持数据的保存,因此非常适合用于嵌入式系统中。闪存存储器还具有高速读取和写入的特点,使得STM32系列微控制器能够实现高性能的应用程序。 MSC模块是用于管理STM32闪存的质量服务分类模块。它提供了一种便捷的接口,使得开发人员可以轻松地以类似于磁盘的方式访问闪存。通过MSC模块,开发人员可以进行闪存的读取、写入、擦除等操作,实现程序的更新、数据的存储和管理。 使用STM32 Flash MSC有以下优点: 1. 闪存存储器的非易失性特性确保了数据的持久保存,即使在断电后也不会丢失。 2. 高速的读写性能使得STM32微控制器能够处理实时性要求较高的应用程序。 3. MSC模块提供了便捷的接口,使得开发人员可以轻松地访问和管理闪存。 4. 可靠的闪存存储和管理功能保证了系统的稳定性和可靠性。 综上所述,STM32 Flash MSC模块为STM32系列微控制器提供了高效、可靠的闪存存储和管理功能,使得开发人员能够轻松地实现程序的更新、数据的存储和管理。这使得STM32微控制器成为嵌入式系统开发中的首选。 ### 回答3: STM32 Flash MSC是指STM32微控制器上的一种功能,其通过Mass Storage Class(MSC)协议实现了在外部存储器上执行Flash操作的能力。 MSC是一种通用的USB设备类协议,允许将STM32微控制器作为USB存储设备连接到计算机上。通过这种协议,我们可以在计算机上像使用U盘一样直接读写STM32Flash存储器。 STM32 Flash MSC功能的实现需要通过USB接口和相关的固件库。通过这种功能,我们可以向STM32微控制器中的Flash存储器中写入数据,也可以从Flash存储器中读取数据。 这对于固件程序的更新和调试非常有用。当我们需要更新固件程序时,我们可以将新的固件程序文件拷贝到STM32Flash存储器中,然后通过Flash MSC功能启动固件更新过程。同样地,当我们需要读取STM32微控制器上的数据时,我们可以将数据文件从Flash存储器中拷贝到计算机上进行分析和处理。 使用STM32 Flash MSC功能需要注意一些细节,比如在使用之前需要初始化USB接口和相关的GPIO引脚,还需要处理MSC类别请求以及处理对Flash存储器的读写操作。 总的来说,STM32 Flash MSC功能通过USB接口,使STM32微控制器具备了类似U盘的读写Flash存储器的能力,大大方便了固件程序的更新和数据的读取,是一种非常有用的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhuzhu、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值