FILE SYSTEM¶
Info
File system is a method of storing and organizing computer files and their data. Here, we will use the FatFs library to interface with the SD card.
FILE SYSTEM AS A MIDDLEWARE¶
In STM32CUBEMX, FATFS is already incorporated into the software as a middleware. To enable FATFS, go to the 'Middleware' tab and enable the 'FATFS' middleware.
FILE SYSTEM CONFIGURATION¶
As shown, select FATFS for SD card, and enable the long file name support.
Then, under the Advanced Settings, select the DMA template for the SD card.
GENERATE AND UPDATE CODE¶
Finally, let's generate the code to save the current progress and to make it ready for following programming steps. Click the 'Generate Code' button at the top right corner of the screen.
PROGRAMMING IN KEIL¶
MODIFY THE CONFIGURATION IN SD_DISKIO.C¶
As shown above, modify the code in the sd_diskio.c file to configure the SD card and FATFS.
INCORPORATE THE MODULE CODE - IFILE¶
We have introduced how to transplant and incorporate the BSP code into the project, and that applies to each respective module. For transplantation:
- Copy the module codes from the BSP project to the user project.
- Add the module codes to the user project include path.
- Add the module codes to the project items.
- Include the header file of the module code in the user project.
- Call the module function in the user project.
Warning
Since we are using FATFS here, and FATFS has a built-in SDCARD driver, it will conflict with our own isdcard driver. Therefore, in the bsp_init
, if we want to use the FATFS file system, we should not include the isdcard driver; otherwise, it will cause a conflict.
CODE REVIEW - FILE-SYS¶
bsp_file.h¶
/**
* @file bsp_file.h
* @author SHUAIWEN CUI (shuaiwencui AT gmail DOT com)
* @brief This is the header file for the bsp_file.c file
* @version 1.0
* @date 2024-07-17
* @ref https://blog.csdn.net/Mculover666/article/details/102688285;https://blog.csdn.net/qq_36561846/article/details/133808890
* @copyright Copyright (c) 2024
*
*/
#ifndef _BSP_FILE_H_
#define _BSP_FILE_H_
/**
* @name INCLUDES
*/
#include "stm32h7xx.h"
#include "main.h"
#include "ff.h" // FATFS main header file
#include "diskio.h" // Disk I/O header file
#include "fatfs.h" // FATFS configuration header file (if using STM32CubeMX)
#include "ff_gen_drv.h" // Generic driver header file
#include "ffconf.h"
#include "stdio.h"
/* Define custom storage device */
/* Number of bytes per sector for user storage device */
#define User_Sector 512
/* FatFs object for user storage device */
#define User_FatFs SDFatFS
/* Volume path for user storage device */
#define User_SDPath SDPath
/*functions*/
void Mount_FatFs(void);
void FatFs_GetDiskInfo(void);
void FatFs_ScanDir(const TCHAR* PathName);
void FatFs_ReadTXTFile(TCHAR *filename);
void FatFs_WriteTXTFile(TCHAR *filename,uint16_t year, uint8_t month, uint8_t day);
void FatFs_GetFileInfo(TCHAR *filename);
void FatFs_DeleteFile(TCHAR *filename);
void FatFs_PrintfFileDate(WORD date, WORD time);
uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks);
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks);
#endif /* _BSP_FILE_H_ */
bsp_file.c¶
/**
* @file bsp_file.c
* @author SHUAIWEN CUI (shuaiwencui AT gmail DOT com)
* @brief This is the source file for the bsp_file.c file
* @version 1.0
* @date 2024-07-17
* @ref https://blog.csdn.net/Mculover666/article/details/102688285;https://blog.csdn.net/qq_36561846/article/details/133808890
* @copyright Copyright (c) 2024
*
*/
#include "bsp_file.h"
#include "bsp_usart.h"
#include "sdmmc.h"
// Define a work buffer for formatting
BYTE workBuffer[4 * User_Sector];
/**
* @name Mount_FatFs
* @brief Mount FatFs file system
* @param None
* @retval None
* @note Working
*/
/* Mount FatFs file system */
void Mount_FatFs(void)
{
// Mount file system
FRESULT retUSER = f_mount(&User_FatFs, User_SDPath, 1);
// Error occurred
if (retUSER != FR_OK)
{
// No file system, need to format
if (retUSER == FR_NO_FILESYSTEM)
{
printf("\r\nNo file system, start formatting\r\n");
// Create file system
retUSER = f_mkfs(User_SDPath, FM_FAT32, 0, workBuffer, 4 * User_Sector);
// Formatting failed
if (retUSER != FR_OK)
{
printf("Formatting failed, error code = %d\r\n", retUSER);
}
// Formatting succeeded
else
{
printf("Formatting succeeded, remounting\r\n");
// Remount after creating file system
retUSER = f_mount(&User_FatFs, User_SDPath, 1);
// Mounting failed
if (retUSER != FR_OK)
{
printf("Error occurred, error code = %d\r\n", retUSER);
}
// Mounting succeeded
else
{
printf("*** File system mounted successfully ***\r\n");
}
}
}
// Other error occurred
else
{
printf("Other error occurred, error code = %d\r\n", retUSER);
}
}
// File system already exists, mounted successfully
else
{
printf("File system mounted successfully\r\n");
}
}
/**
* @name FatFs_GetDiskInfo
* @brief Get disk information and display on LCD
* @param None
* @retval None
* @note Working
*/
/* Get disk information and display on LCD */
void FatFs_GetDiskInfo(void)
{
FATFS *fs;
// Define variable for remaining clusters
DWORD fre_clust;
// Get remaining clusters
FRESULT res = f_getfree("0:", &fre_clust, &fs);
// Getting failed
if (res != FR_OK)
{
printf("f_getfree() error\r\n");
return;
}
printf("\r\n*** FAT disk info ***\r\n");
// Total number of sectors
DWORD tot_sect = (fs->n_fatent - 2) * fs->csize;
// Remaining number of sectors = remaining clusters * sectors per cluster
DWORD fre_sect = fre_clust * fs->csize;
// For SD card and USB flash drive, _MIN_SS=512 bytes
#if _MAX_SS == _MIN_SS
// SD card's _MIN_SS is fixed at 512, right shift 11 bits equals dividing by 2048
// Remaining space size, unit: MB, for SD card and USB flash drive
DWORD freespace = (fre_sect >> 11);
// Total space size, unit: MB, for SD card and USB flash drive
DWORD totalSpace = (tot_sect >> 11);
#else
// Flash storage, small capacity
// Remaining space size, unit: KB
DWORD freespace = (fre_sect * fs->ssize) >> 10;
// Total space size, unit: KB
DWORD totalSpace = (tot_sect * fs->ssize) >> 10;
#endif
// FAT type
printf("FAT type = %d ", fs->fs_type);
printf("[1=FAT12, 2=FAT16, 3=FAT32, 4=exFAT]\r\n");
// Sector size in bytes
printf("Sector size(bytes) = ");
// SD card fixed 512 bytes
#if _MAX_SS == _MIN_SS
printf("%d\r\n", _MIN_SS);
#else
// Flash storage
printf("%d\r\n", fs->ssize);
#endif
printf("Cluster size(sectors) = %d\r\n", fs->csize);
printf("Total cluster count = %ld\r\n", fs->n_fatent - 2);
printf("Total sector count = %ld\r\n", tot_sect);
// Total space
#if _MAX_SS == _MIN_SS
printf("Total space = %ld(MB) = %ld(GB)\r\n", totalSpace, totalSpace >> 10);
#else
printf("Total space = %ld(KB) = %ld(MB)\r\n", totalSpace, totalSpace >> 10);
#endif
// Free cluster count
printf("Free cluster count = %ld\r\n", fre_clust);
// Free sector count
printf("Free sector count = %ld\r\n", fre_sect);
// Free space
#if _MAX_SS == _MIN_SS
printf("Free space = %ld(MB) = %ld(GB)\r\n", freespace, freespace >> 10);
#else
printf("Free space = %ld(KB) = %ld(MB)\r\n", freespace, freespace >> 10);
#endif
printf("Get FAT disk info OK\r\n");
}
/* Create a text file */
void FatFs_WriteTXTFile(TCHAR *filename, uint16_t year, uint8_t month, uint8_t day)
{
FIL file;
printf("\r\n*** Creating TXT file: %s ***\r\n", filename);
FRESULT res = f_open(&file, filename, FA_CREATE_ALWAYS | FA_WRITE);
// File opened/created successfully
if (res == FR_OK)
{
// String must have a newline character "\n"
TCHAR str[] = "Line1: Hello, FatFs***\n";
// Does not write the end character "\0"
f_puts(str, &file);
printf("Write file OK: %s\r\n", filename);
}
else
{
printf("Open file error, error code: %d\r\n", res);
}
// Close the file after use
f_close(&file);
}
/* Read the content of a text file */
void FatFs_ReadTXTFile(TCHAR *filename)
{
printf("\r\n*** Reading TXT file: %s ***\r\n", filename);
FIL file;
// Open file in read-only mode
FRESULT res = f_open(&file, filename, FA_READ);
// Opened successfully
if (res == FR_OK)
{
// Read buffer
TCHAR str[100];
// Not reached the end of file
while (!f_eof(&file))
{
// Read 1 string, automatically add end character "\0"
f_gets(str, 100, &file);
printf("%s", str);
}
printf("\r\n");
}
// File does not exist
else if (res == FR_NO_FILE)
printf("File does not exist\r\n");
// Opening failed
else
printf("f_open() error, error code: %d\r\n", res);
// Close the file
f_close(&file);
}
/* Scan and display files and directories in the specified directory */
void FatFs_ScanDir(const TCHAR *PathName)
{
DIR dir; // Directory object
FILINFO fno; // File information
// Open directory
FRESULT res = f_opendir(&dir, PathName);
// Opening failed
if (res != FR_OK)
{
// Close directory and exit function
f_closedir(&dir);
printf("\r\nf_opendir() error, error code: %d\r\n", res);
return;
}
printf("\r\n*** All entries in dir: %s ***\r\n", PathName);
// Read files in the directory sequentially
while (1)
{
// Read one item in the directory
res = f_readdir(&dir, &fno);
// If file name is empty, no more items to read
if (res != FR_OK || fno.fname[0] == 0)
break;
// If it is a directory
if (fno.fattrib & AM_DIR)
{
printf("DIR: %s\r\n", fno.fname);
}
// If it is a file
else
{
printf("FILE: %s\r\n", fno.fname);
}
}
// Scanning finished, close directory
printf("Scan dir OK\r\n");
f_closedir(&dir);
}
/* Get information of a file */
void FatFs_GetFileInfo(TCHAR *filename)
{
printf("\r\n*** File info of: %s ***\r\n", filename);
FILINFO fno;
// Check if file or subdirectory exists
FRESULT fr = f_stat(filename, &fno);
// If exists, read file information from fno
if (fr == FR_OK)
{
printf("File size(bytes) = %ld\r\n", fno.fsize);
printf("File attribute = 0x%x\r\n", fno.fattrib);
printf("File Name = %s\r\n", fno.fname);
// Output the timestamp of file creation/modification
FatFs_PrintfFileDate(fno.fdate, fno.ftime);
}
// If file does not exist
else if (fr == FR_NO_FILE)
printf("File does not exist\r\n");
// Other error occurred
else
printf("f_stat() error, error code: %d\r\n", fr);
}
/* Delete a file */
void FatFs_DeleteFile(TCHAR *filename)
{
printf("\r\n*** Delete File: %s***\r\n", filename);
FIL file;
// Open file
FRESULT res = f_open(&file, filename, FA_OPEN_EXISTING);
if (res == FR_OK)
{
// Close file
f_close(&file);
printf("Open successfully!\r\n");
}
// Delete file
res = f_unlink(filename);
// Delete successfully
if (res == FR_OK)
{
printf("The file was deleted successfully!\r\n");
}
// Delete failed
else
{
printf("File deletion failed, error code: %d\r\n", res);
}
}
/* Print file date */
void FatFs_PrintfFileDate(WORD date, WORD time)
{
printf("File date = %d/%d/%d\r\n", ((date >> 9) & 0x7F) + 1980, (date >> 5) & 0xF, date & 0x1F);
printf("File time = %d:%d:%d\r\n", (time >> 11) & 0x1F, (time >> 5) & 0x3F, time & 0x1F);
}
// to over write BSP_SD_ReadBlocks_DMA & BSP_SD_WriteBlocks_DMA in bsp_driver_sd.c
uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
uint8_t sd_state = MSD_OK;
SCB_CleanDCache();
/* Read block(s) in DMA transfer mode */
if (HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK)
{
sd_state = MSD_ERROR;
}
return sd_state;
}
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
uint8_t sd_state = MSD_OK;
SCB_CleanDCache();
/* Write block(s) in DMA transfer mode */
if (HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK)
{
sd_state = MSD_ERROR;
}
return sd_state;
}