STM32使用片内FLASH制作小U盘(STM32+FLASH+MSC)
STM32使用片内FLASH制作U盘(STM32+FLASH+MSC)文章目录STM32使用片内FLASH制作U盘(STM32+FLASH+MSC)一、设计原因二、与别人不同的地方三、硬件原理四、CubeMx配置一、设计原因由于平时使用stm32的板子没有带SD卡,有时候也用不了SD的那么大的容量,stm32内部的flash容量都十分充裕。多以产生了使用stm32的片内flash制作一个USB小U
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_FS
、STORAGE_Write_FS
两个函数
代码如下(不同系列的FLash读写结构体有区别
):
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usbd_storage_if.c
* @version : v3.0_Cube
* @brief : Memory management layer.
******************************************************************************
* @attention
*
* <h2><center>© 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_initialize
、USER_read
、USER_write
、USER_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>© 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>© 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在电脑上进行格式化。
文件读写成功:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)