1. Introduction[edit | edit source]
Azure® RTOS FileX is a fully compliant FAT library for media storage and file system management. It supports standard filesystem operations such as media formatting and file/directory management. FileX is designed in a modular way that facilitates the integration of any media storage.
FileX supports FAT16, FAT32 and extFAT formats. It offers a set of APIs to deal with files and directories such as create, delete and read/write. FileX supports both utf8 and Unicode coding as well as the "Long File Name” features to ensure filesystem compatibility between MPU and modern PCs. It also ensures the integrity of the file system via the failsafe feature (fault tolerance) especially for Flash memories where “power loss” may damage the data content and break the whole file system.
Further details are available in the FileX official documentation[1]
Information |
For frequently asked questions, visit the general FAQ section in the Introduction to Azure RTOS with STM32 article. |
2. STM32Cube MPU integration[edit | edit source]
FileX supports common media storage devices such as microSDTM. Combined with LevelX it can also support file systems on NAND and NOR Flash memories.
The media devices below are supported in the context of the STM32Cube MPUÂ :
- SRAM memories: a FAT file system can be created on the MPU internal memories. This is useful for applications with a small footprint and for fast testing and prototyping.
- SDMMC: this is the typical media storage device used in MPU-based applications. It requires both an SDMMC HW IP in the MPU and a uSD connector on the board. Therefore, dedicated BSP APIs are required. The availability of this media depends on the MPU and the board.
- NOR/NAND Flash memories:(via SPI/QSPI/OSPI/FMC). In order to support this type of memory, FileX shall be combined with LevelX. FileX manages the filesystem logic, while LevelX ensures efficient access to these memories in read and write modes (wear-levelling, bad block management, and so on). FileX is hardware agnostic in this case, as LevelX offers a common porting layer for NOR and NAND Flash memories.
In all cases, FileX requires a low-level driver to interact with the underlining media storage device.
- fx_stm32_*_driver.c: these are driver patterns that implement FileX drivers for specific media devices. (ppp can be, SDMMC, SRAM and so on). These drivers are referenced directly by the applications.
Information |
The driver list is not exhaustive and depends on the MPU and boards. |
2.1. FileX and LevelX integration[edit | edit source]
The figure below illustrates how FileX is used in conjunction with LevelX to read and write NAND Flash memories :
2.2. FileX advanced features[edit | edit source]
- Logical sector cache:
By reducing the copy paste of the entire sector, the FileX logic sector cache significantly improves performance. FileX maintains a logical sector cache for each open medium. The depth of the logical sector cache depends on the amount of memory supplied to FileX via the FX_MEDIA_OPEN API call.
- Continuous file support (file access time determinism):
FileX provides continuous file support through the _fx_file_allocate function . This function attempts to allocate the number of consecutive clusters required to satisfy the user's request. If there are enough clusters, the clusters are allocated and linked to the file. Otherwise, an error code is returned to the caller. This feature can significantly improve performance and reduces access time.
- Fault tolerance support (power-down protection):
FileX fault tolerance is designed to prevent file system damage due to interrupts occurring during file or directory update. For example, when adding data to a file, FileX needs to update the content of files, directory entries, and possible FAT entries. If this update process is interrupted (for example by a power failure or by media popping up during the update process), the file system is inconsistent, which may affect the integrity of the entire file system, resulting in corruption of files.
The FileX fault tolerance works by logging all the steps required to update the file or directory during the update process. The log entries are stored in a dedicated sector that FileX can find and access. The location of the log data can be accessed even if there is no appropriate file system. Therefore, in the event of a file system interruption, FileX can still find a log entry and restore the file system to a good condition.
This fault tolerance can be used for all the FAT file systems supported by FileX, including FAT12, FAT16, FAT32, and exFAT. By default, fault tolerance is not enabled in FileX. To enable it, use the FX_ENABLE_FAULT_TOLERANT macro definition to build FileX. At run time, the application starts fault-tolerant service by calling _fx_fault_tolerant_enable function. After the service is started, all files and directory write operations are performed through the fault tolerant module.
- Wear levelling:
LevelX provides NAND and NOR Flash memory wear levelling capabilities to embedded applications. Since both NAND and NOR Flash memories can only be erased a finite number of times, it is critical to distribute the Flash memory use evenly. This is typically called wear levelling and it is the purpose behind LevelX.
2.3. FileX Standalone mode[edit | edit source]
ThreadX is typically required to run FileX. However, it is possible to use FileX in Standalone mode, that is without ThreadX integration, by enabling the FX_STANDALONE_ENABLE and FX_SINGLE_THREAD flag. Using FileX in Standalone mode allows the reduction of code footprint by removing ThreadX files and libraries from the project. Application complexity can also be reduced by removing constraints around thread management.
When FX_STANDALONE_ENABLE flag is activated, local path logic and ThreadX timer setup are disabled.
Unless FX_SINGLE_THREAD or FX_STANDALONE_ENABLE flags are activated, all FileX operations are thread safe.
2.4. Known limitations[edit | edit source]
- No known limitations so far. More details are in the FileX official documentation[1]
3. How to use[edit | edit source]
A FileX based application has two methods to instantiate a media storage driver:
- Formatting the media storage device using one of the following APIs:
UINT _fx_media_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media),
VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size,
CHAR *volume_name, UINT number_of_fats, UINT directory_entries,
UINT hidden_sectors, ULONG total_sectors, UINT bytes_per_sector,
UINT sectors_per_cluster, UINT heads, UINT sectors_per_track);
or:
UINT _fx_media_exFAT_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media),
VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size,
CHAR *volume_name, UINT number_of_fats, ULONG64 hidden_sectors,
ULONG64 total_sectors, UINT bytes_per_sector, UINT sectors_per_cluster,
UINT volume_serial_number, UINT boundary_unit);
- Open the media storage if it already contains a valid FAT file system:
UINT _fx_media_open(FX_MEDIA *media_ptr, CHAR *media_name,
VOID (*media_driver)(FX_MEDIA *), VOID *driver_info_ptr,
VOID *memory_ptr, ULONG memory_size);
The two main items used in the above APIs are:
- struct FX_MEDIA: This structure holds all the information needed about the media storage device.
- VOID (* media_driver) (FX_MEDIA *): This is the pointer to the unique entry point to the low-level driver.
Note: fx_system_initialize() has to be called before calling any other fx_xxx() API
3.1. Example 1: SRAM interface[edit | edit source]
- SRAM driver implementation:
VOID fx_stm32_sram_driver(FX_MEDIA *media_ptr)
{
UCHAR *source_buffer;
UCHAR *destination_buffer;
UINT bytes_per_sector;
/* Process the driver request specified in the media control block. */
switch (media_ptr->fx_media_driver_request)
{
case FX_DRIVER_INIT:
{
/*
* the FX_DRIVER_INIT can be requested either from the fx_media_format() or fx_media_open()
* as the RAM memory should be always formatted before being used, by memset'ing it to '\0'
* we need to avoid double initialization to keep the file system integrity.
*/
if (is_initialized == 0)
{
_fx_utility_memory_set((UCHAR *)FX_SRAM_DISK_BASE_ADDRESS, '\0', FX_SRAM_DISK_SIZE);
is_initialized = 1;
}
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_UNINIT:
{
/* there is nothing to do for FX_DRIVER_UNINIT request
* set the media driver status to FX_SUCCESS.
*/
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_READ:
{
/* Calculate the RAM disk sector offset.*/
source_buffer = ((UCHAR *)FX_SRAM_DISK_BASE_ADDRESS) +
((media_ptr->fx_media_driver_logical_sector + media_ptr->fx_media_hidden_sectors) * media_ptr->fx_media_bytes_per_sector);
/* Copy the RAM sector into the destination. */
_fx_utility_memory_copy(source_buffer, media_ptr -> fx_media_driver_buffer,
media_ptr->fx_media_driver_sectors * media_ptr->fx_media_bytes_per_sector);
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_WRITE:
{
/* Calculate the RAM disk sector offset */
destination_buffer = (UCHAR *)FX_SRAM_DISK_BASE_ADDRESS +
((media_ptr->fx_media_driver_logical_sector + media_ptr->fx_media_hidden_sectors) * media_ptr->fx_media_bytes_per_sector);
/* Copy the source to the RAM sector. */
_fx_utility_memory_copy(media_ptr->fx_media_driver_buffer, destination_buffer,
media_ptr->fx_media_driver_sectors * media_ptr->fx_media_bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_FLUSH:
{
/*
* Nothing to do for the FX_DRIVER_FLUSH Return driver success.
*/
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_ABORT:
{
/*
* Nothing to do for the FX_DRIVER_ABORT Return driver success.
*/
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_READ:
{
/* Calculate the RAM disk boot sector offset, which is at the very beginning of
* the RAM disk.
*/
source_buffer = (UCHAR *)FX_SRAM_DISK_BASE_ADDRESS;
/* For RAM disk only, pickup the bytes per sector.*/
bytes_per_sector = _fx_utility_16_unsigned_read(&source_buffer[FX_BYTES_SECTOR]);
/* Ensure this is less than the media memory size. */
if (bytes_per_sector > media_ptr->fx_media_memory_size)
{
media_ptr->fx_media_driver_status = FX_BUFFER_ERROR;
break;
}
/* Copy the RAM boot sector into the destination. */
_fx_utility_memory_copy(source_buffer, media_ptr -> fx_media_driver_buffer,
bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_WRITE:
{
/*
* Calculate the RAM disk boot sector offset, which is at the very beginning of the RAM disk.
*/
destination_buffer = (UCHAR *)FX_SRAM_DISK_BASE_ADDRESS;
/* Copy the RAM boot sector into the destination. */
_fx_utility_memory_copy(media_ptr->fx_media_driver_buffer, destination_buffer,
media_ptr->fx_media_bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
default:
{
/* Invalid driver request. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
break;
}
}
}
- SRAM driver loading:
/* Format the RAM disk - the memory for the RAM disk was defined above. */
status = _fx_media_format(media_ptr,
driver, /* Driver entry */
driver_info_ptr, /* RAM disk memory pointer */
memory_ptr, /* Media buffer pointer */
memory_size, /* Media buffer size */
volume_name, /* Volume Name */
number_of_fats, /* Number of FATs */
directory_entries, /* Directory Entries */
hidden_sectors, /* Hidden sectors */
total_sectors, /* Total sectors */
bytes_per_sector, /* Sector size */
sectors_per_cluster, /* Sectors per cluster */
heads, /* Heads */
sectors_per_track); /* Sectors per track */
/* Return completion status. */
return(status);
4. Migration from FatFS to FileX[edit | edit source]
Both FileX and FatFS are universal file system (FAT/exFAT) stacks used to implement FAT file system in relatively small embedded devices.
4.1. Main features[edit | edit source]
Feature | FileX | FatFS |
---|---|---|
FAT 12/16/32 and exFAT support | Yes | Yes |
Platform independent | Yes | Yes |
Multiple partition support | Yes | Yes |
Long file name in ANSI/OEM or Unicode | Yes | Yes |
Fault tolerance: Power failure recovery capability | Yes | No |
Wear levelling support | Yes | No |
4.2. Main API group correspondence[edit | edit source]
The following tables summarize the most commonly used APIs for FatFS and their equivalent on FileX side.
Description of file APIs | FatFS | FileX |
---|---|---|
Open/Create a file | f_open | fx_file_open |
Close a file | f_close | fx_file_close |
Read data from a file | f_read | fx_file_read |
Write date to a file | f_write | fx_file_write |
Move the read/write pointer (or expand size) | f_lseek | _fx_file_relative_seek |
Get the current read/write pointer | f_tell | fx_file_seek |
Truncate file size | f_truncate | _fx_file_truncate |
Read a string | f_gets | N/A |
Write a character | f_putc | N/A |
Write a string | f_puts | N/A |
Write a formatted string | f_printf | N/A |
Test for end of file | f_eof | N/A |
Get object size | f_size | N/A |
Check for errors | f_error | N/A |
Description of volume APIs | FatFS | FileX |
---|---|---|
Register/Unregister the work area of the volume | f_mount | fx_media_open / fx_media_close |
Create a FAT volume on the logical drive | f_mkfs | fx_media_format |
Get free space on the volume | f_getfree | fx_media_space_available |
Get volume label | f_getlabel | _fx_media_volume_get |
Set volume label | f_setlabel | _fx_media_volume_set |
Set active code page | f_setcp | N/A |
Description of media interface APIs | FatFS | FileX |
---|---|---|
Get device status | disk_status | _fx_media_check |
Initialize device | disk_initialize | fx_system_initialize |
Read data | disk_read | _fx_media_read |
Write data | disk_wirte | _fx_media_write |
Control device dependent functions | disk_ioctl | N/A |
Get current time | get_fattime | _fx_system_date_get |
5. STM32CubeMPU Package FileX applications[edit | edit source]
5.1. STM32CubeMP13 Package FileX applications[edit | edit source]
STM32CubeMP13 package provides the following set of applications :
Application | Short description |
---|---|
Fx_uSD_File_Edit | Demonstrates how to develop a basic SD card file operations application. The application is designed to handle SD card insertion/removal events, and depending on that state, it starts and stops file operations from and into the SD card. For more information, refer to the application Projects/STM32MP135C-DK/Applications/FileX/Fx_uSD_File_Edit/README.md file. |
Fx_SRAM_File_Edit_Standalone | This application provides an example of FileX stack usage in Standalone mode (without ThreadX). It demonstrates how to create a FAT File system in internal SRAM using FileX API. For more information, refer to the application Projects/STM32MP135C-DK/Applications/FileX/Fx_SRAM_File_Edit_Standalone/README.md file. |
Fx_MultiAccess | Demonstrates the FileX concurrent file access capabilities. The application is designed to execute file operations on the SD card device, the code provides all required software code for handling SD card I/O operations. For more information, refer to the application Projects/STM32MP135C-DK/Applications/FileX/Fx_MultiAccess/README.md file. |
5.2. STM32CubeMP2 Package FileX applications[edit | edit source]
STM32CubeMP2 package provides the following set of applications :
Application | Short description |
---|---|
Fx_NoR_Write_Read_File | Demonstrates how to create a Fat File system on the NOR flash using FileX alongside LevelX. The application is designed to execute file operations on the MX25L51245G NOR flash device, the code provides all required software code for properly managing it. For more information, refer to the application Projects/STM32MP257F-EV1/Applications/FileX/Fx_NoR_Write_Read_File/README.md file. |
Fx_SRAM_File_Edit_Standalone | This application provides an example of FileX stack usage in Standalone mode (without ThreadX). It demonstrates how to create a FAT File system in internal SRAM using FileX API. For more information, refer to the application Projects/STM32MP257F-EV1/Applications/FileX/Fx_SRAM_File_Standalone/README.md file. |