Last edited 4 months ago

Introduction to FILEX

Applicable for STM32MP13x lines


1 Introduction[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 Overview

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]

Info white.png Information
For frequently asked questions, visit the general FAQ section in the Introduction to Azure RTOS with STM32 article.


2 STM32Cube MPU integration[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.

FileX Folders


  • 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.
Info white.png Information
The driver list is not exhaustive and depends on the MPU and boards.


2.1 FileX and LevelX integration[edit source]

The figure below illustrates how FileX is used in conjunction with LevelX to read and write NAND Flash memories :

FileX LevelX Integration

2.2 FileX advanced features[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 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 source]

  • No known limitations so far. More details are in the FileX official documentation[1]

3 How to use[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 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 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 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 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 References[edit source]