📄 emFloat User Guide & Reference Manual
📄 emNet User Guide & Reference Manual
📄 emRun User Guide & Reference Manual
📄 emSecure-ECDSA User Guide & Reference Manual
📄 emSecure-RSA User Guide & Reference Manual
📄 emSSH User Guide & Reference Manual
📄 emSSL User Guide & Reference Manual
📄 emUSB-Device User Guide & Reference Manual
📄 emUSB-Host User Guide & Reference Manual
📄 emVNC User Guide & Reference Manual
📄 emWeb User Guide & Reference Manual
📄 emWin User Guide & Reference Manual
📄 IoT Toolkit User Guide & Reference Manual
📄 SEGGER Assembler User Guide & Reference Manual
📄 SEGGER Compiler User Guide & Reference Manual
📄 SEGGER Linker User Guide & Reference Manual
📄 SEGGER SystemView User Guide
📄 SEGGER Online Documentation
📄 AppWizard User Guide & Reference Manual
📄 embOS Real-Time Operating System User Guide & Reference Manual for embOS-Base and embOS-MPU
📄 embOS-Ultra Real-Time Operating System User Guide & Reference Manual for embOS-Ultra and embOS-Ultra-MPU
📄 emCompress-Embed User Guide & Reference Manual
📄 emCompress-LZMA User Guide & Reference Manual
📄 emCompress-ToGo User Guide & Reference Manual
📄 emCrypt User Guide & Reference Manual
📄 emDropbox User Guide & Reference Manual
📄 emFile User Guide & Reference Manual

emFile
User Guide & Reference Manual
Document: UM02001
Software Version: 5.34.0
Document revision: 0

Introduction to emFile

This section presents an overview of emFile, its structure, and its capabilities.

What is emFile

emFile is a file system design for embedded applications which supports NAND, DataFlash, NOR and SPI Flash, SD and MMC Memory Cards, RAM and USB mass storage devices. emFile is a high performance library optimized for high speed, versatility and a minimal memory footprint of both RAM and ROM. It is written in ANSI C and can be used on any CPU.

Features

The main features of emFile are:

Basic concepts

This section describes the software structure of emFile as well as other general concepts such as fail safety and wear leveling.

emFile structure

emFile is organized in different layers as illustrated in the following diagram. A short description of each layer’s functionality follows below.

File system structure

API layer

The API layer is the interface between emFile and the user application. It is divided in two parts storage API and file system API. The file system API declares file functions in ANSI C standard I/O style, such as FS_FOpen(), FS_FWrite() etc. The API layer transfers any calls to these functions to the file system layer. Currently the FAT file system or an optional file system, called EFS, are available for emFile. Both file systems can be used simultaneously. The storage API declares the functions which are required to initialize and access a storage medium. The storage API allows sector read and write operations. The API layer transfers these calls to the storage layer. The storage API is optimized for applications which do not require file system functionality like file and directory handling. A typical application which uses the storage API could be a USB mass storage device, where data has to be stored on a medium, but all file system functionality is handled by the host PC.

File system layer

The file system layer translates file operations to logical block (sector) operations. After such a translation, the file system calls the logical block layer and specifies the corresponding device driver for a device.

Storage layer

The main purpose of the Storage Layer is to synchronize accesses to a device driver. Furthermore, it provides a simple interface for the File System API. The Storage Layer calls a device driver to perform a block operation. It also contains the cache mechanism.

Driver layer

Device drivers are low-level routines that are used to access sectors of the device and to check status. It is hardware independent but depends on the storage medium.

Hardware layer

These layer contains the low-level routines to access your hardware. These routines simply read and store fixed length sectors. The structure of the device driver is simple in order to allow easy integration of your own hardware.

Choice of file system type: FAT vs. EFS

Within emFile, there is a choice among two different file systems. The first, the FAT file system, is divided into three different sub types, FAT12, FAT16 and FAT32. The other file system EFS, is a proprietary file system developed by SEGGER. The choice of the suitable file system depends on the environment in which the end application is to operate.

The FAT file system was developed by Microsoft to manage file segments, locate available clusters and reassemble files for use. Released in 1976, the first version of the FAT file system was FAT12, which is no longer widely used. It was created for extremely small storage devices. (The early version of FAT12 did not support managing directories).

FAT16 is good for use on multiple operating systems because it is supported by all versions of Microsoft Windows, including DOS and Linux. The newest version, FAT32, improves upon the FAT16 file system by utilizing a partition/disk much more efficiently. It is supported by all Microsoft Windows versions newer than Windows 98 and as well on Linux based systems.

The EFS file system was added to emFile as an alternative to the FAT file system and was specifically designed for embedded devices. This file system uses the storage space dedicated to the file and directory names more efficiently while still offering faster access to embedded storage devices. Another benefit of EFS is that there are no issues concerning long file name (LFN) support. The FAT file system was not designed for long file name support, limiting names to twelve characters (8.3 format). LFN support may be added to any of the FAT file systems. Long file names are inherent to this proprietary file system.

Fail safety

Fail safety is the feature of emFile that ensures the consistency of data in case of unexpected loss of power during a write access to a storage medium. emFile will be fail-safe only when both the file system (FAT/EFS) and the device driver are fail-safe. The journaling add-on of emFile makes the FAT/EFS file systems fail-safe. The device drivers of emFile are all fail-safe by design. You can find detailed information about how the fail-safety works in chapter Journaling and as part of the description of individual device drivers.

Wear leveling

This is a feature of the NAND and NOR flash device drivers that increase the lifetime of a storage medium by ensuring that all the storage blocks are equally well used. The flash storage memories have a limited number of program/erase cycles, typically around 100,000. The manufacturers do not guarantee that the storage device will work properly once this limit is exceeded. The wear leveling logic implemented in the device drivers tries to keep the number of program-erase cycles of a storage block as low as possible. You can find additional information in the description of the respective device drivers.

Implementation notes

This section provides information about the implementation of emFile

File system configuration

The file system is designed to be configurable at runtime. This has various advantages. Most of the configuration is done automatically; the linker builds in only code that is required. This concept allows to put the file system in a library. The file system does not need to be recompiled when the configuration changes, e.g. a different driver is used. Compile time configuration is kept to a minimum, primarily to select the level of multitasking support and the level of debug information. For detailed information about configuration of emFile, refer to Configuration of emFile.

Runtime memory requirements

Because the configuration is selected at runtime the amount of memory required is not known at compile-time. For this reason a mechanism for runtime memory assignment is required. Runtime memory is typically allocated when required during the initialization and in most embedded systems never freed.

Initializing the file system

The first thing that needs to be done after the system start-up and before any file system function can be used, is to call the function FS_Init(). This routine initializes the internals of the file system. While initializing the file system, you have to add your target device to the file system. The function FS_X_AddDevices() adds and initializes the device.

  FS_Init()
    |
    +-> FS_X_AddDevices()
          |
          +-> FS_AssignMemory()
          |
          +-> FS_AddDevice()
          |
          +-> Optional: Other configuration functions

Development environment (compiler)

The CPU used is of no importance; only an ANSI-compliant C compiler complying with at least one of the following international standards is required:

If your compiler has some limitations, let us know and we will inform you if these will be a problem when compiling the software. Any compiler for 16/32/64-bit CPUs or DSPs that we know of can be used; most 8-bit compilers can be used as well. A C++ compiler is not required, but can be used. The application program can therefore also be programmed in C++ if desired.

Getting started

This chapter provides an introduction to using emFile. It explains how to use the Windows sample, which is an easy way to get a first project with emFile up and running.

Package content and installation

emFile is provided in source code and contains everything needed to compile it on any platform. The following table shows the contents of the emFile package:

Files Description
Application Sample applications.
BSP Support files for different evaluation boards
Config Configuration header files.
Doc emFile documentation.
FS emFile source code.
Inc Global header files.
Linux Utility applications for Linux.
Sample Sample drivers and applications.
SEGGER Utility source code.
Simulation Support files for PC simulation.
Windows Utility applications for Windows.
FS_Start.* PC simulation project MS Visual Studio / C++ and FAT.
FS_EFS_Start.* PC simulation project MS Visual Studio / C++ and EFS.
FS_STORAGE_Start.* PC simulation project MS Visual Studio / C++ and storage layer.

emFile is shipped in electronic form in a .zip file. In order to install it, extract the .zip file to any folder of your choice, preserving the directory structure of the .zip file.

Using the Windows sample application

If you have MS Visual C++ 6.00 or any later version available, you will be able to work with a Windows sample project using emFile. Even if you do not have the Microsoft compiler, you should read this chapter in order to understand how an application can use emFile.

Building the sample application

Open the workspace FS_Start.sln with MS Visual Studio (for example double-clicking it). There is no further configuration necessary. You should be able to build the application without any error or warning message.

Overview of the sample application

The sample project uses the RAM disk driver for demonstration. The main function of the sample application Start.c calls the function MainTask(). MainTask() initializes the file system and executes some basic file system operations. The sample application Start.c step-by-step:

void main(void);
void main(void) {
  MainTask();                                           
}
void MainTask(void) {
  U32          v;
  FS_FILE    * pFile;
  char         ac[256];
  char         acFileName[32];
  const char * sVolumeName = "";

  FS_X_Log("Start\n");
  //
  // Initialize file system
  //
  FS_Init();                                            
  //
  // Check if low-level format is required
  //
  FS_FormatLLIfRequired(sVolumeName);                   
  //
  // Check if volume needs to be high level formatted.
  //
  if (FS_IsHLFormatted(sVolumeName) == 0) {             
    FS_X_Log("High-level format\n");
    FS_Format(sVolumeName, NULL);
  }
  sprintf(ac, "Running sample on \"%s\"\n", sVolumeName);
  FS_X_Log(ac);                                         
  v = FS_GetVolumeFreeSpaceKB(sVolumeName);             
  if (v < 0x8000) {
    sprintf(ac, "  Free space: %lu KBytes\n", v);
  } else {
    v >>= 10;
    sprintf(ac, "  Free space: %lu MBytes\n", v);
  }
  FS_X_Log(ac);
  sprintf(acFileName, "%s\\File.txt", sVolumeName);
  sprintf(ac, "  Write test data to file %s\n", acFileName);
  FS_X_Log(ac);
  pFile = FS_FOpen(acFileName, "w");                    
  if (pFile) {
    FS_Write(pFile, "Test", 4);                         
    FS_FClose(pFile);
  } else {
    sprintf(ac, "Could not open file: %s to write.\n", acFileName);
    FS_X_Log(ac);
  }
  v = FS_GetVolumeFreeSpaceKB(sVolumeName);             
  if (v < 0x8000) {
    sprintf(ac, "  Free space: %lu KBytes\n", v);
  } else {
    v >>= 10;
    sprintf(ac, "  Free space: %lu MBytes\n", v);
  }
  FS_X_Log(ac);
  FS_Unmount(sVolumeName);
  FS_X_Log("Finished\n");                               
  while (1) {
    ;
  }
}

  Application start main.c calls MainTask().   File system initialization MainTask() initializes and adds a device to emFile.   Low-level formatting Checks if volume is low-level formatted and formats if required.   High-level formatting Checks if volume is high-level formatted and formats if required.   Volume name Outputs the volume name.   Free space before operation Calls FS_GetVolumeFreeSpace() and outputs the return value - the available free space of the RAM disk - to console window.   File creation Creates and opens a file test with write access (File.txt) on the device.   File write Writes 4 bytes into the file and closes the file handle or outputs an error message.   Free space after operation Calls FS_GetVolumeFreeSpace() and outputs the return value - the available free space of the RAM disk - again to console window.   End of application Outputs a quit message and runs into an endless loop.

Stepping through the sample application

  Application start After starting the debugger by stepping into the application, your screen should look like the screenshot below. The main function calls MainTask().

Application start

  File system initialization The first thing called from MainTask() is the emFile function FS_Init(). This function initializes the file system and calls FS_X_AddDevices(). The function FS_X_AddDevices() is used to add and configure the used device drivers to the file system. In the example configuration only the RAM disk driver is added. FS_Init() must be called before using any other emFile function. You should step over this function.

File system initialization

  Low-level formatting If the initialization was successful, FS_FormatLLIfRequired() is called. It checks if the volume is low-level formatted and formats the volume if required. You should step over this function.

  High-level formatting Afterwards FS_IsHLFormatted() is called. It checks if the volume is high-level formatted and formats the volume if required. You should step over this function.

  Volume name The volume name is printed in the console window.

  Free space before operation The emFile function FS_GetVolumeFreeSpace() is called and the return value is written into the console window.

  File creation Afterwards, you should get to the emFile function call FS_FOpen(). This function creates a file named File.txt in the root directory of your RAM disk. Stepping over this function should return the address of an FS_FILE structure. In case of any error, it would return 0, indicating that the file could not be created.

File creation

  File write If FS_FOpen() returns a valid pointer to an FS_FILE structure, the sample application will write a small ASCII string to this file by calling the emFile function FS_Write(). Step over this function. If a problem occurs, compare the return value of FS_Write() with the length of the ASCII string, which should be written. FS_Write() returns the number of elements which have been written. If no problem occurs the function emFile function FS_FClose() should be reached. FS_FClose() closes the file handle for File.txt. Step over this function.

  Free space after operation Continue stepping over until you reach the place where the function FS_GetVolumeFreeSpace() is called. The emFile function FS_GetVolumeFreeSpace() returns available free drive space in bytes. After you step over this function, the variable v should have a value greater than zero.

  End of application The return value is written in the console window.

End of application

Further source code examples

Further source code examples which demonstrate directory operations and performance measuring are available. All emFile source code examples are located in the Sample/FS/Application folder of the emFile shipment.

We recommend keeping emFile separate from your application files. It is good practice to keep all the program files (including the header files) together in the FS subdirectory of your project’s root directory. This practice has the advantage of being very easy to update to newer versions of emFile by simply replacing the FS directory. Your application files can be stored anywhere.

Warning

When updating to a newer emFile version as files may have been added, moved or deleted, the project directories may need to be updated accordingly.

Warning

Always make sure that you have only one version of each file!

It is frequently a major problem when updating to a new version of emFile if you have old files included and therefore mix different versions. If you keep emFile in the directories as suggested (and only in these), this type of problem cannot occur. When updating to a newer version, you should be able to keep your configuration files and leave them unchanged. For safety reasons, we recommend backing up (or at least renaming) the FS directories before updating.

Running emFile on target hardware

This chapter explains how to integrate and run emFile on your target hardware. It explains this process step-by-step.

Integrating emFile

The default configuration of emFile contains a single storage device: a RAM disk. This should always be the first step to check if emFile functions properly on your target hardware. We assume that you are familiar with the tools you have selected for your development (compiler, project manager, linker, etc.). You should therefore be able to add files, add directories to the include search path, and so on. It is also assumed that you are familiar with the OS that you will be using on your target system (if you are using one). The SEGGER Embedded Studio IDE (https://www.segger.com/embedded-studio.html) is used in this document for all examples and screenshots, but every other ANSI C toolchain can also be used. It is also possible to use makefiles; in this case, when we say “add to the project”, this translates into “add to the makefile”.

Procedure to follow

Integration of emFile is a relatively simple process, which consists of the following steps:

Step 1: Creating a simple project without emFile

We recommend that you create a small “hello world” program for your system. That project should already use your OS and there should be a way to display text on a screen or serial port. If you are using the SEGGER embOS (https://www.segger.com/products/rtos/embos/), you can use the start project shipped with the embOS for this purpose.

Start project

Step 2: Adding emFile to the start project

Add all source files from the following directories (and their subdirectories) to your project:

It is recommended to keep the provided folder structure.

Add source files

Configuring the include path

The include path is the path in which the compiler looks for include files. In cases where the included files (typically header files, .h) do not reside in the same directory as the C file to compile, an include path needs to be set. In order to build the project with all added files, you will need to add the following directories to your include path:

Include paths

Select the start application

For quick and easy testing of your emFile integration, start with the code found in the Application folder of the shipment. Exclude all files in the Application folder of your project except the supplied main.c and FS_Start.c files. The application performs the following steps:

Build the project and test it

Build the project. It should compile without errors and warnings. If you encounter any problem during the build process, check your include path and your project configuration settings. The start application should print out the storage space of the device twice, once before a file has been written to the device and once afterwards.

Step 3: Adding the device driver

To configure emFile with a device driver, two modifications have to be performed:

Each step is explained in the following sections. For example, the implementation of the MMC/SD driver is shown, but all steps can easily be adapted to every other device driver implementation.

Adding the device driver source to project

Add the driver sources to the project and add the directory to the include path.

Add device driver

Most drivers require additional hardware routines to work with the specific hardware. If your driver requires low-level I/O routines to access the hardware, you will have to provide them. Drivers which require hardware routines are:

Nearly all drivers have to be configured before they can be used. The runtime configuration functions which specify for example the memory addresses and the size of memory are located in the configuration file of the respective driver. All required configurations are explained in the configuration section of the respective driver. If you use one of the drivers which do not require hardware routines skip the next section and refer to Step 4: Activating the driver.

Adding hardware routines to project

A template with empty function bodies and in most cases one ore more sample implementations are supplied for every driver that requires hardware routines. The easiest way to start is to use one of the ready-to-use samples. The ready-to-use samples can be found in the subfolders Sample/FS/Driver/<DRIVER_DIR> of the emFile shipment where DRIVER_DIR is the type of the device driver. You should check the Readme.txt file located in the driver directory to see which samples are included. If there is one which is a good or close match for your hardware, it should be used. Otherwise, use the template to implement the hardware routines. The template is a skeleton driver which contains empty implementations of the required functions and is the ideal base to start the implementation of hardware specific I/O routines. What to do Copy the compatible hardware function sample or the template into a subdirectory of your work directory and add it to your project. The template file is located in the Sample/FS/Driver/<DRIVER_DIR> folder; the example implementations are located in the respective directories. If you start the implementation of hardware routines with the hardware routine template, refer to Device drivers for detailed information about the implementation of the driver specific hardware functions, else refer to section Step 4: Activating the driver.

Note

You cannot run and test the project with the new driver on your hardware as long as you have not added the proper configuration file for the driver to your project. Refer to section Step 4: Activating the driver for more information about the activation of the driver with the configuration file.

Step 4: Activating the driver

After adding the driver source, and if required the hardware function implementation, copy the FS_Config<DRIVER_NAME>.c file (for example, FS_ConfigMMC_CardMode.c for the MMC/SD card driver using card mode) into the Config folder of your emFile work directory and add it to your project.

Add template driver

The configuration files contain, all the runtime configuration functions of the file system. The configuration files include a start configuration which allows a quick and easy start with every driver. The most important function for the beginning is FS_X_AddDevices(). It activates and configures the driver, if required. A driver which does not require hardware routines has to be configured before it can be used.

Modifying the runtime configuration

The following example a single CFI compliant NOR flash chip with a 16-bit interface and a size of 256 Mbytes to the file system. The base address, the start address and the size of the NOR flash are defined using the macros NOR_BASE_ADDR, NOR_START_ADDR and NOR_SIZE. Normally, only the “Defines, configurable” section of the configuration files requires changes for typical embedded systems. The “Public code” section which includes the time and date functions and FS_X_AddDevices() does not require modifications on most systems.

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE         0x10000        // Size of memory pool provided 
                                          // to the file system for 
                                          // semi-dynamic memory allocation. 
                                          // This value should be fine-tuned
                                          // according for your system.
#define NOR_BASE_ADDR      0x40000000     // Base address of the NOR flash 
                                          // device to be used as storage
#define NOR_START_ADDR     0x40000000     // Address of the first NOR physical
                                          // sector to be used as storage. 
                                          // If the entire NOR flash device 
                                          // has to be used by file system,
                                          // then this value is identical 
                                          // to the base address.
#define NOR_SIZE           0x200000       // Number of bytes to be used 
                                          // as storage.

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static U32 _aMemBlock[ALLOC_SIZE / 4];    // Memory pool used for semi-dynamic
                                          // allocation of the file system.

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    Configures the file system.
*
*  Additional information
*    This function is called during the file system initialization.
*/
void FS_X_AddDevices(void) {
  //
  // Provide the file system memory to work with.
  //
  FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
  //
  // Add and configure driver the NOR driver.
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(0, NOR_BASE_ADDR, NOR_START_ADDR, NOR_SIZE);
  //
  // Configure a read buffer for the file data.
  //
  FS_ConfigFileBufferDefault(512, 0);
}

After the driver has been added, the configuration functions (in this example FS_NOR_SetPhyType() and FS_NOR_Configure()) should be called. Detailed information about the driver configuration can be found in the configuration section of the respective driver. Refer to section Runtime configuration for detailed information about the other runtime configurations of the file system. Before compiling and running the sample application with the added driver, you have to exclude FS_ConfigRAMDisk.c from the project.

Note

For the drivers which required hardware access routines, if you have only added the template with empty function bodies until now, the project should compile without errors or warning messages. But you can only run the project on your hardware if you have finished the implementation of the hardware functions.

Step 5: Adjusting the RAM usage

The file system needs RAM for management purposes in various places. The amount of RAM required depends primarily on the configuration, especially the drivers used. The drivers which have their own level of management (such as NOR / NAND drivers) require in general more RAM than the “simple” drivers such as for hard drives, compact flash or MMC/SD cards. Every driver needs to allocate RAM. The file system allocates RAM in the initialization phase and holds it while the file system is running. The macro ALLOC_SIZE which is located in the respective driver configuration file specifies the size of RAM used by the file system. This value should be fine-tuned according to the requirements of your target system.

Per default, ALLOC_SIZE is set to a value which should be appropriate for most target systems. Nevertheless, you should adjust it in order to avoid wasting too much RAM. Once your file system project is up and running, you can check the real RAM requirement of the driver via the public variable FS_Global.MemManager.NumBytesAllocated. Check the value of FS_Global.MemManager.NumBytesAllocated after the initialization of the file system and after a volume has been mounted. At this point FS_Global.MemManager.NumBytesAllocated can be used as reference for the dynamic memory usage of emFile. You should reserve a few more bytes for emFile as the value of FS_Global.MemManager.NumBytesAllocated is at this point, since every file which is opened needs dynamic memory for maintenance information. For more information about resource usage of the file handlers, please refer to Dynamic RAM usage.

Note

If you define ALLOC_SIZE with a value which is smaller than the appropriate size, the file system will run into FS_X_Panic(). If you define ALLOC_SIZE with a value which is above the limits of your target system, the linker will give an error during the build process of the project.

API functions

This chapter provides a detailed description of emFile API layer.

General information

Any functions or data structures that are not described in this chapter but are exposed through inclusion of the FS.h header file must be considered private and subject to change.

Volume, file and directory names

A volume, file or directory name is a 0-terminated string the application can use as a parameter to an API function (such as FS_FOpen()) to identify a volume, file or directory the API function has to operate on.

A file or directory name contains the following mandatory and optional elements where the optional elements are surrounded by []:

[VolumeName:[UnitNo:]][DirPath]FileName|DirName

The maximum length of a file or directory name can be configured via the FS_MAX_PATH configuration define.

A volume name contains the following mandatory and optional elements where the optional elements are surrounded by []:

VolumeName:[UnitNo:]

VolumeName and UnitNo have the same meaning as described above.

Examples

The following examples specify the same file name assuming that the first driver added to file system is the NAND driver.

The following examples specify the same volume name assuming that the first driver added to file system is the NOR driver.

API function overview

The table below lists the available API functions within their respective categories.

Function Description
File system control functions
FS_Init() Starts the file system.
FS_DeInit() Frees allocated resources.
FS_Mount() Initializes a volume in default access mode.
FS_MountEx() Initializes a volume in a specified access mode.
FS_SetAutoMount() Sets the automatic mount behavior.
FS_Sync() Saves cached information to storage.
FS_Unmount() Synchronizes the data and marks the volume as not initialized.
FS_UnmountForced() Marks the volume as not initialized.
File system configuration functions
FS_AddDevice() Adds a driver to file system.
FS_AddPhysDevice() Adds a device to file system without assigning a volume to it.
FS_AssignMemory() Assigns a memory pool to the file system.
FS_ConfigFileBufferDefault() Configures the size and flags for the file buffer.
FS_LOGVOL_Create() Creates a driver instance.
FS_LOGVOL_AddDevice() Adds a storage device to a logical volume.
FS_SetFileBufferFlags() Changes the operating mode of the file buffer.
FS_SetFileBufferFlagsEx() Changes the operating mode of the file buffer.
FS_SetFileWriteMode() Configures the file write mode.
FS_SetFileWriteModeEx() Configures the write mode of a specified volume.
FS_SetMemHandler() Configures functions for memory management.
FS_SetMaxSectorSize() Configures the maximum size of a logical sector.
File access functions
FS_FClose() Closes an opened file.
FS_FGets() Reads a line of text from file.
FS_FOpen() Opens an existing file or creates a new one.
FS_FOpenEx() Opens an existing file or creates a new one.
FS_FPrintf() Writes a formatted string to a file.
FS_FPuts() Writes a 0-terminated string to a file.
FS_FRead() Reads data from file.
FS_FSeek() Sets the current position in file.
FS_FSeek64() Modifies the current position in a file.
FS_FWrite() Writes data to file.
FS_FTell() Returns current position in file.
FS_FTell64() Returns current position in a file.
FS_GetFileSize() Returns the size of a file.
FS_GetFileSizeEx() Returns the size of a file.
FS_GetFileSize64() Returns the size of a file.
FS_Read() Reads data from a file.
FS_SetEndOfFile() Sets the file size to current file position.
FS_SetFileSize() Sets the file size to the specified number of bytes.
FS_SetFileSize64() Sets the file size to the specified number of bytes.
FS_SyncFile() Synchronizes file to storage device.
FS_Truncate() Changes the size of a file.
FS_Truncate64() Changes the size of a file.
FS_Verify() Verifies the file contents.
FS_Write() Writes data to file.
Operations on files
FS_CopyFile() Copies a file.
FS_CopyFileEx() Copies a file.
FS_GetFileAttributes() Queries the attributes of a file or directory.
FS_GetFileBufferInfo() Obtains information about a file buffer.
FS_GetFileInfo() Returns information about a file or directory.
FS_GetFileInfo64() Obtains information about a file or directory.
FS_GetFileName() Obtains the name of a file.
FS_GetFileTime() Returns the creation time of a file or directory.
FS_GetFileTimeEx() Gets the timestamp of a file or directory.
FS_IsFileBufferSet() Checks if a file buffer is configured for the specified file.
FS_ModifyFileAttributes() Sets / clears the attributes of a file or directory.
FS_Move() Moves a file or directory to another location.
FS_Remove() Removes a file.
FS_Rename() Changes the name of a file or directory.
FS_SetFileAttributes() Modifies all the attributes of a file or directory.
FS_SetFileBuffer() Assigns a file buffer to an opened file.
FS_SetFileTime() Sets the creation time of a file or directory.
FS_SetFileTimeEx() Sets the timestamp of a file or directory.
FS_UnsetFileBuffer() Frees the file buffer assigned to specified file.
FS_WipeFile() Overwrites the contents of a file with random data.
Directory functions
FS_CopyDir() Copies a directory and its contents to a different location.
FS_CreateDir() Creates a directory including any missing directories in the path.
FS_DeleteDir() Removes a directory and its contents.
FS_FindClose() Ends a directory scanning operation.
FS_FindClose64() Ends a directory scanning operation.
FS_FindFirstFile() Initiates a directory scanning operation.
FS_FindFirstFile64() Initiates a directory scanning operation.
FS_FindNextFile() Returns information about the next file or directory in a directory scanning operation.
FS_FindNextFileEx() Returns information about the next file or directory in a directory scanning operation.
FS_FindNextFile64() Returns information about the next file or directory in a directory scanning operation.
FS_MkDir() Creates a directory.
FS_RmDir() Removes a directory.
Formatting functions
FS_Format() Performs a high-level format.
FS_FormatLLIfRequired() Performs a low-level format.
FS_FormatLow() Performs a low-level format.
FS_IsHLFormatted() Checks if a volume is high-level formatted or not.
FS_IsLLFormatted() Returns whether a volume is low-level formatted or not.
Partitioning functions
FS_CreateGPT() Partitions the specified volume using a GPT (GUID Partition Table) partition scheme.
FS_CreateMBR() Partitions the specified volume using a MBR (Master Boot Record) partition scheme.
FS_GetGPTInfo() Returns information about the GPT partitioning.
FS_GetPartitionInfoMBR() Returns information about a MBR partition.
FS_GetPartitionInfoGPT() Returns information about a GPT partition.
FS_GetPartitioningScheme() Returns information about how a storage device is partitioned.
File system checking functions
FS_CheckAT() Verifies the consistency of the allocation table.
FS_CheckDir() Verifies the consistency of a single directory.
FS_CheckDisk() Checks the consistency of the file system structure.
FS_CheckDisk_ErrCode2Text() Returns a human-readable text description of a disk checking error code.
FS_GetATInfo() Obtains information about the allocation table.
FS_GetClusterInfo() Obtains information about a storage allocation unit.
FS_GetDiskLayout() Obtains information about the data layout of a volume.
FS_GetFirstCluster() Obtains the id of the first cluster assigned to a file or directory.
FS_InitCheck() Initializes a non-blocking disk checking operation.
File system extended functions
FS_ConfigEOFErrorSuppression() Enables / disables the reporting of end-of-file condition as error.
FS_ConfigPOSIXSupport() Enables / disables support for the POSIX-like behavior.
FS_ConfigWriteVerification() Enables / disables the verification of the written data.
FS_FileTimeToTimeStamp() Converts a broken-down date and time specification to a timestamp.
FS_FreeSectors() Informs the device driver about unused sectors.
FS_GetAutoMount() Returns information about how a volume is automatically mounted.
FS_GetFileId() Calculates a value that uniquely identifies a file.
FS_GetFileWriteMode() Returns the write mode.
FS_GetFileWriteModeEx() Returns the write mode configured for a specified volume.
FS_GetFSType() Returns the type of file system assigned to volume.
FS_GetMaxSectorSize() Queries the maximum configured logical sector size.
FS_GetMemInfo() Returns information about the memory management.
FS_GetMountType() Returns information about how a volume is mounted.
FS_GetNumFilesOpen() Queries the number of opened file handles.
FS_GetNumFilesOpenEx() Queries the number of opened file handles on a volume.
FS_GetNumVolumes() Queries the number of configured volumes.
FS_GetVolumeAlias() Returns the alternative name of a volume.
FS_GetVolumeFreeSpace() Returns the free space available on a volume.
FS_GetVolumeFreeSpaceFirst() Initiates the search for free space.
FS_GetVolumeFreeSpaceKB() Returns the free space available on a volume.
FS_GetVolumeFreeSpaceNext() Continues the search for free space.
FS_GetVolumeInfo() Obtains information about a volume.
FS_GetVolumeInfoEx() Obtains information about a volume.
FS_GetVolumeLabel() Returns the label of the volume.
FS_GetVolumeName() Obtains the name of a volume.
FS_GetVolumeSize() Returns the size of a volume.
FS_GetVolumeSizeKB() Returns the size of a volume.
FS_GetVolumeStatus() Returns the presence status of a volume.
FS_IsVolumeMounted() Checks if a volume is mounted.
FS_Lock() Claims exclusive access to file system.
FS_LockVolume() Claims exclusive access to a volume.
FS_SetBusyLEDCallback() Registers a callback for busy status changes of a volume.
FS_SetCharSetType() Configures the character set that is used for the file and directory names.
FS_SetFSType() Sets the type of file system a volume.
FS_SetMemCheckCallback() Registers a callback for checking of 0-copy operations.
FS_SetTimeDateCallback() Configures a function that the file system can use to get the current time and date.
FS_SetVolumeAlias() Assigns an alternative name for a volume.
FS_SetVolumeLabel() Modifies the label of a volume.
FS_TimeStampToFileTime() Converts a timestamp to a broken-down date and time specification.
FS_Unlock() Releases the exclusive access to file system.
FS_UnlockVolume() Releases the exclusive access to a volume.
Storage layer functions
FS_STORAGE_Clean() Performs garbage collection on a volume.
FS_STORAGE_CleanEx() Performs garbage collection on a volume.
FS_STORAGE_CleanOne() Performs garbage collection on a volume.
FS_STORAGE_CleanOneEx() Performs garbage collection on a volume.
FS_STORAGE_DeInit() Frees the resources allocated by the storage layer.
FS_STORAGE_FillSectors() Writes the same sector data to one or more logical sectors.
FS_STORAGE_FillSectorsEx() Writes the same sector data to one or more logical sectors.
FS_STORAGE_FindVolume() Searches for a volume instance by name.
FS_STORAGE_FindVolumeByDevice() Searches for a volume instance by index.
FS_STORAGE_FindVolumeByIndex() Searches for a volume instance by index.
FS_STORAGE_FormatLowEx() Formats the storage device.
FS_STORAGE_FreeSectors() Informs the driver about unused sectors.
FS_STORAGE_FreeSectorsEx() Informs the driver about unused sectors.
FS_STORAGE_GetAutoMountType() Returns information about how a volume is automatically mounted.
FS_STORAGE_GetAutoMountTypeEx() Returns information about how a volume is automatically mounted.
FS_STORAGE_GetCleanCnt() Calculates the number of garbage collection sub-operations.
FS_STORAGE_GetCleanCntEx() Calculates the number of garbage collection sub-operations.
FS_STORAGE_GetCounters() Returns the values of statistical counters.
FS_STORAGE_GetDeviceInfo() Returns information about the storage device.
FS_STORAGE_GetDeviceInfoEx() Returns information about the storage device.
FS_STORAGE_GetMountType() Returns information about how a volume is mounted.
FS_STORAGE_GetMountTypeEx() Returns information about how a volume is mounted.
FS_STORAGE_GetSectorUsage() Returns information about the usage of a logical sector.
FS_STORAGE_GetSectorUsageEx() Returns information about the usage of a logical sector.
FS_STORAGE_GetVolumeStatusEx() Returns the presence status of a volume.
FS_STORAGE_Init() Initializes the storage layer.
FS_STORAGE_IsLLFormattedEx() Checks if a storage device is low-level formatted.
FS_STORAGE_Mount() Initializes a volume in a specified access mode.
FS_STORAGE_MountEx() Initializes a volume in a specified access mode.
FS_STORAGE_ReadSector() Reads the data of one logical sector.
FS_STORAGE_ReadSectorEx() Reads the contents of one logical sector from the storage device.
FS_STORAGE_ReadSectors() Reads the data of one or more logical sectors.
FS_STORAGE_ReadSectorsEx() Reads the contents of multiple logical sectors from a storage device.
FS_STORAGE_RefreshSectors() Reads the contents of a logical sector and writes it back.
FS_STORAGE_RefreshSectorsEx() Reads the contents of a logical sector and writes it back.
FS_STORAGE_ResetCounters() Sets all statistical counters to 0.
FS_STORAGE_SetAutoMountType() Sets the automatic mount behavior.
FS_STORAGE_SetAutoMountTypeEx() Sets the automatic mount behavior.
FS_STORAGE_SetOnDeviceActivityCallback() Registers a function to be called on any logical sector read or write operation.
FS_STORAGE_Sync() Writes cached information to storage device.
FS_STORAGE_SyncEx() Writes cached information to storage device.
FS_STORAGE_SyncSectors() Synchronizes the contents of one or more logical sectors.
FS_STORAGE_SyncSectorsEx() Synchronizes the contents of one or more logical sectors.
FS_STORAGE_Unmount() Synchronizes a volume and marks it as not initialized.
FS_STORAGE_UnmountEx() Synchronizes the volume and marks it as not initialized.
FS_STORAGE_UnmountForced() Marks a volume it as not initialized.
FS_STORAGE_UnmountForcedEx() Marks the volume as not initialized without synchronizing it.
FS_STORAGE_WriteSector() Modifies the data of a logical sector.
FS_STORAGE_WriteSectorEx() Writes a logical sector to the storage device.
FS_STORAGE_WriteSectors() Modifies the data of one or more logical sectors.
FS_STORAGE_WriteSectorsEx() Writes multiple logical sectors to the storage device.
FAT related functions
FS_FAT_ConfigDirtyFlagUpdate() Enables / disables the update of the flag that indicates if the volume has been unmounted correctly.
FS_FAT_ConfigFATCopyMaintenance() Enables / disables the update of the second allocation table.
FS_FAT_ConfigFSInfoSectorUse() Enables / disables the usage of information from the FSInfo sector.
FS_FAT_ConfigROFileMovePermission() Enables / disables the permission to move (and rename) files and directories with the read-only file attribute set.
FS_FAT_DisableLFN() Disables the support for long file names.
FS_FAT_FormatSD() Performs a high-level format as per SD Specification.
FS_FAT_GetConfig() Returns information about how the FAT component is configured to operate.
FS_FAT_GetLFNConverter() Returns the type of configured file name converter.
FS_FAT_GrowRootDir() Increases the size of the root directory.
FS_FAT_SetLFNConverter() Configures how long file names are to be encoded and decoded.
FS_FAT_SupportLFN() Enables the support for long file names.
EFS related functions
FS_EFS_ConfigCaseSensitivity() Configures how the file names are compared.
FS_EFS_ConfigStatusSectorSupport() Enables or disables the usage of information from the status sector.
FS_EFS_GetConfig() Returns information about how the EFS component is configured to operate.
FS_EFS_SetFileNameConverter() Configures how file names are to be encoded.
exFAT related functions
FS_EXFAT_ConfigDirtyFlagUpdate() Enables or disables the update of the flag that indicates if the volume has been unmounted correctly.
FS_EXFAT_ConfigROFileMovePermission() Enables / disables the permission to move (and rename) files and directories with the read-only file attribute set.
FS_EXFAT_ConfigSpaceUsageUpdate() Enables or disables the update of the storage usage.
FS_EXFAT_FormatSD() Performs a high-level format as per SD Specification.
FS_EXFAT_GetConfig() Returns information about how the exFAT component is configured to operate.
FS_EXFAT_GetFileNameConverter() Returns the type of configured file name converter.
FS_EXFAT_GrowRootDir() Increases the size of the root directory.
FS_EXFAT_SetFileNameConverter() Configures how long file names are to be encoded and decoded.
Error handling functions
FS_ClearErr() Clears error status of a file handle.
FS_ErrorNo2Text() Returns a human-readable text description of an API error code.
FS_FEof() Returns if end of file has been reached.
FS_FError() Returns error status of a file handle.
Configuration checking functions
FS_CONF_GetDebugLevel() Returns the level of debug information configured for the file system.
FS_CONF_GetDirectoryDelimiter() Returns the character that is configured as delimiter between the directory names in a file path.
FS_CONF_GetMaxPath() Returns the configured maximum number of characters in a path to a file or directory.
FS_CONF_GetNumVolumes() Returns the maximum number of volumes configured for the file system.
FS_CONF_GetOSLocking() Returns the type of task locking configured for the file system.
FS_CONF_IsCacheSupported() Checks if the file system is configured to support the sector cache.
FS_CONF_IsDeInitSupported() Checks if the file system is configured to support deinitialization.
FS_CONF_IsEFSSupported() Checks if the file system is configured to support the EFS file system.
FS_CONF_IsEncryptionSupported() Checks if the file system is configured to support encryption.
FS_CONF_IsFATSupported() Checks if the file system is configured to support the FAT file system.
FS_CONF_IsFreeSectorSupported() Checks if the file system is configured to support the “free sector” command.
FS_CONF_IsJournalSupported() Checks if the file system is configured to support journaling.
FS_CONF_IsTrialVersion() Checks if the file system has been configured as a trial (limited) version.
FS_GetVersion() Returns the version number of the file system.
Path processing functions
FS_GetPathBaseName() Returns the name of the target file or directory with the extension removed.
FS_GetPathDirName() Returns the path to a target file or directory with the volume name, base name, and extension removed.
FS_GetPathExtension() Returns the extension of a file or directory.
FS_GetPathVolumeName() Returns the name of the volume from a path.
FS_MakePath() Creates a path to a file or directory from individual components.
Obsolete functions
FS_AddOnExitHandler() Registers a deinitialization callback.
FS_CloseDir() Closes a directory.
FS_ConfigOnWriteDirUpdate() Configures if the directory entry has be updated after writing to file.
FS_DirEnt2Attr() Loads attributes of a directory entry.
FS_DirEnt2Name() Loads the name of a directory entry.
FS_DirEnt2Size() Loads the size of a directory entry.
FS_DirEnt2Time() Loads the time stamp of a directory entry.
FS_GetNumFiles() API function.
FS_OpenDir() API function.
FS_ReadDir() Reads next directory entry in directory.
FS_RewindDir() Sets pointer for reading the next directory entry to the first entry in the directory.

File system control functions

FS_Init()

Description

Starts the file system.

Prototype

void FS_Init(void);

Additional information

FS_Init() initializes the file system and creates resources required for the access of the storage device in a multi-tasking environment. This function has to be called before any other file system API function.

Example

#include "FS.h"

void SampleInit(void) {
  FS_Init();
  //
  // Access file system
  //
}

FS_DeInit()

Description

Frees allocated resources.

Prototype

void FS_DeInit(void);

Additional information

This function is optional. FS_DeInit() frees all resources that are allocated by the file system after initialization. Also, all static variables of all file system layers are reset in order to guarantee that the file system remains in a known state after deinitialization.The application can call this function only after it called FS_Init().

This function has to be used when the file system is reset at runtime. For example this is the case if the system uses a software reboot which reinitializes the target application.

This function is available if the emFile sources are compiled with the FS_SUPPORT_DEINIT configuration define set to 1.

Example

#include "FS.h"

void SampleDeInit(void) {
  FS_Init();
  //
  // Access the file system...
  //
  FS_DeInit();
  //
  // The file system cannot be accessed anymore.
  //
}

FS_Mount()

Description

Initializes a volume in default access mode.

Prototype

int FS_Mount(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName The name of a volume. If the empty string is specified, the first device in the volume table is used.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only.
= FS_MOUNT_RW Volume is mounted read/write.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

The storage device has to be mounted before being accessed for the first time after file system initialization. The file system is configured by default to automatically mount the storage device at the first access in read / write mode. This function can be used to explicitly mount the storage device if the automatic mount behavior has been disabled via FS_SetAutoMount(). Refer to FS_SetAutoMount() for an overview of the different automatic mount types.

Example

#include "FS.h"

void SampleMount(void) {
  FS_Init();
  //
  // Mount default volume in read / write mode.
  //
  FS_Mount("");
  //
  // Access the data stored on the file system.
  //
}

FS_MountEx()

Description

Initializes a volume in a specified access mode.

Prototype

int FS_MountEx(const char * sVolumeName,
                     U8     MountType);

Parameters

Parameter Description
sVolumeName The name of the volume. If the empty string is specified, the first device in the volume table is used.
MountType Specifies how the volume has to be mounted. FS_MOUNT_RO Read only access. FS_MOUNT_RW Read / write access.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only.
= FS_MOUNT_RW Volume is mounted read/write.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

Performs the same operation as FS_Mount() while it allows the application to specify how the storage device has to be mounted.

Example

#include "FS.h"

void SampleMountEx(void) {
  FS_Init();
  //
  // Mount default volume in read-only mode.
  //
  FS_MountEx("", FS_MOUNT_RO);
  //
  // Access the data stored on the file system.
  //
}

FS_SetAutoMount()

Description

Sets the automatic mount behavior.

Prototype

void FS_SetAutoMount(const char * sVolumeName,
                           U8     MountType);

Parameters

Parameter Description
sVolumeName Pointer to a string containing the name of the volume. If the empty string is specified, the first device in the volume table is used.
MountType Specifies how the volume has to be mounted. FS_MOUNT_RO Allows to automatically mount the volume in read only mode. FS_MOUNT_RW Allows to automatically mount the volume in read / write mode. 0 Disables the automatic mount operation for the volume.

Additional information

By default, the file system is configured to automatically mount all volumes in read / write mode and this function can be used to change the default automatic mount type or to disable the automatic mounting.

Example

#include "FS.h"

void SampleSetAutoMount(void) {
  FS_SetAutoMount("", FS_MOUNT_R);    // Mount default volume in read-only mode.
}

FS_Sync()

Description

Saves cached information to storage.

Prototype

int FS_Sync(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Pointer to a string containing the name of the volume to be synchronized. If the empty string is specified, the first configured volume is used.

Return value

= 0 OK, volume synchronized
≠ 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text() for more information.

Additional information

The function write the contents of write buffers and updates the management information of all opened file handles to storage device. All the file handles are left open. If configured, FS_Sync() also writes to storage the changes present in the write cache and in the journal. FS_Sync() can be called from the same task as the one writing data or from a different task.

Example

#include "FS.h"

void SampleSync(void) {
  FS_Sync("");      // Synchronize the default volume.
}

FS_Unmount()

Description

Synchronizes the data and marks the volume as not initialized.

Prototype

void FS_Unmount(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Pointer to a string containing the name of the volume to be unmounted. If the empty string is specified, the first device in the volume table is used. Can not be NULL.

Additional information

This function closes all open files and synchronizes the volume, that is writes all cached data to storage device. FS_Unmount() hast to be called before a storage device is removed to make sure that all the information cached by the file system is updated to storage device. This function is also useful when shutting down a system.

The volume is initialized again at the next call to any other file system API function that requires access to storage device. The application can also explicitly initialize the volume via FS_Mount() or FS_MountEx().

Example

#include "FS.h"

void SampleUnmount(void) {
  FS_Unmount("");     // Unmount the default volume.
}

FS_UnmountForced()

Description

Marks the volume as not initialized.

Prototype

void FS_UnmountForced(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Pointer to a string containing the name of the volume to be unmounted. If the empty string is specified, the first device in the volume table is used.

Additional information

This function performs the same operations as FS_Unmount(). FS_UnmountForced() has to be called if a storage device has been removed before it could be regularly unmounted. When using FS_UnmountForced() there is no guarantee that the information cached by the file system is updated to storage.

The volume is initialized again at the next call to any other file system API function that requires access to storage device. The application can also explicitly initialize the volume via FS_Mount() or FS_MountEx().

Opened file handles are only marked as invalid but they are not closed. The application has to close them explicitly by calling FS_FClose().

Example

#include "FS.h"
#include "FS_OS.h"

void SampleUnmountForced(void) {
  int IsPresentNew;
  int IsPresent;

  IsPresent = FS_GetVolumeStatus("");
  while (1) {
    IsPresentNew = FS_GetVolumeStatus("");
    //
    // Check if the presence status of the storage device has been changed.
    //
    if (IsPresentNew != IsPresent) {
      if (IsPresentNew == FS_MEDIA_IS_PRESENT) {
        FS_Mount("");
      } else  {
        FS_UnmountForced("");
      }
      IsPresent = IsPresentNew;
    }
    FS_X_OS_Delay(500);
  }
}

Volume mounting modes

Description

Modes for mounting a volume.

Definition

#define FS_MOUNT_RO    FS_MOUNT_R
#define FS_MOUNT_RW    (FS_MOUNT_R | FS_MOUNT_W)

Symbols

Definition Description
FS_MOUNT_RO Read-only. Data can only be read from storage device.
FS_MOUNT_RW Read / Write. Data can be read form and written to storage device.

File system configuration functions

The file system control functions listed in this section can only be used in the runtime configuration phase. This means in practice that they can only be called from within FS_X_AddDevices().

FS_AddDevice()

Description

Adds a driver to file system.

Prototype

FS_VOLUME *FS_AddDevice(const FS_DEVICE_TYPE * pDevType);

Parameters

Parameter Description
pDevType  in  Pointer to a function table identifying the driver that has to be added.

Return value

≠ 0 OK, driver added.
= 0 An error occurred.

Additional information

This function can be used to add a device or a logical driver to file system. The application has to add at least one driver to file system.

The function performs the following operations:

Example

#include "FS.h"

void FS_X_AddDevices(void) {
  //
  // Basic configuration of the file system...
  //

  //
  // Add and configure a device driver for NAND flash.
  //
  FS_AddDevice(&FS_NAND_UNI_Driver);

  //
  // Additional configuration of the file system...
  //
}

FS_AddPhysDevice()

Description

Adds a device to file system without assigning a volume to it.

Prototype

int FS_AddPhysDevice(const FS_DEVICE_TYPE * pDevType);

Parameters

Parameter Description
pDevType  in  Pointer to a function table identifying the driver that has to be added.

Return value

= 0 OK, storage device added.
≠ 0 An error occurred.

Additional information

This function can be used to add a device or a logical driver to file system. It works similarly to FS_AddDevice() with the difference that it does not assign a logical volume to storage device. This means that the storage device is not directly accessible by the application via the API functions of the file system. An additional logical driver is required to be added via FS_AddDevice() to make the storage device visible to application.

FS_AddPhysDevice() initializes the driver, allowing the driver to identify the storage device as far as required and allocate memory required for driver level management of the device. This makes sector operations possible.

FS_AssignMemory()

Description

Assigns a memory pool to the file system.

Prototype

void FS_AssignMemory(U32 * pData,
                     U32   NumBytes);

Parameters

Parameter Description
pData  in  A pointer to the start of the memory region assigned to file system.
NumBytes Size of the memory pool assigned.

Additional information

emFile comes with a simple semi-dynamic internal memory manager that is used to satisfy the runtime memory requirements of the file system. FS_AssignMemory() can be used to provide a memory pool to the internal memory manager of the file system. If not enough memory is assigned, the file system calls FS_X_Panic() in debug builds which by default halts the execution of the application. The actual number of bytes allocated is stored in the global variable FS_Global.MemManager.NumBytesAllocated. This variable can be used to fine-tune the size of the memory pool.

emFile supports also the use of an external memory manager (e.g. via malloc() and free() functions of the standard C library). The selection between the internal and the external memory management has to be done at compile time via the FS_SUPPORT_EXT_MEM_MANAGER define. The configuration of the memory management functions is done via FS_SetMemHandler().

This function has to be called in the initialization phase of the file system; typically in FS_X_AddDevices(). The support for internal memory management has to be enabled at compile time by setting the FS_SUPPORT_EXT_MEM_MANAGER define to 0. FS_AssignMemory() does nothing if the FS_SUPPORT_EXT_MEM_MANAGER define is set to 1.

Example

#include "FS.h"

#define ALLOC_SIZE    0x1000

static U32 _aMemBlock[ALLOC_SIZE / 4];

void FS_X_AddDevices(void) {
  FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
  //
  // Perform additional file system configuration.
  //
}

FS_ConfigFileBufferDefault()

Description

Configures the size and flags for the file buffer.

Prototype

int FS_ConfigFileBufferDefault(int BufferSize,
                               int Flags);

Parameters

Parameter Description
BufferSize Size of the file buffer in bytes.
Flags File buffer operating mode.

Return value

= 0 OK, the file buffer has been configured.
≠ 0 Error code indicating the failure reason.

Additional information

The function has to be called only once, in FS_X_AddDevices(). If called after FS_Init() the function does nothing and generates a warning.

Flags is a bitwise-or combination of File buffer flags. If Flags is set to 0 then the file buffer caches only the data read from the file.

The file system allocates a file buffer of BufferSize bytes for each file the application opens. The operating mode of the file buffer can be changed at runtime via FS_SetFileBufferFlags(). If file buffers of different sizes are required FS_SetFileBuffer() should be used instead.

For best performance it is recommended to set the size of the file buffer to be equal to the size of the logical sector. Smaller file buffer sizes can also be used to reduce the RAM usage.

FS_SetFileBuffer() is available if the emFile sources are compiled with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

Example

#include "FS.h"

#define ALLOC_SIZE    0x1000

static U32 _aMemBlock[ALLOC_SIZE / 4];

void FS_X_AddDevices(void) {
  FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
  //
  // Set the file buffer of 512 bytes for read and write operations.
  // The file buffer is allocated at runtime for each opened file
  // from _aMemBlock.
  //
#if (FS_USE_FILE_BUFFER || FS_SUPPORT_FILE_BUFFER)
  FS_ConfigFileBufferDefault(512, FS_FILE_BUFFER_WRITE);
#endif
}

FS_LOGVOL_Create()

Description

Creates a driver instance.

Prototype

int FS_LOGVOL_Create(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to create.

Return value

= 0 OK, volume has been created.
≠ 0 An error occurred.

Additional information

This function creates an instance of a logical volume. A logical volume is the representation of one or more physical devices as a single device. It allows treating multiple physical devices as one larger device. The file system takes care of selecting the correct location on the correct physical device when reading from or writing to the logical volume. Logical volumes are typically used if multiple flash devices (NOR or NAND) are present, but they should be presented to the application in the same way as a single device with the combined capacity of both.

sVolumeName is the name that has to be assigned to the logical volume. This is the volume name that is passed to some of the FS API functions and that has to be used in a file path.

FS_LOGVOL_Create() does nothing if the module is configured to work in driver mode by setting the FS_LOGVOL_SUPPORT_DRIVER_MODE define option to 1. In this case a logical driver is created by adding it via FS_AddDevice() to file system.

Normally, all devices are added individually using FS_AddDevice(). This function adds the devices physically as well as logically to the file system. In contrast to adding all devices individually, all devices can be combined in a logical volume with a total size of all combined devices. To create a logical volume the following steps have to be performed: 1. The storage device has to be physically added to the file system using FS_AddPhysDevice(). 2. A logical volume has to be created using FS_LOGVOL_Create(). 3. The devices which are physically added to the file system have to be added to the logical volume using FS_LOGVOL_AddDevice().

FS_LOGVOL_AddDevice()

Description

Adds a storage device to a logical volume.

Prototype

int FS_LOGVOL_AddDevice(const char           * sVolumeName,
                        const FS_DEVICE_TYPE * pDeviceType,
                              U8               DeviceUnit,
                              U32              StartSector,
                              U32              NumSectors);

Parameters

Parameter Description
sVolumeName Name of the logical volume.
pDeviceType Type of the storage device that has to be added.
DeviceUnit Index of the storage device that has to be added (0-based).
StartSector Index of the first sector that has to be used as storage (0-based).
NumSectors Number of sectors that have to be used as storage.

Return value

= 0 OK, storage device added.
≠ 0 An error occurred.

Additional information

Only devices with an identical sector size can be combined to a logical volume. All additionally added devices need to have the same sector size as the first physical device of the logical volume.

This function does nothing if FS_LOGVOL_SUPPORT_DRIVER_MODE is set to 1.

FS_SetFileBufferFlags()

Description

Changes the operating mode of the file buffer.

Prototype

int FS_SetFileBufferFlags(FS_FILE * pFile,
                          int       Flags);

Parameters

Parameter Description
pFile Handle to opened file.
Flags File buffer operating mode.

Return value

= 0 OK, file buffer flags changed.
≠ 0 Error code indicating the failure reason.

Additional information

This function can only be called immediately after the file is opened and before performing any operation on the file.

Flags is a bitwise-or combination of File buffer flags. If Flags is set to 0 then the file buffer caches only the data read from the file.

FS_SetFileBufferFlags() is only available if the file system is built with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

Example

#include "FS.h"

void SampleSetFileBufferFlags(void) {
  FS_FILE * pFile;
  U8        abData[16];

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    memset(abData, 'a', sizeof(abData));
    FS_SetFileBufferFlags(pFile, FS_FILE_BUFFER_WRITE);
    FS_Write(pFile, abData, sizeof(abData));
    FS_FClose(pFile);
  }
}

FS_SetFileBufferFlagsEx()

Description

Changes the operating mode of the file buffer.

Prototype

int FS_SetFileBufferFlagsEx(const char * sVolumeName,
                                  int    Flags);

Parameters

Parameter Description
sVolumeName Name of the volume for which to set the flags.
Flags File buffer operating mode.

Return value

= 0 OK, operating mode changed.
≠ 0 Error code indicating the failure reason.

Additional information

This function can be used to change the operating mode of the file buffer for the files that are located on a specific volume.

Flags is a bitwise-or combination of File buffer flags. If Flags is set to 0 then the file buffer caches only the data read from the file.

FS_SetFileBufferFlagsEx() is available if the emFile sources are compiled with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

FS_SetFileWriteMode()

Description

Configures the file write mode.

Prototype

void FS_SetFileWriteMode(FS_WRITEMODE WriteMode);

Parameters

Parameter Description
WriteMode Specifies how to write to file: FS_WRITEMODE_SAFE Updates the allocation table and the directory entry at each write to file operation. FS_WRITEMODE_MEDIUM Updates the allocation table at each write to file operation. FS_WRITEMODE_FAST The allocation table and directory entry are updated when the file is closed.

Additional information

This function can be called to configure which mode the file system has to use when writing to a file. The file system uses by default FS_WRITEMODE_SAFE which allows the maximum fail-safe behavior, since the allocation table and the directory entry is updated on every write operation to file.

If FS_WRITEMODE_FAST is set, the update of the allocation table is performed using a special algorithm. When writing to the file for the first time, the file system checks how many clusters in series are empty starting with the first one occupied by the file. This cluster chain is remembered, so that if the file grows and needs an additional cluster, the allocation doesn’t have to be read again in order to find the next free cluster. The allocation table is only modified if necessary, which is the case when:

Especially when writing large amounts of data, FS_WRITEMODE_FAST allows maximum performance, since usually the file system has to search for a free cluster in the allocation table and link it with the last one occupied by the file. In worst case, multiple sectors of the allocation table have to be read in order to find a free cluster.

Example

#include "FS.h"

void FS_X_AddDevices(void) {
  //
  // Configure the file system to write as fast as possible
  // to all files on all volumes.
  //
  FS_SetFileWriteMode(FS_WRITEMODE_FAST);
  //
  // Perform other file system configuration...
  //
}

FS_SetFileWriteModeEx()

Description

Configures the write mode of a specified volume.

Prototype

int FS_SetFileWriteModeEx(      FS_WRITEMODE   WriteMode,
                          const char         * sVolumeName);

Parameters

Parameter Description
WriteMode Specifies how to write to file: FS_WRITEMODE_SAFE Updates the allocation table and the directory entry at each write to file operation. FS_WRITEMODE_MEDIUM Updates the allocation table at each write to file operation. FS_WRITEMODE_FAST The allocation table and directory entry are updated when the file is closed.
sVolumeName Identifies the volume for which the write mode has to be changed.

Return value

= 0 OK, write mode set.
≠ 0 Error code indicating the failure reason.

Additional information

When not explicitly set using this function the write mode of a volume is the write mode set via FS_SetFileWriteMode() or the default write mode (FS_WRITEMODE_SAFE). FS_SetFileWriteModeEx() is typically on file system configurations using multiple volumes that require different write modes. For example on a file system configured to use two volumes where one volume has to be configured for maximum write performance (FS_WRITEMODE_FAST) while on the other volume the write operation has to be fail-safe (FS_WRITEMODE_SAFE).

Refer to FS_SetFileWriteMode() for detailed information about the different write modes.

Example

#include "FS.h"

void FS_X_AddDevices(void) {
  //
  // Configure the file system to write as fast as possible
  // to all files on the "nand:0:" volume.
  //
  FS_SetFileWriteModeEx(FS_WRITEMODE_FAST, "nand:0");
  //
  // Perform other file system configuration...
  //
}

FS_SetMemHandler()

Description

Configures functions for memory management.

Prototype

void FS_SetMemHandler(FS_MEM_ALLOC_CALLBACK * pfAlloc,
                      FS_MEM_FREE_CALLBACK  * pfFree);

Parameters

Parameter Description
pfAlloc Pointer to a function that allocates memory (e.g. malloc()). It cannot be NULL.
pfFree Pointer to a function that frees memory (e.g. free()). It cannot be NULL.

Additional information

The application can use this function to configure functions for the memory management. The file system calls pfAlloc to allocate memory and pfFree to release the allocated memory.

This function has to be called in the initialization phase of the file system; typically in FS_X_AddDevices(). The support for external memory management has to be enabled at compile time by setting the FS_SUPPORT_EXT_MEM_MANAGER define to 1. FS_SetMemHandler() does nothing if FS_SUPPORT_EXT_MEM_MANAGER is set to 0 (default).

Example

#include <stdlib.h>
#include "FS.h"

void FS_X_AddDevices(void) {
#if FS_SUPPORT_EXT_MEM_MANAGER
  //
  // Configure functions for dynamic memory allocation.
  //
  FS_SetMemHandler((FS_MEM_ALLOC_CALLBACK *)malloc, free);
#endif // FS_SUPPORT_EXT_MEM_MANAGER
  //
  // Configure the file system...
  //
}

FS_SetMaxSectorSize()

Description

Configures the maximum size of a logical sector.

Prototype

int FS_SetMaxSectorSize(unsigned MaxSectorSize);

Parameters

Parameter Description
MaxSectorSize Number of bytes in the logical sector.

Return value

= 0 OK, the sector size had been set.
≠ 0 Error code indicating the failure reason.

Additional information

The file system uses internal RAM buffers to store the data of logical sectors it accesses. The storage devices added to file system can have different logical sector sizes. Since the size of the logical sectors is not known at the time the internal RAM buffers are allocated the application has to call FS_SetMaxSectorSize() to specify the size of the largest logical sector used by the configured drivers.

The default value for the maximum size of a logical sector is 512 bytes. The size of the logical sector supported by a driver can be found in the section that describes the specific driver.

FS_SetMaxSectorSize() can be called only at file system initialization in FS_X_AddDevices().

Example

#include "FS.h"

void FS_X_AddDevices(void) {
  //
  // This function call is typically required when
  // a NAND flash with 2048 byte pages is used as
  // storage device.
  //
  FS_SetMaxSectorSize(2048);
}

FS_MEM_ALLOC_CALLBACK

Description

Type of function called by the file system to allocate memory dynamically.

Type definition

typedef void * FS_MEM_ALLOC_CALLBACK(U32 NumBytes);

Parameters

Parameter Description
NumBytes Number of bytes to be allocated.

Return value

NULL OK, pointer to the allocated memory block.
= NULL Error, could not allocate memory.

Additional information

The callback function has the same signature as the malloc() standard C function. The application can register the callback function via FS_SetMemHandler().

FS_MEM_FREE_CALLBACK

Description

Type of function called by the file system to release dynamically allocated memory.

Type definition

typedef void FS_MEM_FREE_CALLBACK(void * pData);

Parameters

Parameter Description
pData Memory block to be released.

Additional information

The callback function has the same signature as the free() standard C function. The application can register the callback function via FS_SetMemHandler(). pMem points to a memory block that was allocated using a call to pfAlloc callback function registered via FS_SetMemHandler().

FS_WRITEMODE

Description

Modes of writing to file.

Type definition

typedef enum {
  FS_WRITEMODE_SAFE,
  FS_WRITEMODE_MEDIUM,
  FS_WRITEMODE_FAST,
  FS_WRITEMODE_UNKNOWN
} FS_WRITEMODE;

Enumeration constants

Constant Description
FS_WRITEMODE_SAFE Allows maximum fail-safe behavior. The allocation table and the directory entry are updated after each write access to file. This write mode provides the slowest performance.
FS_WRITEMODE_MEDIUM Medium fail-safe. The allocation table is updated after each write access to file. The directory entry is updated only if file is synchronized that is when FS_Sync(), FS_FClose(), or FS_SyncFile() is called.
FS_WRITEMODE_FAST This write mode provided the maximum performance. The directory entry is updated only if the file is synchronized that is when FS_Sync(), FS_FClose(), or FS_SyncFile() is called. The allocation table is modified only if necessary.
FS_WRITEMODE_UNKNOWN End of enumeration (for internal use only)

File access functions

The functions in this section can be used to access the data stored in a file.

FS_FClose()

Description

Closes an opened file.

Prototype

int FS_FClose(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to the file to be closed.

Return value

= 0 OK, file handle has been successfully closed.
≠ 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Example

#include "FS.h"

void SampleFClose(void) {
  FS_FILE * pFile;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    //
    // Access file.
    //
    FS_FClose(pFile);
  }
}

FS_FGets()

Description

Reads a line of text from file.

Prototype

char *FS_FGets(char    * sData,
               int       SizeOfData,
               FS_FILE * pFile);

Parameters

Parameter Description
sData  out  Buffer that receives the data read from file. It cannot be NULL.
SizeOfData Number of bytes in sData. It cannot be 0.
pFile Handle to opened file. It cannot be NULL.

Return value

NULL OK, data read successfully. The returned value is sData buffer.
= NULL An error occurred.

Additional information

This function starts reading from the current position in the file and advances the current file position by the number of bytes read.

FS_FGets() returns when either a line terminator is read from file and stored to sData, SizeOfData - 1 bytes are stored to sData or the end of file is reached. The data stored to sData is 0-terminated.

A line terminator can be either a single Line Feed character (0x0A), a single Carriage Return character (0x0D) or a Carriage Return and Line Feed character sequence (0x0D 0x0A).

The file to read from has to be opened with read permissions. For more information about open modes refer to FS_FOpen().

The application can check for the actual error using FS_FError().

Example

#include "FS.h"

void SampleFGets(void) {
  FS_FILE * pFile;
  char      ac[128];
  char    * s;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile != NULL) {
    for (;;) {
      s = FS_FGets(ac, sizeof(ac), pFile);
      if (s == NULL) {
        break;
      }
    }
    FS_FClose(pFile);
  }
}

FS_FOpen()

Description

Opens an existing file or creates a new one.

Prototype

FS_FILE *FS_FOpen(const char * sFileName,
                  const char * sMode);

Parameters

Parameter Description
sFileName Name of the file to be opened or created. It is a 0-terminated string that cannot be NULL.
sMode Indicates how the file should be opened. It is a 0-terminated string that cannot be NULL.

Return value

≠ 0 OK, pointer to a file handle that identifies the opened file.
= 0 Error, unable to open the file.

Additional information

The sMode parameter can take one of the following values:

sMode Description
“r” or “rb” Opens file for reading.
“w” or “wb” Truncates to zero length or creates file for writing.
“a” or “ab” Opens or creates file for writing at end of file.
“r+”, “r+b” or “rb+” Opens file for reading and writing.
“w+”, “w+b” or “wb+” Truncates file to zero length or creates file for reading and writing.
“a+”, “a+b” or “ab+” Opens or creates file for reading and writing at end of file.

For more details about FS_FOpen(), refer to the ANSI C documentation of the fopen() function.

The file system does not distinguish between binary and text mode; the files are always accessed in binary mode.

In order to use long file names with FAT, the FS_FAT_SupportLFN() has to be called before after the file system is initialized.

FS_FOpen() accepts file names encoded in UTF-8 format. This feature is disabled by default. To enable it the file system has to be compiled with the FS_FAT_SUPPORT_UTF8 configuration define to 1. Additionally, the support for long file names has to be enabled for volumes formatted as FAT.

Example

#include "FS.h"

void SampleOpenFile(void) {
  FS_FILE * pFile;

  //
  // Opens for reading a file on the default volume.
  //
  pFile = FS_FOpen("Test.txt", "r");
  //
  // Opens for writing a file on the default volume.
  //
  pFile = FS_FOpen("Test.txt", "w");
  //
  // Opens for reading a file in folder "SubDir" on the default volume.
  // The directory delimiter is the '\' character.
  //
  pFile = FS_FOpen("\\SubDir\\Test.txt", "r");
  //
  // Opens for reading a file on the first RAM disk volume.
  //
  pFile = FS_FOpen("ram:Test.txt", "r");
  //
  // Opens for reading a file on the second RAM disk volume.
  //
  pFile = FS_FOpen("ram:1:Test.txt", "r");
  //
  // Opens for writing a file with a long name for writing.
  //
  FS_FAT_SupportLFN();
  pFile = FS_FOpen("Long file name.text", "w");
  //
  // Opens for writing a file with a name encoded in UTF-8 format.
  // The file system has to be compiled with FS_FAT_SUPPORT_UTF8 define
  // set to 1. The name contains the following characters:
  //   small a, umlaut mark
  //   small o, umlaut mark
  //   small sharp s
  //   small u, umlaut mark
  //   '.'
  //   't'
  //   'x'
  //   't'
  //
  FS_FAT_SupportLFN();
  pFile = FS_FOpen("\xC3\xA4\xC3\xB6\xC3\x9F\xC3\xBC.txt", "w");
}

FS_FOpenEx()

Description

Opens an existing file or creates a new one.

Prototype

int FS_FOpenEx(const char     * sFileName,
               const char     * sMode,
                     FS_FILE ** ppFile);

Parameters

Parameter Description
sFileName Name of the file to be opened or created. It is a 0-terminated string that cannot be NULL.
sMode Indicates how the file should be opened. It is a 0-terminated string that cannot be NULL.
ppFile Pointer to a file handle pointer that receives the opened file handle.

Return value

= 0 OK, file opened.
≠ 0 Error code indicating the failure reason.

Additional information

For additional information about the sMode parameter refer to FS_FOpen().

Example

#include <stdio.h>
#include "FS.h"

FS_FILE * pFile;

/*********************************************************************
*
*       SampleFOpenEx
*
*  Function description
*    Opens for reading a file on the default volume.
*/
void SampleFOpenEx(void) {
  int  r;
  char ac[100];

  r = FS_FOpenEx("Test.txt", "r", &pFile);
  if (r) {
    SEGGER_snprintf(ac, sizeof(ac), "Could not open file (Reason: %s)\n", 
      FS_ErrorNo2Text(r));
    FS_X_Log(ac);
  }
}

FS_FPrintf()

Description

Writes a formatted string to a file.

Prototype

int FS_FPrintf(      FS_FILE * pFile,
               const char    * sFormat,
                               ...);

Parameters

Parameter Description
pFile Opened file handle. It cannot be NULL.
sFormat Format of the data to be written (0-terminated string). It cannot be NULL.

Return value

≥ 0 OK, number of bytes written to file.
< 0 Error code indicating the failure reason.

Additional information

This function works in the same way as the fprintf() standard C library function. It formats the data according to sFormat and then writes the formatted string to pFile. The format specification is identical to that of fprintf(). FS_FPrintf() relies on SEGGER_vsnprintfEx() to perform the actual formatting.

The file position is advanced by the number of bytes written.

FS_FPrintf() uses a buffer allocated on the stack for the formatting of the data. The size of this buffer can be configured via FS_BUFFER_SIZE_FILE_PRINT and it has to be at least 1 byte large.

Example

#include "FS.h"

void SampleFPrintf(void) {
  FS_FILE * pFile;
  int       i;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    for (i = 0; i < 10; ++i) {
      FS_FPrintf(pFile, "Counter value: %d\n", i);
    }
    FS_FClose(pFile);
  }
}

FS_FPuts()

Description

Writes a 0-terminated string to a file.

Prototype

int FS_FPuts(const char    * sData,
                   FS_FILE * pFile);

Parameters

Parameter Description
sData Data to be written (0-terminated string). It cannot be NULL.
pFile Opened file handle. It cannot be NULL.

Return value

= 0 OK, data written successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function works in the same way as the fputs() standard C library function. It writes the 0-terminated string sData to the file pFile. The 0-terminator is not written to file. The file position is advanced by the number of bytes written.

Example

#include "FS.h"

const char acText[] = "Hello world\n";

void SampleFPuts(void) {
  FS_FILE * pFile;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    FS_FPuts(acText, pFile);
    FS_FClose(pFile);
  }
}

FS_FRead()

Description

Reads data from file.

Prototype

U32 FS_FRead(void    * pData,
             U32       ItemSize,
             U32       NumItems,
             FS_FILE * pFile);

Parameters

Parameter Description
pData Buffer that receives the data read from file.
ItemSize Size of one item to be read from file (in bytes).
NumItems Number of items to be read from the file.
pFile Handle to opened file. It cannot be NULL.

Return value

Number of items read.

Additional information

The file has to be opened with read permissions. For more information about open modes refer to FS_FOpen().

The application has to check for possible errors using FS_FError() if the number of items actually read is different than the number of items requested to be read by the application.

The data is read from the current position in the file that is indicated by the file pointer. FS_FRead() moves the file pointer forward by the number of bytes successfully read.

Example

#include "FS.h"

char acBuffer[100];

void SampleFRead(void) {
  FS_FILE * pFile;
  U32       NumItems;
  int       ErrCode;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    NumItems = FS_FRead(acBuffer, 1, sizeof(acBuffer), pFile);
    if (NumItems != sizeof(acBuffer)) {
      ErrCode = FS_FError(pFile);
      if (ErrCode) {
        //
        // An error occurred during the read operation.
        //
      }
    }
    FS_FClose(pFile);
  }
}

FS_FSeek()

Description

Sets the current position in file.

Prototype

int FS_FSeek(FS_FILE * pFile,
             I32       Offset,
             int       Origin);

Parameters

Parameter Description
pFile Handle to opened file.
Offset Byte offset for setting the file pointer position.
Origin Indicates how the file pointer has to be moved.

Return value

= 0 OK, file pointer has been positioned according to the specified parameters.
≠ 0 Error code indicating the failure reason.

Additional information

FS_FSeek() moves the file pointer to a new location by a number of bytes relative to the position specified by the Origin parameter. The Origin parameter can take the values specified by File positioning reference.

The file pointer can be repositioned anywhere in the file. It is also possible to reposition the file pointer beyond the end of the file. This feature is used together with FS_SetEndOfFile() to reserve space for a file (preallocate the file).

Alternative name

FS_SetFilePos

Example

#include "FS.h"

const char acText[]="Some text will be overwritten";

void SampleFSeek(void) {
  FS_FILE * pFile;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    //
    // Write the data to file.
    //
    FS_FWrite(acText, 1, strlen(acText), pFile);
    //
    // Move the file pointer back 4 bytes from the current
    // position in file. The data stored in the file looks
    // like this: "Some text will be overwritten"
    //
    FS_FSeek(pFile, -4, FS_SEEK_CUR);
    //
    // The write operation overwrites the last
    // 4 characters that is "tten" of the data
    // written in the previous call to FS_FWrite().
    //
    FS_FWrite(acText, 1, strlen(acText), pFile);
    //
    // The data in the file looks now like this:
    // "Some text will be overwriSome text will be overwritten"
    //
    FS_FClose(pFile);
  }
}

FS_FSeek64()

Description

Modifies the current position in a file.

Prototype

int FS_FSeek64(FS_FILE * pFile,
               I64       Offset,
               int       Origin);

Parameters

Parameter Description
pFile Handle to opened file.
Offset Byte offset for setting the file pointer position.
Origin Indicates how the file pointer has to be moved.

Return value

= 0 OK, file pointer has been positioned according to the specified parameters.
≠ 0 Error code indicating the failure reason.

Additional information

This function moves the file pointer to a new location by a number of bytes specified via the Offset parameter and relative to a position specified via the Origin parameter. The Origin parameter can take the values specified by File positioning reference.

The file pointer can be repositioned anywhere in the file. It is also possible to reposition the file pointer beyond the end of the file. This feature can be used together with FS_SetEndOfFile() to reserve space for a file, also known as file preallocation.

This function performs the same operation as FS_FSeek() with the difference that the set file position can be greater than or equal to 232. This makes FS_Seek64() suitable for setting the position in a file that is larger than or equal to 4 GB.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include "FS.h"

const char acText[]="Some text will be overwritten";

void SampleFSeek64(void) {
  FS_FILE * pFile;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    //
    // Write the data to file.
    //
    FS_FWrite(acText, 1, strlen(acText), pFile);
    //
    // Move the file pointer back 4 bytes from the current
    // position in file. The data stored in the file looks
    // like this: "Some text will be overwritten"
    //
    FS_FSeek64(pFile, -4, FS_SEEK_CUR);
    //
    // The write operation overwrites the last
    // 4 characters that is "tten" of the data
    // written in the previous call to FS_FWrite().
    //
    FS_FWrite(acText, 1, strlen(acText), pFile);
    //
    // The data in the file looks now like this:
    // "Some text will be overwriSome text will be overwritten"
    //
    FS_FClose(pFile);
  }
}

FS_FWrite()

Description

Writes data to file.

Prototype

U32 FS_FWrite(const void    * pData,
                    U32       ItemSize,
                    U32       NumItems,
                    FS_FILE * pFile);

Parameters

Parameter Description
pData Data to be written to file.
ItemSize Size of an item to be written to file (in bytes).
NumItems Number of items to be written to file.
pFile Handle to opened file. It cannot be NULL.

Return value

Number of elements written.

Additional information

The file has to be opened with write permissions. For more information about open modes refer to FS_FOpen().

The application has to check for possible errors using FS_FError() if the number of items actually written is different than the number of items requested to be written by the application.

The data is written at the current position in the file that is indicated by the file pointer. FS_FWrite() moves the file pointer forward by the number of bytes successfully written.

Example

#include "FS.h"

const char acText[] = "Hello world\n";

void SampleFWrite(void) {
  FS_FILE * pFile;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    FS_FWrite(acText, 1, strlen(acText), pFile);
    FS_FClose(pFile);
  }
}

FS_FTell()

Description

Returns current position in file.

Prototype

I32 FS_FTell(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

0xFFFFFFFF OK, current position of the file pointer.
= 0xFFFFFFFF An error occurred.

Additional information

The function returns the file position as a signed value for compatibility reasons. The return value has to be treated as a 32-bit unsigned with the value 0xFFFFFFFF indicating an error.

This function simply returns the file pointer member of the file handle structure pointed by pFile. Nevertheless, you should not access the FS_FILE structure yourself, because that data structure may change in the future.

In conjunction with FS_FSeek(), this function can also be used to examine the file size. By setting the file pointer to the end of the file using FS_SEEK_END, the length of the file can now be retrieved by calling FS_FTell(). Alternatively the FS_GetFileSize() function can be used.

Alternative name

FS_GetFilePos

Example

#include "FS.h"

const char acText[]="Hello world\n";

void SampleFTell(void) {
  FS_FILE * pFile;
  I32       FilePos;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    FS_FWrite(acText, 1, strlen(acText), pFile);
    FilePos = FS_FTell(pFile);
    FS_FClose(pFile);
  }
}

FS_FTell64()

Description

Returns current position in a file.

Prototype

I64 FS_FTell64(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

0xFFFFFFFFFFFFFFFF OK, current position of the file pointer.
= 0xFFFFFFFFFFFFFFFF An error occurred.

Additional information

This function performs the same operation as FS_FTell() with the difference that the returned file position can be greater than or equal to 232. This makes FS_FTell64() suitable for getting the position in a file that is larger than or equal to 4 GB.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include "FS.h"

const char acText[]="Hello world\n";

void SampleFTell64(void) {
  FS_FILE * pFile;
  I64       FilePos;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    FS_FWrite(acText, 1, strlen(acText), pFile);
    FilePos = FS_FTell64(pFile);
    FS_FClose(pFile);
  }
}

FS_GetFileSize()

Description

Returns the size of a file.

Prototype

U32 FS_GetFileSize(const FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

0xFFFFFFFF File size of the given file in bytes.
= 0xFFFFFFFF An error occurred.

Additional information

The file has to be opened with read or write access.

Example

#include "FS.h"

void SampleGetFileSize(void) {
  FS_FILE * pFile;
  U32       FileSize;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    FileSize = FS_GetFileSize(pFile);
    FS_FClose(pFile);
  }
}

FS_GetFileSizeEx()

Description

Returns the size of a file.

Prototype

int FS_GetFileSizeEx(FS_FILE * pFile,
                     U32     * pNumBytes);

Parameters

Parameter Description
pFile Handle to opened file.
pNumBytes  out  Size of the file.

Return value

= 0 OK, file size returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_GetFileSize() with the difference that it returns an error code in case of an error.

The file has to be opened with read or write access.

Example

#include "FS.h"

void SampleGetFileSizeEx(void) {
  FS_FILE * pFile;
  U32       FileSize;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    FileSize = 0;
    FS_GetFileSizeEx(pFile, &FileSize);
    FS_FClose(pFile);
  }
}

FS_GetFileSize64()

Description

Returns the size of a file.

pFile Handle to opened file. pNumBytes  out  Size of the file.

Prototype

int FS_GetFileSize64(FS_FILE * pFile,
                     U64     * pNumBytes);

Return value

= 0 OK, file size returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

The file has to be opened with read or write access.

This function performs the same operation as FS_GetFileSize() with the difference that the returned file size can be greater than or equal to 232. This makes FS_GetFileSize64() suitable for getting the size of a file that is larger than or equal to 4 GB.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include "FS.h"

void SampleGetFileSize64(void) {
  FS_FILE * pFile;
  U64       FileSize;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    FileSize = 0;
    FS_GetFileSize64(pFile, &FileSize);
    FS_FClose(pFile);
  }
}

FS_Read()

Description

Reads data from a file.

Prototype

U32 FS_Read(FS_FILE * pFile,
            void    * pData,
            U32       NumBytes);

Parameters

Parameter Description
pFile Handle to an opened file. It cannot be NULL.
pData Buffer to receive the read data.
NumBytes Number of bytes to be read.

Return value

Number of bytes read.

Additional information

The file has to be opened with read permissions. For more information about open modes refer to FS_FOpen().

The application has to check for possible errors using FS_FError() if the number of bytes actually read is different than the number of bytes requested to be read by the application.

The data is read from the current position in the file that is indicated by the file pointer. FS_Read() moves the file pointer forward by the number of bytes successfully read.

Example

#include "FS.h"

U8 abBuffer[100];

void SampleRead(void) {
  FS_FILE * pFile;
  U32       NumBytesRead;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    NumBytesRead = FS_Read(pFile, abBuffer, sizeof(abBuffer));
    if (NumBytesRead != sizeof(abBuffer)) {
      //
      // An error occurred.
      //
    }
    FS_FClose(pFile);
  }
}

FS_SetEndOfFile()

Description

Sets the file size to current file position.

Prototype

int FS_SetEndOfFile(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

= 0 OK, new file size has been set.
≠ 0 Error code indicating the failure reason.

Additional information

The file has to be opened with write permissions. Refer to FS_FOpen() for more information about the file open modes.

FS_SetEndOfFile() can be used to truncate as well as to extend a file. If the file is extended, the contents of the file between the old end-of-file and the new one are not defined. Extending a file (preallocation) can increase the write performance when the application writes large amounts of data to file as the file system is not required anymore to access the allocation table.

Example

#include "FS.h"

void SampleSetEndOfFile(void) {
  FS_FILE * pFile;

  //
  // Reserve space for a file of 20000 bytes.
  //
  pFile = FS_FOpen("Test.bin", "r+");
  if (pFile) {
    FS_FSeek(pFile, 20000, FS_SEEK_SET);
    FS_SetEndOfFile(pFile);
    FS_FClose(pFile);
  }
}

FS_SetFileSize()

Description

Sets the file size to the specified number of bytes.

Prototype

int FS_SetFileSize(FS_FILE * pFile,
                   U32       NumBytes);

Parameters

Parameter Description
pFile Handle to an opened file.
NumBytes New file size.

Return value

= 0 OK, new file size has been set.
≠ 0 Error code indicating the failure reason.

Additional information

The file has to be opened with write permissions. Refer to FS_FOpen() for more information about the file open modes. FS_SetFileSize() can be used to extend as well as truncate a file. The file position is preserved if the new file size is larger than or equal to the current file position. Else the file position is set to the end of the file.

Example

#include "FS.h"

void SampleSetFileSize(void) {
  FS_FILE * pFile;

  //
  // Create a file 20000 bytes large.
  //
  pFile = FS_FOpen("Test.bin", "r+");
  if (pFile) {
    FS_SetFileSize(pFile, 20000);
    FS_FClose(pFile);
  }
}

FS_SetFileSize64()

Description

Sets the file size to the specified number of bytes.

Prototype

int FS_SetFileSize64(FS_FILE * pFile,
                     U64       NumBytes);

Parameters

Parameter Description
pFile Handle to an opened file.
NumBytes New file size.

Return value

= 0 OK, new file size has been set.
≠ 0 Error code indicating the failure reason.

Additional information

The file has to be opened with write permissions. Refer to FS_FOpen() for more information about the file open modes.

FS_SetFileSize64() can be used to extend as well as truncate a file. The file position is preserved if the new file size is larger than or equal to the current file position. Otherwise the file position is set to the end of the file.

This function performs the same operation as FS_SetFileSize() with the difference that the set file size can be greater than or equal to 232. This makes FS_SetFileSize64() suitable for setting a file size that is larger than or equal to 4 GB.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include "FS.h"

void SampleSetFileSize64(void) {
  FS_FILE * pFile;

  //
  // Create a file that is about 8GB bytes large.
  //
  pFile = FS_FOpen("Test.bin", "r+");
  if (pFile) {
    FS_SetFileSize64(pFile, 8000000000uLL);
    FS_FClose(pFile);
  }
}

FS_SyncFile()

Description

Synchronizes file to storage device.

Prototype

int FS_SyncFile(FS_FILE * pFile);

Parameters

Parameter Description
pFile File pointer identifying the opened file. It can be NULL.

Return value

= 0 OK, file(s) synchronized.
≠ 0 Error code indicating the failure reason.

Additional information

The function synchronizes all the opened files if a NULL is passed as pFile parameter.

FS_SyncFile() cleans the write buffer if configured and updates the management information to storage device. The function performs basically the same operations as FS_FClose() with the only difference that it leaves the file open. FS_SyncFile() is used typically with fast or medium file write modes to make sure that the data cached by the file system for the file is written to storage medium.

The function can also be called from a different task than the one that writes to file if the support for multi-tasking is enabled in the file system. The support for multi-tasking can be enabled by compiling the file system sources with the FS_OS_LOCKING define is set to value different than 0.

Example

#include "FS.h"

void SampleFileSync(void) {
  FS_FILE * pFile;

  FS_SetFileWriteMode(FS_WRITEMODE_FAST);
  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    //
    // Write to file...
    //
    FS_SyncFile(pFile);
    //
    // Write to file...
    //
    FS_SyncFile(pFile);
    //
    // Write to file...
    //
    FS_FClose(pFile);
  }
}

FS_Truncate()

Description

Changes the size of a file.

Prototype

int FS_Truncate(FS_FILE * pFile,
                U32       NumBytes);

Parameters

Parameter Description
pFile Handle to an opened file.
NumBytes The new size of the file.

Return value

= 0 OK, file size successfully modified.
≠ 0 Error code indicating the failure reason.

Additional information

The file has to be opened in write mode. For more information about open modes refer to FS_FOpen().

An error is returned if NumBytes is larger than the actual file size and the support for POSIX operation is disabled.

If the support for POSIX operation is enabled, then this function can also be used to increase the size of the file. The extra bytes are initialized with 0. The application can enable the support for POSIX operation by building the file system with FS_SUPPORT_POSIX set to 1 and by calling at runtime FS_ConfigPOSIXSupport() with the OnOff parameter set to 1.

FS_Truncate() allocates FS_BUFFER_SIZE_TRUNCATE bytes on the stack with the support for the POSIX operation enabled.

Example

#include "FS.h"

void SampleTruncate(void) {
  FS_FILE * pFile;
  U32       FileSize;
  int       r;

  pFile = FS_FOpen("Test.bin", "r+");
  if (pFile) {
    FileSize = FS_GetFileSize(pFile);
    //
    // Reduce the size of the file by 200 bytes.
    //
    r = FS_Truncate(pFile, FileSize - 200);
    if (r) {
      //
      // An error occurred while truncating file.
      //
    }
  }
  FS_FClose(pFile);
}

FS_Truncate64()

Description

Changes the size of a file.

Prototype

int FS_Truncate64(FS_FILE * pFile,
                  U64       NumBytes);

Parameters

Parameter Description
pFile Handle to an opened file.
NumBytes The new size of the file.

Return value

= 0 OK, file size successfully modified.
≠ 0 Error code indicating the failure reason.

Additional information

The file has to be opened in write mode. For more information about open modes refer to FS_FOpen().

An error is returned if NumBytes is larger than the actual file size and the support for POSIX operation is disabled.

If the support for POSIX operation is enabled, then this function can also be used to increase the size of the file. The extra bytes are initialized with 0. The application can enable the support for POSIX operation by building the file system with FS_SUPPORT_POSIX set to 1 and by calling at runtime FS_ConfigPOSIXSupport() with the OnOff parameter set to 1.

FS_Truncate64() allocates FS_BUFFER_SIZE_TRUNCATE bytes on the stack with the support for the POSIX operation enabled.

This function performs the same operation as FS_Truncate() with the difference that the set file size can be greater than or equal to 232. This makes FS_Truncate64() suitable for setting a file size that is larger than or equal to 4 GB.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include "FS.h"

void SampleTruncate64(void) {
  FS_FILE * pFile;
  U64       FileSize;
  int       r;

  pFile = FS_FOpen("Test.bin", "r+");
  if (pFile) {
    r = FS_GetFileSize64(pFile, &FileSize);
    if (r == 0) {
      //
      // Reduce the size of the file by 200 bytes.
      //
      r = FS_Truncate64(pFile, FileSize - 200);
      if (r != 0) {
        //
        // An error occurred while truncating file.
        //
      }
    }
  }
  FS_FClose(pFile);
}

FS_Verify()

Description

Verifies the file contents.

Prototype

int FS_Verify(      FS_FILE * pFile,
              const void    * pData,
                    U32       NumBytes);

Parameters

Parameter Description
pFile Handle to opened file.
pData Data to be checked against.
NumBytes Number of bytes to be checked.

Return value

= 0 Verification was successful.
≠ 0 Verification failed.

Additional information

The function starts checking at the current file position. That is the byte read from file position + 0 is checked against the byte at pData + 0, the byte read from file position + 1 is checked against the byte at pData + 1 and so on. FS_Verify() does not modify the file position.

Example

#include "FS.h"

const U8 abVerifyData[4] = { 1, 2, 3, 4 };

void SampleVerify(void) {
  FS_FILE * pFile;
  int       r;

  //
  // Open file and write data into it.
  //
  pFile = FS_FOpen("Test.bin", "w+");
  if (pFile) {
    FS_Write(pFile, abVerifyData, sizeof(abVerifyData));
    //
    // Set file pointer to the start of the data that has to be verified.
    //
    FS_FSeek(pFile, 0, FS_SEEK_SET);
    //
    // Verify data.
    //
    r = FS_Verify(pFile, abVerifyData, sizeof(abVerifyData));
    if (r == 0) {
      FS_X_Log("Verification was successful.\n");
    } else {
      FS_X_Log("Verification failed.\n");
    }
    FS_FClose(pFile);
  }
}

FS_Write()

Description

Writes data to file.

Prototype

U32 FS_Write(      FS_FILE * pFile,
             const void    * pData,
                   U32       NumBytes);

Parameters

Parameter Description
pFile Handle to opened file.
pData The data to be written to file.
NumBytes Number of bytes to be written to file.

Return value

Number of bytes written.

Additional information

The file has to be opened with write permissions. For more information about open modes refer to FS_FOpen().

The application has to check for possible errors using FS_FError() if the number of bytes actually written is different than the number of bytes requested to be written by the application.

The data is written at the current position in the file that is indicated by the file pointer. FS_FWrite() moves the file pointer forward by the number of bytes successfully written.

Example

#include "FS.h"

void SampleWrite(void) {
  FS_FILE    * pFile;
  const char   acText[] = "Hello world\n";

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    FS_Write(pFile, acText, strlen(acText));
    FS_FClose(pFile);
  }
}

File positioning reference

Description

Reference point when changing the file position.

Definition

#define FS_SEEK_SET    0
#define FS_SEEK_CUR    1
#define FS_SEEK_END    2

Symbols

Definition Description
FS_SEEK_SET The reference is the beginning of the file.
FS_SEEK_CUR The reference is the current position of the file pointer.
FS_SEEK_END The reference is the end-of-file position.

Operations on files

The functions on this section can be used by an application to manipulate files.

FS_CopyFile()

Description

Copies a file.

Prototype

int FS_CopyFile(const char * sFileNameSrc,
                const char * sFileNameDest);

Parameters

Parameter Description
sFileNameSrc Name of the source file (fully qualified).
sFileNameDest Name of the destination file (fully qualified).

Return value

= 0 OK, the file has been copied
≠ 0 Error code indicating the failure reason

Additional information

The copy process uses an internal temporary buffer of 512 bytes that is allocated on the stack. The size of this buffer can be configured via FS_BUFFER_SIZE_FILE_COPY. Alternatively, FS_CopyFileEx() can be used that lets the application specify a copy buffer of an arbitrary size.

FS_CopyFile() overwrites the destination file if it exists. The destination file has to be writable, that is the FS_ATTR_READ_ONLY flag is set to 0.

Example

#include "FS.h"

void SampleCopyFile(void) {
  FS_CopyFile("Src.txt", "ram:\\Dest.txt");
}

FS_CopyFileEx()

Description

Copies a file.

Prototype

int FS_CopyFileEx(const char * sFileNameSrc,
                  const char * sFileNameDest,
                        void * pBuffer,
                        U32    NumBytes);

Parameters

Parameter Description
sFileNameSrc Name of the source file (fully qualified).
sFileNameDest Name of the destination file (fully qualified).
pBuffer Buffer to temporary store the copied data. It cannot be NULL.
NumBytes Size of the buffer size in bytes.

Return value

= 0 OK, the file has been copied.
≠ 0 Error code indicating the failure reason.

Additional information

The copy process uses an external buffer provided by the application. FS_CopyFile() overwrites the destination file if it exists. The destination file has to be writable, that is the FS_ATTR_READ_ONLY flag is set to 0.

The best performance is achieved when the copy buffer is a multiple of sector size and is 32-bit aligned. For example using a 7 KB copy buffer to copy 512 byte sectors is more efficient than using a copy buffer of 7.2 KB therefore the function rounds down the size of the copy buffer to a multiple of sector size. If the application specifies a copy buffer smaller than the sector size a warning is generated in debug builds indicating that the performance of the copy operation is not optimal.

Example

#include "FS.h"

static U32 _aBuffer[1024 / 4];    // Buffer to be used as temporary storage.

void SampleCopyFileEx(void) {
  FS_CopyFileEx("Src.txt", "Dest.txt", _aBuffer, sizeof(_aBuffer));
}

FS_GetFileAttributes()

Description

Queries the attributes of a file or directory.

Prototype

U8 FS_GetFileAttributes(const char * sName);

Parameters

Parameter Description
sName Name of the file or directory to be queried.

Return value

= 0xFF An error occurred.
0xFF Bit mask containing the attributes of file or directory.

Additional information

The return value is an or-combination of the following attributes: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM, FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetFileAttributes(void) {
  U8   Attr;
  char ac[100];

  Attr = FS_GetFileAttributes("Test.txt");
  if (Attr == 0xFF) {
    FS_X_Log("ERROR: Could not get the file attributes.\n");
  } else {
    SEGGER_snprintf(ac, sizeof(ac), 
      "File attributes: %c%c%c%c%c\n",
      (Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
      (Attr & FS_ATTR_HIDDEN)    ? 'H' : '-',
      (Attr & FS_ATTR_SYSTEM)    ? 'S' : '-',
      (Attr & FS_ATTR_ARCHIVE)   ? 'A' : '-',
      (Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
    FS_X_Log(ac);
  }
}

FS_GetFileBufferInfo()

Description

Obtains information about a file buffer.

Prototype

int FS_GetFileBufferInfo(FS_FILE             * pFile,
                         FS_FILE_BUFFER_INFO * pInfo);

Parameters

Parameter Description
pFile Handle to opened file.
pInfo  out  Information about the file buffer.

Return value

= 0 OK, information returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function returns an error if the specified file does not have a file buffer. FS_IsFileBufferSet() can be used to check if a file buffer is configured.

FS_GetFileBufferInfo() is available only if the file system is built with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

This function does not perform any access to the storage device.

Example

#include "FS.h"

void SampleGetFileBufferInfo(void) {
  FS_FILE             * pFile;
  FS_FILE_BUFFER_INFO   Info;
  int                   r;
  char                  ac[100];

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != 0) {
    r = FS_IsFileBufferSet(pFile);
    if (r > 0) {
      memset(&Info, 0, sizeof(Info));
      r = FS_GetFileBufferInfo(pFile, &Info);
      if (r == 0) {
        FS_X_Log("File buffer info:\n");
        FS_X_Log("  Allocated by application: ");
        if (Info.IsExternal != 0) {
          FS_X_Log("yes\n");
        } else {
          FS_X_Log("no\n");
        }
        SEGGER_snprintf(ac, sizeof(ac), 
          "  Buffer size:              %d bytes\n", Info.BufferSize);
        FS_X_Log(ac);
        FS_X_Log("  Operating mode:           READ");
        if (Info.Flags & FS_FILE_BUFFER_WRITE) {
          FS_X_Log(" WRITE");
        }
        if (Info.Flags & FS_FILE_BUFFER_ALIGNED) {
          FS_X_Log(" ALIGNED");
        }
        FS_X_Log("\n");
      }
    }
    FS_FClose(pFile);
  }
}

FS_GetFileInfo()

Description

Returns information about a file or directory.

Prototype

int FS_GetFileInfo(const char         * sName,
                         FS_FILE_INFO * pInfo);

Parameters

Parameter Description
sName Name of the file or directory.
pInfo  out  Information about file or directory.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

The function returns information about the attributes, size and time stamps of the specified file or directory. For more information refer to FS_FILE_INFO.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetFileInfo(void) {
  int          r;
  FS_FILE_INFO FileInfo;
  char         ac[100];
  FS_FILETIME  FileTime;

  r = FS_GetFileInfo("Test.txt", &FileInfo);
  if (r == 0) {
    FS_X_Log("File info:\n");
    SEGGER_snprintf(ac, sizeof(ac), "  Attributes:    0x%x\n", FileInfo.Attributes);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Size:          %ld bytes\n", FileInfo.FileSize);
    FS_X_Log(ac);
    FS_TimeStampToFileTime(FileInfo.CreationTime, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "  Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
    FS_TimeStampToFileTime(FileInfo.LastAccessTime, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "  Access time:   %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
    FS_TimeStampToFileTime(FileInfo.LastWriteTime, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "  Write time:    %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
  }
}

FS_GetFileInfo64()

Description

Obtains information about a file or directory.

Prototype

int FS_GetFileInfo64(const char           * sName,
                           FS_FILE_INFO64 * pInfo);

Parameters

Parameter Description
sName Name of the file or directory.
pInfo  out  Information about file or directory.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

The function returns information about the attributes, size and time stamps of the specified file or directory. For more information refer to FS_FILE_INFO64.

This function performs the same operation as FS_GetFileInfo() with the difference that the size of the queried file or directory can be greater than or equal to 4GB.

This function is available only then the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

#include <stdio.h>
#include "FS.h"

void SampleGetFileInfo64(void) {
  int            r;
  FS_FILE_INFO64 FileInfo;
  char           ac[100];
  FS_FILETIME    FileTime;
  U32            FileSizeLow;
  U32            FileSizeHigh;  

  r = FS_GetFileInfo64("Test.txt", &FileInfo);
  if (r == 0) {
    FileSizeLow  = (U32)(FileInfo.FileSize % 1000000000uLL);
    FileSizeHigh = (U32)(FileInfo.FileSize / 1000000000uLL);
    FS_X_Log("File info:\n");
    SEGGER_snprintf(ac, sizeof(ac), "  Attributes:    0x%x\n", FileInfo.Attributes);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Size:          %ld%ld bytes\n", FileSizeHigh, FileSizeLow);
    FS_X_Log(ac);
    FS_TimeStampToFileTime(FileInfo.CreationTime.TimeDate, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "  Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
    FS_TimeStampToFileTime(FileInfo.LastAccessTime.TimeDate, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "  Access time:   %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
    FS_TimeStampToFileTime(FileInfo.LastWriteTime.TimeDate, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "  Write time:    %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
  }
}

FS_GetFileName()

Description

Obtains the name of a file.

Prototype

int FS_GetFileName(FS_FILE  * pFile,
                   char     * pFileName,
                   unsigned   SizeOfFileName);

Parameters

Parameter Description
pFile Handle to the opened file.
pFileName  out  Receives the name of the file as 0-terminated string. It cannot be NULL.
SizeOfFileName Number of bytes in pFileName.

Return value

> 0 Number of bytes in the file name or number of bytes required to store the volume name.
< 0 Error code indicating the failure reason.

Additional information

If pFileName is sufficiently large to store the entire file name and the 0-terminator then the function returns the number of bytes in the file name without the 0-terminator. If pFileName is not sufficiently large to store the entire file name and the 0-terminator then the function returns the minimum buffer size required to store the entire file name including the 0-terminator. In this case, the function does not store any data to pFileName.

FS_GetFileName() stores at most SizeOfFileName - 1 bytes to pFileName and it terminates the string by a 0.

This function is present only when the file system is built with FS_MULTI_HANDLE_SAFE set to 1.

#include "FS.h"

void SampleGetFileName(void) {
  FS_FILE  * pFile;
  unsigned   SizeOfBuffer;
  int        NumBytes;
  char       acFileName[32];

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    memset(acFileName, 0, sizeof(acFileName));    
    SizeOfBuffer = sizeof(acFileName);
    NumBytes = FS_GetFileName(pFile, acFileName, SizeOfBuffer);
    if ((NumBytes > 0) && (NumBytes < (int)SizeOfBuffer)) {
      FS_X_Log("File name: ");
      FS_X_Log(acFileName);
      FS_X_Log("\n");
    }
    FS_FClose(pFile);
  }
}

FS_GetFileTime()

Description

Returns the creation time of a file or directory.

Prototype

int FS_GetFileTime(const char * sName,
                         U32  * pTimeStamp);

Parameters

Parameter Description
sName File or directory name.
pTimeStamp  out  Receives the timestamp value.

Return value

= 0 OK, timestamp returned.
≠ 0 Error code indicating the failure reason.

Additional information

The date and time encoded in the timestamp using the following format:

Bit field Description
0--4 Second divided by 2
5--10 Minute (0--59)
11--15 Hour (0--23)
16--20 Day of month (1--31)
21--24 Month (1--12, 1: January, 2: February, etc.)
25--31 Year (offset from 1980). Add 1980 to get the current year.

FS_TimeStampToFileTime() can be used to convert the timestamp to a FS_FILETIME structure that can be used to easily process the time information.

The last modification and the last access timestamps can be read via FS_GetFileTimeEx().

Example

#include <stdio.h>
#include "FS.h"

void SampleGetFileTime(void) {
  char        ac[100];
  U32         TimeStamp;
  FS_FILETIME FileTime;
  int         r;

  r = FS_GetFileTime("Test.txt", &TimeStamp);
  if (r == 0) {
    FS_TimeStampToFileTime(TimeStamp, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
  }
}

FS_GetFileTimeEx()

Description

Gets the timestamp of a file or directory.

Prototype

int FS_GetFileTimeEx(const char * sName,
                           U32  * pTimeStamp,
                           int    TimeType);

Parameters

Parameter Description
sName File or directory name.
pTimeStamp  out  Receives the timestamp value.
TimeType Type of timestamp to return. It can take one of the following values: FS_FILETIME_CREATE FS_FILETIME_ACCESS FS_FILETIME_MODIFY

Return value

= 0 OK, timestamp returned.
≠ 0 Error code indicating the failure reason.

Additional information

Refer to FS_GetFileTime() for a description of the timestamp format. FS_TimeStampToFileTime() can be used to convert the timestamp to a FS_FILETIME structure that can be used to easily process the time information.

EFS maintains only one filestamp that is updated when the file is created and updated therefore the same timestamp value is returned for all time types.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetFileTimeEx(void) {
  char        ac[100];
  U32         TimeStamp;
  FS_FILETIME FileTime;
  int         r;

  r = FS_GetFileTimeEx("Test.txt", &TimeStamp, FS_FILETIME_MODIFY);
  if (r == 0) {
    FS_TimeStampToFileTime(TimeStamp, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "Modify time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
  }
}

FS_IsFileBufferSet()

Description

Checks if a file buffer is configured for the specified file.

Prototype

int FS_IsFileBufferSet(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

= 1 OK, file buffer set.
= 0 OK, file buffer not set.
≠ 0 Error code indicating the failure reason.

Additional information

FS_IsFileBufferSet() is available only if the file system is built with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

Example

#include "FS.h"

void SampleIsFileBufferSet(void) {
  FS_FILE * pFile;
  int       r;

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != 0) {
    r = FS_IsFileBufferSet(pFile);
    if (r < 0) {
      FS_X_Log("ERROR: Could not get file buffer status.\n");
    } else {
      if (r != 0) {
        FS_X_Log("File buffer set\n");
      } else {
        FS_X_Log("File buffer not set\n");
      }
    }
    FS_FClose(pFile);
  }
}

FS_ModifyFileAttributes()

Description

Sets / clears the attributes of a file or directory.

Prototype

U8 FS_ModifyFileAttributes(const char * sName,
                                 U8     SetMask,
                                 U8     ClrMask);

Parameters

Parameter Description
sName Name of the file or directory.
SetMask Bit mask of the attributes to be set.
ClrMask Bit mask of the attributes to be cleared.

Return value

= 0xFF An error occurred.
0xFF Bit mask containing the old attributes of the file or directory.

Additional information

This function can be used to set and clear at the same time the attributes of a file or directory. The FS_ATTR_DIRECTORY attribute cannot be modified using this function.

The return value is an or-combination of the following attributes: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM, FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.

The attributes that are specified in the SetMask are set to 1 while the attributes that are specified in the ClrMask are set to 0. SetMask and ClrMask values are an or-combination of the following attributes: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM, or FS_ATTR_ARCHIVE. The attributes that are not specified nor in SetMask either in ClrMask are not modified.

Example

#include <stdio.h>
#include "FS.h"

void SampleModifyFileAttributes(void) {
  U8   Attr;
  char ac[100];

  //
  // Set the read-only and the hidden flags. Clear archive flag.
  //
  Attr = FS_ModifyFileAttributes("Test.txt",
                                 FS_ATTR_READ_ONLY | FS_ATTR_HIDDEN,
                                 FS_ATTR_ARCHIVE);
  SEGGER_snprintf(ac, sizeof(ac), "Old file attributes: %c%c%c%c%c\n",
    (Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
    (Attr & FS_ATTR_HIDDEN)    ? 'H' : '-',
    (Attr & FS_ATTR_SYSTEM)    ? 'S' : '-',
    (Attr & FS_ATTR_ARCHIVE)   ? 'A' : '-',
    (Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
  FS_X_Log(ac);
  Attr = FS_GetFileAttributes("Test.txt");
  SEGGER_snprintf(ac, sizeof(ac), "New file attributes: %c%c%c%c%c\n",
    (Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
    (Attr & FS_ATTR_HIDDEN)    ? 'H' : '-',
    (Attr & FS_ATTR_SYSTEM)    ? 'S' : '-',
    (Attr & FS_ATTR_ARCHIVE)   ? 'A' : '-',
    (Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
  FS_X_Log(ac);
}

FS_Move()

Description

Moves a file or directory to another location.

Prototype

int FS_Move(const char * sNameSrc,
            const char * sNameDest);

Parameters

Parameter Description
sNameSrc Name of the source file or directory (partially qualified). It cannot be NULL.
sNameDest Name of the destination file or directory (partially qualified). It cannot be NULL.

Return value

= 0 OK, file or directory move successfully.
≠ 0 Error code indicating the failure reason.

Additional information

FS_Move() can be used to change the location of a file or directory in the directory tree of the file system.

If the source and the destination file are located on the same volume, then only the directory entry assigned to the moved file is relocated. Otherwise the contents of the file is copied to the destination volume and the source file is deleted.

The function is able to move entire directory trees when the source and destination are located on the same volume. Moving an entire directory tree on a different volume is not supported. This operation has to be performed in the application by iterating over the files and directories and by copying them one-by-one.

By default, the source files and directories that have the FS_ATTR_READ_ONLY attribute set and that are located on a volume formatted as FAT cannot be moved. This behavior can be changed by compiling the file system sources with FS_FAT_PERMIT_RO_FILE_MOVE configuration define to 1. FS_FAT_ConfigROFileMovePermission() can be used to change the behavior at runtime.

Source files and directories located on a EFS formatted volume can be moved even if they have the FS_ATTR_READ_ONLY attribute set.

The operation fails if the destination file or directory already exists.

FS_Move() preserves the timestamps of the moved file or directory.

Example

#include "FS.h"

void SampleMove(void) {
  //
  // File tree before the operation.
  //
  // <root>
  //   |
  //   +->SubDir2
  //        |
  //        +->SubDir3
  //
  FS_Move("SubDir1", "SubDir2\\SubDir3");
  //
  // File tree after the operation.
  //
  // <root>
  //   |
  //   +->SubDir1
  //   |
  //   +->SubDir2
  //
}

FS_Remove()

Description

Removes a file.

Prototype

int FS_Remove(const char * sFileName);

Parameters

Parameter Description
sFileName Name of the file to be removed.

Return value

= 0 OK, file has been removed.
≠ 0 Error code indicating the failure reason.

Additional information

The function removes also files that have the FS_ATTR_READ_ONLY attribute set. The remove operation fails if the file to be deleted is open.

Example

#include "FS.h"

void SampleRemove(void) {
  FS_Remove("Test.txt");
}

FS_Rename()

Description

Changes the name of a file or directory.

Prototype

int FS_Rename(const char * sNameOld,
              const char * sNameNew);

Parameters

Parameter Description
sNameOld Old file or directory name (including the path).
sNameNew New file or directory name (without path).

Return value

= 0 OK, file or directory has been renamed.
≠ 0 Error code indicating the failure reason.

Additional information

The function can rename either a file or a directory.

By default, the files and directories that have the FS_ATTR_READ_ONLY attribute set and that are located on a volume formatted as FAT cannot be renamed. This behavior can be changed by compiling the file system sources with the FS_FAT_PERMIT_RO_FILE_MOVE configuration define to 1. FS_FAT_ConfigROFileMovePermission() can be used to change the behavior at runtime.

Source files and directories located on a EFS formatted volume can be moved event if they have the FS_ATTR_READ_ONLY attribute set.

Example

#include "FS.h"

void SampleRename(void) {
  //
  // File tree before the operation.
  //
  // <root>
  //   |
  //   +->SubDir2
  //        |
  //        +->SubDir3
  //
  FS_Rename("SubDir2\\SubDir3", "SubDir1");
  //
  // File tree after the operation.
  //
  // <root>
  //   |
  //   +->SubDir1
  //        |
  //        +->SubDir3
  //
}

FS_SetFileAttributes()

Description

Modifies all the attributes of a file or directory.

Prototype

int FS_SetFileAttributes(const char * sName,
                               U8     AttrMask);

Parameters

Parameter Description
sName Pointer to a name of the file/directory.
AttrMask Bit mask of the attributes to be set.

Return value

= 0 OK, attributes have been set.
≠ 0 Error code indicating the failure reason.

Additional information

The FS_ATTR_DIRECTORY attribute cannot be modified using this function. The value of AttrMask parameter is an or-combination of the following attributes: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM, FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY. The attributes that are not set in AttrMask are set to 0.

Example

#include <stdio.h>
#include "FS.h"

void SampleFileAttributes(void) {
  U8   Attr;
  char ac[100];

  FS_SetFileAttributes("Test.txt", FS_ATTR_HIDDEN);
  Attr = FS_GetFileAttributes("Test.txt");
  SEGGER_snprintf(ac, sizeof(ac), "File attributes: %c%c%c%c%c\n",
    (Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
    (Attr & FS_ATTR_HIDDEN)    ? 'H' : '-',
    (Attr & FS_ATTR_SYSTEM)    ? 'S' : '-',
    (Attr & FS_ATTR_ARCHIVE)   ? 'A' : '-',
    (Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
  FS_X_Log(ac);
}

FS_SetFileBuffer()

Description

Assigns a file buffer to an opened file.

Prototype

int FS_SetFileBuffer(FS_FILE * pFile,
                     void    * pData,
                     I32       NumBytes,
                     int       Flags);

Parameters

Parameter Description
pFile Handle to opened file.
pData Pointer to the to memory area which should be used as buffer.
NumBytes Number of bytes in the buffer.
Flags Specifies the operating mode of the file buffer.

Return value

= 0 OK, buffer assigned.
≠ 0 Error code indicating the failure reason.

Additional information

This function can only be called immediately after the file is opened and before performing any operation on the file.

Flags is a bitwise-or combination of File buffer flags. If Flags is set to 0 then the file buffer caches only the data read from the file.

If the file buffer is configured in write mode the data of any operation that writes less bytes at once than the size of the file buffer is stored to file buffer. The contents of the file buffer is written to file in the following cases:

In case of a read operation if the data is not present in the file buffer the file system fills the entire file buffer with the data from file.

FS_SetFileBuffer() reports an error if the file system is configured to automatically allocate a file buffer for each file it opens via FS_ConfigFileBufferDefault().

The data required to manage the file buffer is allocated from pData. The FS_SIZEOF_FILE_BUFFER() define can be used to calculate the amount of RAM required to store a specified number of data bytes in the file buffer.

If the file is opened and closed in the same function the file buffer can be allocated locally on the stack. Otherwise the buffer has to be globally allocated. After the file is closed the memory allocated for the file buffer is no longer accessed by the file system and can be safely deallocated or used to store other data.

FS_SetFileBuffer() is available only if the file system is built with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

Example

#include "FS.h"

void SampleSetFileBuffer(void) {
  FS_FILE * pFile;
  U32       aBuffer[FS_SIZEOF_FILE_BUFFER(512) / 4];

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    //
    // Set the file buffer for read and write operation.
    // The file buffer is allocated on the stack since the file
    // is closed before the function returns.
    //
    FS_SetFileBuffer(pFile, aBuffer, sizeof(aBuffer), FS_FILE_BUFFER_WRITE);
    //
    // Data is written to file buffer.
    //
    FS_Write(pFile, "Test", 4);
    //
    // Write the data from file buffer to storage and close the file.
    //
    FS_FClose(pFile);
  }
}

FS_SetFileTime()

Description

Sets the creation time of a file or directory.

Prototype

int FS_SetFileTime(const char * sName,
                         U32    TimeStamp);

Parameters

Parameter Description
sName File or directory name.
TimeStamp The value of the timestamp to be set.

Return value

= 0 OK, timestamp modified.
≠ 0 Error code indicating the failure reason.

Additional information

Refer to FS_GetFileTime() for a description of the timestamp format. FS_FileTimeToTimeStamp() can be used to convert a FS_FILETIME structure to a timestamp that can be used in a call to FS_SetFileTime().

This function is optional. The file system updates automatically the timestamps of file or directories.

Example

#include "FS.h"

void SampleSetFileTime(void) {
  U32         TimeStamp;
  FS_FILETIME FileTime;

  FileTime.Year   = 2005;
  FileTime.Month  = 03;
  FileTime.Day    = 26;
  FileTime.Hour   = 10;
  FileTime.Minute = 56;
  FileTime.Second = 14;
  FS_FileTimeToTimeStamp (&FileTime, &TimeStamp);
  FS_SetFileTime("Test.txt", TimeStamp);
}

FS_SetFileTimeEx()

Description

Sets the timestamp of a file or directory.

Prototype

int FS_SetFileTimeEx(const char * sName,
                           U32    TimeStamp,
                           int    TimeType);

Parameters

Parameter Description
sName File or directory name.
TimeStamp The value of the timestamp to be set.
TimeType Type of timestamp to be modified. It can take of the following values: FS_FILETIME_CREATE FS_FILETIME_ACCESS FS_FILETIME_MODIFY

Return value

= 0 OK, timestamp modified.
≠ 0 Error code indicating the failure reason.

Additional information

Refer to FS_GetFileTime() for a description of the timestamp format. FS_FileTimeToTimeStamp() can be used to convert a FS_FILETIME structure to a timestamp that can be used in a call to FS_SetFileTimeEx().

EFS maintains only one filestamp therefore the TimeType parameter is ignored for files and directories stored on an EFS volume.

This function is optional. The file system updates automatically the timestamps of file or directories.

Example

#include "FS.h"

void SampleSetFileTime(void) {
  U32         TimeStamp;
  FS_FILETIME FileTime;

  FileTime.Year   = 2017;
  FileTime.Month  = 07;
  FileTime.Day    = 07;
  FileTime.Hour   = 14;
  FileTime.Minute = 48;
  FileTime.Second = 14;
  FS_FileTimeToTimeStamp(&FileTime, &TimeStamp);
  //
  // Set the access time of the file.
  //
  FS_SetFileTimeEx("Test.txt", TimeStamp, FS_FILETIME_ACCESS);
}

FS_UnsetFileBuffer()

Description

Frees the file buffer assigned to specified file.

Prototype

int FS_UnsetFileBuffer(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

= 0 OK, file buffer freed successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function can only be called immediately after the file is opened and before performing any operation on the file. An error is returned if an attempt is made to unset a file buffer allocated by the file system with FS_SUPPORT_FILE_BUFFER_LIST set to 0.

FS_UnsetFileBuffer() is available only if the file system is built with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.

This function does not perform any access to the storage device.

Example

#include "FS.h"

void SampleUnsetFileBuffer(void) {
  FS_FILE * pFile;
  int       r;
  U8        abData[4];

  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != 0) {
    if (FS_IsFileBufferSet(pFile)) {
      FS_UnsetFileBuffer(pFile);
    }
    //
    // The following write operation is performed 
    // without a file buffer.
    //
    memset(abData, 0, sizeof(abData));
    FS_Write(pFile, abData, sizeof(abData));
    FS_FClose(pFile);
  }
}

FS_WipeFile()

Description

Overwrites the contents of a file with random data.

Prototype

int FS_WipeFile(const char * sFileName);

Parameters

Parameter Description
sFileName Name of the file to overwrite.

Return value

= 0 Contents of the file overwritten.
≠ 0 Error code indicating the failure reason.

Additional information

When a file is removed, the file system marks the corresponding directory entry and the clusters in the allocation table as free. The contents of the file is not modified and it can be in theory restored by using a disk recovery tool. This can be a problem if the file stores sensitive data. Calling FS_WipeFile() before the file is removed makes the recovery of data impossible.

This function allocates FS_BUFFER_SIZE_FILE_WIPE bytes on the stack.

Example

#include "FS.h"

void SampleWipeFile(void) {
  FS_FILE * pFile;

  //
  // Create a file and write data to it.
  //
  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    FS_Write(pFile, "12345", 5);
    FS_FClose(pFile);
  }
  //
  // Overwrite the file contents with random data.
  //
  FS_WipeFile("Test.txt");
  //
  // Delete the file from storage medium.
  //
  FS_Remove("Test.txt");
}

File attributes

Description

Attributes of files and directories.

Definition

#define FS_ATTR_READ_ONLY    0x01u
#define FS_ATTR_HIDDEN       0x02u
#define FS_ATTR_SYSTEM       0x04u
#define FS_ATTR_ARCHIVE      0x20u
#define FS_ATTR_DIRECTORY    0x10u

Symbols

Definition Description
FS_ATTR_READ_ONLY The file is read-only. Applications can read the file but cannot write to it.
FS_ATTR_HIDDEN The file or directory is marked as hidden. Most of operating systems do not include these files in an ordinary directory listing. This flag is not evaluated by emFile.
FS_ATTR_SYSTEM The file or directory is part of, or is used exclusively by, the operating system. This flag is not evaluated by emFile.
FS_ATTR_ARCHIVE The file or directory is an archive file or directory. Applications can use this attribute to mark files for backup or removal. This flag is not evaluated by emFile.
FS_ATTR_DIRECTORY The file is actually a directory.

File buffer flags

Description

File buffer operating options.

Definition

#define FS_FILE_BUFFER_WRITE      (1uL << 0)
#define FS_FILE_BUFFER_ALIGNED    (1uL << 1)

Symbols

Definition Description
FS_FILE_BUFFER_WRITE Data written to file is cached.
FS_FILE_BUFFER_ALIGNED Cached data is kept aligned to logical sector boundary.

Additional information

A file buffer always caches the data read from the file. This operating mode is always enabled and cannot be disabled.

File buffer size

Description

Calculates the file buffer size.

Definition

#define FS_SIZEOF_FILE_BUFFER(NumBytes)    (FS_SIZEOF_FILE_BUFFER_STRUCT + (NumBytes))

Symbols

Definition Description
FS_SIZEOF_FILE_BUFFER(NumBytes) Calculates the file buffer size.

Additional information

This define can be used in an application to calculate the number of bytes that have to be allocated in order to store the specified number of bytes in the file buffer. NumBytes is typically a multiple of logical sector size.

FS_FILE_BUFFER_INFO

Description

Information about a file buffer.

Type definition

typedef struct {
  U32  BufferSize;
  U8   Flags;
  U8   IsExternal;
} FS_FILE_BUFFER_INFO;

Structure members

Member Description
BufferSize Maximum number of bytes that can be stored in the file buffer.
Flags Operating mode of the file buffer.
IsExternal Specifies where the file buffer was allocated.

Additional information

The Flags member is a bitwise-or combination of File buffer flags

The IsExternal member is set to 1 if the file buffer is provided by the application via FS_SetFileBuffer(). If the file buffer is allocated by the file system then IsExternal is set to 0.

FS_FILE_INFO

Description

Information about a file or directory.

Type definition

typedef struct {
  U8   Attributes;
  U32  CreationTime;
  U32  LastAccessTime;
  U32  LastWriteTime;
  U32  FileSize;
} FS_FILE_INFO;

Structure members

Member Description
Attributes File or directory attributes.
CreationTime Date and time when the file was created.
LastAccessTime Date and time when the file was accessed last.
LastWriteTime Date and time when the file was written to last.
FileSize Size of the file in bytes.

Additional information

The Attributes member is an bitwise-or combination of the following flags: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM, FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.

The FileSize member is always set to 0 for directories located on FAT and EFS volumes.

FS_FILE_INFO64

Description

Information about a file or directory.

Type definition

typedef struct {
  U8            Attributes;
  FS_TIMESTAMP  CreationTime;
  FS_TIMESTAMP  LastAccessTime;
  FS_TIMESTAMP  LastWriteTime;
  U64           FileSize;
} FS_FILE_INFO64;

Structure members

Member Description
Attributes File or directory attributes.
CreationTime Date and time when the file was created.
LastAccessTime Date and time when the file was accessed last.
LastWriteTime Date and time when the file was written to last.
FileSize Size of the file in bytes.

Additional information

The Attributes member is an bitwise-or combination of the following flags: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM, FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.

The FileSize member is always set to 0 for directories located on FAT and EFS volumes.

This structure can store the size of a file that is greater than or equal to 4GB.

File time types

Description

Types of timestamps available for a file or directory.

Definition

#define FS_FILETIME_CREATE    0
#define FS_FILETIME_ACCESS    1
#define FS_FILETIME_MODIFY    2

Symbols

Definition Description
FS_FILETIME_CREATE Date and time when the file or directory was created.
FS_FILETIME_ACCESS Date and time of the last read access to file or directory.
FS_FILETIME_MODIFY Date and time of the last write access to file or directory.

Directory functions

This section describes functions that operate on directories. API functions are provided for creating, deleting and listing directories.

FS_CopyDir()

Description

Copies a directory and its contents to a different location.

Prototype

int FS_CopyDir(const char * sDirNameSrc,
               const char * sDirNameDest,
                     int    MaxRecursionLevel);

Parameters

Parameter Description
sDirNameSrc Name of the source directory (0-terminated string).
sDirNameDest Name of the destination directory (0-terminated string).
MaxRecursionLevel Maximum depth of the directory tree.

Return value

= 0 OK, directory copied successfully.
≠ 0 Error code indicating the failure reason.

Additional information

The function uses recursion to process the directory tree and it requires about 100 bytes of stack for each directory level it processes. The MaxRecursionLevel parameter can be used to prevent a stack overflow if the directory tree is too deep.

This function allocates on the stack two buffers of FS_MAX_PATH bytes and one buffer of FS_BUFFER_SIZE_FILE_COPY bytes.

Following are some examples of the values that can be passed to MaxRecursionLevel.

If present, the destination directory including its contents is removed before the copy operation. The destination directory is created if missing.

Example

#include "FS.h"

void SampleCopyDir(void) {
  FS_CopyDir("SubDir", "CopyDir", 5);
}

FS_CreateDir()

Description

Creates a directory including any missing directories in the path.

Prototype

int FS_CreateDir(const char * sDirName);

Parameters

Parameter Description
sDirName Directory name.

Return value

= 0 Directory path has been created.
= 1 Directory path already exists.
< 0 Error code indicating the failure reason.

Additional information

The function creates automatically any subdirectories that are specified in the path but do not exist on the storage.

FS_CreateDir() uses a work buffer of FS_MAX_PATH bytes that is allocated on the stack. This buffer is used for parsing the path to the created directory.

Example

#include "FS.h"

void SampleCreateDir(void) {
  //
  // File tree before the operation.
  //
  // <root>
  //   |
  //   +->SubDir1
  //
  FS_CreateDir("SubDir1\\SubDir2\\SubDir3");
  //
  // File tree after the operation.
  //
  // <root>
  //   |
  //   +->SubDir1
  //        |
  //        +->SubDir2
  //             |
  //             +->SubDir3
  //
}

FS_DeleteDir()

Description

Removes a directory and its contents.

Prototype

int FS_DeleteDir(const char * sDirName,
                       int    MaxRecursionLevel);

Parameters

Parameter Description
sDirName Directory name.
MaxRecursionLevel Maximum depth of the directory tree.

Return value

= 0 OK, directory has been removed
≠ 0 Error code indicating the failure reason

Additional information

The function uses recursion to process the directory tree and it requires about 100 bytes of stack for each directory level it processes. The MaxRecursionLevel parameter can be used to prevent a stack overflow if the directory tree is too deep.

Following are some examples of the values that can be passed to MaxRecursionLevel.

Example

#include "FS.h"

void SampleDeleteDir(void) {
  //
  // File tree before the operation.
  //
  // <root>
  //   |
  //   +->SubDir1
  //   |
  //   +->SubDir2
  //        |
  //        +->File1.txt
  //        |
  //        +->File2.txt
  //
  FS_DeleteDir("SubDir2", 1);
  //
  // File tree after the operation.
  //
  // <root>
  //   |
  //   +->SubDir1
  //
}

FS_FindClose()

Description

Ends a directory scanning operation.

Prototype

void FS_FindClose(FS_FIND_DATA * pFD);

Parameters

Parameter Description
pFD Context of the directory scanning operation.

Additional information

This function has to be called at the end of the directory scanning operation to clear the used context. After calling this function the same context can be used for a different directory scanning operation.

Example

#include "FS.h"

void SampleFindClose(void) {
  FS_FIND_DATA fd;
  int          r;
  char         acFileName[32];

  //
  // List the files from the root directory.
  //
  r = FS_FindFirstFile(&fd, "", acFileName, sizeof(acFileName));
  if (r == 0) {
    do {
      //
      // Process file or directory...
      //
    } while (FS_FindNextFile(&fd));
  }
  FS_FindClose(&fd);
  //
  // List the files from the "SubDir1" directory.
  //
  r = FS_FindFirstFile(&fd, "SubDir1", acFileName, sizeof(acFileName));
  if (r == 0) {
    do {
      //
      // Process file or directory...
      //
    } while (FS_FindNextFile(&fd));
  }
  FS_FindClose(&fd);
}

FS_FindClose64()

Description

Ends a directory scanning operation.

Prototype

int FS_FindClose64(FS_FIND_DATA64 * pFD);

Parameters

Parameter Description
pFD Context of the directory scanning operation.

Return value

= 0 OK, directory scanning closed successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function has to be called at the end of the directory scanning operation to clear the used context. After calling this function the same context can be used for a different directory scanning operation.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include "FS.h"

void SampleFindClose64(void) {
  FS_FIND_DATA64 fd;
  int            r;
  char           acFileName[32];

  //
  // List the files from the root directory.
  //
  r = FS_FindFirstFile64(&fd, "", acFileName, sizeof(acFileName));
  if (r == 0) {
    for (;;) {
      //
      // Process file or directory...
      //
      r = FS_FindNextFile64(&fd);
      if (r != 0) {
        break;
      }
    }
  }
  (void)FS_FindClose64(&fd);
  //
  // List the files from the "SubDir1" directory.
  //
  r = FS_FindFirstFile64(&fd, "SubDir1", acFileName, sizeof(acFileName));
  if (r == 0) {
    for (;;) {
      //
      // Process file or directory...
      //
      r = FS_FindNextFile64(&fd);
      if (r != 0) {
        break;
      }
    }
  }
  (void)FS_FindClose64(&fd);
}

FS_FindFirstFile()

Description

Initiates a directory scanning operation.

Prototype

int FS_FindFirstFile(      FS_FIND_DATA * pFD,
                     const char         * sDirName,
                           char         * sFileName,
                           int            SizeOfFileName);

Parameters

Parameter Description
pFD Context of the directory scanning operation.
sDirName Name of the directory to search in.
sFileName Buffer that receives the name of the file found.
SizeOfFileName Size in bytes of the sFileName buffer.

Return value

= 0 OK, directory scanning initialized successfully.
= 1 No files or directories available in directory.
< 0 Error code indicating the failure reason.

Additional information

This function returns information about the first file or directory found in the directory. This is typically the special directory name “.” when searching in a directory other than root. FS_FindFirstFile() and FS_FindNextFile() can be used to list all the files and directories in a directory.

The name of the file or directory is returned in sFileName. FS_FindFirstFile() stores at most SizeOfFileName - 1 characters in the buffer and it terminates the name of file or directory by a 0 character. The file or directory name is truncated if it contains more characters than the number of characters that can be stored in sFileName. For files or directories stored on a FAT volume with LFN support the name is truncated by returning the short version (8.3 format) of the file or directory name.

Alternatively, the file name can be accessed via the sFileName member of the pFD structure. Additional information about the file or directory such as size, attributes and timestamps are returned via the corresponding members of pFD structure. For more information refer to FS_FIND_DATA.

The returned file or directory does not necessarily be the first file or directory created in the root directory. The name of the first file or directory can change as files are deleted and created in the root directory.

The file system is able to handle a sFileName buffer with a maximum size of 32767 bytes.

Example

#include <stdio.h>
#include "FS.h"

void SampleFindFirstFile(void) {
  FS_FIND_DATA fd;
  int          r;
  char         acFileName[32];
  char         ac[100];
  FS_FILETIME  FileTime;

  //
  // List the files from the "SubDir1" directory.
  //
  r = FS_FindFirstFile(&fd, "SubDir1", acFileName, sizeof(acFileName));
  if (r == 0) {
    do {
      //
      // Ignore "." and ".." entries.
      //
      if (fd.sFileName[0] == '.') {
        continue;
      }
      //
      // Show information about the file.
      //
      if (fd.Attributes & FS_ATTR_DIRECTORY) {
        SEGGER_snprintf(ac, sizeof(ac), "Directory name: %s\n", fd.sFileName);
      } else {
        SEGGER_snprintf(ac, sizeof(ac), "File name:      %s\n", fd.sFileName);
      }
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "File size:      %lu\n", fd.FileSize);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "Attributes:     %c%c%c%c%c\n",
        (fd.Attributes & FS_ATTR_READ_ONLY) ? 'R' : '-',
        (fd.Attributes & FS_ATTR_HIDDEN)    ? 'H' : '-',
        (fd.Attributes & FS_ATTR_SYSTEM)    ? 'S' : '-',
        (fd.Attributes & FS_ATTR_ARCHIVE)   ? 'A' : '-',
        (fd.Attributes & FS_ATTR_DIRECTORY) ? 'D' : '-');
      FS_X_Log(ac);
      FS_TimeStampToFileTime(fd.CreationTime, &FileTime);
      SEGGER_snprintf(ac, sizeof(ac), "Creation time:  %d-%.2d-%.2d %.2d:%.2d:%.2d",
        FileTime.Year, FileTime.Month,  FileTime.Day,
        FileTime.Hour, FileTime.Minute, FileTime.Second);
      FS_X_Log(ac);
      FS_TimeStampToFileTime(fd.LastAccessTime, &FileTime);
      SEGGER_snprintf(ac, sizeof(ac), "Access time:    %d-%.2d-%.2d %.2d:%.2d:%.2d",
        FileTime.Year, FileTime.Month,  FileTime.Day,
        FileTime.Hour, FileTime.Minute, FileTime.Second);
      FS_X_Log(ac);
      FS_TimeStampToFileTime(fd.LastWriteTime, &FileTime);
      SEGGER_snprintf(ac, sizeof(ac), "Write time:     %d-%.2d-%.2d %.2d:%.2d:%.2d",
        FileTime.Year, FileTime.Month,  FileTime.Day,
        FileTime.Hour, FileTime.Minute, FileTime.Second);
      FS_X_Log(ac);
      FS_X_Log("--\n");
    } while (FS_FindNextFile(&fd));
  }
  FS_FindClose(&fd);
}

FS_FindFirstFile64()

Description

Initiates a directory scanning operation.

Prototype

int FS_FindFirstFile64(      FS_FIND_DATA64 * pFD,
                       const char           * sDirName,
                             char           * sFileName,
                             int              SizeOfFileName);

Parameters

Parameter Description
pFD Context of the directory scanning operation.
sDirName Name of the directory to search in.
sFileName Buffer that receives the name of the file found.
SizeOfFileName Size in bytes of the sFileName buffer.

Return value

= 1 OK, no files or directories available in directory.
= 0 OK, directory scanning initialized successfully.
< 0 Error code indicating the failure reason.

Additional information

This function returns information about the first file or directory found in the directory. This is typically the special directory name “.” when searching in a directory other than root. FS_FindFirstFile64() and FS_FindNextFile64() can be used to list all the files and directories that are located in a specified directory.

The name of the file or directory is returned via sFileName. FS_FindFirstFile64() stores at most SizeOfFileName - 1 characters in the buffer and it terminates the name of file or directory by a 0-character. The file or directory name is truncated if it contains more characters than the number of characters that can be stored in sFileName. For files or directories stored on a FAT volume with LFN support the name is truncated by returning the short version (8.3 format) of the file or directory name.

Alternatively, the file name can be accessed via the sFileName member of the pFD structure. Additional information about the file or directory such as size, attributes and timestamps are returned via the corresponding members of pFD structure. For more information refer to FS_FIND_DATA.

If the file name is truncated then value of the FileNameLen member of the pFD structure is greater than the length of the 0-terminated string stored in the sFileName member of the same structure.

The returned file or directory does not necessarily be the first file or directory created in the root directory. The name of the first file or directory can change as files are deleted and created in the root directory.

The file system is able to handle a sFileName buffer with a maximum size of 32767 bytes.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

#include <stdio.h>
#include "FS.h"

void SampleFindFirstFile64(void) {
  FS_FIND_DATA64 fd;
  int            r;
  char           acFileName[32];
  char           ac[100];
  FS_FILETIME    FileTime;

  //
  // List the files from the "SubDir1" directory.
  //
  r = FS_FindFirstFile64(&fd, "SubDir1", acFileName, sizeof(acFileName));
  if (r == 0) {
    for (;;) {
      //
      // Skip over system directory entries.
      //
      if ((fd.sFileName[0] == '.') && (fd.sFileName[1] == '\0')) {
        continue;
      }
      if ((fd.sFileName[0] == '.') && (fd.sFileName[1] == '.') && (fd.sFileName[2] == '\0')) {
        continue;
      }
      //
      // Show information about the file.
      //
      if (fd.Attributes & FS_ATTR_DIRECTORY) {
        SEGGER_snprintf(ac, sizeof(ac), "Directory name: %s\n", fd.sFileName);
      } else {
        SEGGER_snprintf(ac, sizeof(ac), "File name:      %s\n", fd.sFileName);
      }
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "File size:      %lu\n", fd.FileSize);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "Attributes:     %c%c%c%c%c\n",
        (fd.Attributes & FS_ATTR_READ_ONLY) ? 'R' : '-',
        (fd.Attributes & FS_ATTR_HIDDEN)    ? 'H' : '-',
        (fd.Attributes & FS_ATTR_SYSTEM)    ? 'S' : '-',
        (fd.Attributes & FS_ATTR_ARCHIVE)   ? 'A' : '-',
        (fd.Attributes & FS_ATTR_DIRECTORY) ? 'D' : '-');
      FS_X_Log(ac);
      FS_TimeStampToFileTime(fd.CreationTime.TimeDate, &FileTime);
      SEGGER_snprintf(ac, sizeof(ac), "Creation time:  %d-%.2d-%.2d %.2d:%.2d:%.2d",
        FileTime.Year, FileTime.Month,  FileTime.Day,
        FileTime.Hour, FileTime.Minute, FileTime.Second);
      FS_X_Log(ac);
      FS_TimeStampToFileTime(fd.LastAccessTime.TimeDate, &FileTime);
      SEGGER_snprintf(ac, sizeof(ac), "Access time:    %d-%.2d-%.2d %.2d:%.2d:%.2d",
        FileTime.Year, FileTime.Month,  FileTime.Day,
        FileTime.Hour, FileTime.Minute, FileTime.Second);
      FS_X_Log(ac);
      FS_TimeStampToFileTime(fd.LastWriteTime.TimeDate, &FileTime);
      SEGGER_snprintf(ac, sizeof(ac), "Write time:     %d-%.2d-%.2d %.2d:%.2d:%.2d",
        FileTime.Year, FileTime.Month,  FileTime.Day,
        FileTime.Hour, FileTime.Minute, FileTime.Second);
      FS_X_Log(ac);
      FS_X_Log("--\n");
      r = FS_FindNextFile64(&fd);
      if (r != 0) {
        break;
      }
    }
  }
  (void)FS_FindClose64(&fd);
}

FS_FindNextFile()

Description

Returns information about the next file or directory in a directory scanning operation.

Prototype

int FS_FindNextFile(FS_FIND_DATA * pFD);

Parameters

Parameter Description
pFD Context of the directory scanning operation.

Return value

1 OK, information returned successfully.
0 Error occurred or end of directory reached.

Additional information

FS_FindNextFile() returns information about the next file or directory located after the file or directory returned via a previous call to FS_FindFirstFile() or FS_FindNextFile() within the same listing context.

The name of the file or directory is returned in sFileName member of pFD. FS_FindNextFile() stores at most one less than the buffer size characters in the buffer and it terminates the name of the file or directory by a 0 character. The buffer for the file or directory name is specified in the call to FS_FindFirstFile(). The file or directory name is truncated if it contains more characters than the number of characters that can be stored in sFileName. For files or directories stored on a FAT volume with LFN support the name is truncated by returning the short version (8.3 format) of the file or directory name.

Additional information about the file or directory such as size, attributes and timestamps are returned via the corresponding members of pFD structure. For more information refer to FS_FIND_DATA.

FS_FindFirstFile() has to be called first to initialize the listing operation. It is allowed to perform operations on files or directories (creation, deletion, etc.) within the listing loop.

Example

Refer to the example of FS_FindFirstFile()

FS_FindNextFileEx()

Description

Returns information about the next file or directory in a directory scanning operation.

Prototype

int FS_FindNextFileEx(FS_FIND_DATA * pFD);

Parameters

Parameter Description
pFD Context of the directory scanning operation.

Return value

= 1 No files or directories available in directory.
= 0 OK, information returned successfully.
< 0 Error code indicating the failure reason.

Additional information

FS_FindNextFileEx() performs the same operation as FS_FindNextFile() with the difference that its return value is consistent with the return value of the other emFile API functions.

FS_FindNextFile64()

Description

Returns information about the next file or directory in a directory scanning operation.

Prototype

int FS_FindNextFile64(FS_FIND_DATA64 * pFD);

Parameters

Parameter Description
pFD Context of the directory scanning operation.

Return value

= 1 OK, no files or directories available in directory.
= 0 OK, information returned successfully.
< 0 Error code indicating the failure reason.

Additional information

This function can be called only after an initial call to the FS_FindFirstFile64() with the same directory scanning context.

This function is available only when the file system is built with FS_SUPPORT_LARGE_FILES set to 1.

Example

Refer to the example of FS_FindFirstFile64()

FS_MkDir()

Description

Creates a directory.

Prototype

int FS_MkDir(const char * sDirName);

Parameters

Parameter Description
sDirName Directory name.

Return value

= 0 OK, directory has been created
≠ 0 Error code indicating the failure reason

Additional information

The function fails if a directory with the same name already exists in the target directory. FS_MkDir() expects that all the directories in the path to the created directory exists. Otherwise the function returns with an error. FS_CreateDir() can be used to create a directory along with any missing directories in the path.

Example

#include "FS.h"

void SampleMkDir(void) {
  FS_MkDir("SubDir1");
}

FS_RmDir()

Description

Removes a directory.

Prototype

int FS_RmDir(const char * sDirName);

Parameters

Parameter Description
sDirName Directory name.

Return value

= 0 OK, directory has been removed
≠ 0 Error code indicating the failure reason

Additional information

The function fails if the directory is not empty. FS_DeleteDir() can be used to remove a directory and its contents.

Example

#include "FS.h"

void SampleRmDir(void) {
  FS_RmDir("SubDir1");
}

FS_FIND_DATA

Description

Information about a file or directory.

Type definition

typedef struct {
  U8      Attributes;
  U32     CreationTime;
  U32     LastAccessTime;
  U32     LastWriteTime;
  U32     FileSize;
  char  * sFileName;
  U16     SizeofFileName;
  FS_DIR  Dir;
} FS_FIND_DATA;

Structure members

Member Description
Attributes Attributes of the file or directory.
CreationTime Date and time when the file or directory was created.
LastAccessTime Date and time when the file or directory was accessed last.
LastWriteTime Date and time when the file or directory was modified last.
FileSize Size of the file in bytes.
sFileName Name of the file or directory as 0-terminated string.
SizeofFileName Internal. Not to be used by the application.
Dir Internal. Not to be used by the application.

Additional information

sFileName points to the buffer passed as argument to FS_FindFirstFile().

This structure contains also the context for the file listing operation. These members are considered internal and should not be used by the application. FS_FIND_DATA is used as context by the FS_FindFirstFile(), FS_FindNextFile(), FS_FindNextFileEx() and FS_FindClose() set of functions.

FS_FIND_DATA64

Description

Information about a file or directory.

Type definition

typedef struct {
  U8            Attributes;
  FS_TIMESTAMP  CreationTime;
  FS_TIMESTAMP  LastAccessTime;
  FS_TIMESTAMP  LastWriteTime;
  U64           FileSize;
  char        * sFileName;
  U16           FileNameLen;
  U16           SizeOfFileName;
  FS_DIR        Dir;
} FS_FIND_DATA64;

Structure members

Member Description
Attributes Attributes of the file or directory.
CreationTime Date and time when the file or directory was created.
LastAccessTime Date and time when the file or directory was accessed last.
LastWriteTime Date and time when the file or directory was modified last.
FileSize Size of the file in bytes.
sFileName Name of the file or directory as 0-terminated string.
FileNameLen Actual length of the file name in bytes.
SizeOfFileName Internal. Not to be used by the application.
Dir Internal. Not to be used by the application.

Additional information

sFileName points to the buffer passed as argument to FS_FindFirstFile64().

This structure contains also the context for the file listing operation. These members are considered internal and should not be used by the application. FS_FIND_DATA64 is used as context by the FS_FindFirstFile64(), FS_FindNextFile64() and FS_FindClose64() set of functions.

If FileNameLen is greater than the length of the 0-terminated string stored to sFileName then the file name was truncated.

Formatting functions

A storage device has to be formatted before it can be used to write data to it. SD and MMC memory cards as well as USB drives are usually already preformatted. Normally, the NAND and NOR flash devices have to be reformatted. These storage devices require a low-level format first, followed by a high-level format. The low-level format is device-specific while the high-level format depends on the type of file system.

FS_Format()

Description

Performs a high-level format.

Prototype

int FS_Format(const char           * sVolumeName,
              const FS_FORMAT_INFO * pFormatInfo);

Parameters

Parameter Description
sVolumeName Volume name.
pFormatInfo  in  Additional format information. It can be set to NULL.

Return value

= 0 OK, storage device formatted successfully.
≠ 0 Error code indicating the failure reason.

Additional information

The high-level format operation prepares a storage device for the access via the file system. It has to be performed once before writing any data to the storage device.

The term “high-level” indicates that the format operation is performed at the file system level in comparison with a low-level format operation that is performed at the device driver level that is located below the file system level in the file system stack. A low-level format operation can be performed via FS_FormatLow().

The high-level format operation writes to the storage device basic management information that is required by the file system to operate correctly. This includes the initialization of the allocation table and of the root directory, as well as of the BIOS Parameter Block (BPB) for a volume formatted as FAT and of the Information Sector for a volume formatted as EFS. The amount of data written during the high-level format operation is typically smaller than 1 percent of the capacity of the storage device.

The type of file system can be selected at compile time via FS_SUPPORT_FAT and FS_SUPPORT_EFS defines. If both file systems are enabled at compile time the type of file system can be configured via FS_SetFSType().

pFormatInfo can be used to specify how the storage device has to be formatted such as the cluster size and the number of entries in the root directory. For a typical application, this parameter can safely be set to NULL. If set to NULL, the file system uses reasonable format parameters that are calculated based on the capacity of the storage device.

For increased performance it is recommended to format the storage device with clusters as large as possible. In this way the number of accesses to the allocation table the file system has to perform during a read or write operation is kept to a minimum. For more information about format parameters see FS_FORMAT_INFO.

After performing a high-level format operation all the files and directory that were present on the storage device are lost.

An application can check if a storage device is high-level formatted by calling FS_IsHLFormatted().

Example

#include <string.h>
#include "FS.h"

void SampleFormat(void) {
  FS_FORMAT_INFO FormatInfo;
  //
  // Format default volume using reasonable defaults.
  //
  FS_Format("", NULL);
  //
  // Format the "mmc:0:" volume using 32 Kbyte clusters
  // assuming that the size of the logical sector used
  // by the storage device is 512 bytes.
  //
  memset(&FormatInfo, 0, sizeof(FormatInfo));
  FormatInfo.SectorsPerCluster = 64;
  FS_Format("mmc:0:", &FormatInfo);
}

FS_FormatLLIfRequired()

Description

Performs a low-level format.

Prototype

int FS_FormatLLIfRequired(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be formatted.

Return value

= 0 OK, low-level format successful.
= 1 Low-level format not required.
< 0 Error code indicating the failure reason.

Additional information

This function performs a low-level format of a storage device if it is not already low-level formatted. FS_FormatLLIfRequired() does nothing if the storage device is already low-level formatted. A storage device has to be low-level formatted once before the file system can perform any data access. All the data present on the storage device is lost after a low-level format.

The low-level format operation is required only for the storage devices that are managed by the file system such as NAND and NOR flash devices. SD cards and e.MMC devices do not require a low-level format.

Example

#include "FS.h"

void SampleFormatLLIfRequired(void) {
  FS_Init();
  //
  // Perform a low-level format if required.
  // Equivalent to the following sequence:
  //
  // if (FS_IsLLFormatted("nand:0:") == 0) {
  //   FS_FormatLow("nand:0:");
  // }
  //
  FS_FormatLLIfRequired("nand:0:");
}

FS_FormatLow()

Description

Performs a low-level format.

Prototype

int FS_FormatLow(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be formatted.

Return value

= 0 OK, low-level format successful.
≠ 0 Error code indicating the failure reason.

Additional information

The low-level format operation prepares a storage device for the data access. It has to be performed once before writing any data to the storage device.

This operation is performed by the device driver that is used to access the storage device. The low-level format operation has to be performed only for a storage device that is managed by the file system such as NAND and NOR flash. SD cards and eMMC devices do not support and do not require a low-level format.

The term “low-level” indicates that the format operation is performed at the device driver level in comparison with a high-level format operation that is performed at the file system level that is located above the device driver level in the file system stack. A high-level format operation can be performed either via FS_Format() or FS_FAT_FormatSD().

The low-level format operation writes to the storage device basic management information that is required by the device driver to operate correctly. A typical low-level format operation erases all the blocks in the partition that is used as storage and then stores format information in the first block of the partition.

The file system reports an error if an attempt is made to access a storage device that is not low-level formatted. The application can check if a storage device is low-level formatted by calling FS_IsLLFormatted().

All the data present on the storage device is lost after a low-level format.

Typically, a low-level format operation has to be followed by a high-level format operation if a file system is used for accessing the storage device. If the storage device is accessed only via the functions of the storage layer such as when the contents of the storage device is exposed via USB Mass Storage then a high-level format operation is not required.

Example

#include "FS.h"

void SampleFormatLow(void) {
  FS_Init();
  //
  // Performs a low-level format of the NOR flash.
  //
  FS_FormatLow("nor:0:");
}

FS_IsHLFormatted()

Description

Checks if a volume is high-level formatted or not.

Prototype

int FS_IsHLFormatted(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be checked.

Return value

= 1 Volume is formatted.
= 0 Volume is not formatted.
< 0 Error code indicating the failure reason.

Additional information

This function can be use to determine if the format of a volume is supported by the file system. If the volume format is unknown the function returns 0.

Example

#include "FS.h"

void SampleIsHLFormatted(void) {
  FS_Init();
  //
  // Perform a high-level format if required.
  //
  if (FS_IsHLFormatted("") == 0) {
    FS_Format("", NULL);
  }
}

FS_IsLLFormatted()

Description

Returns whether a volume is low-level formatted or not.

Prototype

int FS_IsLLFormatted(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be checked. It cannot be NULL.

Return value

= 1 Volume is low-level formatted
= 0 Volume is not low-level formatted
< 0 Error code indicating the failure reason

Example

#include "FS.h"

void SampleIsLLFormatted(void) {
  FS_Init();
  //
  // Perform a low-level format if required.
  // Equivalent to the following sequence:
  //
  // FS_FormatLLIfRequired("nor:0:");
  //
  if (FS_IsLLFormatted("nor:0:") == 0) {
    FS_FormatLow("nor:0:");
  }
}

FS_FORMAT_INFO

Description

Parameters for the high-level format.

Type definition

typedef struct {
  U16           SectorsPerCluster;
  U16           NumRootDirEntries;
  FS_DEV_INFO * pDevInfo;
  U8            Flags;
  U16           SectorsPerClusterHigh;
} FS_FORMAT_INFO;

Structure members

Member Description
SectorsPerCluster Number of sectors in a cluster.
NumRootDirEntries Number of directory entries in the root directory.
pDevInfo Information about the storage device.
Flags Formatting options.
SectorsPerClusterHigh High-order 16-bits of the number of sectors in a cluster.

Additional information

This structure can be passed to FS_Format() to specify additional information about how the storage device has to be formatted.

A cluster is the allocation unit of the file system that consists of one or more consecutive logical sectors. The size of the cluster can be specified in number of sectors via SectorsPerCluster that has to be a power of 2 value. Using large clusters can help improve the performance of the file system because this reduces the number of accesses to the allocation table. Using small clusters makes more efficient use of disk space. Permitted values for SectorsPerCluster are:

A value of 0 means that the file system has to determine the size of the cluster automatically.

NumRootDirEntries represents the number of directory entries in the root directory should have. This is only a proposed value. The actual value depends on the FAT type. This value is typically used for FAT12 or FAT16 formatted volume that have a fixed number of entries in the root directory. On FAT32 formatted volume the root directory can grow dynamically. The file system uses a default value of 256 if NumRootDirEntries is set to 0.

pDevInfo should be typically set to NULL unless some specific information about the storage device has to be passed to format function. The file system requests internally the information from storage device if pDevInfo is set to NULL.

Flags is a bitwise-or combination of Formatting flags.

Formatting flags

Description

Options for formatting a storage device.

Definition

#define FS_FORMAT_FLAG_IGNORE_PARTITIONING    0x01u

Symbols

Definition Description
FS_FORMAT_FLAG_IGNORE_PARTITIONING Overwrite any existing partitioning information.

Partitioning functions

The functions in this section can be used to manage separate volumes on the same storage device.

FS_CreateGPT()

Description

Partitions the specified volume using a GPT (GUID Partition Table) partition scheme.

Prototype

int FS_CreateGPT(const char                  * sVolumeName,
                       FS_GPT_INFO           * pGPTInfo,
                       FS_PARTITION_INFO_GPT * pPartInfo,
                       int                     NumPartitions);

Parameters

Parameter Description
sVolumeName Name of the volume to be partitioned.
pGPTInfo  in  Information about the GPT partitioning. It cannot be NULL.
pPartInfo  in  List of the partitions to be created. It cannot be NULL.
NumPartitions Number of partitions to be created. It cannot be 0 or negative.

Return value

= 0 OK, volume partitioned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

The partition information is stored starting with the first logical sector of the storage device. The number of logical sectors occupied by the partitioning information depends on the number of partitions created. The partitioning information requires at least three logical sectors that is one logical sector for the protective MBR, one logical sector for the GPT header and one logical sector for the partition table. In addition, a copy of the GPT header and of the partition table is stored for redundancy purposes at the end of the storage device. For this reason, FS_CreateGPT() overwrites any information present in these logical sectors of the specified volume.

The partition entries are stored in the order specified in the pPartInfo array: the information found in pPartInfo[0] is stored to first partition entry, the information found in pPartInfo[1] is stored to the second partition entry, and so on.

The actual number of created partition entries is calculated as the maximum of NumPartitions and pGPTInfo::NumPartitions If pGPTInfo::NumPartitions is greater than NumPartitions then FS_CreateGPT() creates empty partitions for partition indexes greater than or equal to NumPartitions.

FS_CreateGPT() calculates the values of pGPTInfo::StartSector and pGPTInfo::NumSectors based on the capacity of the storage device if these members are set to 0. If pPartInfo::StartSector is set to 0 then FS_CreateGPT() set is to the next available sector that immediately follows the previous partition entry. pPartInfo::NumSectors can be set to 0 only for the last partition in the list in which case the last partition occupies the remaining free space on the storage device. For any other partitions pPartInfo::NumSectors must be different than 0.

FS_CreateGPT() checks the validity of values in pGPTInfo and pPartInfo. Any misconfiguration such as overlapping partitions is reported as an error and the partition table is not created.

The partitioning information such as the disk id and the number of partitions can be queried via FS_GetGPTInfo(). The information about individual partitions can be obtained via FS_GetPartitionInfoGPT().

The DISKPART logical driver can be used to access the data of the created partitions.

Example

#include <string.h>
#include "FS.h"

static const U8 _abDiskId[FS_NUM_BYTES_GUID] = {            // FB223EF0-C45C-D24A-4787-F2E856469D59
  0xFB, 0x22, 0x3E, 0xF0, 
  0xC4, 0x5C, 
  0xD2, 0x4A, 
  0x47, 0x87, 
  0xF2, 0xE8, 0x56, 0x46, 0x9D, 0x59
};

static const U8 _abTypeBasicData[FS_NUM_BYTES_GUID] = {     // A2A0D0EB-E5B9-3344-87C0-68B6B72699C7
  0xA2u, 0xA0u, 0xD0u, 0xEBu,
  0xE5u, 0xB9u,
  0x33u, 0x44u,
  0x87u, 0xC0u,
  0x68u, 0xB6u, 0xB7u, 0x26u, 0x99u, 0xC7
};

static const U8 _abPartId0[FS_NUM_BYTES_GUID] = {           // E633CD2E-2D08-7C46-5E97-7283101E324D
  0xE6, 0x33, 0xCD, 0x2E, 
  0x2D, 0x08, 
  0x7C, 0x46, 
  0x5E, 0x97, 
  0x72, 0x83, 0x10, 0x1E, 0x32, 0x4D
};

static const U8 _abPartId1[FS_NUM_BYTES_GUID] = {           // 6D8195A2-A800-3442-4007-999793ECE605  
  0x6D, 0x81, 0x95, 0xA2, 
  0xA8, 0x00, 
  0x34, 0x42, 
  0x40, 0x07, 
  0x99, 0x97, 0x93, 0xEC, 0xE6, 0x05  
};

static const U8 _abPartId2[FS_NUM_BYTES_GUID] = {           // 621D39CB-6DD4-6448-7539-487394C67FCF
  0x62, 0x1D, 0x39, 0xCB, 
  0x6D, 0xD4, 
  0x64, 0x48, 
  0x75, 0x39, 
  0x48, 0x73, 0x94, 0xC6, 0x7F, 0xCF
};

void SampleCreateGPT(void) {
  FS_PARTITION_INFO_GPT aPartInfo[3];
  FS_GPT_INFO           gptInfo;

  //
  // This example creates a GUID partition table with three partitions.
  // The position and size of first partition is configured explicitly.
  // The position of the second partition is calculated by FS_CreateGPT()
  // and it starts right after the first partition.
  // The third partition occupies the remaining of the storage device.
  //
  memset(aPartInfo, 0, sizeof(aPartInfo));
  memset(&gptInfo, 0, sizeof(gptInfo));
  //
  // We fill here only the disk id. The information related to
  // the partition location and the number of partitions is
  // calculated by FS_CreateGPT();
  //
  memcpy(gptInfo.abId, _abDiskId, FS_NUM_BYTES_GUID);
  //
  // First partition.
  //
  aPartInfo[0].StartSector = 32;
  aPartInfo[0].NumSectors  = 5000;
  memcpy(aPartInfo[0].abId, _abPartId0, FS_NUM_BYTES_GUID);
  memcpy(aPartInfo[0].abType, _abTypeBasicData, FS_NUM_BYTES_GUID);
  //
  // Second partition.
  //
  aPartInfo[1].StartSector = 0;
  aPartInfo[1].NumSectors  = 10000;
  memcpy(aPartInfo[1].abId, _abPartId1, FS_NUM_BYTES_GUID);
  memcpy(aPartInfo[1].abType, _abTypeBasicData, FS_NUM_BYTES_GUID);
  //
  // Third partition.
  //
  aPartInfo[2].StartSector = 0;
  aPartInfo[2].NumSectors  = 0;
  memcpy(aPartInfo[2].abId, _abPartId1, FS_NUM_BYTES_GUID);
  memcpy(aPartInfo[2].abType, _abTypeBasicData, FS_NUM_BYTES_GUID);
  //
  // Create the partition table.
  //
  FS_CreateGPT("", &gptInfo, aPartInfo, 3);
}

FS_CreateMBR()

Description

Partitions the specified volume using a MBR (Master Boot Record) partition scheme.

Prototype

int FS_CreateMBR(const char                  * sVolumeName,
                       FS_PARTITION_INFO_MBR * pPartInfo,
                       int                     NumPartitions);

Parameters

Parameter Description
sVolumeName Name of the volume to be partitioned.
pPartInfo  in  List of the partitions to be created.
NumPartitions Number of partitions to be created.

Return value

= 0 OK, volume partitioned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

The Master Boot Record is a special logical sector that contains information about how the storage device is partitioned. This partitioning information is located on the first logical sector of a storage device (sector index 0). The MBR information can be queried via FS_GetPartitionInfoMBR(). FS_CreateMBR() overwrites any information present in the first logical sector of the specified volume.

The partition entries are stored in the order specified in the pPartInfo array: the information found in pPartInfo[0] is stored to first partition entry, the information found in pPartInfo[1] is stored to the second partition entry, and so on.

If the Type member of the FS_PARTITION_INFO_MBR structure is set to 0 then FS_CreateMBR() automatically calculates the partition type and the CHS (Cylinder/Head/Sector) addresses (Type, StartAddr and EndAddr) based on the values stored in the StartSector and NumSector members.

The data of the created partitions can be accessed using the DISKPART logical driver.

Example

#include <string.h>
#include "FS.h"

void SampleCreateMBR(void) {
  FS_PARTITION_INFO_MBR aPartInfo[2];

  //
  // This example creates a MBR with two partitions.
  // The first partition is configured to be bootable.
  // All parameters are explicitly configured.
  // The second partition is configured not to be bootable.
  // The partition type and CHS address are calculated
  // automatically by FS_CreateMBR().
  //
  memset(aPartInfo, 0, sizeof(aPartInfo));
  //
  // First partition.
  //
  aPartInfo[0].IsActive           = 1;
  aPartInfo[0].StartSector        = 10;
  aPartInfo[0].NumSectors         = 100000;
  aPartInfo[0].Type               = 6;
  aPartInfo[0].StartAddr.Cylinder = 0;
  aPartInfo[0].StartAddr.Head     = 0;
  aPartInfo[0].StartAddr.Sector   = 11;
  aPartInfo[0].EndAddr.Cylinder   = 538;
  aPartInfo[0].EndAddr.Head       = 1;
  aPartInfo[0].EndAddr.Sector     = 10;
  //
  // Second partition.
  //
  aPartInfo[1].StartSector = 200000;
  aPartInfo[1].NumSectors  = 10000;
  FS_CreateMBR("", aPartInfo, 2);
}

FS_GetGPTInfo()

Description

Returns information about the GPT partitioning.

Prototype

int FS_GetGPTInfo(const char        * sVolumeName,
                        FS_GPT_INFO * pGPTInfo);

Parameters

Parameter Description
sVolumeName Name of the volume on which the partition is located.
pGPTInfo  out  Information about the GPT partitioning.

Return value

= 0 OK, partition information read.
≠ 0 Error code indicating the failure reason.

Example

#include <string.h>
#include "FS.h"

void SampleGetGPTInfo(void) {
  char        ac[100];
  int         r;
  FS_GPT_INFO gptInfo;

  memset(&gptInfo, 0, sizeof(gptInfo));
  r = FS_GetGPTInfo("", &gptInfo);
  if (r == 0) {
    FS_X_Log("GPT partitioning info:\n");
    SEGGER_snprintf(ac, sizeof(ac), "  StartSector:   %lu\n", 
      (U32)gptInfo.StartSector);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  NumSectors:    %lu\n", 
      (U32)gptInfo.NumSectors);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  NumPartitions: %u\n", gptInfo.NumPartitions);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  IsValidMain:   %u\n", gptInfo.IsValidMain);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  IsValidBackup: %u\n", gptInfo.IsValidBackup);
    FS_X_Log(ac);
    FS_X_Log("  Id:            ");
    SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X", 
      gptInfo.abId[0], gptInfo.abId[1], 
      gptInfo.abId[2], gptInfo.abId[3]);
    FS_X_Log(ac);
    FS_X_Log("-");
    SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
      gptInfo.abId[4], gptInfo.abId[5]);
    FS_X_Log(ac);
    FS_X_Log("-");
    SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
      gptInfo.abId[6], gptInfo.abId[7]);
    FS_X_Log(ac);
    FS_X_Log("-");
    SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
      gptInfo.abId[8], gptInfo.abId[9]);
    FS_X_Log(ac);
    FS_X_Log("-");
    SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X%02X%02X",
      gptInfo.abId[10], gptInfo.abId[11], gptInfo.abId[12], 
      gptInfo.abId[13], gptInfo.abId[14], gptInfo.abId[15]);
    FS_X_Log(ac);
    FS_X_Log("\n");
  }
}

FS_GetPartitionInfoMBR()

Description

Returns information about a MBR partition.

Prototype

int FS_GetPartitionInfoMBR(const char                  * sVolumeName,
                                 FS_PARTITION_INFO_MBR * pPartInfo,
                                 U8                      PartIndex);

Parameters

Parameter Description
sVolumeName Name of the volume on which the partition is located.
pPartInfo  out  Information about the partition.
PartIndex Index of the partition to query.

Return value

= 0 OK, partition information read.
≠ 0 Error code indicating the failure reason.

Additional information

The function reads the information from the Master Boot Record (MBR) that is stored on the first sector (the sector with the index 0) of the specified volume. An error is returned if no MBR information is present on the volume. If the Type member of the FS_PARTITION_INFO_MBR structure is 0, the partition entry is not valid.

Permitted values for PartIndex are 0 to 3.

Example

#include <string.h>
#include "FS.h"

void SampleGetPartitionInfoMBR(void) {
  int                   iPart;
  FS_PARTITION_INFO_MBR PartInfo;
  char                  ac[100];

  //
  // Show the contents of the partition list stored in the Master
  // Boot Record. Only the valid entries are displayed.
  //
  FS_X_Log("MBR partition list:\n");
  for (iPart = 0; iPart < FS_MAX_NUM_PARTITIONS_MBR; ++iPart) {
    memset(&PartInfo, 0, sizeof(PartInfo));
    FS_GetPartitionInfoMBR("", &PartInfo, iPart);
    if (PartInfo.Type != 0) {
      SEGGER_snprintf(ac, sizeof(ac), "  Index:         %u\n", iPart);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  StartSector:   %lu\n", PartInfo.StartSector);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  NumSectors:    %lu\n", PartInfo.NumSectors);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  Type:          %u\n", PartInfo.Type);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  IsActive:      %u\n", PartInfo.IsActive);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  FirstCylinder: %u\n", PartInfo.StartAddr.Cylinder);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  FirstHead:     %u\n", PartInfo.StartAddr.Head);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  FirstSector:   %u\n", PartInfo.StartAddr.Sector);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  LastCylinder:  %u\n", PartInfo.EndAddr.Cylinder);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  LastHead:      %u\n", PartInfo.EndAddr.Head);
      FS_X_Log(ac);
      SEGGER_snprintf(ac, sizeof(ac), "  LastSector:    %u\n", PartInfo.EndAddr.Sector);
      FS_X_Log(ac);
      FS_X_Log("\n");
    }
  }
}

Deprecated name

FS_GetPartitionInfo

FS_GetPartitionInfoGPT()

Description

Returns information about a GPT partition.

Prototype

int FS_GetPartitionInfoGPT(const char                  * sVolumeName,
                                 FS_PARTITION_INFO_GPT * pPartInfo,
                                 unsigned                PartIndex);

Parameters

Parameter Description
sVolumeName Name of the volume on which the partition is located.
pPartInfo  out  Information about the partition.
PartIndex Index of the partition to query.

Return value

= 0 OK, partition information read.
≠ 0 Error code indicating the failure reason.

Example

#include <string.h>
#include "FS.h"

void SampleGetPartitionInfoGPT(void) {
  int                   iPart;
  FS_PARTITION_INFO_GPT PartInfo;
  char                  ac[100];
  int                   r;
  FS_GPT_INFO           gptInfo;
  int                   IsEmpty;
  unsigned              i;

  //
  // Show the contents of a GUID partition table.
  // Only the valid entries are displayed.
  //
  memset(&gptInfo, 0, sizeof(gptInfo));
  r = FS_GetGPTInfo("", &gptInfo);
  if (r == 0) {
    FS_X_Log("GPT partition list:\n");
    for (iPart = 0; iPart < gptInfo.NumPartitions; ++iPart) {
      memset(&PartInfo, 0, sizeof(PartInfo));
      r = FS_GetPartitionInfoGPT("", &PartInfo, iPart);
      IsEmpty = 1;
      //
      // An empty partition entry has all the bytes in the GUID type set to 0;
      //
      for (i = 0; i < sizeof(PartInfo.abType); ++i) {
        if (PartInfo.abType[i] != 0) {
          IsEmpty = 0;
        }
      }
      if (IsEmpty == 0) {
        SEGGER_snprintf(ac, sizeof(ac), "  Index:         %u\n", iPart);
        FS_X_Log(ac);
        SEGGER_snprintf(ac, sizeof(ac), "  StartSector:   %lu\n", 
          (U32)PartInfo.StartSector);
        FS_X_Log(ac);
        SEGGER_snprintf(ac, sizeof(ac), "  NumSectors:    %lu\n", 
          (U32)PartInfo.NumSectors);
        FS_X_Log(ac);
        SEGGER_snprintf(ac, sizeof(ac), "  Attr:          0x%08X%08X\n", 
          (U32)(PartInfo.Attributes >> 32), (U32)(PartInfo.Attributes & 0xFFFFFFFFuL));
        FS_X_Log(ac);
        SEGGER_snprintf(ac, sizeof(ac), "  Name:          %s\n", PartInfo.acName);
        FS_X_Log(ac);
        FS_X_Log("  Type:        ");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X", 
          PartInfo.abType[0], PartInfo.abType[1], 
          PartInfo.abType[2], PartInfo.abType[3]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
          PartInfo.abType[4], PartInfo.abType[5]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
          PartInfo.abType[6], PartInfo.abType[7]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
          PartInfo.abType[8], PartInfo.abType[9]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X%02X%02X",
          PartInfo.abType[10], PartInfo.abType[11], PartInfo.abType[12], 
          PartInfo.abType[13], PartInfo.abType[14], PartInfo.abType[15]);
        FS_X_Log(ac);
        FS_X_Log("  Unique:      ");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X", 
          PartInfo.abId[0], PartInfo.abId[1], 
          PartInfo.abId[2], PartInfo.abId[3]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
          PartInfo.abId[4], PartInfo.abId[5]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
          PartInfo.abId[6], PartInfo.abId[7]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X", 
          PartInfo.abId[8], PartInfo.abId[9]);
        FS_X_Log(ac);
        FS_X_Log("-");
        SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X%02X%02X",
          PartInfo.abId[10], PartInfo.abId[11], PartInfo.abId[12], 
          PartInfo.abId[13], PartInfo.abId[14], PartInfo.abId[15]);
        FS_X_Log(ac);
        FS_X_Log("\n");
        FS_X_Log("\n");
      }
    }
  }
}

FS_GetPartitioningScheme()

Description

Returns information about how a storage device is partitioned.

Prototype

int FS_GetPartitioningScheme(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume on which the partition is located.

Return value

≥ 0 OK, partitioning type. Can be one of the Partitioning schemes values.
≠ 0 Error code indicating the failure reason.

Example

#include "FS.h"

void SampleGetPartitioningScheme(void) {
  int Scheme;

  Scheme = FS_GetPartitioningScheme("");
  if (Scheme >= 0) {
    switch (Scheme) {
    case FS_PARTITIONING_SCHEME_NONE:
      FS_X_Log("The storage device is not partitioned.\n");
      break;
    case FS_PARTITIONING_SCHEME_MBR:
      FS_X_Log("The storage device is partitioned via MBR.\n");
      break;
    case FS_PARTITIONING_SCHEME_GPT:
      FS_X_Log("The storage device is partitioned via GPT.\n");
      break;
    default:
      FS_X_Log("Unknown partitioning scheme.\n");
      break;
    }
  }
}

FS_GPT_INFO

Description

Information about a GUID partition table.

Type definition

typedef struct {
  U64  StartSector;
  U64  NumSectors;
  U16  NumPartitions;
  U8   IsValidMain;
  U8   IsValidBackup;
  U8   abId[];
} FS_GPT_INFO;

Structure members

Member Description
StartSector Index of the first logical sector that can be used for partition data (FirstUsableLBA field).
NumSectors Index of the last logical sector that can be used for partition data (LastUsableLBA field - FirstUsableLBA field + 1).
NumPartitions Number of partitions present on the storage device (NumberOfPartitionEntries field).
IsValidMain Indicates if the main partition table is valid.
IsValidBackup Indicates if the backup partition table is valid.
abId GUID that uniquely identifies the storage device (DiskGUID field)

Additional information

The partitioning information can be obtained via FS_GetGPTInfo().

FS_PARTITION_INFO_MBR

Description

Information about a MBR partition.

Type definition

typedef struct {
  U32          NumSectors;
  U32          StartSector;
  FS_CHS_ADDR  StartAddr;
  FS_CHS_ADDR  EndAddr;
  U8           Type;
  U8           IsActive;
} FS_PARTITION_INFO_MBR;

Structure members

Member Description
NumSectors Total number of sectors in the partition.
StartSector Index of the first sector in the partition relative to the beginning of the storage device.
StartAddr Address of the first sector in the partition in CHS format.
EndAddr Address of the last sector in the partition in CHS format.
Type Type of the partition.
IsActive Set to 1 if the partition is bootable.

Example

For an example usage refer to FS_GetPartitionInfoMBR().

Deprecated name

FS_PARTITION_INFO_MBR

FS_PARTITION_INFO_GPT

Description

Information about a GPT partition.

Type definition

typedef struct {
  U8    abType[];
  U8    abId[];
  U64   StartSector;
  U64   NumSectors;
  U64   Attributes;
  char  acName[];
} FS_PARTITION_INFO_GPT;

Structure members

Member Description
abType Partition type as GUID (PartitionTypeGUID field).
abId Unique id of the partition as GUID (UniquePartitionGUID field).
StartSector Index of the first logical sector in the partition (StartingLBA field).
NumSectors Index of the last logical sector in the partition (EndingLBA field - StartingLBA field + 1).
Attributes Partition attributes (Attributes field).
acName Partition name as 0-terminated string, UTF-8 encoded (PartitionName field).

Additional information

The name of the partition returned via acName member is a 0-terminated string encoded as UTF-8. The size of this member can be configured via FS_MAX_NUM_BYTES_PART_NAME.

Example

For an example usage refer to FS_GetPartitionInfoGPT().

Partitioning schemes

Description

Methods for partitioning a storage device.

Definition

#define FS_PARTITIONING_SCHEME_NONE    0
#define FS_PARTITIONING_SCHEME_MBR     1
#define FS_PARTITIONING_SCHEME_GPT     2

Symbols

Definition Description
FS_PARTITIONING_SCHEME_NONE The storage device is not partitioned.
FS_PARTITIONING_SCHEME_MBR The storage device is partitioned as MBR.
FS_PARTITIONING_SCHEME_GPT The storage device is partitioned as GPT.

Example

Refer to FS_GetPartitioningScheme() for an example usage.

File system checking functions

The functions in this section can be used by an application to check the consistency of the file system structure.

FS_CheckAT()

Description

Verifies the consistency of the allocation table.

Prototype

int FS_CheckAT(FS_CHECK_DATA * pCheckData);

Parameters

Parameter Description
pCheckData  in  Checking context. It cannot be NULL.

Return value

= FS_CHECKDISK_RETVAL_OK No errors found or the callback returned FS_CHECKDISK_ACTION_DO_NOT_REPAIR.
= FS_CHECKDISK_RETVAL_RETRY An error has been found. The error has been corrected since the callback function returned FS_CHECKDISK_ACTION_SAVE_CLUSTERS or FS_CHECKDISK_ACTION_DELETE_CLUSTERS. FS_CheckDir() has to be called again to check for the next error.
= FS_CHECKDISK_RETVAL_ABORT The application requested the abort of disk checking operation through the callback returning FS_CHECKDISK_ACTION_ABORT.
= FS_CHECKDISK_RETVAL_CONTINUE Indicates that not all the allocation table has been checked. The entire volume has to be checked again using FS_CheckDir().
< 0 Error code indicating the failure reason.

Additional information

FS_CheckAT() has to be called in combination with FS_InitCheck() and FS_CheckDir() to check the consistency of the file system.

pCheckData has to be initialized via a call to FS_InitCheck().

Example

Refer to FS_InitCheck() for a usage example.

FS_CheckDir()

Description

Verifies the consistency of a single directory.

Prototype

int FS_CheckDir(      FS_CHECK_DATA * pCheckData,
                const char          * sPath);

Parameters

Parameter Description
pCheckData  in  Checking context. It cannot be NULL.
sPath Path to the directory to be checked. It cannot be NULL.

Return value

= FS_CHECKDISK_RETVAL_OK No errors found or the callback returned FS_CHECKDISK_ACTION_DO_NOT_REPAIR.
= FS_CHECKDISK_RETVAL_RETRY An error has been found. The error has been corrected since the callback function returned FS_CHECKDISK_ACTION_SAVE_CLUSTERS or FS_CHECKDISK_ACTION_DELETE_CLUSTERS. FS_CheckDir() has to be called again to check for the next error.
= FS_CHECKDISK_RETVAL_ABORT The application requested the abort of disk checking operation through the callback returning FS_CHECKDISK_ACTION_ABORT.
= FS_CHECKDISK_RETVAL_MAX_RECURSE Maximum recursion level reached. The disk checking operation has been aborted.
< 0 Error code indicating the failure reason.

Additional information

FS_CheckDir() has to be called in combination with FS_InitCheck() and FS_CheckAT() to check the consistency of the file system.

pCheckData has to be initialized via a call to FS_InitCheck(). In order to check the entire file system structure, the application will have to call FS_CheckDir() with every different directory path present on the file system.

Example

Refer to FS_InitCheck() for a usage example.

FS_CheckDisk()

Description

Checks the consistency of the file system structure.

Prototype

int FS_CheckDisk(const char                           * sVolumeName,
                       void                           * pBuffer,
                       U32                              BufferSize,
                       int                              MaxRecursionLevel,
                       FS_CHECKDISK_ON_ERROR_CALLBACK * pfOnError);

Parameters

Parameter Description
sVolumeName Name of the volume to be checked.
pBuffer Work buffer to be used for checking the allocation table.
BufferSize Size of the work buffer in bytes. It cannot be NULL.
MaxRecursionLevel The maximum directory depth the function is allowed to check.
pfOnError Function that has to be called when an error is found. It cannot be NULL.

Return value

= FS_CHECKDISK_RETVAL_OK No errors found or the callback returned FS_CHECKDISK_ACTION_DO_NOT_REPAIR.
= FS_CHECKDISK_RETVAL_RETRY An error has been found. The error has been corrected since the callback function returned FS_CHECKDISK_ACTION_SAVE_CLUSTERS or FS_CHECKDISK_ACTION_DELETE_CLUSTERS. FS_CheckDisk() has to be called again to check for the next error.
= FS_CHECKDISK_RETVAL_ABORT The application requested the abort of disk checking operation through the callback returning FS_CHECKDISK_ACTION_ABORT.
= FS_CHECKDISK_RETVAL_MAX_RECURSE Maximum recursion level reached. The disk checking operation has been aborted.
< 0 Error code indicating the failure reason.

Additional information

This function can be used to check if any errors are present on a specific volume and, if necessary, to repair these errors. Ideally, the work buffer has to be large enough to store the usage information of all the clusters in the allocation table. FS_CheckDisk() uses one bit to store the usage state of a cluster. The typical size of the work buffer is about 2 KBytes. Additional iterations are performed if the work buffer is not large enough to check the whole allocation table in one step.

FS_CheckDisk() can detect and correct the following file system errors:

The contents of a lost cluster chain is saved during the repair operation to files named FILE<FileIndex>.CHK that are stored in directories named FOUND.<DirIndex>. FileIndex is a 0-based 4-digit decimal number that is incremented by one for each cluster chain saved. DirIndex is a 0-based 3-digit decimal number that is incremented by one each time FS_CheckDisk() is called. For example the first created directory has the name FOUND.000, the second FOUND.001, and so on while the first file in the directory has the name FILE0000.CHK, the second FILE0001.CHK, and so on.

The callback function is used to notify the application about the errors found by FS_CheckDisk() during the disk checking operation. FS_CheckDisk() uses the return value of the callback function to decide if the error hast to be repaired or not. For more information refer to FS_CHECKDISK_ON_ERROR_CALLBACK.

FS_CheckDisk() closes all opened files before it starts the disk checking operation. The application is not allowed to access the storage device from a different task as long as the operation is in progress.

Example

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "FS.h"

static U32 _aBuffer[1024 / 4];
static int _NumErrors;

/*********************************************************************
*
*       _OnError
*/
static int _OnError(int ErrCode, ...) {
  va_list      ParamList;
  const char * sFormat;
  char         c;
  char         ac[256];

  (void)memset(&ParamList, 0, sizeof(ParamList));
  sFormat = FS_CheckDisk_ErrCode2Text(ErrCode);
  if (sFormat) {
    va_start(ParamList, ErrCode);
    vsprintf(ac, sFormat, ParamList);
    FS_X_Log(ac);
    FS_X_Log("\n");
  }
  if (ErrCode != FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED) {
    FS_X_Log("  Do you want to repair this? (y/n/a) ");
  } else {
    FS_X_Log("  * Convert lost cluster chain into file (y)\n");
    FS_X_Log("  * Delete cluster chain                 (d)\n");
    FS_X_Log("  * Do not repair                        (n)\n");
    FS_X_Log("  * Abort                                (a)\n");
  }
  _NumErrors++;
  c = getchar();
  FS_X_Log("\n");
  if ((c == 'y') || (c == 'Y')) {
    return FS_CHECKDISK_ACTION_SAVE_CLUSTERS;
  } else if ((c == 'a') || (c == 'A')) {
    return FS_CHECKDISK_ACTION_ABORT;
  } else if ((c == 'd') || (c == 'D')) {
    return FS_CHECKDISK_ACTION_DELETE_CLUSTERS;
  }
  return FS_CHECKDISK_ACTION_DO_NOT_REPAIR;     // Do not repair anything.
}

/*********************************************************************
*
*       SampleCheckDisk
*/
void SampleCheckDisk(void) {
  int r;

  while (1) {
    r = FS_CheckDisk("", _aBuffer, sizeof(_aBuffer), 5, _OnError);
    if (r != FS_CHECKDISK_RETVAL_RETRY) {
      break;
    }
  }
  if (_NumErrors == 0) {
    FS_X_Log("No errors were found.\n");
  } else {
    FS_X_Log("Errors were found.\n");
  }
}

FS_CheckDisk_ErrCode2Text()

Description

Returns a human-readable text description of a disk checking error code.

Prototype

char *FS_CheckDisk_ErrCode2Text(int ErrCode);

Parameters

Parameter Description
ErrCode Error code for which the text description has to be returned.

Return value

Text description as 0-terminated string.

Additional information

This function can be invoked inside the callback for FS_CheckDisk() to format the error information in human-readable format. The text description includes format specifiers for the printf() family of functions that can be used to show additional information about the file system error.

Refer to FS_CheckDisk() for more information about how to use this function.

FS_GetATInfo()

Description

Obtains information about the allocation table.

Prototype

int FS_GetATInfo(const char       * sVolumeName,
                       FS_AT_INFO * pATInfo);

Parameters

Parameter Description
sVolumeName Name of the volume that stores the allocation table. It cannot be NULL.
pATInfo  out  Allocation table information. It cannot be NULL.

Return value

= 0 OK, information returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This is an optional function that can be used to get information about the allocation table. The allocation table is a data structure maintained by the file system that stores information about how the clusters are allocated.

Example

#include "FS.h"

void SampleGetATInfo(void) {
  int        r;
  FS_AT_INFO ATInfo;
  char       ac[100];
  
  memset(&ATInfo, 0, sizeof(ATInfo));
  r = FS_GetATInfo("", &ATInfo);
  if (r == 0) {
    FS_X_Log("Allocation table info:");
    SEGGER_snprintf(ac, sizeof(ac), "  First cluster: %u\n", ATInfo.FirstClusterId);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Last cluster:  %u\n", ATInfo.LastClusterId);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Write count:   %u\n", ATInfo.WriteCnt);
    FS_X_Log(ac);
  }
}

FS_GetClusterInfo()

Description

Obtains information about a storage allocation unit.

Prototype

int FS_GetClusterInfo(const char            * sVolumeName,
                            U32               ClusterId,
                            FS_CLUSTER_INFO * pClusterInfo);

Parameters

Parameter Description
sVolumeName Name of the volume that stores the cluster. It cannot be NULL.
ClusterId Id of the cluster to be queried.
pClusterInfo  out  Cluster information. It cannot be NULL.

Return value

= 0 OK, information returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This is an optional function that can be used to get detailed information about a storage allocation unit (cluster).

The file system reserves the first entries in the allocation table for internal usage. These entries of the allocation table do not have any associated cluster. The id of the first and of the last valid cluster can be obtain via FS_GetATInfo().

Example

#include "FS.h"

void SampleGetClusterInfo(void) {
  int             r;
  FS_CLUSTER_INFO ClusterInfo;
  char            ac[100];
  
  memset(&ClusterInfo, 0, sizeof(ClusterInfo));
  r = FS_GetClusterInfo("", 2, &ClusterInfo);
  if (r == 0) {
    FS_X_Log("Cluster info:");
    SEGGER_snprintf(ac, sizeof(ac), "  Sector index: %u\n", ClusterInfo.SectorIndex);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Status:       %s\n", 
      ClusterInfo.IsFree ? "free" : "allocated");
    FS_X_Log(ac);
    if (ClusterInfo.IsFree == 0) {
      if (ClusterInfo.IsEOC != 0) {
        SEGGER_snprintf(ac, sizeof(ac), "  Next cluster: <end of chain>\n");
      } else {
        SEGGER_snprintf(ac, sizeof(ac), "  Next cluster: %u\n", ClusterInfo.NextClusterId);
      }
      FS_X_Log(ac);
    }
  }
}

FS_GetDiskLayout()

Description

Obtains information about the data layout of a volume.

Prototype

int FS_GetDiskLayout(const char           * sVolumeName,
                           FS_DISK_LAYOUT * pDiskLayout);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried. It cannot be NULL.
pDiskLayout  out  Layout information. It cannot be NULL.

Return value

= 0 OK, information returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This is an optional function that can be used to get detailed information about where the file system stores the data on a volume. The information is provided in in a form of logical sector ranges.

Example

#include "FS.h"

void SampleGetDiskLayout(void) {
  int            r;
  FS_DISK_LAYOUT DiskLayout;
  U32            aBuffer[512 / 4];
  U32            SectorIndex;
  
  memset(&DiskLayout, 0, sizeof(DiskLayout));
  r = FS_GetDiskLayout("", &DiskLayout);
  if (r == 0) {
    //
    // Read the first logical sector of the root directory.
    // Works only for volumes formatted as FAT12 or FAT16.
    //
    if (   (DiskLayout.FSType == FS_TYPE_FAT12)
        || (DiskLayout.FSType == FS_TYPE_FAT16)) {
      SectorIndex = DiskLayout.FSLayout.fat.SectorIndexRootDir;
      (void)FS_STORAGE_ReadSector("", aBuffer, SectorIndex);
    }    
  }
}

FS_GetFirstCluster()

Description

Obtains the id of the first cluster assigned to a file or directory.

Prototype

int FS_GetFirstCluster(const char * sName,
                             U32  * pClusterId);

Parameters

Parameter Description
sName Name of the file or directory to query.
pClusterId  out  Id of the first cluster.

Return value

= 0 OK, cluster id returned successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This is an optional function that can be used to get the id of the first cluster assigned to a file or directory for analysis purposes.

Empty files do not have any cluster assigned to them. In this case the returned cluster id is 0.

Subdirectories always have a cluster id assigned to them because they are never empty since the system directory entries “.” and “..” are always present and cannot be deleted.

The root directory of a FAT32 and EFS formatted storage device always have a cluster id assigned to them that is set when the storage device is formatted.

The root directory of a FAT12 and FAT16 formatted storage device is allocated on a special area of the file system and has a fixed size. For this reason the such a root directory does not have any cluster allocated to it. FS_GetFirstCluster() returns an error in this case.

Example

#include "FS.h"

void SampleGetFirstCluster(void) {
  char ac[100];
  U32  ClusterId;
  int  r;
  
  r = FS_MkDir("SubDir1");
  if (r == 0) {
    r = FS_GetFirstCluster("SubDir1", &ClusterId);
    if (r == 0) {
      SEGGER_snprintf(ac, sizeof(ac), "%u is the first cluster in the chain\n", ClusterId);
      FS_X_Log(ac);
    }
  }
}

FS_InitCheck()

Description

Initializes a non-blocking disk checking operation.

Prototype

int FS_InitCheck(      FS_CHECK_DATA                  * pCheckData,
                 const char                           * sVolumeName,
                       void                           * pBuffer,
                       U32                              BufferSize,
                       FS_CHECKDISK_ON_ERROR_CALLBACK * pfOnError);

Parameters

Parameter Description
pCheckData  out  Checking context. It cannot be NULL.
sVolumeName Name of the volume on which the checking is performed. It cannot be NULL.
pBuffer  in  Working buffer. It cannot be NULL.
BufferSize Number of bytes in pBuffer.
pfOnError Callback function to be invoked in case of a file system damage. It cannot be NULL.

Return value

= FS_CHECKDISK_RETVAL_OK OK, disk checking has been initialized.
< 0 Error code indicating the failure reason.

Additional information

FS_InitCheck() has to be called in combination with FS_CheckDir() and FS_CheckAT() to check the consistency of the file system. These functions perform the same operation as FS_CheckDisk() with the difference that the access to the file system is blocked only for a limited period of time.

It is mandatory to call FS_InitCheck() before any call to FS_CheckDir() or FS_CheckAT(). The purpose of FS_InitCheck() is to prepare the checking context pCheckData for the operation. This context must be passed to FS_CheckDir() and FS_CheckAT().

The parameters sVolumeName, pBuffer, BufferSize and pfOnError have the same meaning as the corresponding parameters of FS_CheckDisk(). Refer to FS_CheckDisk() for more information about the usage of these parameters.

In a typical usage the application calls FS_InitCheck() once followed by multiple calls to FS_CheckDir() and FS_CheckAT(). In addition, each time FS_CheckDir() and FS_CheckAT() find and correct an error FS_InitCheck() has to be called again to re-initialize the operation.

Example

The following example demonstrates how the consistency of the file system structure can be checked while the application performs normal file system operations.

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "FS.h"

#define VOLUME_NAME       ""
#define MAX_RECURSION     5

static U32 _aBuffer[1024 / 4];
static int _NumErrors;

/*********************************************************************
*
*       _IsSystemDir
*/
static int _IsSystemDir(const char * sDirName) {
  if (((*sDirName == '.') && (*(sDirName + 1) == '\0'))) {
    return 1;
  }
  if (((*sDirName == '.') && (*(sDirName + 1) == '.')  && (*(sDirName + 2) == '\0'))) {
    return 1;
  }
  return 0;
}

/*********************************************************************
*
*       _cbOnError
*/
static int _cbOnError(int ErrCode, ...) {
  va_list      ParamList;
  const char * sFormat;
  int          c;
  char         ac[1000];

  //lint --e{438} -esym(530, ParamList)
  sFormat = FS_CheckDisk_ErrCode2Text(ErrCode);
  if (sFormat) {
    va_start(ParamList, ErrCode);
    SEGGER_vsnprintf(ac, sizeof(ac), sFormat, ParamList);
    va_end(ParamList);
    FS_X_Log(ac);
    FS_X_Log("\n");
  }
  if (ErrCode != FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED) {
    FS_X_Log("  Do you want to repair this error? (y/n/a) ");
  } else {
    FS_X_Log("  * Convert lost cluster chain into file (y)\n");
    FS_X_Log("  * Delete cluster chain                 (d)\n");
    FS_X_Log("  * Do not repair                        (n)\n");
    FS_X_Log("  * Abort                                (a)\n");
  }
  ++_NumErrors;
  c = getchar();
  FS_X_Log("\n");
  if ((c == 'y') || (c == 'Y')) {
    return FS_CHECKDISK_ACTION_SAVE_CLUSTERS;
  } else if ((c == 'a') || (c == 'A')) {
    return FS_CHECKDISK_ACTION_ABORT;
  } else if ((c == 'd') || (c == 'D')) {
    return FS_CHECKDISK_ACTION_DELETE_CLUSTERS;
  }
  return FS_CHECKDISK_ACTION_DO_NOT_REPAIR;
}

/*********************************************************************
*
*       _CheckDir
*
*  Function description
*    Checks the consistency of a directory tree.
*
*  Notes
*    (1) This function calls itself recursively.
*/
static int _CheckDir(FS_CHECK_DATA * pCheckData, char * sDirPath, 
                     unsigned SizeOfDirPath, int MaxRecursionLevel) {
  int            r;
  int            Result;
  FS_FIND_DATA   FindData;
  char           acDirName[32];
  unsigned       LenPath;
  unsigned       LenName;
  char         * p;
  char         * pEnd;
  unsigned       NumBytes;

  r = FS_CheckDir(pCheckData, sDirPath);
  if (r == FS_CHECKDISK_RETVAL_OK) {
    //
    // Search for subdirectories and descend into them.
    //
    memset(&FindData, 0, sizeof(FindData));
    Result = FS_FindFirstFile(&FindData, sDirPath, acDirName, sizeof(acDirName));
    if (Result == 0) {
      while (1) {
        //
        // Descend into any directory other than "." and "..".
        //
        if (FindData.Attributes & FS_ATTR_DIRECTORY) {
          if (_IsSystemDir(FindData.sFileName) == 0) {
            if (MaxRecursionLevel == 0) {
              r = FS_CHECKDISK_RETVAL_MAX_RECURSE;        // Error, deepest directory 
                                                          // level reached.
              break;
            }
            //
            // Create the path to the directory.
            //
            LenPath = strlen(sDirPath);
            if (LenPath >= (SizeOfDirPath - 1)) {
              r = FS_ERRCODE_BUFFER_TOO_SMALL;            // Error, cannot create path 
                                                          // to directory.
              break;
            }
            NumBytes = SizeOfDirPath - LenPath;
            LenName  = strlen(FindData.sFileName);
            if ((LenName + 1 + 1) >= NumBytes) {
              r = FS_ERRCODE_BUFFER_TOO_SMALL;            // Error, cannot create path 
                                                          // to directory.
              break;
            }
            pEnd  = sDirPath + LenPath;
            p     = pEnd;
            strcpy(p, FindData.sFileName);                // Add the directory name.
            p    += LenName;
            *p++  = FS_DIRECTORY_DELIMITER;               // Separate the path from 
                                                          // directory name.
            *p    = '\0';
            r = _CheckDir(pCheckData, sDirPath, SizeOfDirPath, MaxRecursionLevel - 1);
            *pEnd = '\0';                                 // Restore the path to parent 
                                                          // directory.
            if (r != FS_CHECKDISK_RETVAL_OK) {
              break;
            }
          }
        }
        Result = FS_FindNextFile(&FindData);
        if (Result == 0) {
          break;                                          // End of directory reached 
                                                          // or error.
        }
      }
    }
  }
  if (r == FS_CHECKDISK_RETVAL_SKIP) {
    r = FS_CHECKDISK_RETVAL_OK;                           // Make sure that we return 
                                                          // the same value as FS_CheckDisk()
  }
  return r;
}

/*********************************************************************
*
*       _CheckDisk
*
*  Function description
*    Checks the consistency of the file system.
*/
static int _CheckDisk(void) {
  int           r;
  char          acDirName[FS_MAX_PATH];
  FS_CHECK_DATA CheckData;

  memset(&CheckData, 0, sizeof(CheckData));
  for (;;) {
    //
    // Initialize the operation.
    //
    r = FS_InitCheck(&CheckData, VOLUME_NAME, _aBuffer, sizeof(_aBuffer), _cbOnError);
    if (r != 0) {
      break;                                              // Error, could not initialize 
                                                          // the operation.
    }
    for (;;) {
      memset(acDirName, 0, sizeof(acDirName));            // Begin the checking with the 
                                                          // root directory.
      strncpy(acDirName, VOLUME_NAME, sizeof(acDirName) - 1);
      //
      // Check the directory structure.
      //
      r = _CheckDir(&CheckData, acDirName, sizeof(acDirName), MAX_RECURSION);
      if (r != FS_CHECKDISK_RETVAL_OK) {
        break;                                            // An error occurred.
      }
      //
      // Check the allocation table.
      //
      r = FS_CheckAT(&CheckData);
      if (r != FS_CHECKDISK_RETVAL_CONTINUE) {
        break;                                            // No more checks are required 
                                                          // or an error was found and corrected.
      }
    }
    if (r != FS_CHECKDISK_RETVAL_RETRY) {
      break;                                              // Operation completed.
    }
  }
  return r;
}

/*********************************************************************
*
*       SampleCheckDiskBG
*/
void SampleCheckDiskBG(void) {
  FS_CHECK_DATA CheckData;
  FS_CHECK_DATA CheckDataOld;
  int           r;

  //
  // Initialize the check context.
  //
  memset(&CheckDataOld, 0, sizeof(CheckDataOld));
  memset(&CheckData, 0, sizeof(CheckData));
  for (;;) {
    //
    // Wait for a file system change.
    //
    for (;;) {
      r = FS_InitCheck(&CheckData, VOLUME_NAME, _aBuffer, sizeof(_aBuffer), _cbOnError);
      if (r == 0) {
        r = memcmp(&CheckData, &CheckDataOld, sizeof(FS_CHECK_DATA));
        if (r != 0) {
          break;
        }
      }
      //
      // TBD: Delay execution using a RTOS function.
      //
    }
    _NumErrors = 0;
    //
    // Check and correct file system errors.
    //
    r = _CheckDisk();
    if (r != 0) {
      FS_X_Log("Disk checking operation failed.\n");
    } else {
      if (_NumErrors == 0) {
        FS_X_Log("File system structure is consistent.\n");
      }
    }
    memcpy(&CheckDataOld, &CheckData, sizeof(FS_CHECK_DATA));
  }
}

FS_AT_INFO

Description

Information about the allocation table.

Type definition

typedef struct {
  U32  FirstClusterId;
  U32  LastClusterId;
  U32  WriteCnt;
} FS_AT_INFO;

Structure members

Member Description
FirstClusterId Id of the first cluster used as storage.
LastClusterId Id of the last cluster used as storage.
WriteCnt Number of times the allocation table was modified since mounting the file system.

Additional information

The information can be obtained using FS_GetATInfo().

FS_CLUSTER_INFO

Description

Information about a storage allocation unit.

Type definition

typedef struct {
  U32  SectorIndex;
  U32  NextClusterId;
  U8   IsFree;
  U8   IsEOC;
} FS_CLUSTER_INFO;

Structure members

Member Description
SectorIndex Index of the first sector in the cluster.
NextClusterId Id of the linked cluster.
IsFree Usage status.
IsEOC End of chain status.

Additional information

NextClusterId is valid only if IsFree and IsEOC are set to 0.

IsFree is set to 1 if the cluster is not allocated to any file or directory.

IsEOC is set to 1 if the cluster is the last in the chain. If the cluster is linked to another cluster then IsEOC is set to 0. In this case NextClusterId stores the index of the linked cluster.

Information about a cluster can be obtained using FS_GetClusterInfo().

FS_DISK_LAYOUT

Description

Layout of the data stored on the volume.

Type definition

typedef struct {
  U32           SectorIndexPart;
  U32           NumSectorsPart;
  U16           FSType;
  FS_FS_LAYOUT  FSLayout;
} FS_DISK_LAYOUT;

Structure members

Member Description
SectorIndexPart Index of the logical sector that stores the first data in the file system partition.
NumSectorsPart Number of logical sectors in the file system partition.
FSType Type of the file system stored on the volume.
FSLayout Information about the layout of the file system data.

Additional information

SectorIndexPart is set to 0 if the storage device is not partitioned. The sector indexes in the FSLayout.fat and FSLayout.efs structures are relative to SectorIndexPart.

FSType indicates the type of file system stored on the volume. It can be set to one of the Format types values. If FSType is set to either FS_TYPE_FAT12, FS_TYPE_FAT16 or FS_TYPE_FAT32 then the layout information is stored in FSLayout.fat. If FSType is set to FS_TYPE_EFS then the layout information is stored in FSLayout.efs.

The data layout of a volume can be obtained using FS_GetVolumeLayout().

FS_EFS_LAYOUT

Description

Data layout of an EFS partition.

Type definition

typedef struct {
  U32  SectorIndexInfo;
  U32  SectorIndexStatus;
  U32  SectorIndexAT;
  U32  NumSectorsAT;
  U32  SectorIndexData;
  U32  NumSectorsData;
} FS_EFS_LAYOUT;

Structure members

Member Description
SectorIndexInfo Index of the logical sector that stores the format information.
SectorIndexStatus Index of the logical sector that stores information about the status of file system.
SectorIndexAT Index of the logical sector that stores the beginning of the allocation table.
NumSectorsAT Number of logical sectors in the allocation table.
SectorIndexData Index of the logical sector that stores the beginning of the area reserved for files and directories.
NumSectorsData Number of logical sectors available for file and directories.

FS_FAT_LAYOUT

Description

Data layout of a FAT partition.

Type definition

typedef struct {
  U32  SectorIndexBPB;
  U32  SectorIndexBPBBackup;
  U32  SectorIndexFSInfo;
  U32  SectorIndexFSInfoBackup;
  U32  NumSectorsReserved;
  U32  SectorIndexAT;
  U32  SectorIndexATBackup;
  U32  NumSectorsAT;
  U32  SectorIndexRootDir;
  U32  NumSectorsRootDir;
  U32  SectorIndexData;
  U32  NumSectorsData;
} FS_FAT_LAYOUT;

Structure members

Member Description
SectorIndexBPB Index of the logical sector that stores the format information.
SectorIndexBPBBackup Index of the logical sector that stores a copy of the format information.
SectorIndexFSInfo Index of the logical sector that stores information about the status of file system.
SectorIndexFSInfoBackup Index of the logical sector that stores a copy of the data stored at SectorIndexFSInfo.
NumSectorsReserved Number of reserved logical sectors.
SectorIndexAT Index of the logical sector that stores the beginning of the allocation table.
SectorIndexATBackup Index of the logical sector that stores the beginning of the copy of the allocation table.
NumSectorsAT Number of logical sectors in the allocation table.
SectorIndexRootDir Index of the logical sector that stores the beginning of the root directory.
NumSectorsRootDir Number of logical sectors allocated for the root directory.
SectorIndexData Index of the logical sector that stores the beginning of the area reserved for files and directories.
NumSectorsData Number of logical sectors available for file and directories.

Additional information

SectorIndexBPB is typically set to 0.

SectorIndexBPBBackup is typically set to 6. This member is valid only for FAT32 formatted volumes.

SectorIndexFSInfo is typically set to 1. This member is valid only for FAT32 formatted volumes.

SectorIndexFSInfoBackup is typically set to 7. This member is valid only for FAT32 formatted volumes.

NumSectorsReserved is never set to 0 because it includes at least the BPB sector and the FSInfo sector.

SectorIndexATBackup is set to 0 if the backup AT is not present.

SectorIndexRootDir is valid only for FAT12 and FAT16 formatted volumes. For FAT32 formatted volumes this member is set to 0 to indicate that the root directory is dynamically allocated at runtime.

NumSectorsRootDir is valid only for FAT12 and FAT16 formatted volumes. For FAT32 formatted volumes this member is set to 0 to indicate that the root directory is dynamically allocated at runtime.

FS_EXFAT_LAYOUT

Description

Data layout of an exFAT partition.

Type definition

typedef struct {
  U32  SectorIndexBoot;
  U32  SectorIndexBootBackup;
  U32  SectorIndexBootEx;
  U32  SectorIndexBootExBackup;
  U32  NumSectorsBootEx;
  U32  SectorIndexOEMPara;
  U32  SectorIndexOEMParaBackup;
  U32  SectorIndexReserved;
  U32  SectorIndexReservedBackup;
  U32  SectorIndexCheckSum;
  U32  SectorIndexCheckSumBackup;
  U32  SectorIndexAT;
  U32  SectorIndexATBackup;
  U32  NumSectorsAT;
  U32  SectorIndexData;
  U32  NumSectorsData;
  U32  SectorIndexRootDir;
  U32  SectorIndexAB;
  U32  NumSectorsAB;
  U32  SectorIndexUT;
  U32  NumSectorsUT;
} FS_EXFAT_LAYOUT;

Structure members

Member Description
SectorIndexBoot Index of the logical sector that stores the format information.
SectorIndexBootBackup Index of the logical sector that stores a copy of the format information.
SectorIndexBootEx Index of the first logical sector that stores extended boot information.
SectorIndexBootExBackup Index of the first logical sector that stores a copy of the extended boot information.
NumSectorsBootEx Number of sectors that store extended boot information.
SectorIndexOEMPara Index of the logical sector that stores OEM parameters.
SectorIndexOEMParaBackup Index of the logical sector that stores a copy of the OEM parameters.
SectorIndexReserved Index of the logical sector that stores reserved information.
SectorIndexReservedBackup Index of the logical sector that stores a copy of the reserved information.
SectorIndexCheckSum Index of the logical sector that stores checksum information.
SectorIndexCheckSumBackup Index of the logical sector that stores a copy of the checksum information.
SectorIndexAT Index of the logical sector that stores the beginning of the allocation table.
SectorIndexATBackup Index of the logical sector that stores the beginning of the copy of the allocation table.
NumSectorsAT Number of logical sectors in the allocation table.
SectorIndexData Index of the logical sector that stores the beginning of the area reserved for files and directories.
NumSectorsData Number of logical sectors available for file and directories.
SectorIndexRootDir Index of the first logical sector of the root directory.
SectorIndexAB Index of the first logical sector of the Allocation Bitmap.
NumSectorsAB Number of logical sectors in the Allocation Bitmap.
SectorIndexUT Index of the first logical sector of the Up-case Table.
NumSectorsUT Number of logical sectors in the Up-case Table.

Additional information

SectorIndexBoot is typically set to 0.

SectorIndexBootBackup is typically set to 12.

SectorIndexATBackup is set to 0 if the backup AT is not present.

FS_FS_LAYOUT

Description

Data layout of the file system.

Type definition

typedef union {
  FS_FAT_LAYOUT    fat;
  FS_EFS_LAYOUT    efs;
  FS_EXFAT_LAYOUT  exFAT;
} FS_FS_LAYOUT;

Structure members

Member Description
fat Information about the layout of the FAT file system data.
efs Information about the layout of the EFS file system data.
exFAT Information about the layout of the exFAT file system data.

File system extended functions

This section describes API functions that do not fall in any other category. It includes function that operate on volumes, utility functions as well as functions for locking the file system against concurrent access from different tasks.

FS_ConfigEOFErrorSuppression()

Description

Enables / disables the reporting of end-of-file condition as error.

Prototype

void FS_ConfigEOFErrorSuppression(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 EOF is reported as error. 1 EOF is not reported as error.

Additional information

The end-of-file indicator of a file handle is set to 1 as soon as the application tries to read more bytes than available in the file. This function controls if an error is reported via FS_FError() when the end-of-file indicator is set for a file handle. The default is to report the end-of-file condition as error. The configuration has effect on all the opened file handles.

This function is available only when the file system is built with FS_SUPPRESS_EOF_ERROR set to 1.

FS_ConfigPOSIXSupport()

Description

Enables / disables support for the POSIX-like behavior.

Prototype

void FS_ConfigPOSIXSupport(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 POSIX behavior is disabled. 1 POSIX behavior is enabled.

Additional information

The end-of-file indicator of a file handle is set to 1 as soon as the application tries to read more bytes than available in the file. This function controls if an error is reported via FS_FError() when the end-of-file indicator is set for a file handle. The default is to report the end-of-file condition as error. The configuration has effect on all the opened file handles.

FS_ConfigWriteVerification()

Description

Enables / disables the verification of the written data.

Prototype

void FS_ConfigWriteVerification(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Verification is disabled. 1 Verification is enabled.

Additional information

If enabled, this feature requests the file system to check that the data has been written correctly to storage device. This operation is performed by reading back and comparing the read with the written data. The verification is performed one logical sector at a time. A sector buffer is allocated from the memory pool for this operation.

FS_FileTimeToTimeStamp()

Description

Converts a broken-down date and time specification to a timestamp.

Prototype

void FS_FileTimeToTimeStamp(const FS_FILETIME * pFileTime,
                                  U32         * pTimeStamp);

Parameters

Parameter Description
pFileTime  in  Broken-down date and time to be converted. It cannot be NULL.
pTimeStamp  out  Converted timestamp. It cannot be NULL.

Additional information

This function can be used to convert a broken-down date and time specification to a timestamp used by the file system. The converted timestamp can be directly passed to FS_SetFileTime() or FS_SetFileTimeEx() to change the timestamps of files and directories.

For a description of the timestamp format refer to FS_GetFileTime().

Example

#include "FS.h"

void SampleSetFileTime(void) {
  U32         TimeStamp;
  FS_FILETIME FileTime;

  FileTime.Year   = 2005;
  FileTime.Month  = 03;
  FileTime.Day    = 26;
  FileTime.Hour   = 10;
  FileTime.Minute = 56;
  FileTime.Second = 14;
  FS_FileTimeToTimeStamp (&FileTime, &TimeStamp);
  FS_SetFileTime("Test.txt", TimeStamp);
}

FS_FreeSectors()

Description

Informs the device driver about unused sectors.

Prototype

int FS_FreeSectors(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume on which to perform the operation.

Return value

= 0 OK, sectors have been freed.
≠ 0 Error code indicating the failure reason.

Additional information

The function visits each entry of the allocation table and checks if the cluster is used to store data. If the cluster is free, informs the storage layer that the sectors assigned to the cluster do not store valid data. This information is used by the NAND and NOR device drivers to optimize the internal wear-leveling process.

FS_FreeSectors() is available only when the support for the free sector operation is enabled. The support for the free sector operation can be enabled or disabled via FS_SUPPORT_FREE_SECTOR.

Example

#include "FS.h"

void SampleFreeSectors(void) {
  FS_FreeSectors("nand:0:");
}

FS_GetAutoMount()

Description

Returns information about how a volume is automatically mounted.

Prototype

int FS_GetAutoMount(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

= 0 Volume is not mounted automatically.
= FS_MOUNT_RO Volume is mounted automatically in read only mode.
= FS_MOUNT_RW Volume is mounted automatically in read/write mode.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

After the initialization of the file system all the volumes are configured to be automatically mounted as read/write at the first access to the file system. The type of mount operation can be configured via FS_SetAutoMount().

FS_GetFileId()

Description

Calculates a value that uniquely identifies a file.

Prototype

int FS_GetFileId(const char * sFileName,
                       U8   * pId);

Parameters

Parameter Description
sFileName Name of the file for which to calculate the id.
pId A 16-byte array where the id is stored.

Return value

= 0 Id returned OK.
≠ 0 Error code indicating the failure reason.

Additional information

The calculated value is a combination of the sector number that stores the directory entry assigned to file combined with the index of the directory index. Typically used by USB MTP component of SEGGER emUSB-Device to create an unique object id to the file.

FS_GetFileWriteMode()

Description

Returns the write mode.

Prototype

FS_WRITEMODE FS_GetFileWriteMode(void);

Return value

WriteMode Specifies how to write to file:

Additional information

This function can be used to query the write mode configured for the entire file system. The write mode for the entire file system can be configured via FS_SetFileWriteMode(). The write mode is set by default to FS_WRITEMODE_SAFE when the file system is initialized.

Refer to FS_SetFileWriteMode() for detailed information about the different write modes.

FS_GetFileWriteModeEx()

Description

Returns the write mode configured for a specified volume.

Prototype

FS_WRITEMODE FS_GetFileWriteModeEx(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Identifies the volume that have to be queried.

Return value

WriteMode Specifies how to write to file:

Additional information

This function can be used to query the write mode configured for the specified volume. The write mode of the volume can be configured via FS_SetFileWriteModeEx(). If the write mode is not explicitly configured by the application for the volume via FS_SetFileWriteModeEx() then the write mode configured for the entire file system is returned. The write mode for the entire file system can be configured via FS_SetFileWriteMode(). The write mode is set by default to FS_WRITEMODE_SAFE when the file system is initialized.

Refer to FS_SetFileWriteMode() for detailed information about the different write modes.

FS_GetFSType()

Description

Returns the type of file system assigned to volume.

Prototype

int FS_GetFSType(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried. It cannot be NULL.

Return value

≥ 0 File system type.
< 0 Error code indicating the failure reason.

Additional information

This function is optional and available only when the file system is built with support for multiple file system types. The support for multiple file system types is activated when more than two of the following configuration defines are set to 1:

The return value can be one of the value specified by File system types

Example

#include "FS.h"

void SampleGetFSType(void) {
  int FSType;

#if FS_SUPPORT_MULTIPLE_FS
  FSType = FS_GetFSType("");
#else
  FSType = FS_FAT;
#endif
  FS_X_Log("File system type: ");
  switch (FSType) {
  case FS_FAT:
    FS_X_Log("FAT");
    break;
  case FS_EFS:
    FS_X_Log("EFS");
    break;
  default:
    FS_X_Log("<unknown>");
    break;
  }
  FS_X_Log("\n");
}

FS_GetMaxSectorSize()

Description

Queries the maximum configured logical sector size.

Prototype

U32 FS_GetMaxSectorSize(void);

Return value

Maximum logical sector size in bytes.

Additional information

Default value of the maximum logical sector size is 512 bytes. Refer to FS_SetMaxSectorSize() for more information about the maximum logical sector size.

Example

#include "FS.h"

void SampleGetMaxSectorSize(void) {
  U32 MaxSectorSize;

  MaxSectorSize = FS_GetMaxSectorSize();
}

FS_GetMemInfo()

Description

Returns information about the memory management.

Prototype

int FS_GetMemInfo(FS_MEM_INFO * pMemInfo);

Parameters

Parameter Description
pMemInfo  out  Returned information.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

Additional information

The application can use this function to obtain information about the memory management such as number of bytes allocated by the file system, type of memory management used, etc.

FS_GetMountType()

Description

Returns information about how a volume is mounted.

Prototype

int FS_GetMountType(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only.
= FS_MOUNT_RW Volume is mounted read/write.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

sVolumeName is the name of a volume that already exists. If the volume name is not known to file system then an error is returned. Alternatively, the application can call FS_IsVolumeMounted() if the information about how the volume is actually mounted is not important. After the file system initialization all volumes are in unmounted state.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetMountType(void) {
  int          r;
  const char * sMountType;
  char         ac[100];

  r = FS_GetMountType("");
  switch (r) {
  case 0:
    sMountType = "not mounted";
    break;
  case FS_MOUNT_RO:
    sMountType = "read only";
    break;
  case FS_MOUNT_RW:
    sMountType = "read/write";
    break;
  default:
    sMountType = FS_ErrorNo2Text(r);
    break;
  }
  SEGGER_snprintf(ac, sizeof(ac), "Mount type: %s\n", sMountType);
  FS_X_Log(ac);
}

FS_GetNumFilesOpen()

Description

Queries the number of opened file handles.

Prototype

int FS_GetNumFilesOpen(void);

Return value

Total number of file handles that are open.

Additional information

This function counts the number of file handles that were opened by the application via FS_FOpen() or FS_FOpenEx() and that were not closed yet via FS_FClose().

The returned value is not the actual number of files opened because the same file can be opened by an application more than one time. For example, FS_GetNumFilesOpen() returns 2 if the same file is opened by the application twice.

Example

#include "FS.h"

void SampleGetNumFilesOpen(void) {
  FS_FILE * pFile1;
  FS_FILE * pFile2;
  int       NumFileHandles;

  FS_Init();
  //
  // The number of opened files is 0 at this stage.
  //
  NumFileHandles = FS_GetNumFilesOpen();
  //
  // Open the first file.
  //
  pFile1 = FS_FOpen("File1.txt", "w");
  //
  // The number of opened files is 1 at this stage.
  //
  NumFileHandles = FS_GetNumFilesOpen();
  //
  // Open the second file.
  //
  pFile2 = FS_FOpen("File2.txt", "w");
  //
  // The number of opened files is 2 at this stage.
  //
  NumFileHandles = FS_GetNumFilesOpen();
  //
  // Close first file.
  //
  FS_FClose(pFile1);
  //
  // The number of opened files is 1 at this stage.
  //
  NumFileHandles = FS_GetNumFilesOpen();
  //
  // Close second file.
  //
  FS_FClose(pFile2);
  //
  // The number of opened files is 0 at this stage.
  //
  NumFileHandles = FS_GetNumFilesOpen();
}

FS_GetNumFilesOpenEx()

Description

Queries the number of opened file handles on a volume.

Prototype

int FS_GetNumFilesOpenEx(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume (0-terminated string). NULL is permitted.

Return value

≥ 0 Total number of file handles that are open on the volume.
< 0 Error code indicating the failure reason.

Additional information

This function counts the number of file handles that were opened by the application via FS_FOpen() or FS_FOpenEx() and that were not closed yet via FS_FClose() on a specified volume.

The returned value is not the actual number of files opened because the same file can be opened by an application more than one time. For example, FS_GetNumFilesOpenEx() returns 2 if the same file is opened by the application twice.

FS_GetNumFilesOpenEx() works in the same way as FS_GetNumFilesOpen() if sVolumeName is set to NULL.

FS_GetNumVolumes()

Description

Queries the number of configured volumes.

Prototype

int FS_GetNumVolumes(void);

Return value

Number of volumes.

Additional information

This function can be used to check how many volumes are configured in the file system. Each call to FS_AddDevice() creates a separate volume. Calling FS_AddPhysDevice() does not create a volume. The maximum number of volumes is limited only by available memory.

FS_GetNumVolumes() can be used together with FS_GetVolumeName() to list the names of all configured volumes.

Example

#include "FS.h"

void SampleGetVolumeName(void) {
  int  NumVolumes;
  int  iVolume;
  int  BufferSize;
  int  NumBytesStored;
  char acVolumeName[32];

  BufferSize = sizeof(acVolumeName);
  NumVolumes = FS_GetNumVolumes();
  FS_X_Log("Available volumes:\n");
  for (iVolume = 0; iVolume < NumVolumes; iVolume++) {
    NumBytesStored = FS_GetVolumeName(iVolume, acVolumeName, BufferSize);
    if (NumBytesStored < BufferSize) {
      FS_X_Log("  ");
      FS_X_Log(acVolumeName);
      FS_X_Log("\n");
    }
  }
}

FS_GetVolumeAlias()

Description

Returns the alternative name of a volume.

Prototype

char *FS_GetVolumeAlias(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName  in  Name of the volume to be queried. It cannot be set to NULL.

Return value

= NULL No volume alias configure or an error occurred.
NULL Configured volume alias.

Additional information

This function is optional. It can be used by an application to obtain the alternative name of a volume if configured. For more information about the volume alias refer to FS_SetVolumeAlias().

This function is available only when FS_SUPPORT_VOLUME_ALIAS is set to 1.

The alias of a volume can also be queried either via FS_GetVolumeInfo() or FS_GetVolumeInfoEx(). The sAlias member of the FS_DISK_INFO structure stores the configured alias.

FS_GetVolumeFreeSpace()

Description

Returns the free space available on a volume.

Prototype

U32 FS_GetVolumeFreeSpace(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be checked.

Return value

≠ 0 Number of bytes available on the volume.
= 0 An error occurred.

Additional information

This function returns the free space available to application to store files and directories.

A free space larger than four Gbytes is reported as 0xFFFFFFFF because this is the maximum value that can be represented in an unsigned 32-bit integer. The function FS_GetVolumeFreeSpaceKB() can be used instead if the available free space is larger than four Gbytes.

FS_GetVolumeFreeSpace() can sill be reliably used if the application does not need to know if there is more than four GBytes of free space available.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetVolumeFreeSpace(void) {
  U32  NumBytes;
  char ac[100];

  NumBytes = FS_GetVolumeFreeSpace("");
  if (NumBytes < 0x8000) {
    SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Kbytes\n", NumBytes);
  } else {
    NumBytes >>= 10;
    SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Mbytes\n", NumBytes);
  }
  FS_X_Log(ac);
}

FS_GetVolumeFreeSpaceFirst()

Description

Initiates the search for free space.

Prototype

int FS_GetVolumeFreeSpaceFirst(      FS_FREE_SPACE_DATA * pFSD,
                               const char               * sVolumeName,
                                     void               * pBuffer,
                                     int                  SizeOfBuffer);

Parameters

Parameter Description
pFSD Context of the free space search.
sVolumeName Name of the volume to search on.
pBuffer Work buffer.
SizeOfBuffer Size of the work buffer in bytes.

Return value

= 1 OK, the entire allocation table has been searched.
= 0 OK, search is not completed.
< 0 Error code indicating the failure reason.

Additional information

FS_GetVolumeFreeSpaceFirst() together with FS_GetVolumeFreeSpaceNext() can be used to calculate the amount of available free space on a volume. This pair of functions implement the same functionality as FS_GetVolumeFreeSpace() with the difference that they block the access to the file system for a very short time.

Typically, FS_GetVolumeFreeSpace() uses the information stored to the FSInfo sector of a FAT file system or to the Status sector of an EFS file system to get the number of free clusters on the volume. If this information is not available then FS_GetVolumeFreeSpace() calculates the free space by reading and evaluating the entire allocation table. The size of the allocation table depends on the size of the volume with sizes of a few tens of Mbytes for a volume pf 4 Gbytes or larger. Reading such amount of data can take a relatively long time to complete during which the application is not able to access the file system. FS_GetVolumeFreeSpaceFirst() and FS_GetVolumeFreeSpaceNext() can be used in such cases by calculating the available free space while the application is performing other file system accesses.

FS_GetVolumeFreeSpaceFirst() is used by the application to initiate the search process followed by one or more calls to FS_GetVolumeFreeSpaceNext(). The free space is returned in the NumClustersFree member of pFSD. The cluster size can be determined by calling FS_GetVolumeInfoEx() with the Flags parameter set to 0.

The specified work buffer is used by the file system for the read operations only when FS_SUPPORT_SECTOR_BUFFER_BURST is set to 1. The file system is able to use the work buffer for burst operations only if pBuffer is aligned according to the value configured via FS_DRIVER_ALIGNMENT.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetVolumeFreeSpace(void) {
  char               ac[100];
  FS_FREE_SPACE_DATA fsd;
  int                r;
  FS_DISK_INFO       VolumeInfo;
  U32                BytesPerCluster;
  U32                NumKBytesFree;

  r = FS_GetVolumeFreeSpaceFirst(&fsd, "", NULL, 0);
  if (r < 0) {
    SEGGER_snprintf(ac, sizeof(ac), "Could not initiate searching (%s)\n", 
      FS_ErrorNo2Text(r));
    FS_X_Log(ac);
  } else {
    if (r == 0) {
      for (;;) {
        r = FS_GetVolumeFreeSpaceNext(&fsd);
        if (r < 0) {
          SEGGER_snprintf(ac, sizeof(ac), "Could not continue searching (%s)\n",  
            FS_ErrorNo2Text(r));
          FS_X_Log(ac);
          break;
        }
        if (r == 1) {
          // End of allocation table reached.
          break;
        }
      }
    }
  }
  FS_GetVolumeInfoEx("", &VolumeInfo, 0);
  BytesPerCluster = (VolumeInfo.BytesPerSector * VolumeInfo.SectorsPerCluster);
  NumKBytesFree   = fsd.NumClustersFree * (BytesPerCluster >> 10);
  SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Kbytes\n", NumKBytesFree);
  FS_X_Log(ac);
}

FS_GetVolumeFreeSpaceKB()

Description

Returns the free space available on a volume.

Prototype

U32 FS_GetVolumeFreeSpaceKB(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be checked.

Return value

≠ 0 The space available on the volume in Kbytes.
= 0 An error occurred.

Additional information

This function returns the free space available to application to store files and directories.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetVolumeFreeSpaceKB(void) {
  U32  NumKBytes;
  char ac[100];

  NumKBytes = FS_GetVolumeFreeSpaceKB("");
  SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Kbytes\n", NumKBytes);
  FS_X_Log(ac);
}

FS_GetVolumeFreeSpaceNext()

Description

Continues the search for free space.

Prototype

int FS_GetVolumeFreeSpaceNext(FS_FREE_SPACE_DATA * pFSD);

Parameters

Parameter Description
pFSD Context of the free space search.

Return value

= 1 OK, the entire allocation table has been searched.
= 0 OK, search is not completed.
< 0 Error code indicating the failure reason.

Additional information

pFSD has to be initialized via a call to FS_GetVolumeFreeSpaceFirst(). One or more calls to FS_GetVolumeFreeSpaceNext() are required in order to determine the available free space. For more information refer to FS_GetVolumeFreeSpaceFirst().

Example

Refer to FS_GetVolumeFreeSpaceFirst() for an example usage.

FS_GetVolumeInfo()

Description

Obtains information about a volume.

Prototype

int FS_GetVolumeInfo(const char         * sVolumeName,
                           FS_DISK_INFO * pInfo);

Parameters

Parameter Description
sVolumeName Name of the volume to query. It cannot be NULL.
pInfo  out  Volume information. It cannot be NULL.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

Additional information

This function returns the information about a volume such as volume size, available free space, format type, etc.

Example

#include <stdio.h>
#include <string.h>
#include "FS.h"

void SampleGetVolumeInfo(void) {
  FS_DISK_INFO   VolumeInfo;
  int            r;
  char           ac[100];
  const char   * sFSType;

  memset(&VolumeInfo, 0, sizeof(VolumeInfo));
  r = FS_GetVolumeInfo("", &VolumeInfo);
  if (r == 0) {
    SEGGER_snprintf(ac, sizeof(ac), "Total number of clusters:         %lu\n", 
      VolumeInfo.NumTotalClusters);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Number of free clusters:          %lu\n", 
      VolumeInfo.NumFreeClusters);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Sectors per cluster:              %d\n", 
      VolumeInfo.SectorsPerCluster);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Bytes per sector:                 %d\n", 
      VolumeInfo.BytesPerSector);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Number of root directory entries: %d\n", 
      VolumeInfo.NumRootDirEntries);
    FS_X_Log(ac);
    switch (VolumeInfo.FSType) {
    case FS_TYPE_FAT12:
      sFSType = "FAT12";
      break;
    case FS_TYPE_FAT16:
      sFSType = "FAT16";
      break;
    case FS_TYPE_FAT32:
      sFSType = "FAT32";
      break;
    case FS_TYPE_EFS:
      sFSType = "EFS";
      break;
    default:
      sFSType = "<Unknown>";
      break;
    }
    SEGGER_snprintf(ac, sizeof(ac), "File system type:                 %s\n", 
      sFSType);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Formatted acc. to SD spec.:       %s\n", 
      VolumeInfo.IsSDFormatted ? "Yes" : "No");
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Has been modified:                %s\n", 
      VolumeInfo.IsDirty ? "Yes" : "No");
    FS_X_Log(ac);
  }
}

FS_GetVolumeInfoEx()

Description

Obtains information about a volume.

Prototype

int FS_GetVolumeInfoEx(const char         * sVolumeName,
                             FS_DISK_INFO * pInfo,
                             int            Flags);

Parameters

Parameter Description
sVolumeName The volume name.
pInfo  out  Volume information.
Flags Specifies what type of information the function has to return.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_GetVolumeInfo() with the difference it gives the application more control about what type of information it has to return. The type of information that has to be returned can be controlled via the Flags parameter.

Flags is an bitwise-or combination of Volume information flags.

Example

#include <stdio.h>
#include <string.h>
#include "FS.h"

void SampleGetVolumeInfoEx(void) {
  FS_DISK_INFO   VolumeInfo;
  int            r;
  char           ac[100];
  const char   * sFSType;

  memset(&VolumeInfo, 0, sizeof(VolumeInfo));
  //
  // Return also the available free space.
  //
  r = FS_GetVolumeInfoEx("", &VolumeInfo, FS_DISKINFO_FLAG_FREE_SPACE);
  if (r == 0) {
    SEGGER_snprintf(ac, sizeof(ac), "Number of total clusters:         %lu\n", 
      VolumeInfo.NumTotalClusters);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Number of free clusters:          %lu\n", 
      VolumeInfo.NumFreeClusters);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Sectors per cluster:              %d\n", 
      VolumeInfo.SectorsPerCluster);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Bytes per sector:                 %d\n", 
      VolumeInfo.BytesPerSector);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Number of root directory entries: %d\n", 
      VolumeInfo.NumRootDirEntries);
    FS_X_Log(ac);
    switch (VolumeInfo.FSType) {
    case FS_TYPE_FAT12:
      sFSType = "FAT12";
      break;
    case FS_TYPE_FAT16:
      sFSType = "FAT16";
      break;
    case FS_TYPE_FAT32:
      sFSType = "FAT32";
      break;
    case FS_TYPE_EFS:
      sFSType = "EFS";
      break;
    default:
      sFSType = "<Unknown>";
      break;
    }
    SEGGER_snprintf(ac, sizeof(ac), "File system type:                 %s\n", 
      sFSType);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Formatted acc. to SD spec.:       %s\n", 
      VolumeInfo.IsSDFormatted ? "Yes" : "No");
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "Has been modified:                %s\n", 
      VolumeInfo.IsDirty ? "Yes" : "No");
    FS_X_Log(ac);
  }
}

FS_GetVolumeLabel()

Description

Returns the label of the volume.

Prototype

int FS_GetVolumeLabel(const char     * sVolumeName,
                            char     * sVolumeLabel,
                            unsigned   SizeOfVolumeLabel);

Parameters

Parameter Description
sVolumeName Identifies the volume to be queried. It cannot be NULL.
sVolumeLabel Buffer that receives the volume label. It cannot be NULL.
SizeOfVolumeLabel Number of characters in pVolumeName buffer.

Return value

= 0 OK, volume label read.
≠ 0 Error code indicating the failure reason.

Additional information

The function stores at most SizeOfVolumeLabel - 1 bytes to pVolumeLabel buffer. The returned volume label is 0-terminated. The volume label is truncated if it contains more characters than the number of characters that can be stored to pVolumeLabel.

EFS does not have a volume label. FS_GetVolumeLabel() returns with an error if the application tries to read the volume label of a volume formatted as EFS.

Example

#include "FS.h"

void SampleGetVolumeName(void) {
  char acVolumeLabel[16];
  int  r;

  r = FS_GetVolumeLabel("", acVolumeLabel, sizeof(acVolumeLabel));
  if (r == 0) {
    FS_X_Log("Volume label: ");
    FS_X_Log(acVolumeLabel);
    FS_X_Log("\n");
  }
}

FS_GetVolumeName()

Description

Obtains the name of a volume.

Prototype

int FS_GetVolumeName(int    VolumeIndex,
                     char * pVolumeName,
                     int    SizeOfVolumeName);

Parameters

Parameter Description
VolumeIndex 0-based index of the volume to be queried.
pVolumeName  out  Receives the name of the volume as 0-terminated string. It cannot be NULL.
SizeOfVolumeName Number of bytes in pVolumeName.

Return value

> 0 Number of bytes in the volume name or number of bytes required to store the volume name.
< 0 Error code indicating the failure reason.

Additional information

If pVolumeName is sufficiently large to store the entire volume name and the 0-terminator then the function returns the number of bytes in the volume name without the 0-terminator. If pVolumeName is not sufficiently large to store the entire volume name and the 0-terminator then the function returns the minimum buffer size required to store the entire volume name and the 0-terminator. In this case the function does not store any data to pVolumeName.

FS_GetVolumeName() stores at most SizeOfVolumeName - 1 bytes to pVolumeName and it terminates the string by a 0.

VolumeIndex specifies the position of the volume in the internal volume list of the file system. The first volume added to file system in FS_X_AddDevices() via FS_AddDevice() is stored at index 0 in the volume list, the second volume added via FS_AddDevice() is store at the index 1 in the volume list and so on. The total number of volumes can be queried via FS_GetNumVolumes().

Example

#include "FS.h"

void SampleGetVolumeName(void) {
  int  NumVolumes;
  int  iVolume;
  int  BufferSize;
  int  NumBytesStored;
  char acVolumeName[32];

  BufferSize = sizeof(acVolumeName);
  NumVolumes = FS_GetNumVolumes();
  FS_X_Log("Available volumes:\n");
  for (iVolume = 0; iVolume < NumVolumes; iVolume++) {
    NumBytesStored = FS_GetVolumeName(iVolume, acVolumeName, BufferSize);
    if (NumBytesStored < BufferSize) {
      FS_X_Log("  ");
      FS_X_Log(acVolumeName);
      FS_X_Log("\n");
    }
  }
}

FS_GetVolumeSize()

Description

Returns the size of a volume.

Prototype

U32 FS_GetVolumeSize(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

≠ 0 Total number of bytes available to file system.
= 0 An error occurred.

Additional information

This function returns the total number of bytes available to file system as data storage. The actual number of bytes available to application for files and directories is smaller than the value returned by FS_GetVolumeSize() since the file system requires some space for the boot sector and the allocation table.

A size larger than four Gbytes is reported as 0xFFFFFFFF because this is the maximum value that can be represented in an unsigned 32-bit integer. The function FS_GetVolumeSizeKB() can be used instead if the volume size is larger than four Gbytes.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetVolumeSize(void) {
  U32  NumBytes;
  char ac[100];

  NumBytes = FS_GetVolumeSize("");
  if (NumBytes < 0x8000) {
    SEGGER_snprintf(ac, sizeof(ac), "Volume size: %lu Kbytes\n", NumBytes);
  } else {
    NumBytes >>= 10;
    SEGGER_snprintf(ac, sizeof(ac), "Volume size: %lu Mbytes\n", NumBytes);
  }
  FS_X_Log(ac);
}

FS_GetVolumeSizeKB()

Description

Returns the size of a volume.

Prototype

U32 FS_GetVolumeSizeKB(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

≠ 0 Storage available to file system in Kbytes.
= 0 An error occurred.

Additional information

This function returns the total number of bytes available to file system as data storage. The actual number of bytes available to application for files and directories is smaller than the value returned by FS_GetVolumeSize() since the file system requires some space for the boot sector and the allocation table.

Example

#include <stdio.h>
#include "FS.h"

void SampleGetVolumeSizeKB(void) {
  U32  NumKBytes;
  char ac[100];

  NumKBytes = FS_GetVolumeSizeKB("");
  SEGGER_snprintf(ac, sizeof(ac), "Volume size: %lu Kbytes\n", NumKBytes);
  FS_X_Log(ac);
}

FS_GetVolumeStatus()

Description

Returns the presence status of a volume.

Prototype

int FS_GetVolumeStatus(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume. It cannot be NULL.

Return value

FS_MEDIA_NOT_PRESENT Storage device is not present.
FS_MEDIA_IS_PRESENT Storage device is present.
FS_MEDIA_STATE_UNKNOWN Presence status is unknown.

Additional information

This function can be used to check if a removable storage device that is assigned to a volume is present or not. FS_GetVolumeStatus() is typically called periodically from a separate task to handle the insertion and removal of a removable storage device.

Example

#include "FS.h"
#include "FS_OS.h"

void SampleUnmountForced(void) {
  int IsPresentNew;
  int IsPresent;

  IsPresent = FS_GetVolumeStatus("");
  while (1) {
    IsPresentNew = FS_GetVolumeStatus("");
    //
    // Check if the presence status of the storage device has been changed.
    //
    if (IsPresentNew != IsPresent) {
      if (IsPresentNew == FS_MEDIA_IS_PRESENT) {
        FS_Mount("");
      } else  {
        FS_UnmountForced("");
      }
      IsPresent = IsPresentNew;
    }
    FS_X_OS_Delay(500);
  }
}

FS_IsVolumeMounted()

Description

Checks if a volume is mounted.

Prototype

int FS_IsVolumeMounted(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

1 Volume is mounted.
0 Volume is not mounted or does not exist.

Additional information

The function returns 1 if the volume is mounted either in read-only mode or in read / write mode.

Example

#include "FS.h"

void SampleIsVolumeMounted(void) {
  int IsMounted;

  IsMounted = FS_IsVolumeMounted("");
  if (IsMounted) {
    FS_X_Log("Volume is mounted.\n");
  } else {
    FS_X_Log("Volume is not mounted.\n");
  }
}

FS_Lock()

Description

Claims exclusive access to file system.

Prototype

void FS_Lock(void);

Additional information

The execution of the task that calls this function is suspended until the file system grants it exclusive access. After the task gets exclusive access to file system the other tasks that try to perform file system operations are blocked until the task calls FS_Unlock().

FS_Lock() is typically used by applications that call device driver functions from different tasks. These functions are usually not protected against concurrent accesses. Additionally, FS_Lock() can be used to protect a group of file system operations against concurrent access.

FS_Lock() is available if FS_OS_LOCKING set to 1. The function does nothing if FS_OS_LOCKING set to 0 or 2. The calls to FS_Lock() / FS_Unlock() cannot be nested.

The API functions of the file system are multitasking safe. It is not required to explicitly lock these function calls via FS_Lock() / FS_Unlock(). All API functions call internal versions of FS_Lock() and FS_Unlock() on function entry and exit respectively.

Example

#include "FS.h"

void SampleLock(void) {
  FS_FILE           * pFile;
  FS_NAND_DISK_INFO   DiskInfo;

  //
  // The device driver functions are not protected against concurrent
  // access from different tasks. Make sure that only one task can access
  // the file system.
  //
#if (FS_OS_LOCKING == 1)
  FS_Lock();
#endif // FS_OS_LOCKING == 1
  FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
#if (FS_OS_LOCKING == 1)
  FS_Unlock();
#endif // FS_OS_LOCKING == 1
  //
  // Make sure that the write operation is not interrupted
  // by a different task.
  //
#if (FS_OS_LOCKING == 1)
  FS_Lock();
#endif // FS_OS_LOCKING == 1
  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    FS_Write(pFile, "Test", 4);
    FS_FClose(pFile);
  }
#if (FS_OS_LOCKING == 1)
  FS_Unlock();
#endif // FS_OS_LOCKING == 1
}

FS_LockVolume()

Description

Claims exclusive access to a volume.

Prototype

void FS_LockVolume(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume that has to be locked.

Additional information

The execution of the task that calls this function is suspended until the file system grants it exclusive access to the specified volume. After the task gets exclusive access to volume the other tasks that try to perform file system operations on that volume are blocked until the task calls FS_UnlockVolume() with the same volume name as in the call to FS_LockVolume().

FS_LockVolume() is typically used by applications that call device driver functions from different tasks. These functions are usually not protected against concurrent accesses. Additionally, FS_LockVolume() can be used to protect a group of file system operations against concurrent access.

FS_LockVolume() is available if FS_OS_LOCKING set to 2. The function does nothing if FS_OS_LOCKING set to 0 or 1. The calls to FS_LockVolume() / FS_UnlockVolume() cannot be nested.

The API functions of the file system are multitasking safe. It is not required to explicitly lock these function calls via FS_LockVolume() / FS_UnlockVolume(). All API functions call internal versions of FS_LockVolume() and FS_UnlockVolume() on function entry and exit respectively.

Example

#include "FS.h"

void SampleLockVolume(void) {
  FS_FILE           * pFile;
  FS_NAND_DISK_INFO   DiskInfo;

  //
  // The device driver functions are not protected against concurrent
  // access from different tasks. Make sure that only one task can access
  // the file system.
  //
#if (FS_OS_LOCKING == 2)
  FS_LockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
  FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
#if (FS_OS_LOCKING == 2)
  FS_UnlockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
  //
  // Make sure that the write operation is not interrupted
  // by a different task.
  //
#if (FS_OS_LOCKING == 2)
  FS_LockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
  pFile = FS_FOpen("nand:0:\\Test.txt", "w");
  if (pFile) {
    FS_Write(pFile, "Test", 4);
    FS_FClose(pFile);
  }
#if (FS_OS_LOCKING == 2)
  FS_UnlockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
}

FS_SetBusyLEDCallback()

Description

Registers a callback for busy status changes of a volume.

Prototype

int FS_SetBusyLEDCallback(const char                 * sVolumeName,
                                FS_BUSY_LED_CALLBACK * pfBusyLED);

Parameters

Parameter Description
sVolumeName Name of the volume for which the callback has to be registered. It cannot be NULL.
pfBusyLED Function to be called when the busy status changes. It cannot be NULL.

Return value

= 0 OK, callback registered.
≠ 0 Error code indicating the failure reason.

Additional information

The application can use this FS_SetBusyLEDCallback() to register a function that is called by the file system each time the busy status of a volume changes. The volume becomes busy when it starts an access to storage device. When the access to storage device ends the volume becomes ready. The busy status of a volume can change several times during a single file system operation.

FS_SetBusyLEDCallback() is available if the FS_SUPPORT_BUSY_LED configuration define is set to 1. The function does nothing if FS_SUPPORT_BUSY_LED is set to 0.

Example

#include "FS.h"

static void _cbBusyLED(U8 OnOff) {
  if (OnOff) {
    //
    // Set LED on.
    //
  } else {
    //
    // Set LED off.
    //
  }
}

void SampleSetBusyLEDCallback(void) {
  FS_FILE * pFile;

  FS_SetBusyLEDCallback("nand:0:", _cbBusyLED);
  pFile = FS_FOpen("nand:0:\\File.txt", "w");
  FS_FClose(pFile);
}

FS_SetCharSetType()

Description

Configures the character set that is used for the file and directory names.

Prototype

void FS_SetCharSetType(const FS_CHARSET_TYPE * pCharSetType);

Parameters

Parameter Description
pCharSetType Type of character set used.

Additional information

Permitted values of pCharSetType are:

Identifier Description
FS_CHARSET_CP437 Latin characters
FS_CHARSET_CP932 Japanese characters encoded as Shift JIS
FS_CHARSET_CP936 Simplified Chinese characters encoded as GBK
FS_CHARSET_CP949 Korean characters encoded as UHC
FS_CHARSET_CP950 Chinese characters encoded as Big5

FS_SetFSType()

Description

Sets the type of file system a volume.

Prototype

int FS_SetFSType(const char * sVolumeName,
                       int    FSType);

Parameters

Parameter Description
sVolumeName Name of the volume for which the type of the file system has to be set. It cannot be NULL.
FSType Type of file system.

Return value

= 0 OK, file system type set.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional and available only when the file system is built with support for multiple file system types. The support for multiple file system types is activated when more than two of the following configuration defines are set to 1:

FSType can be one of the value specified by File system types

In a multi-volume configuration the application has to call FS_SetFSType() before formatting a volume that was never formatted or when the volume was formatted using a different file system type.

Example

#include "FS.h"

void SampleSetFSType(void) {
  //
  // Format the "nand:0:" volume as EFS.
  //
#if FS_SUPPORT_MULTIPLE_FS
  FS_SetFSType("nand:0:", FS_EFS);
#endif // FS_SUPPORT_MULTIPLE_FS
  FS_Format("nand:0:", NULL);
  //
  // Format the "nor:0:" volume as FAT.
  //
#if FS_SUPPORT_MULTIPLE_FS
  FS_SetFSType("nor:0:", FS_FAT);
#endif // FS_SUPPORT_MULTIPLE_FS
  FS_Format("nor:0:", NULL);
}

FS_SetMemCheckCallback()

Description

Registers a callback for checking of 0-copy operations.

Prototype

int FS_SetMemCheckCallback(const char                  * sVolumeName,
                                 FS_MEM_CHECK_CALLBACK * pfMemCheck);

Parameters

Parameter Description
sVolumeName Name of the volume for which the callback has to be registered. It cannot be NULL.
pfMemCheck Function to be called before a 0-copy operation is executed. It cannot be NULL.

Return value

= 0 OK, callback registered.
≠ 0 Error code indicating the failure reason.

Additional information

FS_SetMemCheckCallback() can be used by an application to register a function that is called by the file system before any read or write operation to check if a data buffer can be used in 0-copy operation. In a 0-copy operation, a pointer to the data is passed directly to the device driver instead of the data being copied first in an internal buffer and then being passed it to device driver.

Example

#include "FS.h"

#if FS_SUPPORT_CHECK_MEMORY

static int _cbMemCheck(void * p, U32 NumBytes) {
  if ((U32)p > 0x100000uL) {
    return 1;   // 0-copy allowed.
  } else {
    return 0;   // 0-copy not allowed
  }
}

#endif // FS_SUPPORT_CHECK_MEMORY

void SampleSetMemCheckCallback(void) {
  FS_FILE * pFile;

#if FS_SUPPORT_CHECK_MEMORY
  FS_SetMemCheckCallback("", _cbMemCheck);
#endif // FS_SUPPORT_CHECK_MEMORY
  pFile = FS_FOpen("File.txt", "w");
  if (pFile) {
    FS_Write(pFile, "Test\n", 5);
  }
  FS_FClose(pFile);
}

FS_SetTimeDateCallback()

Description

Configures a function that the file system can use to get the current time and date.

Prototype

void FS_SetTimeDateCallback(FS_TIME_DATE_CALLBACK * pfTimeDate);

Parameters

Parameter Description
pfTimeDate Function to be invoked.

Additional information

During the initialization of the file system via FS_Init() the callback function is initialized to point to FS_X_GetTimeDate().

FS_SetVolumeAlias()

Description

Assigns an alternative name for a volume.

Prototype

int FS_SetVolumeAlias(const char * sVolumeName,
                      const char * sVolumeAlias);

Parameters

Parameter Description
sVolumeName  in  Name of the volume to which the alternative name has to be assigned. It cannot be set to NULL.
sVolumeAlias  in  Alternative name as 0-terminated string. Can be set to NULL.

Return value

= 0 OK, the alternative name has been assigned.
< 0 Error code indicating the failure reason.

Additional information

The assigned alias can be used as replacement in any path to a file or directory that contains a volume name and it can be passed instead of a volume name to any API function that requires one. The alias replaces the volume and the unit number. When used as a volume name the volume separator character (’:’) has to be added to the end of the alias otherwise it is not recognized as a valid volume name by the file system.

Valid characters in an alias are ASCII capital and small letters, digits and the underscore character. The comparison applied to alias is case sensitive and is performed after the file system checks the real volume names.

The alias name is copied to the internal instance of the volume. The function fails with an error if the alias is longer that the space available in the internal buffer. The size of the internal buffer for the alias can be configured at compile time via FS_MAX_LEN_VOLUME_ALIAS. The alias can be removed by either passing a NULL or an empty string as sVolumeAlias parameter. If FS_MAX_LEN_VOLUME_ALIAS is set to 0 then only the pointer to the volume alias is stored. The application has to make sure that the memory region that stores the volume alias remains valid until the file system is deinitialized via FS_DeInit().

This function is available only when FS_SUPPORT_VOLUME_ALIAS is set to 1.

The alias of a volume can be queried either via FS_GetVolumeInfo() or FS_GetVolumeInfoEx(). The sAlias member of the FS_DISK_INFO structure stores the configured alias. In addition, the volume alias can be obtained via FS_GetVolumeAlias().

Example

#include "FS.h"

void SampleSetVolumeAlias(void) {
  FS_SetVolumeAlias("nor:0:", "flash");
}

FS_SetVolumeLabel()

Description

Modifies the label of a volume.

Prototype

int FS_SetVolumeLabel(const char * sVolumeName,
                      const char * sVolumeLabel);

Parameters

Parameter Description
sVolumeName Name of the volume for which the label has to be modified. It cannot be NULL.
sVolumeLabel Volume label as 0-terminated ASCII string. The volume label is deleted if set to NULL.

Return value

= 0 OK, volume label set.
≠ 0 Error code indicating the failure reason.

Additional information

The volume label is a ASCII string that can be assigned to a volume. It is not evaluated by the file system and it cannot be used as volume name. A Windows PC shows the volume label of a removable storage device in the “Computer” window when it is mounted via USB MSD. The volume label can be read via FS_GetVolumeLabel().

The volume label of a FAT-formatted volume can contain at most 11 characters. The following characters are not allowed in a volume name: ’“’, ’&’, ’*’, ’+’, ’-’, ’,’, ’.’, ’/’, ’:’, ’;’, ’<’, ’=’, ’>’, ’?’, ’[’, ’]’, ’\’.

EFS does not have a volume label. FS_GetVolumeLabel() returns with an error if the application tries to read the volume label of a volume formatted as EFS.

Example

#include "FS.h"

void SampleSetVolumeName(void) {
  FS_SetVolumeLabel("", "SEGGER");
}

FS_TimeStampToFileTime()

Description

Converts a timestamp to a broken-down date and time specification.

Prototype

void FS_TimeStampToFileTime(U32           TimeStamp,
                            FS_FILETIME * pFileTime);

Parameters

Parameter Description
TimeStamp Timestamp to be converted.
pFileTime  out  Converted broken-down date and time. It cannot be NULL.

Additional information

This function can be used to convert a timestamp as used by the file system a broken-down date and time specification.

For a description of the timestamp format refer to FS_GetFileTime().

Example

#include <stdio.h>
#include "FS.h"

void SampleGetFileTime(void) {
  char        ac[100];
  U32         TimeStamp;
  FS_FILETIME FileTime;
  int         r;

  r = FS_GetFileTime("Test.txt", &TimeStamp);
  if (r == 0) {
    FS_TimeStampToFileTime(TimeStamp, &FileTime);
    SEGGER_snprintf(ac, sizeof(ac), "Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
      FileTime.Year, FileTime.Month,  FileTime.Day,
      FileTime.Hour, FileTime.Minute, FileTime.Second);
    FS_X_Log(ac);
  }
}

FS_Unlock()

Description

Releases the exclusive access to file system.

Prototype

void FS_Unlock(void);

Additional information

This function has to be called in pair with FS_Lock() to allow other tasks to access the file system. For each call to FS_Lock() the application has to call FS_Unlock().

FS_Unlock() is available if FS_OS_LOCKING set to 1. The function does nothing if FS_OS_LOCKING set to 0 or 2. The calls to FS_Lock() / FS_Unlock() cannot be nested.

Example

Refer to FS_Lock() for an example usage.

FS_UnlockVolume()

Description

Releases the exclusive access to a volume.

Prototype

void FS_UnlockVolume(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume that has to be locked.

Additional information

This function has to be called in pair with FS_LockVolume() to allow other tasks to access the volume. For each call to FS_LockVolume() the application has to call FS_UnlockVolume() with the same volume name as parameter.

FS_UnlockVolume() is available if FS_OS_LOCKING set to 2. The function does nothing if FS_OS_LOCKING set to 0 or 1. The calls to FS_LockVolume() / FS_UnlockVolume() cannot be nested.

Example

Refer to FS_LockVolume() for an example usage.

Disk checking error codes

Description

Error codes reported by FS_CheckDisk() during operation.

Definition

#define FS_CHECKDISK_ERRCODE_0FILE                      0x10
#define FS_CHECKDISK_ERRCODE_SHORTEN_CLUSTER            0x11
#define FS_CHECKDISK_ERRCODE_CROSSLINKED_CLUSTER        0x12
#define FS_CHECKDISK_ERRCODE_FEW_CLUSTER                0x13
#define FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED             0x14
#define FS_CHECKDISK_ERRCODE_CLUSTER_NOT_EOC            0x15
#define FS_CHECKDISK_ERRCODE_INVALID_CLUSTER            0x16
#define FS_CHECKDISK_ERRCODE_INVALID_DIRECTORY_ENTRY    0x17
#define FS_CHECKDISK_ERRCODE_SECTOR_NOT_IN_USE          0x18
#define FS_CHECKDISK_ERRCODE_INVALID_FILE               0x19

Symbols

Definition Description
FS_CHECKDISK_ERRCODE_0FILE A cluster chain is assigned to a file that does not contain any data.
FS_CHECKDISK_ERRCODE_SHORTEN_CLUSTER The cluster chain assigned to a file is longer than the size of the file.
FS_CHECKDISK_ERRCODE_CROSSLINKED_CLUSTER A cluster is assigned to more than one file or directory.
FS_CHECKDISK_ERRCODE_FEW_CLUSTER The size of the file is larger than the cluster chain assigned to file.
FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED A cluster is marked as in use, but not assigned to any file or directory.
FS_CHECKDISK_ERRCODE_CLUSTER_NOT_EOC A cluster is does not have end-of-chain marker.
FS_CHECKDISK_ERRCODE_INVALID_CLUSTER Invalid cluster id.
FS_CHECKDISK_ERRCODE_INVALID_DIRECTORY_ENTRY Invalid directory entry.
FS_CHECKDISK_ERRCODE_SECTOR_NOT_IN_USE A logical sector that stores data is not marked as in use in the device driver.
FS_CHECKDISK_ERRCODE_INVALID_FILE A fragment file was found that does not belong to any big file.

Additional information

The error codes are reported via the ErrCode parameter of the callback function.

Example

Refer to FS_CheckDisk() for an example usage.

Disk checking return values

Description

Error codes returned by FS_CheckDisk().

Definition

#define FS_CHECKDISK_RETVAL_OK             0
#define FS_CHECKDISK_RETVAL_RETRY          1
#define FS_CHECKDISK_RETVAL_ABORT          2
#define FS_CHECKDISK_RETVAL_MAX_RECURSE    3
#define FS_CHECKDISK_RETVAL_CONTINUE       4
#define FS_CHECKDISK_RETVAL_SKIP           5

Symbols

Definition Description
FS_CHECKDISK_RETVAL_OK OK, file system not in corrupted state
FS_CHECKDISK_RETVAL_RETRY An error has be found and repaired, retry is required.
FS_CHECKDISK_RETVAL_ABORT User aborted operation via callback or API call
FS_CHECKDISK_RETVAL_MAX_RECURSE Maximum recursion level reached, operation aborted
FS_CHECKDISK_RETVAL_CONTINUE FS_CheckAT() returns this value to indicate that the allocation table has not been entirely checked.
FS_CHECKDISK_RETVAL_SKIP FS_CheckDir() returns this value to indicate that the directory entry does not have to be checked.

Example

Refer to FS_CheckDisk() for an example usage.

Disk checking action codes

Description

Values returned by the FS_CheckDisk() callback function.

Definition

#define FS_CHECKDISK_ACTION_DO_NOT_REPAIR      0
#define FS_CHECKDISK_ACTION_SAVE_CLUSTERS      1
#define FS_CHECKDISK_ACTION_ABORT              2
#define FS_CHECKDISK_ACTION_DELETE_CLUSTERS    3

Symbols

Definition Description
FS_CHECKDISK_ACTION_DO_NOT_REPAIR The error does not have to be repaired.
FS_CHECKDISK_ACTION_SAVE_CLUSTERS The data stored in the clusters of a faulty cluster chain has to be saved to a file.
FS_CHECKDISK_ACTION_ABORT The disk checking operation has to be aborted.
FS_CHECKDISK_ACTION_DELETE_CLUSTERS The data stored in the clusters of a faulty cluster chain has to be deleted.

Additional information

These values indicate FS_CheckDisk() how to handle a file system error.

Example

Refer to FS_CheckDisk() for an example usage.

File system types

Description

Types of file systems supported.

Definition

#define FS_FAT                 0
#define FS_EFS                 1
#define FS_EXFAT               2
#define FS_FAT_TYPE_UNKONWN    0u
#define FS_FAT_TYPE_FAT12      12u
#define FS_FAT_TYPE_FAT16      16u
#define FS_FAT_TYPE_FAT32      32u

Symbols

Definition Description
FS_FAT File Allocation Table (FAT).
FS_EFS SEGGER Embedded File System (EFS).
FS_EXFAT Extensible File Allocation Table (exFAT).
FS_FAT_TYPE_UNKONWN Internal use.
FS_FAT_TYPE_FAT12 Internal use.
FS_FAT_TYPE_FAT16 Internal use.
FS_FAT_TYPE_FAT32 Internal use.

Format types

Description

Types of format supported.

Definition

#define FS_TYPE_FAT12    0x000Cu
#define FS_TYPE_FAT16    0x0010u
#define FS_TYPE_FAT32    0x0020u
#define FS_TYPE_EFS      0x0120u
#define FS_TYPE_EXFAT    0x0220u

Symbols

Definition Description
FS_TYPE_FAT12 FAT with 12-bit allocation table entries.
FS_TYPE_FAT16 FAT with 16-bit allocation table entries.
FS_TYPE_FAT32 FAT with 32-bit allocation table entries.
FS_TYPE_EFS SEGGER Embedded File System (EFS) with 32-bit allocation table entries.
FS_TYPE_EXFAT exFAT with 32-bit allocation table entries.

FS_BUSY_LED_CALLBACK

Description

Type of function called by the file system to report a change in the busy status of a volume.

Type definition

typedef void FS_BUSY_LED_CALLBACK(U8 OnOff);

Parameters

Parameter Description
OnOff Indicates if the volume is busy or not. 1 The volume is busy. 0 The volume is ready.

Additional information

A function of this type can be registered with the file system via FS_SetBusyLEDCallback(). FS_BUSY_LED_CALLBACK() is called by the file system each time the volume changes the busy status from busy to ready and reverse. Therefore, an application can use FS_BUSY_LED_CALLBACK()to indicate the busy / ready status of a volume via LED or by other means.

The file system calls FS_BUSY_LED_CALLBACK() with OnOff set to 1 when the volume goes busy. When the volume becomes ready FS_BUSY_LED_CALLBACK() is called again with OnOff set to 0.

Example

Refer to FS_SetBusyLEDCallback() for an example usage.

FS_CHECKDISK_ON_ERROR_CALLBACK

Description

Type of function called by FS_CheckDisk() to report an error.

Type definition

typedef int FS_CHECKDISK_ON_ERROR_CALLBACK(int ErrCode,
                                           ... ...);

Parameters

Parameter Description
ErrCode Code of the reported error.

Return value

Value that indicates FS_CheckDisk() how the error should be handled.

Additional information

ErrCode is one of the FS_CHECKDISK_ERRCODE_ defines. The value returned by FS_CHECKDISK_ON_ERROR_CALLBACK() can be one of the FS_CHECKDISK_ACTION_ defines.

In addition to ErrCode FS_CheckDisk() can pass other parameters FS_CHECKDISK_ON_ERROR_CALLBACK() providing information about the reported error. These parameters can be directly passed to a printf()-style function along with the format returned by FS_CheckDisk_ErrCode2Text() to create a text description of the error in human-readable format.

Example

Refer to FS_CheckDisk() for an example usage.

FS_CHS_ADDR

Description

Address of physical block on a mechanical drive.

Type definition

typedef struct {
  U16  Cylinder;
  U8   Head;
  U8   Sector;
} FS_CHS_ADDR;

Structure members

Member Description
Cylinder Cylinder number (0-based)
Head Read / write head (0-based)
Sector Index of the sector on a cylinder.

FS_DISK_INFO

Description

Information about a volume.

Type definition

typedef struct {
  U32          NumTotalClusters;
  U32          NumFreeClusters;
  U16          SectorsPerCluster;
  U16          BytesPerSector;
  U16          NumRootDirEntries;
  U16          FSType;
  U8           IsSDFormatted;
  U8           IsDirty;
  const char * sAlias;
  void       * pBuffer;
  int          SizeOfBuffer;
  U16          SectorsPerClusterHigh;
} FS_DISK_INFO;

Structure members

Member Description
NumTotalClusters Total number of clusters on the storage device.
NumFreeClusters Number of clusters that are not in use.
SectorsPerCluster Number of sectors in a cluster.
BytesPerSector Size of the logical sector in bytes.
NumRootDirEntries Number of directory entries in the root directory.
FSType Type of file system.
IsSDFormatted Set to 1 if the volume was formatted according to SD Specification.
IsDirty Set to 1 if the volume was not unmounted correctly or the file system modified the storage.
sAlias Alternative name of the volume (0-terminated).
pBuffer Buffer to be used for the access to the storage device.
SizeOfBuffer Number of bytes in pBuffer.
SectorsPerClusterHigh High-order 16-bits of the number of sectors in a cluster.

Additional information

IsDirty can be used to check if the volume formatted as FAT has been correctly unmounted before a system reset. IsDirty is set to 1 at file system initialization if the file system was not properly unmounted.

NumRootDirEntries is valid only for volumes formatted FAT12 or FAT16.

FSType can be one of Format types.

IsSDFormatted and IsDirty are valid only for volumes formatted as FAT.

sAlias is set to NULL if the volume alias feature is disabled.

The members pBuffer and SizeOfBuffer can be used to specify a work buffer for the operation that calculates the available free space. This work buffer is used by the file system to read data from the allocation table of the file system. Specifying a work buffer larger than a logical sector size can help increasing the performance of the operation when using a storage device that can efficiently perform read burst operations such as SD card, eMMC device or USB drive. The file system is able to use the work buffer for burst operations only if pBuffer is aligned according to the value configured via FS_DRIVER_ALIGNMENT. The work buffer is used only when the flag FS_DISKINFO_FLAG_WORK_BUFFER is set in the Flags parameter passed to FS_GetVolumeInfoEx() and the file system is built with FS_SUPPORT_SECTOR_BUFFER_BURST set to 1. The file system uses an internal sector buffer for the operation if either pBuffer is set to NULL or SizeOfBuffer is set to 0.

Example

Refer to FS_GetVolumeInfo() for an example usage.

FS_FILETIME

Description

Time and date representation.

Type definition

typedef struct {
  U16  Year;
  U16  Month;
  U16  Day;
  U16  Hour;
  U16  Minute;
  U16  Second;
} FS_FILETIME;

Structure members

Member Description
Year Year (The value has to be greater than 1980.)
Month Month (1--12, 1: January, 2: February, etc.)
Day Day of the month (1--31)
Hour Hour (0--23)
Minute Minute (0--59)
Second Second (0--59)

Additional information

FS_FILETIME represents a timestamp using individual members for the month, day, year, weekday, hour, minute, and second values. This can be useful for getting or setting a timestamp of a file or directory. The conversion between timestamp and FS_FILETIME can be done using FS_FileTimeToTimeStamp() and FS_TimeStampToFileTime()

FS_FREE_SPACE_DATA

Description

Information the number of free space available on a volume.

Type definition

typedef struct {
  U32         NumClustersFree;
  int         SizeOfBuffer;
  void      * pBuffer;
  FS_VOLUME * pVolume;
  U32         FirstClusterId;
} FS_FREE_SPACE_DATA;

Structure members

Member Description
NumClustersFree Number of unallocated clusters found.
SizeOfBuffer Internal. Do not use. Number of bytes in the work buffer.
pBuffer Internal. Do not use. Work buffer.
pVolume Internal. Do not use. Volume information.
FirstClusterId Internal. Do not use. Id of the first cluster to be checked.

Additional information

This structure stores the result and context of the operation that calculates the amount of free space available on a volume. The amount of free space is returned as a number of clusters via the NumClustersFree member. The members of the search context are considered internal and should not be used by the application. FS_FREE_SPACE_DATA is used by the FS_GetVolumeFreeSpaceFirst() FS_GetVolumeFreeSpaceNext() pair of API functions.

FS_MEM_CHECK_CALLBACK

Description

Type of function called by the file system to check if a memory region can be used in a 0-copy operation.

Type definition

typedef int FS_MEM_CHECK_CALLBACK(void * pMem,
                                  U32    NumBytes);

Parameters

Parameter Description
pMem Points to the first byte in the memory area to be checked.
NumBytes Size of the memory area in bytes.

Return value

≠ 0 The memory region can be used in a 0 copy operation.
= 0 The memory region cannot be used in a 0 copy operation.

Additional information

A function of this type is called by the file system before any read or write operation performed by the application. The function has to check if the memory region defined by pMem and NumBytes can be passed directly to the device driver during a 0-copy operation.

The callback function is typically required on a system where the device driver uses DMA to transfer data to and from the storage device and where not all the memory regions can be accessed by the DMA. If the memory region cannot be accessed by DMA the callback function has to return 0. The file system copies then the data to an internal buffer that is accessible to DMA and performs the data transfer. The callback has to return a value different than 0 if the DMA can access the specified memory region. In this case the memory region is passed directly to device driver to perform the data transfer and the internal copy operation of the file system is skipped.

FS_MEM_INFO

Description

Information about the memory management.

Type definition

typedef struct {
  U8   IsExternal;
  U32  NumBytesTotal;
  U32  NumBytesAllocated;
} FS_MEM_INFO;

Structure members

Member Description
IsExternal Memory allocator type.
NumBytesTotal Size of the memory pool in bytes.
NumBytesAllocated Number of bytes allocated from the memory pool.

Additional information

The information can be queried via FS_GetMemInfo().

IsExternal contains the value of the FS_SUPPORT_EXT_MEM_MANAGER configuration define.

If the file system is configured to use the internal memory allocator (FS_SUPPORT_EXT_MEM_MANAGER set to 0) then NumBytesTotal stores the value passed as second parameter to FS_AssignMemory(). NumBytesTotal is set to 0 if the file system is configured to use an external memory allocator (FS_SUPPORT_EXT_MEM_MANAGER set to 1) because this value is not known to the file system.

The value of NumBytesAllocated stores the number of bytes allocated by the file system at the time FS_GetMemInfo() is called. In emFile versions older than 5.xx this information was stored in the global variable FS_NumBytesAllocated.

FS_TIME_DATE_CALLBACK

Description

Type of function called by the file system to get the actual time an date.

Type definition

typedef U32 FS_TIME_DATE_CALLBACK(void);

Return value

Current time and date in a format suitable for the file system.

Additional information

The time and date have to be encoded as follows: Bit 0-4: 2-second count (0-29) Bit 5-10: Minutes (0-59) Bit 11-15: Hours (0-23) Bit 16-20: Day of month (1-31) Bit 21-24: Month of year (1-12) Bit 25-31: Count of years from 1980 (0-127) The callback function can be registered via FS_SetTimeDateCallback(). FS_X_GetTimeDate() is set as default callback function at the file system initialization. The application has to provide the implementation of FS_X_GetTimeDate().

Example

Refer to FS_SetTimeDateCallback() for an example usage.

FS_TIMESTAMP

Description

Recorded time of an action performed on a file or directory.

Type definition

typedef struct {
  U32  TimeDate;
  U8   Milliseconds;
  U8   Offset;
} FS_TIMESTAMP;

Structure members

Member Description
TimeDate Local time and date.
Milliseconds Number of milliseconds.
Offset Time difference to UTC.

Additional information

TimeDate is encoded as documented in the description of FS_GetFileTime().

Milliseconds is stored in ten-millisecond multiples. The valid value range for Milliseconds is 0-199.

Offset is encoded in the same way as the UtcOffset field of an exFAT timestamp.

Volume information flags

Description

Flags that control the information returned by FS_GetVolumeInfoEx().

Definition

#define FS_DISKINFO_FLAG_FREE_SPACE     0x01
#define FS_DISKINFO_FLAG_WORK_BUFFER    0x02

Symbols

Definition Description
FS_DISKINFO_FLAG_FREE_SPACE Returns the available free space on the storage device.
FS_DISKINFO_FLAG_WORK_BUFFER Specifies a working buffer for the read operations.

Storage layer functions

The functions described in this section can be used to access and to manage the data at the logical sector level effectively bypassing the file system. These functions are typically used when the application comes with its own file system or when the storage device has to be mounted as mass storage device via USB.

FS_STORAGE_Clean()

Description

Performs garbage collection on a volume.

Prototype

int FS_STORAGE_Clean(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume on which to perform the garbage collection.

Return value

= 0 OK, volume cleaned.
≠ 0 Error code indicating the failure reason.

Additional information

The application can call this function to convert storage blocks that contain invalid data to free space that can be used to store new data. This operation is supported only by storage devices that are managed by the file system such as NAND and NOR flash.

FS_STORAGE_Clean() is optional since the device drivers perform the garbage collection operation automatically. The function can be used to increase the write performance by preparing the storage device in advance of the write operation.

The actions executed by FS_STORAGE_Clean() depend on the device driver used. For example, the Sector Map NOR driver converts all logical blocks that contain invalid data into free (writable) logical blocks. As a consequence, the following write operation will run faster because physical sectors does not have to be erased.

FS_STORAGE_Clean() can potentially take a long time to complete, preventing the access of other tasks to the file system. How long the execution takes depends on the type of storage device and on the number of storage blocks that contain invalid data. The file system provides an alternative function FS_STORAGE_CleanOne() that completes in a shorter period of time than FS_STORAGE_Clean(). This is realized by executing only one sub-operation of the entire garbage collection operation at a time. For more information refer to FS_STORAGE_CleanOne().

Additional information about the garbage collection operation can be found in the “Garbage collection” section of the NAND and NOR drivers of the emFile manual.

Example

#include "FS.h"

void SampleStorageClean(void) {
  FS_FILE * pFile;

  //
  // Perform garbage collection on the storage device.
  //
  FS_STORAGE_Clean("nor:0:");
  //
  // The write to file is fast since the NOR driver does not have to perform
  // any garbage collection during the write operation.
  //
  pFile = FS_FOpen("nor:0:\\File.txt", "w");
  if (pFile) {
    FS_Write(pFile, "Test", 4);
    FS_FClose(pFile);
  }
}

FS_STORAGE_CleanEx()

Description

Performs garbage collection on a volume.

Prototype

int FS_STORAGE_CleanEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume on which to perform the garbage collection.

Return value

= 0 OK, volume cleaned.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_Clean() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_CleanOne()

Description

Performs garbage collection on a volume.

Prototype

int FS_STORAGE_CleanOne(const char * sVolumeName,
                              int  * pMoreToClean);

Parameters

Parameter Description
sVolumeName Name of the storage volume on which to perform the garbage collection.
pMoreToClean  out  Indicates if the storage device has been cleaned completely or not. It can be NULL. ≠0 Not cleaned completely. =0 Completely clean.

Return value

= 0 OK, clean operation executed.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_Clean() with the difference that it executes only one sub-operation of the garbage collection operation at a time. This is practical if other tasks of the application require access to the file system before the garbage collection operation is completed. The completion of the garbage collection operation is indicated via pMoreToClean. FS_STORAGE_CleanOne() returns a value different than 0 via pMoreToClean if the operation is not completed.

Additional information about the garbage collection operation can be found in the “Garbage collection” section of the NAND and NOR drivers.

Example

#include "FS.h"

void SampleStorageCleanOne(void) {
  FS_FILE * pFile;
  int       MoreToClean;

  //
  // Perform garbage collection on the storage device.
  //
  MoreToClean = 0;
  do {
    FS_STORAGE_CleanOne("nand:0:", &MoreToClean);
  } while (MoreToClean);
  //
  // The write to file is fast since the NAND driver does not have to perform
  // any garbage collection during the write operation.
  //
  pFile = FS_FOpen("nand:0:\\File.txt", "w");
  if (pFile) {
    FS_Write(pFile, "Test", 4);
    FS_FClose(pFile);
  }
}

FS_STORAGE_CleanOneEx()

Description

Performs garbage collection on a volume.

Prototype

int FS_STORAGE_CleanOneEx(FS_VOLUME * pVolume,
                          int       * pMoreToClean);

Parameters

Parameter Description
pVolume Instance of the storage volume on which to perform the garbage collection.
pMoreToClean  out  Indicates if the storage device has been cleaned completely or not. It can be NULL. ≠0 Not cleaned completely. =0 Completely clean.

Return value

= 0 OK, clean operation executed.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_CleanOne() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_DeInit()

Description

Frees the resources allocated by the storage layer.

Prototype

void FS_STORAGE_DeInit(void);

Additional information

This function is optional. FS_STORAGE_DeInit() frees all resources that are allocated by the storage layer after initialization. The application can call this function only after it called FS_STORAGE_Init().

This function is available if the emFile sources are compiled with the FS_SUPPORT_DEINIT configuration define set to 1.

Example

#include "FS.h"

void SampleStorageDeInit(void) {
  FS_STORAGE_Init();
#if FS_SUPPORT_DEINIT
  //
  // Access the storage layer...
  //
  FS_STORAGE_DeInit();
#endif // FS_SUPPORT_DEINIT
  //
  // The storage layer cannot be accessed anymore.
  //
}

FS_STORAGE_FillSectors()

Description

Writes the same sector data to one or more logical sectors.

Prototype

int FS_STORAGE_FillSectors(const char * sVolumeName,
                           const void * pData,
                                 U32    SectorIndex,
                                 U32    NumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume to write to. It cannot be NULL.
pData  in  Buffer that contains the sector data to be written. It cannot be NULL.
SectorIndex Index of the first sector to be written.
NumSectors Number of sectors to be written.

Return value

= 0 OK, sector data modified.
≠ 0 Error code indicating the failure reason.

Additional information

This function can be used to write the same sector data to multiple consecutive logical sectors. pData has to point to a memory region that stores the contents of a single logical sector that has to be written.

The size of the logical sector depends on the type of storage device used. The application can query the size of the logical sector as well as the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo(). Typically, the size of a logical sector is 512 bytes.

SectorIndex is a 0-based index that identifies the first logical sector to be written. The range of the logical sectors modified by this function is SectorIndex to SectorIndex + NumSectors - 1.

FS_STORAGE_FillSectors() reports an error and does not perform any operation if the specified range of logical sectors exceeds the size of the storage device.

FS_STORAGE_FillSectorsEx()

Description

Writes the same sector data to one or more logical sectors.

Prototype

int FS_STORAGE_FillSectorsEx(      FS_VOLUME * pVolume,
                             const void      * pData,
                                   U32         SectorIndex,
                                   U32         NumSectors);

Parameters

Parameter Description
pVolume Instance of the volume to write to.
pData  in  Contents of the logical sector.
SectorIndex Index of the logical sector to be written.
NumSectors Number of logical sectors to be written.

Return value

= 0 OK, logical sectors written successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_FillSectors() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_FindVolume()

Description

Searches for a volume instance by name.

Prototype

FS_VOLUME *FS_STORAGE_FindVolume(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume.

Return value

NULL Pointer to the volume instance.
= NULL Volume not found.

Additional information

This function returns the volume instance assigned to the specified volume name. The return value can be passed as parameter to the API functions of the Storage layer that identify a volume by instance and not by name.

The returned volume instance is no longer valid after the file system is deinitialized via a call to FS_DeInit(). The application must call FS_STORAGE_FindVolume() to get a new volume instance after the file system is reinitialized.

FS_STORAGE_FindVolumeByDevice()

Description

Searches for a volume instance by index.

Prototype

FS_VOLUME *FS_STORAGE_FindVolumeByDevice(FS_DEVICE * pDevice);

Parameters

Parameter Description
pDevice Device instance assigned to the volume.

Return value

NULL Pointer to the volume instance.
= NULL Volume not found.

Additional information

This function performs the same operation as FS_STORAGE_FindVolumeByIndex() with the difference that the volume to be searched for is specified via device instance instead of volume index.

A device index can be obtained via the callback of the function registered via FS_STORAGE_SetOnDeviceActivityCallback() or FS_STORAGE_SetOnDeviceActivityCallbackEx().

FS_STORAGE_FindVolumeByIndex()

Description

Searches for a volume instance by index.

Prototype

FS_VOLUME *FS_STORAGE_FindVolumeByIndex(int VolumeIndex);

Parameters

Parameter Description
VolumeIndex Index of the volume.

Return value

NULL Pointer to the volume instance.
= NULL Volume not found.

Additional information

This function returns the volume instance assigned to the volume with the specified index. The first volume added to the file system via FS_AddDevice() has the index 0, the second index 1 and so on. The total number of configured volumes can be queried via FS_GetNumVolumes().

The return value of this function can be passed as parameter to the API functions of the Storage layer that identify a volume by instance and not by name.

The returned volume instance is no longer valid after the file system is deinitialized via a call to FS_DeInit(). The application must call FS_STORAGE_FindVolumeByIndex() to get a new volume instance after the file system is reinitialized.

FS_STORAGE_FormatLowEx()

Description

Formats the storage device.

Prototype

int FS_STORAGE_FormatLowEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be formatted.

Return value

= 0 OK, low level format was successful.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_FormatLow() with the difference that the volume to be queried is identified by a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_FreeSectors()

Description

Informs the driver about unused sectors.

Prototype

int FS_STORAGE_FreeSectors(const char * sVolumeName,
                                 U32    SectorIndex,
                                 U32    NumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume on which to perform the operation.
SectorIndex Index of the first logical sector to be marked as invalid (0-based).
NumSectors Number of sectors to be marked as invalid starting with SectorIndex.

Return value

= 0 OK, sectors freed.
≠ 0 Error code indicating the failure reason

Additional information

Typically, this function is called by the application to inform the driver which logical sectors are no longer used for data storage. The NAND and NOR drivers can use this information to optimize the internal relocation of data blocks during the wear-leveling operation. The data of the logical sectors marked as not in use is not copied anymore that can typically lead to an improvement of the write performance.

FS_STORAGE_FreeSectors() performs a similar operation as the trim command of SSDs (Solid-State Drives). The data stored to a logical sector is no longer available to an application after the logical sector has been freed via FS_STORAGE_FreeSectors(),

Example

#include "FS.h"

void SampleStorageFreeSectors(void) {
  //
  // Inform the NAND driver that the logical sectors
  // with the indexes 2, 3, and 4 are no longer in use.
  //
  FS_STORAGE_FreeSectors("nand:0:", 2, 3);
}

FS_STORAGE_FreeSectorsEx()

Description

Informs the driver about unused sectors.

Prototype

int FS_STORAGE_FreeSectorsEx(FS_VOLUME * pVolume,
                             U32         SectorIndex,
                             U32         NumSectors);

Parameters

Parameter Description
pVolume Instance of the volume on which to perform the operation.
SectorIndex Index of the first logical sector to be marked as invalid (0-based).
NumSectors Number of sectors to be marked as invalid starting with SectorIndex.

Return value

= 0 OK, sectors freed.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_FreeSectors() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_GetAutoMountType()

Description

Returns information about how a volume is automatically mounted.

Prototype

int FS_STORAGE_GetAutoMountType(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

= 0 Volume is not mounted automatically.
= FS_MOUNT_RO Volume is mounted automatically in read only mode.
= FS_MOUNT_RW Volume is mounted automatically in read and write mode.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

This function is available only if the file system is built with FS_STORAGE_SUPPORT_MOUNT set to 1.

FS_STORAGE_GetAutoMountTypeEx()

Description

Returns information about how a volume is automatically mounted.

Prototype

int FS_STORAGE_GetAutoMountTypeEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be queried.

Return value

= 0 Volume is not mounted automatically.
= FS_MOUNT_RO Volume is mounted automatically in read only mode.
= FS_MOUNT_RW Volume is mounted automatically in read and write mode.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

This function performs the same operation as FS_STORAGE_GetAutoMountType() with the difference that the volume is specified via a volume instance instead of a volume name.

This function is available only if the file system is built with FS_STORAGE_SUPPORT_MOUNT set to 1.

FS_STORAGE_GetCleanCnt()

Description

Calculates the number of garbage collection sub-operations.

Prototype

int FS_STORAGE_GetCleanCnt(const char * sVolumeName,
                                 U32  * pCleanCnt);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.
pCleanCnt  out  Number of sub-operations left.

Return value

= 0 OK, clean count returned.
≠ 0 Error code indicating the failure reason.

Additional information

FS_STORAGE_GetCleanCnt() calculates and returns the number of sub-operations that the application has to perform until the garbage collection operation is completed. The value returned via pCleanCnt is the number of times FS_STORAGE_CleanOne() has to be called to complete the garbage collection. FS_STORAGE_GetCleanCnt() is supported only for volumes mounted on a storage device managed by emFile such as NAND or NOR flash.

Example

#include "FS.h"

void SampleStorageGetCleanCnt(void) {
  U32 CleanCnt;

  CleanCnt = 0;
  FS_STORAGE_GetCleanCnt("nor:0:", &CleanCnt);
  if (CleanCnt) {
    do {
      FS_STORAGE_CleanOne("nor:0:", NULL);
    } while (--CleanCnt);
  }
}

FS_STORAGE_GetCleanCntEx()

Description

Calculates the number of garbage collection sub-operations.

Prototype

int FS_STORAGE_GetCleanCntEx(FS_VOLUME * pVolume,
                             U32       * pCleanCnt);

Parameters

Parameter Description
pVolume Instance of the volume to be queried.
pCleanCnt  out  Number of sub-operations left.

Return value

= 0 OK, clean count returned.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_GetCleanCnt() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_GetCounters()

Description

Returns the values of statistical counters.

Prototype

void FS_STORAGE_GetCounters(FS_STORAGE_COUNTERS * pStat);

Parameters

Parameter Description
pStat  out  Current values of statistical counters.

Additional information

This function returns the values of the counters that indicate how many operations the storage layer executed since the file system initialization or the last call to FS_STORAGE_ResetCounters().

The statistical counters are updated only on debug builds if the file system sources are compiled with FS_DEBUG_LEVEL greater then or equal to FS_DEBUG_LEVEL_CHECK_PARA or FS_STORAGE_ENABLE_STAT_COUNTERS set to 1.

Example

#include <stdio.h>
#include "FS.h"

void SampleStorageGetCounters(void) {
  FS_STORAGE_COUNTERS StatCnt;
  char                ac[100];

  FS_STORAGE_GetCounters(&StatCnt);
  SEGGER_snprintf(ac, sizeof(ac), "Num. read operations:                %lu\n", 
    StatCnt.ReadOperationCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read:                   %lu\n", 
    StatCnt.ReadSectorCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read (from cache):      %lu\n", 
    StatCnt.ReadSectorCachedCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read (alloc. table):    %lu\n", 
    StatCnt.ReadSectorCntMan);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read (dir. entry):      %lu\n", 
    StatCnt.ReadSectorCntDir);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. write operations:               %lu\n", 
    StatCnt.WriteOperationCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written:                %lu\n", 
    StatCnt.WriteSectorCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written (by cache):     %lu\n", 
    StatCnt.WriteSectorCntCleaned);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written (alloc. table): %lu\n", 
    StatCnt.WriteSectorCntMan);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written (dir. entry):   %lu\n", 
    StatCnt.WriteSectorCntDir);
  FS_X_Log(ac);
}

FS_STORAGE_GetDeviceInfo()

Description

Returns information about the storage device.

Prototype

int FS_STORAGE_GetDeviceInfo(const char        * sVolumeName,
                                   FS_DEV_INFO * pDeviceInfo);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried. It cannot be NULL.
pDeviceInfo  out  Information about the storage device. It cannot be NULL.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

Additional information

This function returns information about the logical organization of the storage device such as the number of logical sectors and the size of the logical sector supported. FS_STORAGE_GetDeviceInfo() requests the information directly from the device driver.

Deprecated name

FS_GetDeviceInfo

Example

#include <stdio.h>
#include "FS.h"

void SampleStorageGetDeviceInfo(void) {
  FS_DEV_INFO DeviceInfo;
  char        ac[100];

  FS_STORAGE_GetDeviceInfo("", &DeviceInfo);
  SEGGER_snprintf(ac, sizeof(ac), "Total num. sectors:      %lu\n", 
    DeviceInfo.NumSectors);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. bytes per sector:   %d\n", 
    DeviceInfo.BytesPerSector);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. read / write heads: %d\n", 
    DeviceInfo.NumHeads);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Num. sectors per track:  %d\n", 
    DeviceInfo.SectorsPerTrack);
  FS_X_Log(ac);
}

FS_STORAGE_GetDeviceInfoEx()

Description

Returns information about the storage device.

Prototype

int FS_STORAGE_GetDeviceInfoEx(FS_VOLUME   * pVolume,
                               FS_DEV_INFO * pDeviceInfo);

Parameters

Parameter Description
pVolume Instance of the volume to be queried.
pDeviceInfo  out  Information about the storage device.

Return value

= 0 OK, volume information returned.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_GetDeviceInfo() with the difference that the volume to be queried is identified by a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_GetMountType()

Description

Returns information about how a volume is mounted.

Prototype

int FS_STORAGE_GetMountType(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be queried.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only.
= FS_MOUNT_RW Volume is mounted read/write.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

This function is available only if the file system is built with FS_STORAGE_SUPPORT_MOUNT set to 1.

FS_STORAGE_GetMountTypeEx()

Description

Returns information about how a volume is mounted.

Prototype

int FS_STORAGE_GetMountTypeEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be queried.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only.
= FS_MOUNT_RW Volume is mounted read/write.
< 0 Error code indicating the failure reason. Refer to FS_ErrorNo2Text().

Additional information

This function performs the same operation as FS_STORAGE_GetMountType() with the difference that the volume is specified via a volume instance instead of a volume name.

This function is available only if the file system is built with FS_STORAGE_SUPPORT_MOUNT set to 1.

FS_STORAGE_GetSectorUsage()

Description

Returns information about the usage of a logical sector.

Prototype

int FS_STORAGE_GetSectorUsage(const char * sVolumeName,
                                    U32    SectorIndex);

Parameters

Parameter Description
sVolumeName Name of the volume.
SectorIndex Index of the sector to be queried.

Return value

= FS_SECTOR_IN_USE The sector contains valid data.
= FS_SECTOR_NOT_USED The sector contains invalid data.
= FS_SECTOR_USAGE_UNKNOWN The usage of the sector is unknown or the operation is not supported.
< 0 Error code indicating the failure reason.

Additional information

After a low-level format all the logical sectors contain invalid information. The data of a logical sector becomes valid after the application performs a write operation to that sector. The sector data can be explicitly invalidated by calling FS_STORAGE_FreeSectors().

Example

#include "FS.h"

void SampleStorageGetSectorUsage(void) {
  int SectorUsage;

  SectorUsage = FS_STORAGE_GetSectorUsage("", 7);
  switch (SectorUsage) {
  case FS_SECTOR_IN_USE:
    FS_X_Log("The sector is used to store data.\n");
    break;
  case FS_SECTOR_NOT_USED:
    FS_X_Log("The sector is not used to store data.\n");
    break;
  case FS_SECTOR_USAGE_UNKNOWN:
    FS_X_Log("The sector usage is unknown.\n");
    break;
  default:
    FS_X_Log("An error occurred during the operation.\n");
  }
}

FS_STORAGE_GetSectorUsageEx()

Description

Returns information about the usage of a logical sector.

Prototype

int FS_STORAGE_GetSectorUsageEx(FS_VOLUME * pVolume,
                                U32         SectorIndex);

Parameters

Parameter Description
pVolume Instance of the volume that stores the logical sector.
SectorIndex Index of the sector to be queried.

Return value

= FS_SECTOR_IN_USE The sector contains valid data.
= FS_SECTOR_NOT_USED The sector contains invalid data.
= FS_SECTOR_USAGE_UNKNOWN The usage of the sector is unknown or the operation is not supported.
< 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_GetSectorUsage() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_GetVolumeStatusEx()

Description

Returns the presence status of a volume.

Prototype

int FS_STORAGE_GetVolumeStatusEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be queried.

Return value

FS_MEDIA_NOT_PRESENT Volume is not present.
FS_MEDIA_IS_PRESENT Volume is present.
FS_MEDIA_STATE_UNKNOWN Volume presence state is unknown.

Additional information

This function performs the same operation as FS_GetVolumeStatus() with the difference that the volume to be queried is identified by a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_Init()

Description

Initializes the storage layer.

Prototype

unsigned FS_STORAGE_Init(void);

Return value

Number of OS synchronization objects required to protect the file system against concurrent access from different tasks.

Additional information

This function initializes the only drivers and if necessary the OS layer. It has to be called before any other function of the storage layer (FS_STORAGE_) The storage layer allows an application to access the file system at logical sector level. The storage device is presented as an array of logical sector that can be accessed via a 0-based index. This can be useful when using the file system as USB mass storage client driver.

FS_STORAGE_Init() is called internally at the initialization of the file system. The return value of this function is used by FS_Init() to calculate the number of internal buffers the file system has to allocate for the read and write operations. The application is not required to call FS_STORAGE_Init() if it already calls FS_Init().

FS_STORAGE_DeInit() is the counterpart of FS_STORAGE_Init() that can be used to free the resources allocated by the drivers and if enabled of the OS layer.

Deprecated name

FS_InitStorage

Example

#include "FS.h"

void SampleStorageInit(void) {
  FS_STORAGE_Init();
  //
  // Access logical sectors...
  //
}

FS_STORAGE_IsLLFormattedEx()

Description

Checks if a storage device is low-level formatted.

Prototype

int FS_STORAGE_IsLLFormattedEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be queried.

Return value

= 1 Volume is low level formatted.
= 0 Volume is not low level formatted.
< 0 Low level format not supported by volume or an error occurred.

Additional information

This function performs the same operation as FS_IsLLFormatted() with the difference that the volume to be queried is identified by a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_Mount()

Description

Initializes a volume in a specified access mode.

Prototype

int FS_STORAGE_Mount(const char * sVolumeName,
                           U8     MountType);

Parameters

Parameter Description
sVolumeName Name of the volume to be mounted.
MountType Specifies how the volume has to be mounted. FS_MOUNT_RO Read only access mode. FS_MOUNT_RW Read and write access mode.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only mode.
= FS_MOUNT_RW Volume is mounted read and write mode.
< 0 Error code indicating the failure reason.

Additional information

The application is not required to call this function before the first access to the storage device. The file system mounts by default the storage device at the first access after the file system initialization. This behavior can be configured via FS_SetAutoMount().

A mounted volume can be unmounted via FS_STORAGE_Unmount() or FS_STORAGE_UnmountForced().

FS_STORAGE_MountEx()

Description

Initializes a volume in a specified access mode.

Prototype

int FS_STORAGE_MountEx(FS_VOLUME * pVolume,
                       U8          MountType);

Parameters

Parameter Description
pVolume Instance of the volume to be mounted.
MountType Specifies how the volume has to be mounted. FS_MOUNT_RO Read only access mode. FS_MOUNT_RW Read and write access mode.

Return value

= 0 Volume is not mounted.
= FS_MOUNT_RO Volume is mounted read only mode.
= FS_MOUNT_RW Volume is mounted read and write mode.
< 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_Mount() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_ReadSector()

Description

Reads the data of one logical sector.

Prototype

int FS_STORAGE_ReadSector(const char * sVolumeName,
                                void * pData,
                                U32    SectorIndex);

Parameters

Parameter Description
sVolumeName Name of the volume to read from. It cannot be NULL.
pData  out  Buffer that receives the read sector data. It cannot be NULL.
SectorIndex Index of the sector to read from.

Return value

= 0 OK, sector data read.
≠ 0 Error code indicating the failure reason.

Additional information

pData has to point to a memory region sufficiently large to store the contents of one logical sector.

The size of the logical sector depends on the type of storage device used. The application can query the size of the logical sector as well as the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo(). Typically, the size of a logical sector is 512 bytes.

FS_STORAGE_ReadSector() reports an error and does not store any data to pData if SectorIndex is out of bounds.

The application can call FS_STORAGE_ReadSectors() instead of calling FS_STORAGE_ReadSector() multiple times if it has to read consecutive logical sectors at once.

Deprecated name

FS_ReadSector

Example

#include "FS.h"

void SampleStorageReadSector(void) {
  U32 aSectorData[512 / 4];

  //
  // Read the data of the logical sector with the index 10.
  //
  FS_STORAGE_ReadSector("", aSectorData, 10);
}

FS_STORAGE_ReadSectorEx()

Description

Reads the contents of one logical sector from the storage device.

Prototype

int FS_STORAGE_ReadSectorEx(FS_VOLUME * pVolume,
                            void      * pData,
                            U32         SectorIndex);

Parameters

Parameter Description
pVolume Instance of the volume to read from.
pData  out  Contents of the logical sector.
SectorIndex Index of the logical sector to be read.

Return value

= 0 OK, logical sector read successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_ReadSector() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume() or FS_STORAGE_FindVolumeByIndex().

FS_STORAGE_ReadSectors()

Description

Reads the data of one or more logical sectors.

Prototype

int FS_STORAGE_ReadSectors(const char * sVolumeName,
                                 void * pData,
                                 U32    SectorIndex,
                                 U32    NumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume to read from. It cannot be NULL.
pData  out  Buffer that receives the read sector data. It cannot be NULL.
SectorIndex Index of the first sector to read from.
NumSectors Number of sectors to be read.

Return value

= 0 OK, sector data read.
≠ 0 Error code indicating the failure reason.

Additional information

This function can be used to read the contents of multiple consecutive logical sectors. pData has to point to a memory region sufficiently large to store the contents of all logical sectors read.

The size of the logical sector depends on the type of storage device used. The application can query the size of the logical sector as well as the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo(). Typically, the size of a logical sector is 512 bytes.

FS_STORAGE_ReadSectors() reports an error and does not perform any operation if the specified range of logical sectors exceeds the size of the storage device.

Example

#include "FS.h"

void SampleStorageReadSectors(void) {
  U32 aSectorData[512 * 2 / 4];

  //
  // Read the data of the logical sectors with the indexes 10 and 11.
  //
  FS_STORAGE_ReadSectors("", aSectorData, 10, 2);
}

FS_STORAGE_ReadSectorsEx()

Description

Reads the contents of multiple logical sectors from a storage device.

Prototype

int FS_STORAGE_ReadSectorsEx(FS_VOLUME * pVolume,
                             void      * pData,
                             U32         SectorIndex,
                             U32         NumSectors);

Parameters

Parameter Description
pVolume Instance of the volume to read from.
pData  out  Contents of the logical sector.
SectorIndex Index of the logical sector to be read.
NumSectors Number of logical sectors to be read.

Return value

= 0 OK, logical sectors read successfully.
≠ 0 Error code indicating the failure reason

Additional information

This function performs the same operation as FS_STORAGE_ReadSectors() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume() or FS_STORAGE_FindVolumeByIndex().

FS_STORAGE_RefreshSectors()

Description

Reads the contents of a logical sector and writes it back.

Prototype

int FS_STORAGE_RefreshSectors(const char * sVolumeName,
                                    U32    SectorIndex,
                                    U32    NumSectors,
                                    void * pBuffer,
                                    U32    NumBytes);

Parameters

Parameter Description
sVolumeName Name of the volume on which to perform the operation. It cannot be NULL.
SectorIndex Index of the first sector to refresh (0-based).
NumSectors Number of sectors to refresh starting with SectorIndex.
pBuffer Temporary storage for the sector data. Must be at least one sector large. It cannot be NULL.
NumBytes Number of bytes in pBuffer.

Return value

= 0 OK, sectors refreshed.
≠ 0 Error code indicating the failure reason

Additional information

This function reads the contents of each specified logical sector to pBuffer and then it writes the same data to it. FS_STORAGE_RefreshSectors() can read and write more than one logical sector at once if the size of pBuffer allows it. The larger pBuffer the faster runs the refresh operation.

FS_STORAGE_RefreshSectors() function can be used on volumes mounted on a NAND flash device to prevent the accumulation of bit errors due to excessive read operations (read disturb effect). The function can also be used to prevent data loses caused by the data reaching the retention limit. Reading and then writing back the contents of a logical sector causes the NAND driver to relocate the data on the NAND flash device that in turn eliminates bit errors. Typically, the refresh operation has to be performed periodically at large time intervals (weeks). The NAND flash may wear out too soon if the refresh operation is performed too often.

Example

#include "FS.h"

static U32 _aBuffer[2048 * 2 / 4];

void SampleStorageRefreshSectors(void) {

  //
  // Refresh the logical sectors with the indexes 10-99
  // stored on the NAND flash.
  //
  FS_STORAGE_RefreshSectors("nand:0:", 10, 100, _aBuffer, sizeof(_aBuffer));
}

FS_STORAGE_RefreshSectorsEx()

Description

Reads the contents of a logical sector and writes it back.

Prototype

int FS_STORAGE_RefreshSectorsEx(FS_VOLUME * pVolume,
                                U32         SectorIndex,
                                U32         NumSectors,
                                void      * pBuffer,
                                U32         NumBytes);

Parameters

Parameter Description
pVolume Instance of the volume on which to perform the operation. It cannot be NULL.
SectorIndex Index of the first sector to refresh (0-based).
NumSectors Number of sectors to refresh starting with SectorIndex.
pBuffer Temporary storage for the sector data. Must be at least one sector large. It cannot be NULL.
NumBytes Number of bytes in pBuffer.

Return value

= 0 OK, sectors refreshed.
≠ 0 Error code indicating the failure reason

Additional information

This function performs the same operation as FS_STORAGE_RefreshSectors() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_ResetCounters()

Description

Sets all statistical counters to 0.

Prototype

void FS_STORAGE_ResetCounters(void);

Additional information

This function can be used to set to 0 all the statistical counters maintained by the storage layer. This can be useful for example in finding out how many sector operations are performed during a specific file system operation. The application calls FS_STORAGE_ResetCounters() before the file system operation and then FS_STORAGE_GetCounters() at the end.

The statistical counters are available only on debug builds if the file system sources are compiled with FS_DEBUG_LEVEL greater then or equal to FS_DEBUG_LEVEL_CHECK_PARA or FS_STORAGE_ENABLE_STAT_COUNTERS set to 1.

Example

#include "FS.h"

void SampleStorageResetCounters(void) {
  FS_STORAGE_COUNTERS StatCnt;

  //
  // Set all statistical counters to 0.
  //
  FS_STORAGE_ResetCounters();

  //
  // Perform the file system operation...
  //

  //
  // Check the statistical counters.
  //
  FS_STORAGE_GetCounters(&StatCnt);
}

FS_STORAGE_SetAutoMountType()

Description

Sets the automatic mount behavior.

Prototype

int FS_STORAGE_SetAutoMountType(const char * sVolumeName,
                                      U8     MountType);

Parameters

Parameter Description
sVolumeName Name of the volume to be configured.
MountType Specifies how the volume has to be mounted. FS_MOUNT_RO Allows to automatically mount the volume in read only mode. FS_MOUNT_RW Allows to automatically mount the volume in read and write mode. 0 Disables the automatic mount operation for the volume.

Return value

≥ 0 OK, the previous mount type.
< 0 Error code indicating the failure reason.

Additional information

This function is available only if the file system is built with FS_STORAGE_SUPPORT_MOUNT set to 1.

FS_STORAGE_SetAutoMountTypeEx()

Description

Sets the automatic mount behavior.

Prototype

int FS_STORAGE_SetAutoMountTypeEx(FS_VOLUME * pVolume,
                                  U8          MountType);

Parameters

Parameter Description
pVolume Instance of the volume to be configured.
MountType Specifies how the volume has to be mounted. FS_MOUNT_RO Allows to automatically mount the volume in read only mode. FS_MOUNT_RW Allows to automatically mount the volume in read and write mode. 0 Disables the automatic mount operation for the volume.

Return value

≥ 0 OK, the previous mount type.
< 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_SetAutoMount() with the difference that the volume is specified via a volume instance instead of a volume name.

This function is available only if the file system is built with FS_STORAGE_SUPPORT_MOUNT set to 1.

FS_STORAGE_SetOnDeviceActivityCallback()

Description

Registers a function to be called on any logical sector read or write operation.

Prototype

void FS_STORAGE_SetOnDeviceActivityCallback
                       (const char                           * sVolumeName,
                              FS_ON_DEVICE_ACTIVITY_CALLBACK * pfOnDeviceActivity);

Parameters

Parameter Description
sVolumeName Name of the volume for which the callback function is registered. It cannot be NULL.
pfOnDeviceActivity Function to be invoked.

Additional information

This function is optional. It is available only when the file system is built with FS_DEBUG_LEVEL set to a value grater than or equal to FS_DEBUG_LEVEL_CHECK_PARA or with FS_STORAGE_SUPPORT_DEVICE_ACTIVITY set to 1.

Example

Refer to the sample application FS_DeviceActivity.c located in the Sample/FS/Application folder of the emFile shipment.

FS_STORAGE_Sync()

Description

Writes cached information to storage device.

Prototype

void FS_STORAGE_Sync(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be synchronized.

Additional information

This function updates all the information present only in sector cache (if enabled) to storage device. It is also requests the driver to perform a synchronization operation. The operations performed during the synchronization are driver-dependent.

Typically, FS_STORAGE_Sync() has to be called if a write-back sector cache is configured for the volume to reduce the chance of a data loss in case of an unexpected reset.

Deprecated name

FS_CleanVolume

Example

#include <string.h>
#include "FS.h"

void SampleStorageSync(void) {
  U32 aSectorData[512 / 4];

  memset(aSectorData, 'a', sizeof(aSectorData));
  //
  // Write some data to sector with the index 0.
  //
  FS_STORAGE_WriteSector("", aSectorData, 0);
  //
  // Make sure that the data is written to storage device.
  //
  FS_STORAGE_Sync("");
}

FS_STORAGE_SyncEx()

Description

Writes cached information to storage device.

Prototype

int FS_STORAGE_SyncEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be synchronized.

Return value

= 0 OK, volume synchronized successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_Sync() with the difference that the volume to be synchronized is identified by a volume instance instead of a volume name.

FS_STORAGE_SyncSectors()

Description

Synchronizes the contents of one or more logical sectors.

Prototype

int FS_STORAGE_SyncSectors(const char * sVolumeName,
                                 U32    SectorIndex,
                                 U32    NumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume that stores the logical sectors.
SectorIndex Index of the first sector to be synchronized (0-based).
NumSectors Number of sectors to be synchronized starting with SectorIndex.

Return value

= 0 OK, sectors synchronized.
≠ 0 Error code indicating the failure reason.

Additional information

This operation is driver-dependent and is currently supported only by the RAID1 logical driver. The operation updates the contents of the specified logical sectors that are located on the secondary storage (mirrored) with the contents of the corresponding logical sectors from the primary storage (master). RAID1 logical driver updates the logical sectors only if the contents is different.

Example

#include "FS.h"

void SampleStorageSyncSectors(void) {
  //
  // Synchronizes the logical sectors with the indexes 7, 8 and 9.
  //
  FS_STORAGE_SyncSectors("", 7, 3);
}

FS_STORAGE_SyncSectorsEx()

Description

Synchronizes the contents of one or more logical sectors.

Prototype

int FS_STORAGE_SyncSectorsEx(FS_VOLUME * pVolume,
                             U32         SectorIndex,
                             U32         NumSectors);

Parameters

Parameter Description
pVolume Instance of the volume that stores the logical sectors.
SectorIndex Index of the first sector to be synchronized (0-based).
NumSectors Number of sectors to be synchronized starting with SectorIndex.

Return value

= 0 OK, sectors synchronized.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_SyncSectors() with the difference that the volume is specified via a volume instance instead of a volume name.

FS_STORAGE_Unmount()

Description

Synchronizes a volume and marks it as not initialized.

Prototype

void FS_STORAGE_Unmount(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be unmounted. It cannot be NULL.

Additional information

The function sends an unmount command to the driver and marks the volume as unmounted and uninitialized. If a write sector cache is enabled, FS_STORAGE_Unmount() also stores any modified data from sector cache to storage device. This function has to be called before the device is shutdown to prevent a data loss.

The file system mounts automatically the volume at the call to an API function of the storage layer.

Deprecated name

FS_UnmountLL

Example

#include "FS.h"

void SampleStorageUnmount(void) {
  //
  // Synchronize the sector cache and mark the volume as not initialized.
  //
  FS_STORAGE_Unmount("");
  //
  // The device can be shutdown here without loosing any data.
  //
}

FS_STORAGE_UnmountEx()

Description

Synchronizes the volume and marks it as not initialized.

Prototype

void FS_STORAGE_UnmountEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be unmounted.

Additional information

This function performs the same operation as FS_STORAGE_Unmount() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume() or FS_STORAGE_FindVolumeByIndex().

FS_STORAGE_UnmountForced()

Description

Marks a volume it as not initialized.

Prototype

void FS_STORAGE_UnmountForced(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be unmounted. It cannot be NULL.

Additional information

This function performs the same operations as FS_STORAGE_Unmount(). FS_STORAGE_UnmountForced() has to be called if a storage device has been removed before being regularly unmounted. When using FS_STORAGE_UnmountForced() there is no guarantee that the information cached by the file system is updated to storage.

The file system mounts automatically the volume at the call to an API function of the storage layer.

Example

#include "FS.h"

void SampleStorageUnmountForced(void) {
  if (FS_GetVolumeStatus("") == FS_MEDIA_IS_PRESENT) {
    //
    // Synchronize the sector cache and mark the volume as not initialized.
    //
    FS_STORAGE_Unmount("");
    //
    // The device can be shutdown here without loosing any data.
    //
  } else {
    //
    // Storage device has been removed. Mark the volume as not initialized.
    // Data loss is possible.
    //
    FS_STORAGE_UnmountForced("");
  }
}

FS_STORAGE_UnmountForcedEx()

Description

Marks the volume as not initialized without synchronizing it.

Prototype

void FS_STORAGE_UnmountForcedEx(FS_VOLUME * pVolume);

Parameters

Parameter Description
pVolume Instance of the volume to be unmounted.

Additional information

This function performs the same operation as FS_STORAGE_UnmountForced() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_WriteSector()

Description

Modifies the data of a logical sector.

Prototype

int FS_STORAGE_WriteSector(const char * sVolumeName,
                           const void * pData,
                                 U32    SectorIndex);

Parameters

Parameter Description
sVolumeName Name of the volume to write to. It cannot be NULL.
pData  in  Buffer that contains the sector data to be written. It cannot be NULL.
SectorIndex Index of the sector to write to.

Return value

= 0 OK, sector data modified.
≠ 0 Error code indicating the failure reason.

Additional information

pData has to point to a memory region that stores the contents of one logical sector.

The size of the logical sector depends on the type of storage device used. The application can query the size of the logical sector as well as the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo(). Typically, the size of a logical sector is 512 bytes.

FS_STORAGE_WriteSector() reports an error and does modify the contents of the logical sector if SectorIndex is out of bounds.

The application can call FS_STORAGE_WriteSectors() instead of calling FS_STORAGE_WriteSector() multiple times if it has to write consecutive logical sectors at once.

Deprecated name

FS_WriteSector

Example

#include <string.h>
#include "FS_Storage.h"

void SampleStorageWriteSector(void) {
  U32 aSectorData[512 / 4];

  memset(aSectorData, 'a', sizeof(aSectorData));
  //
  // Write the data of the logical sector with the index 7.
  //
  FS_STORAGE_WriteSector("", aSectorData, 7);
}

FS_STORAGE_WriteSectorEx()

Description

Writes a logical sector to the storage device.

Prototype

int FS_STORAGE_WriteSectorEx(      FS_VOLUME * pVolume,
                             const void      * pData,
                                   U32         SectorIndex);

Parameters

Parameter Description
pVolume Instance of the volume to write to.
pData  in  Contents of the logical sector.
SectorIndex Index of the logical sector to be written.

Return value

= 0 OK, logical sector written successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_WriteSector() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().

FS_STORAGE_WriteSectors()

Description

Modifies the data of one or more logical sectors.

Prototype

int FS_STORAGE_WriteSectors(const char * sVolumeName,
                            const void * pData,
                                  U32    SectorIndex,
                                  U32    NumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume to write to. It cannot be NULL.
pData  in  Buffer that contains the sector data to be written. It cannot be NULL.
SectorIndex Index of the first sector to be written.
NumSectors Number of sectors to be written.

Return value

= 0 OK, sector data modified.
≠ 0 Error code indicating the failure reason.

Additional information

This function can be used to modify the contents of multiple consecutive logical sectors. pData has to point to a memory area that stores the contents of all the logical sectors to be written.

The size of the logical sector depends on the type of storage device used. The application can query the size of the logical sector as well as the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo(). Typically, the size of a logical sector is 512 bytes.

FS_STORAGE_WriteSectors() reports an error and does not perform any operation if the specified range of logical sectors exceeds the size of the storage device.

Example

#include "FS.h"

void SampleStorageWriteSectors(void) {
  U32 aSectorData[512 / 4 * 2];

  //
  // Write the data of the logical sectors with the indexes 7 and 8.
  //
  FS_STORAGE_WriteSectors("", aSectorData, 7, 2);
}

FS_STORAGE_WriteSectorsEx()

Description

Writes multiple logical sectors to the storage device.

Prototype

int FS_STORAGE_WriteSectorsEx(      FS_VOLUME * pVolume,
                              const void      * pData,
                                    U32         SectorIndex,
                                    U32         NumSectors);

Parameters

Parameter Description
pVolume Instance of the volume to write to.
pData  in  Contents of the logical sector.
SectorIndex Index of the logical sector to be written.
NumSectors Number of logical sectors to be written.

Return value

= 0 OK, logical sectors written successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function performs the same operation as FS_STORAGE_WriteSectors() with the difference that the volume is specified via a volume instance instead a volume name. The application can get a volume instance form a volume name by calling FS_STORAGE_FindVolume().

FS_DEV_INFO

Description

Information about the storage device.

Type definition

typedef struct {
  U16  NumHeads;
  U16  SectorsPerTrack;
  U32  NumSectors;
  U16  BytesPerSector;
} FS_DEV_INFO;

Structure members

Member Description
NumHeads Number of read / write heads.
SectorsPerTrack Number of sectors stored on a track.
NumSectors Total number of sectors on the storage device.
BytesPerSector Size of a logical sector in bytes.

Additional information

NumHeads and SectorsPerTrack are relevant only for mechanical drives. The application can access the information about the storage device by calling FS_STORAGE_GetDeviceInfo().

FS_ON_DEVICE_ACTIVITY_CALLBACK

Description

The type of the callback function invoked by the file system on a logical sector read or write operation.

Type definition

typedef void (FS_ON_DEVICE_ACTIVITY_CALLBACK)(FS_DEVICE * pDevice,
                                              unsigned    Operation,
                                              U32         StartSector,
                                              U32         NumSectors,
                                              int         SectorType);

Parameters

Parameter Description
pDevice Storage device that performed the operation.
Operation Type of the operation performed. Can be one of the values listed in Transfer direction
StartSector Index of the first logical sector transfered (0-based)
NumSectors Number of logical sectors transfered in the current operation.
SectorType Type of the data stored in the logical sector. It can be one of the values listed in Sector data type

Additional information

This is the type of function that can be registered via FS_STORAGE_SetOnDeviceActivityCallback()

FS_STORAGE_COUNTERS

Description

Statistical counters.

Type definition

typedef struct {
  U32  ReadOperationCnt;
  U32  ReadSectorCnt;
  U32  ReadSectorCachedCnt;
  U32  WriteOperationCnt;
  U32  WriteSectorCnt;
  U32  WriteSectorCntCleaned;
  U32  ReadSectorCntMan;
  U32  ReadSectorCntDir;
  U32  WriteSectorCntMan;
  U32  WriteSectorCntDir;
} FS_STORAGE_COUNTERS;

Structure members

Member Description
ReadOperationCnt Number of “Read sector operation” calls.
ReadSectorCnt Number of sectors read (before cache).
ReadSectorCachedCnt Number of sectors read from cache
WriteOperationCnt Number of “Write sector operation” calls
WriteSectorCnt Number of sectors written (before cache).
WriteSectorCntCleaned Number of sectors written by the cache to storage in order to make room for other data.
ReadSectorCntMan Number of management sectors read (before cache).
ReadSectorCntDir Number of directory sectors (which store directory entries) read (before cache).
WriteSectorCntMan Number of management sectors written (before cache).
WriteSectorCntDir Number of directory sectors (which store directory entries) written (before cache).

Additional information

ReadSectorCnt can be (and typically is) higher than ReadOperationCnt, since one read operation can request multiple sectors (in a burst). The same applies to write operations: WriteSectorCnt can be (and typically is) higher than WriteOperationCnt, since one read operation can request multiple sectors (in a burst).

The statistical counters can be read via FS_STORAGE_GetCounters(). They are set to 0 when the file system is initialized. Additionally, the application can explicitly set them to 0 via FS_STORAGE_ResetCounters().

Sector data type

Description

Type of data stored in a logical sector

Definition

#define FS_SECTOR_TYPE_DATA    0u
#define FS_SECTOR_TYPE_DIR     1u
#define FS_SECTOR_TYPE_MAN     2u

Symbols

Definition Description
FS_SECTOR_TYPE_DATA Sector that stores file data.
FS_SECTOR_TYPE_DIR Sector that stores directory entries.
FS_SECTOR_TYPE_MAN Sector that stores entries of the allocation table.

Transfer direction

Description

Direction of the transfered data.

Definition

#define FS_OPERATION_READ     0
#define FS_OPERATION_WRITE    1

Symbols

Definition Description
FS_OPERATION_READ Data is transferred from storage device to MCU.
FS_OPERATION_WRITE Data is transferred from MCU to storage device.

Additional information

One of these values is passed by the file system via Operation parameter to the callback function registered via FS_STORAGE_SetOnDeviceActivityCallback()

The functions described in this section can be used only on volumes formatted as FAT.

FS_FAT_ConfigDirtyFlagUpdate()

Description

Enables / disables the update of the flag that indicates if the volume has been unmounted correctly.

Prototype

void FS_FAT_ConfigDirtyFlagUpdate(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

If enabled, the file system updates an internal dirty flag that is set to 1 each time data is written to storage device. The dirty flag is set to 0 when the application unmounts the file system. The value of the dirty flag is updated to storage device and can be used to check if the storage device has been properly unmounted before the system reset. FS_GetVolumeInfo() can be used to get the value of this dirty flag (IsDirty member of FS_DISK_INFO).

The update of the dirty flag is enabled by default if the compile-time option FS_FAT_UPDATE_DIRTY_FLAG is set to 1. FS_FAT_ConfigDirtyFlagUpdate() is available only if the compile-time option FS_FAT_UPDATE_DIRTY_FLAG is set to 1.

Example

#include "FS.h"

void SampleFATConfigDirtyFlagUpdate(void) {
  FS_FILE      * pFile;
  FS_DISK_INFO   VolumeInfo;

  FS_Init();
#if FS_FAT_UPDATE_DIRTY_FLAG
  FS_FAT_ConfigDirtyFlagUpdate(1);
#endif
  pFile = FS_FOpen("Test.txt", "w");
  if (pFile) {
    FS_FClose(pFile);
  }
  FS_GetVolumeInfo("", &VolumeInfo);
  if (VolumeInfo.IsDirty) {
    FS_X_Log("Volume has been modified.\n");
  } else {
    FS_X_Log("Volume has not been modified.\n");
  }
}

FS_FAT_ConfigFATCopyMaintenance()

Description

Enables / disables the update of the second allocation table.

Prototype

void FS_FAT_ConfigFATCopyMaintenance(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

The FAT file system has support for a second (redundant) allocation table. FS_FAT_ConfigFATCopyMaintenance() can be used to enable or disable the update of the second allocation table. The data in the second allocation table is not used by the file system but it may be required to be present by some PC file system checking utilities. Enabling this option can possible reduce the write performance of the file system.

The update of the second allocation table is enabled by default if the compile-time option FS_MAINTAIN_FAT_COPY is set to 1. FS_FAT_ConfigFATCopyMaintenance() is available only if the compile-time option FS_MAINTAIN_FAT_COPY is set to 1.

Example

#include "FS.h"

void SampleFATConfigFATCopyMaintenance(void) {
  FS_Init();
#if FS_MAINTAIN_FAT_COPY
  FS_FAT_ConfigFATCopyMaintenance(1);
#endif
  //
  // At each write access to the allocation table
  // the second allocation table is also updated.
  //
}

FS_FAT_ConfigFSInfoSectorUse()

Description

Enables / disables the usage of information from the FSInfo sector.

Prototype

void FS_FAT_ConfigFSInfoSectorUse(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

FSInfo sector is a management sector present on FAT32-formatted volumes that stores information about the number of free clusters and the id of the first free cluster. This information, when available and valid, can be used to increase the performance of the operation that calculates the available free space on a volume such as FS_GetVolumeFreeSpace(), FS_GetVolumeFreeSpaceKB(), FS_GetVolumeInfo(), or FS_GetVolumeInfoEx(). If the information in the FSInfo sector is missing or invalid, the file system has to scan the entire allocation to calculate the available free space an operation that can take a long time to complete on storage devices with a large capacity (few Gbytes.)

The file system invalidates the information in the FSInfo sector on the first operation that allocates or frees a cluster. The FSInfo sector is updated when the volume is unmounted via FS_Unmount() or synchronized via FS_Sync().

FSInfo sector is evaluated and updated by default if the compile-time option FS_FAT_USE_FSINFO_SECTOR is set to 1. FS_FAT_ConfigFSInfoSectorUse() is available only if the compile-time option FS_FAT_USE_FSINFO_SECTOR is set to 1.

Example

#include "FS.h"

void SampleFATConfigFSInfoSectorUse(void) {
  U32 NumBytes;

  FS_Init();
#if FS_FAT_USE_FSINFO_SECTOR
  FS_FAT_ConfigFSInfoSectorUse(1);
#endif
  NumBytes = FS_GetVolumeFreeSpace("");
}

FS_FAT_ConfigROFileMovePermission()

Description

Enables / disables the permission to move (and rename) files and directories with the read-only file attribute set.

Prototype

void FS_FAT_ConfigROFileMovePermission(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

The application is per default allowed to move or rename via FS_Move() and FS_Rename() respectively files and directories that have the read-only file attribute (FS_ATTR_READ_ONLY) set. FS_FAT_ConfigROFileMovePermission() can be used to disable this option and thus to prevent an application to perform move or rename operations on files and directories marked as read-only.

FS_FAT_ConfigROFileMovePermission() is available only if the compile-time option FS_FAT_PERMIT_RO_FILE_MOVE is set to 1.

Example

#include "FS.h"

void SampleFATConfigROFileMovePermission(void) {
  FS_FILE * pFile;
  int       r;

#if FS_FAT_PERMIT_RO_FILE_MOVE
  FS_FAT_ConfigROFileMovePermission(0);
#endif
  pFile = FS_FOpen("Test.txt", "w");
  if (pFile != NULL) {
    FS_FClose(pFile);
  }
  FS_SetFileAttributes("Test.txt", FS_ATTR_READ_ONLY);
  r = FS_Move("Test.txt", "TestOld.txt");
  if (r != 0) {
    //
    // A file marked as read-only cannot be moved to another location.
    //
  }
}

FS_FAT_DisableLFN()

Description

Disables the support for long file names.

Prototype

void FS_FAT_DisableLFN(void);

Additional information

After calling this function the file system accepts only file and directory names in 8.3 format. Files and directories created with support for long file names enabled are still accessible since each long file name has an associated name in 8.3 format. The short name is automatically generated by the file system based on the first characters of the long name and a sequential index. The support for long file names can be activated via FS_FAT_SupportLFN().

This function applies only to volumes formatted as FAT. EFS-formatted volumes have native support for long file names.

Example

#include "FS.h"

void SampleFATDisableLFN(void) {
  FS_FILE * pFile;

  FS_Init();
#if FS_SUPPORT_FAT
  FS_FAT_DisableLFN();
#endif
  pFile = FS_FOpen("FileName.txt", "w");
  if (pFile) {
    FS_FClose(pFile);
  }
}

FS_FAT_FormatSD()

Description

Performs a high-level format as per SD Specification.

Prototype

int FS_FAT_FormatSD(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be formatted.

Return value

= 0 OK, format successful.
≠ 0 Error code indicating the failure reason.

Additional information

The SD Specification defines a layout for the information that is stored to an SD, SDHC or SDXC card that ensures the best read and write performance. The layout of the information is set during the format operation and takes advantage of the physical structure of the storage device being formatted in order to optimize the access to it. FS_FAT_FormatSD() formats the storage device using this layout.

SEGGER recommends formatting an SD card or an eMMC device using this function for improved file system performance. FS_FAT_FormatSD() can be used as well to format other types of storage devices.

Typically, FS_FAT_FormatSD() reserves more space for the file system management information in comparison to FS_Format(). For this reason, slightly less storage space will be available for the application when formatting using FS_FAT_FormatSD().

FS_FAT_FormatSD() performs the following operations:

The type of FAT formatting used depends on the capacity of the storage device. The following table shows this relationship.

FAT type Storage capacity
FAT12 smaller than about 256 MB
FAT16 between about 256 MB and about 2 GB
FAT32 greater than about 2 GB

The function is available only if the file system is built with the FS_SUPPORT_FAT configuration define set to 1.

Deprecated name

FS_FormatSD

Example

#include "FS.h"

void SampleFATFormatSD(void) {
  FS_Init();
#if FS_SUPPORT_FAT
  FS_FAT_FormatSD("");
#endif
}

FS_FAT_GetConfig()

Description

Returns information about how the FAT component is configured to operate.

Prototype

int FS_FAT_GetConfig(FS_FAT_CONFIG * pConfig);

Parameters

Parameter Description
pConfig  out  Configuration information.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

FS_FAT_GetLFNConverter()

Description

Returns the type of configured file name converter.

Prototype

FS_UNICODE_CONV *FS_FAT_GetLFNConverter(void);

Return value

Configured file name converter.

Additional information

This function is available only if FS_SUPPORT_FILE_NAME_ENCODING is set to 1 which is the default. Refer to pUnicodeConv parameter of FS_FAT_SetLFNConverter() for a list of possible return values.

FS_FAT_GrowRootDir()

Description

Increases the size of the root directory.

Prototype

U32 FS_FAT_GrowRootDir(const char * sVolumeName,
                             U32    NumAddEntries);

Parameters

Parameter Description
sVolumeName Name of the volume for which to increase the root directory.
NumAddEntries Number of directory entries to be added.

Return value

> 0 Number of entries added.
= 0 Clusters after root directory are not free. The number of entries in the root directory has not been changed.
= 0xFFFFFFFF An error occurred.

Additional information

The formatting function allocates per default one cluster for the root directory of a FAT32 formatted volume. The file system increases automatically the size of the root directory as more files are added to it. This operation has a certain overhead that depends on the size of the allocation table and on the available free space. This overhead can be eliminated by calling FS_FAT_GrowRootDir() to increase the size of the root directory to the number of files and directories the application is expected to store in it.

This function increases the size of the root directory on a FAT32 formatted volume by the number of entries specified in NumAddEntries. The file system allocates one directory entry for each file or directory if the support for long file names is not enabled. With the support for long file names enabled the number of directory entries allocated to a file or directory depends on the number of characters in the name of the created file or directory.

This function fails if one of the following conditions is true:

FS_FAT_GrowRootDir() is available only if the compile-time option FS_SUPPORT_FAT set to 1.

Example

#include "FS.h"

void SampleFATGrowRootDir(void) {
  FS_Format("", NULL);
#if FS_SUPPORT_FAT
  FS_FAT_GrowRootDir("", 64);
#endif
}

FS_FAT_SetLFNConverter()

Description

Configures how long file names are to be encoded and decoded.

Prototype

void FS_FAT_SetLFNConverter(const FS_UNICODE_CONV * pUnicodeConv);

Parameters

Parameter Description
pUnicodeConv File name converter.

Additional information

This function is available only if FS_SUPPORT_FILE_NAME_ENCODING is set to 1 which is the default.

Permitted values for pUnicodeConv are:

Identifier Description
FS_UNICODE_CONV_CP437 Unicode <-> CP437 (DOS Latin US) converter
FS_UNICODE_CONV_CP932 Unicode <-> CP932 (Shift JIS) converter
FS_UNICODE_CONV_CP936 Unicode <-> CP936 (GBK) converter
FS_UNICODE_CONV_CP949 Unicode <-> CP949 (Unified Hangul Code) converter
FS_UNICODE_CONV_CP950 Unicode <-> CP950 (Big5) converter
FS_UNICODE_CONV_UTF8 Unicode <-> UTF-8 converter

FS_FAT_SupportLFN()

Description

Enables the support for long file names.

Prototype

void FS_FAT_SupportLFN(void);

Additional information

The file system accepts per default only file and directory names in 8.3 format, that is maximum 8 characters in the base name of a file, an optional period character, and an optional extension of maximum 3 characters. The application can call FS_FAT_SupportLFN() to enable the file system to work with names for files and directories longer that in the 8.3 format.

This function applies only to volumes formatted as FAT. EFS-formatted volumes have native support for long file names.

Example

#include "FS.h"

void SampleFATSupportLFN(void) {
  FS_FILE * pFile;

  FS_Init();
#if FS_SUPPORT_FAT
  FS_FAT_SupportLFN();
#endif
  pFile = FS_FOpen("This is an unusually long file name", "w");
  if (pFile) {
    FS_FClose(pFile);
  }
}

FS_FAT_CONFIG

Description

Information about the FAT configuration.

Type definition

typedef struct {
  U8  IsLFNSupported;
  U8  IsFSInfoSectorUsed;
  U8  IsATCopyMaintained;
  U8  IsROFileMovePermitted;
  U8  IsDirtyFlagUpdated;
  U8  IsFAT32Supported;
  U8  IsDeleteOptimized;
  U8  LinearAccessOptimizationLevel;
  U8  IsFreeClusterCacheSupported;
  U8  IsLowerCaseSFNSupported;
} FS_FAT_CONFIG;

Structure members

Member Description
IsLFNSupported Indicates if the support for long file names is enabled.
IsFSInfoSectorUsed Indicates if the information about the free clusters is read from the FSInfo sector.
IsATCopyMaintained Indicates if the copy of the allocation table is update.
IsROFileMovePermitted Indicates if the file system is allowed to move file that have the read-only attribute set.
IsDirtyFlagUpdated Indicates if the updates the dirty flag in the BPB sector.
IsFAT32Supported Indicates if the support for FAT32 formatted volumes is enabled.
IsDeleteOptimized Indicates if the optimization for the deletion of large files is enabled.
LinearAccessOptimizationLevel Optimization level for the access to linearly allocated files.
IsFreeClusterCacheSupported Indicates if the support for the cache of free clusters is enabled.
IsLowerCaseSFNSupported Indicates if the optimization for storing of short file names in lower case is enabled.

The functions described in this section can be used only on volumes formatted as EFS.

FS_EFS_ConfigCaseSensitivity()

Description

Configures how the file names are compared.

Prototype

void FS_EFS_ConfigCaseSensitivity(int OnOff);

Parameters

Parameter Description
OnOff Specifies if the case of a character is important or not. 1 Character case is important. 0 Character case is ignored.

Additional information

This function is optional and is active only when the file system is compiled with FS_EFS_CASE_SENSITIVE set to 1. By default the EFS file system layer ignores the case of a character in file names when it compares two file names. That is, “testfile.txt”, “TestFile.txt” and “TESTFILE.TXT” represent the same file name. The case of a file name is preserved when the file is created via FS_FOpen() or FS_FOpenEx() or in case of a directory when FS_MkDir() and FS_CreateDir() is called to create one.

If the case sensitivity is enabled by calling FS_EFS_ConfigCaseSensitivity() with the OnOff parameter set to 1 than “testfile.txt”, “TestFile.txt” and “TESTFILE.TXT” are three different file names.

FS_EFS_ConfigStatusSectorSupport()

Description

Enables or disables the usage of information from the status sector.

Prototype

void FS_EFS_ConfigStatusSectorSupport(int OnOff);

Parameters

Parameter Description
OnOff Specifies if the status sector information has to be used or not. 1 Status sector information is used. 0 Status sector information is not used.

Additional information

This function is optional an is active only when the file system is compiled with FS_EFS_SUPPORT_STATUS_SECTOR set to 1. The status sector stores information about the free space available on the storage which helps the file system improve the performance of the operations that return the available free space such as FS_GetVolumeInfo().

FS_EFS_GetConfig()

Description

Returns information about how the EFS component is configured to operate.

Prototype

int FS_EFS_GetConfig(FS_EFS_CONFIG * pConfig);

Parameters

Parameter Description
pConfig  out  Configuration information.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

FS_EFS_SetFileNameConverter()

Description

Configures how file names are to be encoded.

Prototype

void FS_EFS_SetFileNameConverter(const FS_UNICODE_CONV * pUnicodeConv);

Parameters

Parameter Description
pUnicodeConv File name converter.

Additional information

This function is available only if FS_SUPPORT_FILE_NAME_ENCODING is set to 1. By default, FS_SUPPORT_FILE_NAME_ENCODING is set to 0 in order to reduce the RAM and ROM usage.

Permitted values for pUnicodeConv are:

Identifier Description
FS_UNICODE_CONV_CP437 Unicode <-> CP437 (DOS Latin US) converter
FS_UNICODE_CONV_CP932 Unicode <-> CP932 (Shift JIS) converter
FS_UNICODE_CONV_CP936 Unicode <-> CP936 (GBK) converter
FS_UNICODE_CONV_CP949 Unicode <-> CP949 (Unified Hangul Code) converter
FS_UNICODE_CONV_CP950 Unicode <-> CP950 (Big5) converter
FS_UNICODE_CONV_UTF8 Unicode <-> UTF-8 converter

FS_EFS_CONFIG

Description

Information about the EFS configuration.

Type definition

typedef struct {
  U8  IsStatusSectorSupported;
  U8  IsCaseSensitiveName;
  U8  IsDirEntryBufferSupported;
  U8  NumDirEntryBuffers;
  U8  IsDeleteOptimized;
  U8  LinearAccessOptimizationLevel;
  U8  IsFreeClusterCacheSupported;
  U8  MaxDirEntrySize;
} FS_EFS_CONFIG;

Structure members

Member Description
IsStatusSectorSupported Indicates if the information of the status sector is updated.
IsCaseSensitiveName Indicates if the comparison of file names is case sensitive.
IsDirEntryBufferSupported Indicates if the support for directory entry buffers is enabled.
NumDirEntryBuffers Number of configured directory entry buffers.
IsDeleteOptimized Indicates if the optimization for the deletion of large files is enabled.
LinearAccessOptimizationLevel Optimization level for the access to linearly allocated files.
IsFreeClusterCacheSupported Indicates if the support for the cache of free clusters is enabled.
MaxDirEntrySize Maximum number of bytes in a directory entry.

The functions described in this section can be used only on volumes formatted as exFAT.

FS_EXFAT_ConfigDirtyFlagUpdate()

Description

Enables or disables the update of the flag that indicates if the volume has been unmounted correctly.

Prototype

void FS_EXFAT_ConfigDirtyFlagUpdate(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

If enabled, the file system updates an internal dirty flag that is set to 1 each time data is written to storage device. The dirty flag is set to 0 when the application unmounts the file system. The value of the dirty flag is updated to storage device and can be used to check if the storage device has been properly unmounted before the system reset. FS_GetVolumeInfo() can be used to get the value of this dirty flag (IsDirty member of FS_DISK_INFO).

The update of the dirty flag is enabled by default if the compile-time option FS_EXFAT_UPDATE_DIRTY_FLAG is set to 1. FS_EXFAT_ConfigDirtyFlagUpdate() is available only if the compile-time option FS_EXFAT_UPDATE_DIRTY_FLAG is set to 1.

FS_EXFAT_ConfigROFileMovePermission()

Description

Enables / disables the permission to move (and rename) files and directories with the read-only file attribute set.

Prototype

void FS_EXFAT_ConfigROFileMovePermission(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

The application is per default allowed to move or rename via FS_Move() and FS_Rename() respectively files and directories that have the read-only file attribute (FS_ATTR_READ_ONLY) set. FS_EXFAT_ConfigROFileMovePermission() can be used to disable this option and thus to prevent an application to perform move or rename operations on files and directories marked as read-only.

FS_EXFAT_ConfigROFileMovePermission() is available only if the compile-time option FS_EXFAT_PERMIT_RO_FILE_MOVE is set to 1.

FS_EXFAT_ConfigSpaceUsageUpdate()

Description

Enables or disables the update of the storage usage.

Prototype

void FS_EXFAT_ConfigSpaceUsageUpdate(int OnOff);

Parameters

Parameter Description
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

If enabled, the file system updates the information about the amount of storage used by the file system in the boot sector of the volume.

The update of the usage information is enabled by default if the compile-time option FS_EXFAT_UPDATE_SPACE_USAGE is set to 1. FS_EXFAT_ConfigSpaceUsageUpdate() is available only if the compile-time option FS_EXFAT_UPDATE_SPACE_USAGE is set to 1.

FS_EXFAT_FormatSD()

Description

Performs a high-level format as per SD Specification.

Prototype

int FS_EXFAT_FormatSD(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume to be formatted.

Return value

= 0 OK, format successful.
≠ 0 Error code indicating the failure reason.

Additional information

The SD Standard defines a layout for the information that is stored to an SD, SDHC or SDXC card that ensures the best read and write performance. The layout of the information is set during the format operation and takes advantage of the physical structure of the storage device being formatted in order to optimize the access to it. FS_EXFAT_FormatSD() formats the storage device using this layout.

SEGGER recommends formatting an SD card or an eMMC device using this function for improved file system performance. FS_EXFAT_FormatSD() can be used to format other types of storage devices as well.

Typically, FS_EXFAT_FormatSD() reserves more space for the file system management information in comparison to FS_Format(). For this reason, slightly less storage space will be available for the application when formatting using FS_EXFAT_FormatSD().

FS_EXFAT_FormatSD() performs the following operations:

The function is available only if the file system is built with the FS_SUPPORT_EXFAT configuration define set to 1.

FS_EXFAT_GetConfig()

Description

Returns information about how the exFAT component is configured to operate.

Prototype

int FS_EXFAT_GetConfig(FS_EXFAT_CONFIG * pConfig);

Parameters

Parameter Description
pConfig  out  Configuration information.

Return value

= 0 OK, information returned.
≠ 0 Error code indicating the failure reason.

FS_EXFAT_GetFileNameConverter()

Description

Returns the type of configured file name converter.

Prototype

FS_UNICODE_CONV *FS_EXFAT_GetFileNameConverter(void);

Return value

Configured file name converter.

Additional information

This function is available only if FS_SUPPORT_FILE_NAME_ENCODING is set to 1 which is the default. Refer to pUnicodeConv parameter of FS_EXFAT_SetFileNameConverter() for a list of possible return values.

FS_EXFAT_GrowRootDir()

Description

Increases the size of the root directory.

Prototype

U32 FS_EXFAT_GrowRootDir(const char * sVolumeName,
                               U32    NumAddEntries);

Parameters

Parameter Description
sVolumeName Name of the volume for which to increase the root directory.
NumAddEntries Number of directory entries to be added.

Return value

> 0 Number of entries added.
= 0 Clusters after root directory are not free. The number of entries in the root directory has not been changed.
= 0xFFFFFFFF An error occurred.

Additional information

The formatting function allocates by default one cluster for the root directory of a formatted volume. The file system increases automatically the size of the root directory as more files are added to it. This operation has a certain overhead that depends on the size of the allocation table and on the available free space. This overhead can be eliminated by calling FS_EXFAT_GrowRootDir() to increase the size of the root directory to the number of files and directories the application is expected to store in it.

This function increases the size of the root directory on a formatted volume by the number of entries specified in NumAddEntries. The file system allocates one directory entry for each file or directory if the support for long file names is not enabled. With the support for long file names enabled the number of directory entries allocated to a file or directory depends on the number of characters in the name of the created file or directory.

This function fails if one of the following conditions is true:

FS_EXFAT_GrowRootDir() is available only if the compile-time option FS_SUPPORT_EXFAT set to 1.

FS_EXFAT_SetFileNameConverter()

Description

Configures how long file names are to be encoded and decoded.

Prototype

void FS_EXFAT_SetFileNameConverter(const FS_UNICODE_CONV * pUnicodeConv);

Parameters

Parameter Description
pUnicodeConv File name converter.

Additional information

This function is available only if FS_SUPPORT_FILE_NAME_ENCODING is set to 1 which is the default.

Permitted values for pUnicodeConv are:

Identifier Description
FS_UNICODE_CONV_CP437 Unicode <-> CP437 (DOS Latin US) converter
FS_UNICODE_CONV_CP932 Unicode <-> CP932 (Shift JIS) converter
FS_UNICODE_CONV_CP936 Unicode <-> CP936 (GBK) converter
FS_UNICODE_CONV_CP949 Unicode <-> CP949 (Unified Hangul Code) converter
FS_UNICODE_CONV_CP950 Unicode <-> CP950 (Big5) converter
FS_UNICODE_CONV_UTF8 Unicode <-> UTF-8 converter

FS_EXFAT_CONFIG

Description

Information about the exFAT configuration.

Type definition

typedef struct {
  U8  IsSpaceUsageUpdated;
  U8  IsROFileMovePermitted;
  U8  IsDirtyFlagUpdated;
  U8  IsDeleteOptimized;
  U8  LinearAccessOptimizationLevel;
  U8  IsFreeClusterCacheSupported;
} FS_EXFAT_CONFIG;

Structure members

Member Description
IsSpaceUsageUpdated Indicates if the information about storage usage is updated in the boot sector.
IsROFileMovePermitted Indicates if the file system is allowed to move file that have the read-only attribute set.
IsDirtyFlagUpdated Indicates if the updates the dirty flag in the BPB sector.
IsDeleteOptimized Indicates if the optimization for the deletion of large files is enabled.
LinearAccessOptimizationLevel Optimization level for the access to linearly allocated files.
IsFreeClusterCacheSupported Indicates if the support for the cache of free clusters is enabled.

Error-handling functions

An application can use the following functions to check and clear the error status of a file handle.

FS_ClearErr()

Description

Clears error status of a file handle.

Prototype

void FS_ClearErr(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Additional information

The function sets the error status of a file handle to FS_ERRCODE_OK. FS_ClearErr() is the only function that clears the error status of a file handle. The other API functions modify the error status of a file handle only if it is cleared. The application has to call this function after it detects that an error occurred during a file system operation on an opened file handle and before it starts a new file system operation if it wants to get the correct error status in case of a failure.

Example

#include <stdio.h>
#include "FS.h"

void SampleClearErr(void) {
  FS_FILE * pFile;
  U32       aBuffer[32 / 4];
  int       ErrCode;
  char      ac[100];
  U32       NumBytesRead;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    NumBytesRead = FS_Read(pFile, aBuffer, sizeof(aBuffer));
    ErrCode = FS_FError(pFile);
    if (ErrCode == FS_ERRCODE_OK) {
      SEGGER_snprintf(ac, sizeof(ac), "First read operation failed with: %d (%s)\n",
        ErrCode, FS_ErrorNo2Text(ErrCode));
      FS_X_Log(ac);
      FS_ClearErr(pFile);
    } else {
      SEGGER_snprintf(ac, sizeof(ac), "The first operation read %lu bytes from file.\n", 
        NumBytesRead);
      FS_X_Log(ac);
    }
    NumBytesRead = FS_Read(pFile, aBuffer, sizeof(aBuffer));
    ErrCode = FS_FError(pFile);
    if (ErrCode != FS_ERRCODE_OK) {
      SEGGER_snprintf(ac, sizeof(ac), "Second read operation failed with: %d (%s)\n",
        ErrCode, FS_ErrorNo2Text(ErrCode));
      FS_X_Log(ac);
      FS_ClearErr(pFile);
    } else {
      SEGGER_snprintf(ac, sizeof(ac), "The second operation read %lu bytes from file.\n", 
        NumBytesRead);
      FS_X_Log(ac);
    }
    FS_FClose(pFile);
  }
}

FS_ErrorNo2Text()

Description

Returns a human-readable text description of an API error code.

Prototype

char *FS_ErrorNo2Text(int ErrCode);

Parameters

Parameter Description
ErrCode Error code for which the text description has to be returned.

Return value

The text description as 0-terminated ASCII string.

Additional information

For a list of supported error codes refer to Error codes. If the error code is not known FS_ErrorNo2Text() returns the “Unknown error” string. The error status of an opened file handle can be queried via FS_FError(). Most of the API functions of the file system also return one of the defined codes in case of an error. This error code can be passed to FS_ErrorNo2Text() to get a human-readable text description.

Example

#include <stdio.h>
#include "FS.h"

void SampleErrorNo2Text(void) {
  FS_FILE * pFile;
  int       r;
  char      ac[100];

  r = FS_FOpenEx("Test.txt", "r", &pFile);
  if (r) {
    SEGGER_snprintf(ac, sizeof(ac), 
      "The file open operation failed with: %d (%s)\n", r, FS_ErrorNo2Text(r));
    FS_X_Log(ac);
  } else {
    //
    // Access the file contents...
    //
    FS_FClose(pFile);
  }
}

FS_FEof()

Description

Returns if end of file has been reached.

Prototype

int FS_FEof(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

= 1 An attempt was made to read beyond the end of the file.
= 0 The end of file has not been reached.
< 0 An error occurred.

Additional information

The end-of-file flag of the file handle is set by the file system when the application tries to read more bytes than available in the file. This is not an error condition but just an indication that the file pointer is positioned beyond the last byte in the file and that by trying to read from this position no bytes are returned.

Example

#include "FS.h"

void SampleFEof(void) {
  FS_FILE * pFile;
  U32       aBuffer[32 / 4];
  int       r;
  int       ErrCode;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    while (1) {
      FS_Read(pFile, aBuffer, sizeof(aBuffer));
      if (FS_FEof(pFile)) {
        break;                  // End of file reached.
      }
      ErrCode = FS_FError(pFile);
      if (ErrCode) {
        break;                  // An error occurred while reading from file.
      }
    }
    FS_FClose(pFile);
  }
}

FS_FError()

Description

Returns error status of a file handle.

Prototype

I16 FS_FError(FS_FILE * pFile);

Parameters

Parameter Description
pFile Handle to opened file.

Return value

= FS_ERRCODE_OK No error present.
FS_ERRCODE_OK An error has occurred.

Additional information

The application can use this function to check what kind of error caused an API function that does not return an error code such as FS_Read(), FS_FRead(), FS_Write() or FS_FWrite() to fail. The error status remains set until the application calls FS_ClearErr().

FS_ErrorNo2Text() can be used to return a human-readable description of the error as a 0-terminated string.

Example

#include <stdio.h>
#include "FS.h"

void SampleFError(void) {
  FS_FILE * pFile;
  U32       aBuffer[32 / 4];
  int       ErrCode;
  char      ac[100];
  U32       NumBytesRead;

  pFile = FS_FOpen("Test.txt", "r");
  if (pFile) {
    NumBytesRead = FS_Read(pFile, aBuffer, sizeof(aBuffer));
    ErrCode = FS_FError(pFile);
    if (ErrCode != FS_ERRCODE_OK) {
      SEGGER_snprintf(ac, sizeof(ac), "The read operation failed with: %d (%s)\n",
        ErrCode, FS_ErrorNo2Text(ErrCode));
      FS_X_Log(ac);
      FS_ClearErr(pFile);
    } else {
      SEGGER_snprintf(ac, sizeof(ac), "The operation read %lu bytes from file.\n", 
        NumBytesRead);
      FS_X_Log(ac);
    }
    FS_FClose(pFile);
  }
}

Error codes

Description

Values returned by the API functions to indicate the reason of an error.

Definition

#define FS_ERRCODE_OK                            0
#define FS_ERRCODE_EOF                           (-1)
#define FS_ERRCODE_PATH_TOO_LONG                 (-2)
#define FS_ERRCODE_INVALID_PARA                  (-3)
#define FS_ERRCODE_WRITE_ONLY_FILE               (-5)
#define FS_ERRCODE_READ_ONLY_FILE                (-6)
#define FS_ERRCODE_READ_FAILURE                  (-7)
#define FS_ERRCODE_WRITE_FAILURE                 (-8)
#define FS_ERRCODE_FILE_IS_OPEN                  (-9)
#define FS_ERRCODE_PATH_NOT_FOUND                (-10)
#define FS_ERRCODE_FILE_DIR_EXISTS               (-11)
#define FS_ERRCODE_NOT_A_FILE                    (-12)
#define FS_ERRCODE_TOO_MANY_FILES_OPEN           (-13)
#define FS_ERRCODE_INVALID_FILE_HANDLE           (-14)
#define FS_ERRCODE_VOLUME_NOT_FOUND              (-15)
#define FS_ERRCODE_READ_ONLY_VOLUME              (-16)
#define FS_ERRCODE_VOLUME_NOT_MOUNTED            (-17)
#define FS_ERRCODE_NOT_A_DIR                     (-18)
#define FS_ERRCODE_FILE_DIR_NOT_FOUND            (-19)
#define FS_ERRCODE_NOT_SUPPORTED                 (-20)
#define FS_ERRCODE_CLUSTER_NOT_FREE              (-21)
#define FS_ERRCODE_INVALID_CLUSTER_CHAIN         (-22)
#define FS_ERRCODE_STORAGE_NOT_PRESENT           (-23)
#define FS_ERRCODE_BUFFER_NOT_AVAILABLE          (-24)
#define FS_ERRCODE_STORAGE_TOO_SMALL             (-25)
#define FS_ERRCODE_STORAGE_NOT_READY             (-26)
#define FS_ERRCODE_BUFFER_TOO_SMALL              (-27)
#define FS_ERRCODE_INVALID_FS_FORMAT             (-28)
#define FS_ERRCODE_INVALID_FS_TYPE               (-29)
#define FS_ERRCODE_FILENAME_TOO_LONG             (-30)
#define FS_ERRCODE_VERIFY_FAILURE                (-31)
#define FS_ERRCODE_VOLUME_FULL                   (-32)
#define FS_ERRCODE_DIR_NOT_EMPTY                 (-33)
#define FS_ERRCODE_IOCTL_FAILURE                 (-34)
#define FS_ERRCODE_INVALID_MBR                   (-35)
#define FS_ERRCODE_OUT_OF_MEMORY                 (-36)
#define FS_ERRCODE_UNKNOWN_DEVICE                (-37)
#define FS_ERRCODE_ASSERT_FAILURE                (-38)
#define FS_ERRCODE_TOO_MANY_TRANSACTIONS_OPEN    (-39)
#define FS_ERRCODE_NO_OPEN_TRANSACTION           (-40)
#define FS_ERRCODE_INIT_FAILURE                  (-41)
#define FS_ERRCODE_FILE_TOO_LARGE                (-42)
#define FS_ERRCODE_INVALID_CONFIG                (-43)
#define FS_ERRCODE_INVALID_USAGE                 (-44)
#define FS_ERRCODE_TOO_MANY_INSTANCES            (-45)
#define FS_ERRCODE_TRANSACTION_ABORTED           (-46)
#define FS_ERRCODE_INVALID_CHAR                  (-47)
#define FS_ERRCODE_INVALID_GPT                   (-48)
#define FS_ERRCODE_INVALID_CONTENT               (-49)
#define FS_ERRCODE_COMPRESS_FAILURE              (-50)
#define FS_ERRCODE_CRYPT_FAILURE                 (-51)
#define FS_ERRCODE_INVALID_DIR                   (-52)
#define FS_ERRCODE_DEFECTIVE_STORAGE             (-53)
#define FS_ERRCODE_ERASE_FAILURE                 (-54)
#define FS_ERRCODE_PERMANENT_FAILURE             (-55)

Symbols

Definition Description
FS_ERRCODE_OK No error
FS_ERRCODE_EOF End of file reached
FS_ERRCODE_PATH_TOO_LONG Path to file or directory is too long
FS_ERRCODE_INVALID_PARA Invalid parameter passed
FS_ERRCODE_WRITE_ONLY_FILE File can only be written
FS_ERRCODE_READ_ONLY_FILE File can not be written
FS_ERRCODE_READ_FAILURE Error while reading from storage device
FS_ERRCODE_WRITE_FAILURE Error while writing to storage device
FS_ERRCODE_FILE_IS_OPEN Trying to delete a file which is open
FS_ERRCODE_PATH_NOT_FOUND Path to file or directory not found
FS_ERRCODE_FILE_DIR_EXISTS File or directory already exists
FS_ERRCODE_NOT_A_FILE Trying to open a directory instead of a file
FS_ERRCODE_TOO_MANY_FILES_OPEN Exceeded number of files opened at once
FS_ERRCODE_INVALID_FILE_HANDLE The file handle has been invalidated
FS_ERRCODE_VOLUME_NOT_FOUND The volume name specified in a path is does not exist
FS_ERRCODE_READ_ONLY_VOLUME Trying to write to a volume mounted in read-only mode
FS_ERRCODE_VOLUME_NOT_MOUNTED Trying access a volume which is not mounted
FS_ERRCODE_NOT_A_DIR Trying to open a file instead of a directory
FS_ERRCODE_FILE_DIR_NOT_FOUND File or directory not found
FS_ERRCODE_NOT_SUPPORTED Functionality not supported
FS_ERRCODE_CLUSTER_NOT_FREE Trying to allocate a cluster which is not free
FS_ERRCODE_INVALID_CLUSTER_CHAIN Detected a shorter than expected cluster chain
FS_ERRCODE_STORAGE_NOT_PRESENT Trying to access a removable storage which is not inserted
FS_ERRCODE_BUFFER_NOT_AVAILABLE No more sector buffers available
FS_ERRCODE_STORAGE_TOO_SMALL Not enough sectors on the storage device
FS_ERRCODE_STORAGE_NOT_READY Storage device can not be accessed
FS_ERRCODE_BUFFER_TOO_SMALL Sector buffer smaller than sector size of storage device
FS_ERRCODE_INVALID_FS_FORMAT Storage device is not formatted or the format is not valid
FS_ERRCODE_INVALID_FS_TYPE Type of file system is invalid or not configured
FS_ERRCODE_FILENAME_TOO_LONG The name of the file is too long
FS_ERRCODE_VERIFY_FAILURE Data verification failure
FS_ERRCODE_VOLUME_FULL No more space on storage device
FS_ERRCODE_DIR_NOT_EMPTY Trying to delete a directory which is not empty
FS_ERRCODE_IOCTL_FAILURE Error while executing a driver control command
FS_ERRCODE_INVALID_MBR Invalid information in the Master Boot Record
FS_ERRCODE_OUT_OF_MEMORY Could not allocate memory
FS_ERRCODE_UNKNOWN_DEVICE Storage device is not configured
FS_ERRCODE_ASSERT_FAILURE FS_DEBUG_ASSERT() macro failed
FS_ERRCODE_TOO_MANY_TRANSACTIONS_OPEN Maximum number of opened journal transactions exceeded
FS_ERRCODE_NO_OPEN_TRANSACTION Trying to close a journal transaction which is not opened
FS_ERRCODE_INIT_FAILURE Error while initializing the storage medium
FS_ERRCODE_FILE_TOO_LARGE Trying to write to a file which is larger than 4 Gbytes
FS_ERRCODE_INVALID_CONFIG The file system is not configured correctly
FS_ERRCODE_INVALID_USAGE Trying to call a function in an invalid state
FS_ERRCODE_TOO_MANY_INSTANCES Trying to create one instance more than maximum configured
FS_ERRCODE_TRANSACTION_ABORTED A journal transaction has been stopped by the application
FS_ERRCODE_INVALID_CHAR Invalid character in the name of a file
FS_ERRCODE_INVALID_GPT Invalid information in the GUID partition
FS_ERRCODE_INVALID_CONTENT The content of a file is invalid
FS_ERRCODE_COMPRESS_FAILURE Error while compressing or decompressing the data
FS_ERRCODE_CRYPT_FAILURE Error while encrypting or decrypting the data
FS_ERRCODE_INVALID_DIR Invalid directory contents
FS_ERRCODE_DEFECTIVE_STORAGE Storage device is not working properly
FS_ERRCODE_ERASE_FAILURE Error while erasing a storage device block
FS_ERRCODE_PERMANENT_FAILURE Processing disabled because of a critical error

Additional information

The last error code of an file handle can be checked using FS_FError().

Configuration checking functions

The functions described in this section are useful to check at runtime how the file system has been configured at compile time.

FS_CONF_GetDebugLevel()

Description

Returns the level of debug information configured for the file system.

Prototype

int FS_CONF_GetDebugLevel(void);

Return value

Value of FS_DEBUG_LEVEL configuration define.

FS_CONF_GetDirectoryDelimiter()

Description

Returns the character that is configured as delimiter between the directory names in a file path.

Prototype

char FS_CONF_GetDirectoryDelimiter(void);

Return value

Value of FS_DIRECTORY_DELIMITER configuration define.

Example

#include <stdio.h>
#include "FS.h"

void SampleCONFGetDirectoryDelimiter(void) {
  char ac[100];
  char Delim;

  Delim = FS_CONF_GetDirectoryDelimiter();
  SEGGER_snprintf(ac, sizeof(ac), 
    "The '%c' character is used to delimit directory names in a path\n", Delim);
  FS_X_Log(ac);
}

FS_CONF_GetMaxPath()

Description

Returns the configured maximum number of characters in a path to a file or directory.

Prototype

int FS_CONF_GetMaxPath(void);

Return value

Value of FS_MAX_PATH configuration define.

Example

#include <stdio.h>
#include "FS.h"

void SampleCONFGetMaxPath(void) {
  char ac[100];
  int  NumChars;

  NumChars = FS_CONF_GetMaxPath();
  SEGGER_snprintf(ac, sizeof(ac), 
    "The maximum number of characters in the path is: %d\n", NumChars);
  FS_X_Log(ac);
}

FS_CONF_GetNumVolumes()

Description

Returns the maximum number of volumes configured for the file system.

Prototype

int FS_CONF_GetNumVolumes(void);

Return value

Returns the value of FS_NUM_VOLUMES configuration define.

Example

#include <stdio.h>
#include "FS.h"

void SampleCONFGetNumVolumes(void) {
  char ac[100];
  int  NumVolumes;

  NumVolumes = FS_CONF_GetNumVolumes();
  SEGGER_snprintf(ac, sizeof(ac), 
    "The maximum number of supported by Journal: %d\n", NumVolumes);
  FS_X_Log(ac);
}

FS_CONF_GetOSLocking()

Description

Returns the type of task locking configured for the file system.

Prototype

int FS_CONF_GetOSLocking(void);

Return value

Value of FS_OS_LOCKING configuration define.

Example

#include "FS.h"

void SampleCONFGetOSLocking(void) {
  int LockingType;

  LockingType = FS_CONF_GetOSLocking();
  switch (LockingType) {
  case FS_OS_LOCKING_NONE:
    FS_X_Log("The file system is not locked against concurrent access.\n");
    break;
  case FS_OS_LOCKING_API:
    FS_X_Log("The file system is locked at API function level.\n");
    break;
  case FS_OS_LOCKING_DRIVER:
    FS_X_Log("The file system is locked at device driver level.\n");
    break;
  default:
    FS_X_Log("The type of locking is unknown.\n");
    break;
  }
}

FS_CONF_IsCacheSupported()

Description

Checks if the file system is configured to support the sector cache.

Prototype

int FS_CONF_IsCacheSupported(void);

Return value

Value of FS_SUPPORT_CACHE configuration define.

Additional information

This function does not check if the sector cache is actually active. It only indicates if the file system has been compiled with support for sector cache. The sector cache has to be activated via FS_AssignCache().

Example

#include "FS.h"

void SampleCONFIsCacheSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsCacheSupported();
  if (IsSupported) {
    FS_X_Log("The sector cache is supported.\n");
  } else {
    FS_X_Log("The sector cache is not supported.\n");
  }
}

FS_CONF_IsDeInitSupported()

Description

Checks if the file system is configured to support deinitialization.

Prototype

int FS_CONF_IsDeInitSupported(void);

Return value

Value of FS_SUPPORT_DEINIT configuration define.

Example

#include "FS.h"

void SampleCONFIsDeInitSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsDeInitSupported();
  if (IsSupported) {
    FS_X_Log("File system deinitialization is supported.\n");
  } else {
    FS_X_Log("File system deinitialization is not supported.\n");
  }
}

FS_CONF_IsEFSSupported()

Description

Checks if the file system is configured to support the EFS file system.

Prototype

int FS_CONF_IsEFSSupported(void);

Return value

Value of FS_SUPPORT_EFS configuration define.

Example

#include "FS.h"

void SampleCONFIsEFSSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsEFSSupported();
  if (IsSupported) {
    FS_X_Log("The file system supports EFS.\n");
  } else {
    FS_X_Log("The file system does not support EFS.\n");
  }
}

FS_CONF_IsEncryptionSupported()

Description

Checks if the file system is configured to support encryption.

Prototype

int FS_CONF_IsEncryptionSupported(void);

Return value

Value of FS_SUPPORT_ENCRYPTION configuration define.

Example

#include "FS.h"

void SampleCONFIsEncryptionSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsEncryptionSupported();
  if (IsSupported) {
    FS_X_Log("The file system supports encryption.\n");
  } else {
    FS_X_Log("The file system does not support encryption.\n");
  }
}

FS_CONF_IsFATSupported()

Description

Checks if the file system is configured to support the FAT file system.

Prototype

int FS_CONF_IsFATSupported(void);

Return value

Value of FS_SUPPORT_FAT configuration define.

Example

#include "FS.h"

void SampleCONFIsFATSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsFATSupported();
  if (IsSupported) {
    FS_X_Log("The file system supports FAT.\n");
  } else {
    FS_X_Log("The file system does not support FAT.\n");
  }
}

FS_CONF_IsFreeSectorSupported()

Description

Checks if the file system is configured to support the “free sector” command.

Prototype

int FS_CONF_IsFreeSectorSupported(void);

Return value

Value of FS_SUPPORT_FREE_SECTOR configuration define.

Example

#include "FS.h"

void SampleCONFIsFreeSectorSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsFreeSectorSupported();
  if (IsSupported) {
    FS_X_Log("The file system supports \"free sector\" operation.\n");
  } else {
    FS_X_Log("The file system does not support \"free sector\" operation.\n");
  }
}

FS_CONF_IsJournalSupported()

Description

Checks if the file system is configured to support journaling.

Prototype

int FS_CONF_IsJournalSupported(void);

Return value

Value of FS_SUPPORT_JOURNAL configuration define.

Example

#include "FS.h"

void SampleCONFIsJournalSupported(void) {
  int IsSupported;

  IsSupported = FS_CONF_IsJournalSupported();
  if (IsSupported) {
    FS_X_Log("The file system supports journaling.\n");
  } else {
    FS_X_Log("The file system does not support journaling.\n");
  }
}

FS_CONF_IsTrialVersion()

Description

Checks if the file system has been configured as a trial (limited) version.

Prototype

int FS_CONF_IsTrialVersion(void);

Return value

= 0 Full version.
≠ 0 Trial version.

Example

#include "FS.h"

void SampleCONFIsTrialVersion(void) {
  int IsTrial;

  IsTrial = FS_CONF_IsTrialVersion();
  if (IsTrial) {
    FS_X_Log("This is a trial version of emFile.\n");
  } else {
    FS_X_Log("This is a full-featured version of emFile.\n");
  }
}

FS_GetVersion()

Description

Returns the version number of the file system.

Prototype

U32 FS_GetVersion(void);

Return value

Version number.

Additional information

The version is formatted as follows: Mmmrr

where:

For example 40201 represents the version 4.02a (major version: 4, minor version: 2, revision: a)

Example

#include <stdio.h>
#include "FS.h"

void SampleGetVersion(void) {
  int  Version;
  int  MajorVersion;
  int  MinorVersion;
  char PatchVersion;
  char ac[100];

  Version = FS_GetVersion();
  MajorVersion = Version / 10000;
  MinorVersion = Version / 100 % 100;
  PatchVersion = Version % 100;
  SEGGER_snprintf(ac, sizeof(ac), "This is the version %d.%d.%d of emFile.\n",
    MajorVersion, MinorVersion, PatchVersion);
  FS_X_Log(ac);
}

Path processing functions

This section described functions that can be used to manipulate a path to a file or directory.

FS_GetPathBaseName()

Description

Returns the name of the target file or directory with the extension removed.

Prototype

int FS_GetPathBaseName(const char     * sPath,
                             char     * pBaseName,
                             unsigned   SizeOfBaseName);

Parameters

Parameter Description
sPath  in  Path to the file or directory (0-terminated string). It cannot be set to NULL.
pBaseName  out  The basename of the file or directory as 0-terminated string. It can be set to NULL.
SizeOfBaseName Number of bytes in pBaseName. It can be set to 0.

Return value

> 0 Length of the basename in bytes.
< 0 An error occurred.

Additional information

The function returns the length of the basename excluding the 0-terminator irrespective of whether pBaseName is sufficiently large to store the basename or not. If pBaseName is not sufficiently large to store the basename including the 0-terminator, then the basename stored in pBaseName is truncated. The application can check for this condition by comparing the returned value with the value of SizeOfBaseName. If the returned value is greater than or equal to SizeOfBaseName, then the basename stored to pBaseName is truncated. In any of the above cases, the basename stored to pBaseName is 0-terminated.

The following tables show some usage examples.

Parameter Value
sPath “nor:1:/SubDir”
pBaseName “SubDir”
SizeOfBaseName ≥ 7
Result 6
Parameter Value
sPath “SubDir/File.txt”
pBaseName “File”
SizeOfBaseName ≥ 5
Result 4
Parameter Value
sPath “nand:0:/SubDir/File.txt”
pBaseName “File”
SizeOfBaseName ≥ 5
Result 4
Parameter Value
sPath “File.txt”
pBaseName “File”
SizeOfBaseName ≥ 5
Result 4
Parameter Value
sPath “ram:1:/SubDir/”
pBaseName “”
SizeOfBaseName ≥ 1
Result 0
Parameter Value
sPath “File.old.txt”
pBaseName “File.old”
SizeOfBaseName ≥ 9
Result 8
Parameter Value
sPath “File.txt”
pBaseName “Fi”
SizeOfBaseName = 3
Result 4

Example

#include "FS.h"

void SampleGetPathBaseName(void) {
  char acBaseName[32];

  FS_GetPathBaseName("nand:0:\\SubDir\\File.txt", acBaseName, sizeof(acBaseName));
}

FS_GetPathDirName()

Description

Returns the path to a target file or directory with the volume name, base name, and extension removed.

Prototype

int FS_GetPathDirName(const char     * sPath,
                            char     * pDirName,
                            unsigned   SizeOfDirName);

Parameters

Parameter Description
sPath  in  Path to the file or directory (0-terminated string). It cannot be set to NULL.
pDirName  out  The path to the file or directory as 0-terminated string. It can be set to NULL.
SizeOfDirName Number of bytes in pDirName. It can be set to 0.

Return value

> 0 Length of the directory name in bytes.
< 0 An error occurred.

Additional information

The function returns the length of the directory name excluding the 0-terminator irrespective of whether pDirName is sufficiently large to store the directory name or not. If pDirName is not sufficiently large to store the directory name including the 0-terminator, then the directory name stored in pDirName is truncated. The application can check for this condition by comparing the returned value with the value of SizeOfDirName. If the returned value is greater than or equal to SizeOfDirName, then the directory name stored to pDirName is truncated. In any of the above cases, the directory name stored to pDirName is 0-terminated.

The following tables show some usage examples.

Parameter Value
sPath “SubDir/File.txt”
pDirName “SubDir/”
SizeOfDirName ≥ 8
Result 7
Parameter Value
sPath “nand:0:/SubDir/File.txt”
pDirName “/SubDir/”
SizeOfDirName ≥ 9
Result 8
Parameter Value
sPath “File.txt”
pDirName “”
SizeOfDirName ≥ 1
Result 0
Parameter Value
sPath “ram:1:/SubDir/”
pDirName “/SubDir/”
SizeOfDirName ≥ 9
Result 8
Parameter Value
sPath “/SubDir1/SubDir2/SubDir3”
pDirName “/SubDir1/SubDir2/”
SizeOfDirName ≥ 18
Result 17
Parameter Value
sPath “nor:SubDir”
pDirName “/”
SizeOfDirName ≥ 2
Result 1
Parameter Value
sPath “ram:1:/SubDir/”
pDirName “/SubDi”
SizeOfDirName = 7
Result 7

Example

#include "FS.h"

void SampleGetPathDirName(void) {
  char acDirName[32];

  FS_GetPathDirName("ram:1:\\SubDir\\Test.txt", acDirName, sizeof(acDirName));
}

FS_GetPathExtension()

Description

Returns the extension of a file or directory.

Prototype

int FS_GetPathExtension(const char     * sPath,
                              char     * pExtension,
                              unsigned   SizeOfExtension);

Parameters

Parameter Description
sPath  in  Path to the file or directory (0-terminated string). It cannot be set to NULL.
pExtension  out  The extension of the file or directory as 0-terminated string. It can be set to NULL.
SizeOfExtension Number of bytes in pExtension. It can be set to 0.

Return value

> 0 Length of the extension in bytes.
< 0 An error occurred.

Additional information

The function returns the length of the extension excluding the 0-terminator irrespective of whether pExtension is sufficiently large to store the extension or not. If pExtension is not sufficiently large to store the extension including the 0-terminator, then the extension stored in pExtension is truncated. The application can check for this condition by comparing the returned value with the value of SizeOfExtension. If the returned value is greater than or equal to SizeOfExtension, then the extension stored to pExtension is truncated. In any of the above cases, the extension stored to pExtension is 0-terminated and contains the leading point.

The following tables show some usage examples.

Parameter Value
sPath “nor:1:/SubDir”
pExtension “”
SizeOfExtension ≥ 1
Result 0
Parameter Value
sPath “SubDir/File.txt”
pExtension “.txt”
SizeOfExtension ≥ 5
Result 4
Parameter Value
sPath “nand:0:/SubDir/File.txt”
pExtension “.txt”
SizeOfExtension ≥ 5
Result 4
Parameter Value
sPath “File.old.txt”
pExtension “.txt”
SizeOfExtension ≥ 4
Result 0
Parameter Value
sPath “ram:1:/SubDir/”
pExtension “”
SizeOfExtension ≥ 1
Result 0
Parameter Value
sPath “File”
pExtension “”
SizeOfExtension ≥ 1
Result 0
Parameter Value
sPath “.txt”
pExtension “.txt”
SizeOfExtension ≥ 5
Result 4
Parameter Value
sPath “File.txt”
pExtension “.tx”
SizeOfExtension = 3
Result 3

Example

#include "FS.h"

void SampleGetPathExtension(void) {
  char acExtension[32];

  FS_GetPathExtension("SubDir\\File.txt", acExtension, sizeof(acExtension));
}

FS_GetPathVolumeName()

Description

Returns the name of the volume from a path.

Prototype

int FS_GetPathVolumeName(const char     * sPath,
                               char     * pVolumeName,
                               unsigned   SizeOfVolumeName);

Parameters

Parameter Description
sPath  in  Path to the file or directory (0-terminated string). It cannot be set to NULL.
pVolumeName  out  The name of the volume as 0-terminated string. It can be set to NULL.
SizeOfVolumeName Number of bytes in pVolumeName. It can be set to 0.

Return value

> 0 Length of the volume name in bytes.
< 0 An error occurred.

Additional information

The function returns the length of the volume name excluding the 0-terminator irrespective of whether pVolumeName is sufficiently large to store the volume name or not. If pVolumeName is not sufficiently large to store the volume name including the 0-terminator, then the volume name stored in pVolumeName is truncated. The application can check for this condition by comparing the returned value with the value of SizeOfVolumeName. If the returned value is greater than or equal to SizeOfVolumeName, then the volume name stored to pVolumeName is truncated. In any of the above cases, the volume name stored to pVolumeName is 0-terminated.

The following tables show some usage examples.

Parameter Value
sPath “nor:1:/SubDir”
pVolumeName “nor:1:”
SizeOfVolumeName ≥ 7
Result 6
Parameter Value
sPath “nand:0:/File.txt”
pVolumeName “nand:”
SizeOfVolumeName ≥ 6
Result 5
Parameter Value
sPath “SubDir/File.txt”
pVolumeName “”
SizeOfVolumeName ≥ 1
Result 0
Parameter Value
sPath “SubDir”
pVolumeName “”
SizeOfVolumeName ≥ 1
Result 0
Parameter Value
sPath “”
pVolumeName “”
SizeOfVolumeName ≥ 1
Result 0
Parameter Value
sPath “ram:0:”
pVolumeName “ram:0:”
SizeOfVolumeName ≥ 7
Result 6
Parameter Value
sPath “mmc:0”
pVolumeName “mmc:”
SizeOfVolumeName ≥ 5
Result 5
Parameter Value
sPath “/SubDir1/SubDir2/SubDir3”
pVolumeName “/SubDir1/SubDir2/”
SizeOfVolumeName ≥ 18
Result 17
Parameter Value
sPath “nor:SubDir”
pVolumeName “no”
SizeOfVolumeName = 3
Result 3

Example

#include "FS.h"

void SampleGetPathVolumeName(void) {
  char acVolumeName[32];

  FS_GetPathVolumeName("ram:1:\\Test.txt", acVolumeName, sizeof(acVolumeName));
}

FS_MakePath()

Description

Creates a path to a file or directory from individual components.

Prototype

int FS_MakePath(      char     * pPath,
                      unsigned   SizeOfPath,
                const char     * sVolumeName,
                const char     * sDirName,
                const char     * sBaseName,
                const char     * sExtension);

Parameters

Parameter Description
pPath  out  Created path (0-terminated string). It can be set to NULL.
SizeOfPath Number of bytes in pPath. It can be set to 0.
sVolumeName  in  Volume name (0-terminated string) It can be set to NULL.
sDirName  in  Directory name (0-terminated string) It can be set to NULL.
sBaseName  in  Basename of file or directory (0-terminated string) It can be set to NULL.
sExtension  in  Extension of file or directory (0-terminated string) It can be set to NULL.

Return value

> 0 Length of the path in bytes.
< 0 An error occurred.

Additional information

This function returns the length of the path excluding the 0-terminator irrespective of whether pPath is sufficiently large to store the path or not. If pPath is not sufficiently large to store the path including the 0-terminator, then the path stored in pPath is truncated. The application can check for this condition by comparing the returned value with the value of SizeOfPath. If the returned value is greater than or equal to SizeOfPath, then the path stored to pPath is truncated. In any of the above cases, the path stored to pPath is 0-terminated.

FS_MakePath() adds missing volume, directory and extension delimiters.

The following tables show some usage examples.

Parameter Value
sVolumeName “nor:0:”
sDirName “/SubDir/”
sBaseName “File”
sExtension “.txt”
pPath “nor:0:/SubDir/File.txt”
SizeOfPath ≥ 23
Result 22
Parameter Value
sVolumeName “nand:0:”
sDirName “SubDir”
sBaseName NULL
sExtension NULL
pPath “nand:0:/SubDir/”
SizeOfPath ≥ 16
Result 15
Parameter Value
sVolumeName NULL
sDirName “SubDir”
sBaseName NULL
sExtension NULL
pPath “SubDir/”
SizeOfPath ≥ 8
Result 7
Parameter Value
sVolumeName NULL
sDirName “/SubDir”
sBaseName “File”
sExtension “.txt”
pPath “/SubDir/File.txt”
SizeOfPath ≥ 17
Result 16
Parameter Value
sVolumeName NULL
sDirName “/SubDir1/SubDir2”
sBaseName “SubDir3”
sExtension NULL
pPath “/SubDir1/SubDir2/SubDir3”
SizeOfPath ≥ 25
Result 24
Parameter Value
sVolumeName NULL
sDirName NULL
sBaseName “File.old”
sExtension “txt”
pPath “File.old.txt”
SizeOfPath ≥ 13
Result 12
Parameter Value
sVolumeName “ram”
sDirName NULL
sBaseName “File”
sExtension “.txt”
pPath “ram:/File.txt”
SizeOfPath ≥ 14
Result 13
Parameter Value
sVolumeName “ram”
sDirName NULL
sBaseName “File”
sExtension “.txt”
pPath “ram:/File.tx”
SizeOfPath = 13
Result 13

Example

#include "FS.h"

void SampleMakePath(void) {
  char acPath[FS_MAX_PATH];

  FS_MakePath(acPath, sizeof(acPath), "nor:0:", "\\SubDir\\",  "File", ".txt");
}

Obsolete functions

This section describes API functions that should no longer be used in new applications. These functions will be removed in a future version of emFile.

FS_AddOnExitHandler()

Description

Registers a deinitialization callback.

Prototype

void FS_AddOnExitHandler(FS_ON_EXIT_CB * pCB,
                         void            ( *pfOnExit)());

Parameters

Parameter Description
pCB  in  Structure holding the callback information.
pfOnExit Pointer to the callback function to be invoked.

Additional information

The pCB memory location is used internally by the file system and it should remain valid from the time the handler is registered until the FS_DeInit() function is called. The FS_DeInit() function invokes all the registered callback functions in reversed order that is the last registered function is called first. In order to use this function the binary compile time switch FS_SUPPORT_DEINIT has to be set to 1.

FS_CloseDir()

Description

Closes a directory.

Prototype

int FS_CloseDir(FS_DIR * pDir);

Parameters

Parameter Description
pDir Handle to an opened directory.

Return value

= 0 Directory has been closed.
≠ 0 An error occurred.

FS_ConfigOnWriteDirUpdate()

Description

Configures if the directory entry has be updated after writing to file.

Prototype

void FS_ConfigOnWriteDirUpdate(char OnOff);

Parameters

Parameter Description
OnOff Specifies if the feature has to be enabled or disabled. 1 Enable update directory after write. 0 Do not update directory. FS_FClose() updates the directory entry.

FS_DirEnt2Attr()

Description

Loads attributes of a directory entry.

Prototype

void FS_DirEnt2Attr(FS_DIRENT * pDirEnt,
                    U8        * pAttr);

Parameters

Parameter Description
pDirEnt  in  Data of directory entry.
pAttr  out  Pointer to a memory location that receives the attributes.

FS_DirEnt2Name()

Description

Loads the name of a directory entry.

Prototype

void FS_DirEnt2Name(FS_DIRENT * pDirEnt,
                    char      * pBuffer);

Parameters

Parameter Description
pDirEnt  in  Data of directory entry.
pBuffer  out  Pointer to a memory location that receives the name.

FS_DirEnt2Size()

Description

Loads the size of a directory entry.

Prototype

U32 FS_DirEnt2Size(FS_DIRENT * pDirEnt);

Parameters

Parameter Description
pDirEnt  in  Data of directory entry.

Return value

Size of the file or directory.

FS_DirEnt2Time()

Description

Loads the time stamp of a directory entry.

Prototype

U32 FS_DirEnt2Time(FS_DIRENT * pDirEnt);

Parameters

Parameter Description
pDirEnt  in  Data of directory entry.

Return value

Time stamp of the file or directory.

FS_GetNumFiles()

Description

API function. Returns the number of files in a directory.

Prototype

U32 FS_GetNumFiles(FS_DIR * pDir);

Parameters

Parameter Description
pDir Pointer to an opened directory handle.

Return value

0xFFFFFFFF Indicates failure. 0 - 0xFFFFFFFE File size of the given file.

FS_OpenDir()

Description

API function. Open an existing directory for reading.

Prototype

FS_DIR *FS_OpenDir(const char * sDirName);

Parameters

Parameter Description
sDirName Fully qualified directory name.

Return value

= 0 Unable to open the directory.
≠ 0 Address of an FS_DIR data structure.

FS_ReadDir()

Description

Reads next directory entry in directory.

Prototype

FS_DIRENT *FS_ReadDir(FS_DIR * pDir);

Parameters

Parameter Description
pDir Handle to an opened directory.

Return value

≠ 0 Pointer to a directory entry.
= 0 No more directory entries or error.

FS_RewindDir()

Description

Sets pointer for reading the next directory entry to the first entry in the directory.

Prototype

void FS_RewindDir(FS_DIR * pDir);

Parameters

Parameter Description
pDir Handle to an opened directory.

Caching and buffering

This chapter gives an introduction into cache handling of emFile. Furthermore, it contains the function description and an example.

Sector cache

The sector cache is a memory area where frequently used sector data can be stored for fast access. In many cases, this can enhance the average access time thus increasing the performance. With applications which do not use a cache, data will always be read from the storage medium even if it has been used before. The sector cache stores accessed and processed sector data. If the sector data has to be processed again, it will be copied out of the cache instead of reading it from the storage device. This condition is called “hit”. When the sector data is not present in the sector cache and it has to be read from the storage device. This condition is called “miss”. The sector cache works efficiently when the number of hit conditions is greater than the number of miss conditions. The number of hit and miss conditions can be queried using the FS_STORAGE_GetCounters() function.

Write cache and journaling

The write back caching has to be disabled if the journaling is employed to make the file system fail safe. The journaling will not work properly if the write back cache (and generally any form of write cache) is enabled. More detailed information can be found in the section Journaling and write caching.

Types of caches

emFile supports the usage of different cache modules as listed in the following table:

Cache module Description
FS_CACHE_ALL A pure read cache.
FS_CACHE_MAN A pure read cache that caches only the management sectors.
FS_CACHE_RW A read / write cache module.
FS_CACHE_RW_QUOTA A read / write cache module with configurable capacity per sector type.
FS_CACHE_MULTI_WAY A read / write cache module with configurable associativity level.
FS_CACHE_ALL

This module is a pure read cache. All sectors that are read from a volume are cached. The caching is enabled right after calling FS_AssignCache().

FS_CACHE_MAN

This module is also a pure read cache. In contrast to the FS_CACHE_ALL, this module only caches the management sectors of the file system (for example, the sectors of the allocation table). The caching is enabled right after calling FS_AssignCache(). This type of cache is useful if the application is creating and deleting a large number of files.

FS_CACHE_RW

This is a configurable cache module. It can be either used as read, write or as read / write cache. Additionally, the type of sectors that has to be cached are also configurable via FS_CACHE_SetMode().

FS_CACHE_RW_QUOTA

This is a configurable cache module. It can be either used as read, write or as read / write cache. Additionally, the type of sectors and the maximum number of sectors of a given type that can be cached at the same time are configurable via FS_CACHE_SetMode() and FS_CACHE_SetQuota() respectively. It is mandatory to call FS_CACHE_SetMode() and FS_CACHE_SetQuota(), otherwise the functionality of the cache module is disabled.

FS_CACHE_MULTI_WAY

This is configurable cache module that can be used as read, write or read / write cache. The type of sectors that should be cached and the number of places in the cache where the data of a sector can be mapped (associativity level) is configurable via FS_CACHE_SetMode() and FS_CACHE_SetQuota() respectively. Per default, this cache works with an associativity level of two.

Cache API functions

The following functions can be used to enable, configure and control the emFile sector cache modules.

Function Description
FS_AssignCache() Enables or disables a sector cache for a specific volume.
FS_CACHE_Clean() Writes modified sector data to storage device.
FS_CACHE_GetNumSectors() Obtains the size of the sector cache.
FS_CACHE_GetType() Obtains the type of the configured sector cache.
FS_CACHE_Invalidate() Removes all sector data from cache.
FS_CACHE_SetAssocLevel() Modifies the associativity level of multi-way cache.
FS_CACHE_SetMode() Sets the operating mode of sector cache.
FS_CACHE_SetQuota() Sets the quotas of a specific sector cache.
FS_AssignCache()

Description

Enables or disables a sector cache for a specific volume.

Prototype

U32 FS_AssignCache(const char          * sVolumeName,
                         void          * pData,
                         I32             NumBytes,
                         FS_CACHE_TYPE   Type);

Parameters

Parameter Description
sVolumeName Name of the volume on which the sector cache should be enabled / disabled. Cannot be NULL.
pData Pointer to a memory area that should be used as cache.
NumBytes Number of bytes in the memory area pointed by pData.
Type Specifies the type of the sector cache to be configured. It can take one of the following values: FS_CACHE_ALL FS_CACHE_MAN FS_CACHE_RW FS_CACHE_RW_QUOTA FS_CACHE_MULTI_WAY.

Return value

> 0 OK, Number of sectors which fit in cache.
= 0 An error occurred. The memory area cannot be used as sector cache.

Additional information

The first configured volume is used if the empty string is specified as sVolumeName.

To disable the cache for a specific device, call FS_AssignCache() with NumBytes set to 0. In this case the function returns 0.

A range of the memory block assigned to the sector cache is used to store the management data. The following defines can help an application allocate a memory block sufficiently large to store a specified number of logical sectors: FS_SIZEOF_CACHE_ALL(), FS_SIZEOF_CACHE_MAN(), FS_SIZEOF_CACHE_RW(), FS_SIZEOF_CACHE_RW_QUOTA(), or FS_SIZEOF_CACHE_MULTI_WAY().

Example

The following example demonstrates how to enable and then disable a sector cache of type FS_CACHE_ALL.

#include "FS.h"

#define CACHE_SIZE FS_SIZEOF_CACHE_ALL(200, 512) // 200 sectors of 512 bytes.

static U32 _aCache[CACHE_SIZE / 4]; // Allocate RAM for the cache buffer.

void SampleCacheAssign(void) {
  //
  // Assign a read cache to the first configured storage device.
  //
  FS_AssignCache("", _aCache, sizeof(_aCache), FS_CACHE_ALL);

  //
  // Access the file system with sector cache.
  //

  //
  // Disable the read cache.
  //
  FS_AssignCache("", 0, 0, 0);
}
FS_CACHE_Clean()

Description

Writes modified sector data to storage device.

Prototype

int FS_CACHE_Clean(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.

Return value

= 0 OK, the sector cache was emptied successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function can be used to make sure that modifications made to cached data are also committed to storage device.

Because only write or read / write caches need to be cleaned, this function can only be called for volumes where FS_CACHE_RW, FS_CACHE_RW_QUOTA, or FS_CACHE_MULTI_WAY module is assigned. The other cache modules ignore the cache clean operation.

The cleaning of the cache is also performed when the volume is unmounted via FS_Unmount() or when the cache is disabled or reassigned via FS_AssignCache().

Example

#include "FS.h"

void SampleCacheClean(void) {
  FS_CACHE_Clean("");
}
FS_CACHE_GetNumSectors()

Description

Obtains the size of the sector cache.

Prototype

int FS_CACHE_GetNumSectors(const char * sVolumeName,
                                 U32  * pNumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
pNumSectors  out  Number of sectors that can be stored in the cache at the same time. It cannot be NULL.

Return value

= 0 OK, number of sectors in the sector cache.
≠ 0 An error occurred.

Additional information

This function returns the number of sectors that can be stored in the cache at the same time.

Example

#include "FS.h"
#include <stdio.h>

void SampleCacheGetNumSectors(void) {
  U32  NumSectors;
  char ac[100];

  FS_CACHE_GetNumSectors("", &NumSectors);
  SEGGER_snprintf(ac, sizeof(ac), "Number of sectors in cache: %lu\n", NumSectors);
  FS_X_Log(ac);
}
FS_CACHE_GetType()

Description

Obtains the type of the configured sector cache.

Prototype

int FS_CACHE_GetType(const char          * sVolumeName,
                           FS_CACHE_TYPE * pType);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
pType  out  Cache sector type. FS_CACHE_NONE No sector cache configured. FS_CACHE_ALL A pure read cache. FS_CACHE_MAN A pure read cache that caches only the management sectors. FS_CACHE_RW A read / write cache module. FS_CACHE_RW_QUOTA A read / write cache module with configurable capacity per sector type. FS_CACHE_MULTI_WAY A read / write cache module with configurable associativity level.

Return value

= 0 OK, type of sector cache returned.
≠ 0 Error code indicating the failure reason.
FS_CACHE_Invalidate()

Description

Removes all sector data from cache.

Prototype

int FS_CACHE_Invalidate(const char * sVolumeName);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.

Return value

= 0 OK, the sector cache was emptied successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function can be called to remove all the sectors from the cache. FS_CACHE_Invalidate() does not write to storage modified sector data. After calling FS_CACHE_Invalidate() the contents of modified sector data is lost. FS_CACHE_Clean() has to be called first to prevent a data loss.

Example

#include "FS.h"

void SampleCacheInvalidate(void) {
  FS_CACHE_Invalidate("");
}
FS_CACHE_SetAssocLevel()

Description

Modifies the associativity level of multi-way cache.

Prototype

int FS_CACHE_SetAssocLevel(const char * sVolumeName,
                                 int    AssocLevel);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
AssocLevel Number of entries in the cache. It has to be a power of two value.

Return value

= 0 OK, associativity level set successfully.
≠ 0 Error code indicating the failure reason error occurred.

Additional information

This function is supported only by the FS_CACHE_MULTI_WAY cache module. An error is returned if the function is used with any other cache module.

The associativity level specifies on how many different places in the cache the data of the same sector can be stored. The cache replacement policy uses this information to decide where to store the contents of a sector in the cache. Caches with higher associativity levels tend to have higher hit rates. The default associativity level is two.

Example

The following example shows how to configure the FS_CACHE_MULTI_WAY cache module to store the data of the same sector at 4 different places on the cache.

#include "FS.h"

void SampleCacheSetAssocLevel(void) {
  FS_CACHE_SetAssocLevel("", 4);
}
FS_CACHE_SetMode()

Description

Sets the operating mode of sector cache.

Prototype

int FS_CACHE_SetMode(const char * sVolumeName,
                           int    TypeMask,
                           int    ModeMask);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
TypeMask Specifies the types of the sectors that have to be cached. This parameter can be an OR-combination of the Sector type masks (FS_SECTOR_TYPE_MASK_…)
ModeMask Specifies the operating mode of the cache module. This parameter can be one of the values defined as Sector cache modes (FS_CACHE_MODE_…)

Return value

= 0 OK, mode set successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function is supported by the following cache types: FS_CACHE_RW, FS_CACHE_RW_QUOTA, and FS_CACHE_MULTI_WAY. These cache modules have to be configured using this function otherwise, neither read nor write operations are cached.

When configured in FS_CACHE_MODE_WB mode the cache module writes the sector data automatically to storage device if free space is required for new sector data. The application can call the FS_CACHE_Clean() function at any time to write all the cache sector data to storage device.

Example

The following example shows how to configure the FS_CACHE_MULTI_WAY cache module to use a read cache for the data sectors, a write back cache for the management and directory sectors.

#include "FS.h"

#define CACHE_SIZE FS_SIZEOF_CACHE_MULTI_WAY(200, 512)

static U32 _aCache[CACHE_SIZE / 4];  // Allocate RAM for the cache buffer.

void SampleCacheSetMode(void) {
  //
  // Assign a cache to the first available storage device.
  //
  FS_AssignCache("", _aCache, sizeof(_aCache), FS_CACHE_MULTI_WAY);
  //
  // Configure a read cache for the sectors that store file data.
  //
  FS_CACHE_SetMode("", FS_SECTOR_TYPE_MASK_DATA, FS_CACHE_MODE_R);
  //
  // Configure a write back cache for the sectors that store directory
  // and allocation table entries.
  //
  FS_CACHE_SetMode("",
                   FS_SECTOR_TYPE_MASK_DIR | FS_SECTOR_TYPE_MASK_MAN,
                   FS_CACHE_MODE_WB);
  //
  // Access the file system with sector cache.
  //

  //
  // Disable the cache.
  //
  FS_AssignCache("", 0, 0, FS_CACHE_NONE);
}
FS_CACHE_SetQuota()

Description

Sets the quotas of a specific sector cache.

Prototype

int FS_CACHE_SetQuota(const char * sVolumeName,
                            int    TypeMask,
                            U32    NumSectors);

Parameters

Parameter Description
sVolumeName Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
TypeMask Specifies the types of the sectors that have to be cached. This parameter can be an OR-combination of the Sector type masks (FS_SECTOR_TYPE_MASK_…)
NumSectors Specifies the maximum number of sectors to be stored for each sector type specified in TypeMask.

Return value

= 0 OK, maximum number of sectors set successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function is currently only usable with the FS_CACHE_RW_QUOTA cache module. After the FS_CACHE_RW_QUOTA cache module has been assigned to a volume and the cache mode has been set, the quotas for the different sector types have to be configured using this function. Otherwise, neither read nor write operations are cached.

Example

The following example shows how to configure the FS_CACHE_RW_QUOTA cache module to limit the number of directory and data sector types to a maximum of 10 each.

#include "FS.h"

#define CACHE_SIZE   FS_SIZEOF_CACHE_RW_QUOTA(200, 512)

static U32 _acCache[CACHE_SIZE / 4];  // Allocate RAM for the cache buffer.

void SampleCacheSetQuota(void) {
  //
  // Assign a cache to the first available storage device.
  //
  FS_AssignCache("", _acCache, sizeof(_acCache), FS_CACHE_RW_QUOTA);
  //
  // Configure the cache module to cache all sectors. The sector data is cached
  // for read and write. Write operation to storage device are delayed.
  //
  FS_CACHE_SetMode("", FS_SECTOR_TYPE_MASK_ALL, FS_CACHE_MODE_WB);
  //
  // Set the maximum number of sectors to cache for directory
  // and data sector types 10 sectors each.
  //
  FS_CACHE_SetQuota("", FS_SECTOR_TYPE_MASK_DATA | FS_SECTOR_TYPE_MASK_DIR, 10);

  //
  // Access the file system with sector cache.
  //

  //
  // Make sure that the data is written to storage device.
  //
  FS_CACHE_Clean("");

  //
  // Perform other accesses to file system with sector cache.
  //

  //
  // Disable the cache.
  //
  FS_AssignCache("", 0, 0, FS_CACHE_NONE);
}
Sector cache types

Description

Types of sector caches.

Definition

#define FS_CACHE_NONE         NULL
#define FS_CACHE_ALL          FS_CacheAll_Init
#define FS_CACHE_MAN          FS_CacheMan_Init
#define FS_CACHE_RW           FS_CacheRW_Init
#define FS_CACHE_RW_QUOTA     FS_CacheRWQuota_Init
#define FS_CACHE_MULTI_WAY    FS_CacheMultiWay_Init

Symbols

Definition Description
FS_CACHE_NONE Pseudo-type that can be used to disable the sector cache.
FS_CACHE_ALL A pure read cache.
FS_CACHE_MAN A pure read cache that caches only the management sectors.
FS_CACHE_RW A read / write cache module.
FS_CACHE_RW_QUOTA A read / write cache module with configurable capacity per sector type.
FS_CACHE_MULTI_WAY A read / write cache module with configurable associativity level.

Additional information

The type of a cache module can be configured via FS_AssignCache() function when the sector cache is enabled for a specified volume.

Sector cache modes

Description

Operating modes of sector caches.

Definition

#define FS_CACHE_MODE_R     0x01u
#define FS_CACHE_MODE_WT    (FS_CACHE_MODE_R | FS_CACHE_MODE_W)
#define FS_CACHE_MODE_WB    (FS_CACHE_MODE_R | FS_CACHE_MODE_W | FS_CACHE_MODE_D)

Symbols

Definition Description
FS_CACHE_MODE_R Pure read cache.
FS_CACHE_MODE_WT Write-through cache.
FS_CACHE_MODE_WB Write-back cache.

Additional information

The operating mode of a cache module can be configured via the FS_CACHE_SetMode() function separately for each sector type.

Sector cache size

Description

Calculates the cache size.

Definition

#define FS_SIZEOF_CACHE_ALL(NumSectors,          SectorSize)         (FS_SIZEOF_CACHE_ALL_DATA +               \
   (FS_SIZEOF_CACHE_ALL_BLOCK_INFO +       \
   (SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_MAN(NumSectors,          SectorSize)         (FS_SIZEOF_CACHE_MAN_DATA +               \
   (FS_SIZEOF_CACHE_MAN_BLOCK_INFO +       \
   (SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_RW(NumSectors,           SectorSize)          (FS_SIZEOF_CACHE_RW_DATA +                \
   (FS_SIZEOF_CACHE_RW_BLOCK_INFO +        \
   (SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_RW_QUOTA(NumSectors,     SectorSize)    (FS_SIZEOF_CACHE_RW_QUOTA_DATA +          \
   (FS_SIZEOF_CACHE_RW_QUOTA_BLOCK_INFO +  \
   (SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_MULTI_WAY(NumSectors,    SectorSize)   (FS_SIZEOF_CACHE_MULTI_WAY_DATA +         \
   (FS_SIZEOF_CACHE_MULTI_WAY_BLOCK_INFO + \
   (SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_ANY(NumSectors,          SectorSize)         FS_SIZEOF_CACHE_RW_QUOTA(NumSectors, SectorSize)

Symbols

Definition Description
FS_SIZEOF_CACHE_ALL(NumSectors, Calculates the cache size of a FS_CACHE_ALL cache module.
FS_SIZEOF_CACHE_MAN(NumSectors, Calculates the cache size of a FS_CACHE_MAN cache module.
FS_SIZEOF_CACHE_RW(NumSectors, Calculates the cache size of a FS_CACHE_RW cache module.
FS_SIZEOF_CACHE_RW_QUOTA(NumSectors, Calculates the cache size of a FS_CACHE_RW_QUOTA cache module.
FS_SIZEOF_CACHE_MULTI_WAY(NumSectors, Calculates the cache size of a FS_CACHE_MULTI_WAY cache module.
FS_SIZEOF_CACHE_ANY(NumSectors, Calculates the size of cache that works with any cache module.

Additional information

These defines can be used to calculate the size of the memory area to be assigned to a cache module based on the size of a sector (SectorSize) and the number of sectors to be cached (NumSectors). The sector size of a specific volume can be queried via FS_GetVolumeInfo().

Sector data flags

Description

Type of data stored in a logical sector.

Definition

#define FS_SECTOR_TYPE_MASK_DATA    (1u << FS_SECTOR_TYPE_DATA)
#define FS_SECTOR_TYPE_MASK_DIR     (1u << FS_SECTOR_TYPE_DIR)
#define FS_SECTOR_TYPE_MASK_MAN     (1u << FS_SECTOR_TYPE_MAN)
#define FS_SECTOR_TYPE_MASK_ALL     (FS_SECTOR_TYPE_MASK_DATA | \
   FS_SECTOR_TYPE_MASK_DIR  | \
   FS_SECTOR_TYPE_MASK_MAN)
#define FS_SECTOR_TYPE_COUNT        3u

Symbols

Definition Description
FS_SECTOR_TYPE_MASK_DATA Sector that stores file data.
FS_SECTOR_TYPE_MASK_DIR Sector that stores directory entries.
FS_SECTOR_TYPE_MASK_MAN Sector that stores entries of the allocation table.
FS_SECTOR_TYPE_MASK_ALL All sector types.
FS_SECTOR_TYPE_COUNT Number of sector types (for internal use only)

Additional information

These flags are typically used with the sector cache API functions to specify the type of sector data for which a specified parameter applies. The bit positions of the flags correspond to the values defined via Sector data type

Performance and resource usage

Performance

The listed performance values depend on the compiler options, the compiler version, the used CPU, the storage medium and the defined cache size. The performance values have been measured on a SEGGER emPower evaluation board https://www.segger.com/evaluate-our-software/segger/empower/ using an SD card as storage device. The test application has been compiled using SEGGER Embedded Studio IDE https://www.segger.com/products/development-tools/embedded-studio/ but any other IDE can be used as well. The test application is provided in source code and is located in the Application folder of the emFile shipment.

Description of the test

Terminal output

Start
High-level formatting
Cache disabled
Creation of 50 files took: 16 ms
Cache enabled
Creation of 50 files took: 2 ms
Cache flush took: 0 ms
Cache disabled
Creation of 50 files took: 57 ms
Finished

Source code

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : FS_SectorCache.c
Purpose : Demonstrates how to configure and use the sector cache.

Additional information:
  Preparations:
    Works out-of-the-box with any storage device.

  Expected behavior:
    Measures the time it takes to create a number of files with
    and without the sector cache enabled. The results are output
    on the debug console.

  Sample output:
    Start
    Cache disabled
    Creation of 50 files took: 60 ms
    Cache enabled
    Creation of 50 files took: 18 ms
    Cache flush took: 0 ms
    Cache disabled
    Creation of 50 files took: 114 ms
    Finished
*/

/*********************************************************************
*
*       #include Section
*
**********************************************************************
*/
#include <string.h>
#include "FS.h"
#include "FS_OS.h"
#include "SEGGER.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define VOLUME_NAME   ""
#define NUM_FILES     32

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static U32  _aCache[0x400];
static char _aacFileName[NUM_FILES][13];
static char _ac[128];

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _CreateFiles
*/
static void _CreateFiles(void) {
  int       i;
  U32       Time;
  FS_FILE * apFile[NUM_FILES];

  Time = FS_X_OS_GetTime();
  for (i = 0; i < NUM_FILES; i++) {
    apFile[i] = FS_FOpen(&_aacFileName[i][0], "w");
#if ((FS_SUPPORT_FILE_BUFFER != 0) && (FS_SUPPORT_FILE_BUFFER_LIST != 0))
    //
    // A file buffer is not required for this test.
    //
    if (apFile[i] != NULL) {
      if (FS_IsFileBufferSet(apFile[i]) != 0) {
        (void)FS_UnsetFileBuffer(apFile[i]);
      }
    }
#endif // ((FS_SUPPORT_FILE_BUFFER != 0) && (FS_SUPPORT_FILE_BUFFER_LIST != 0))
  }
  Time = FS_X_OS_GetTime() - Time;
  SEGGER_snprintf(_ac, (int)sizeof(_ac), "Creation of %d files took: %d ms\n", NUM_FILES, Time);
  FS_X_Log(_ac);
  for (i = 0; i < NUM_FILES; i++) {
    (void)FS_FClose(apFile[i]);
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       MainTask
*/
#ifdef __cplusplus
extern "C" {     /* Make sure we have C-declarations in C++ programs */
#endif
void MainTask(void);
#ifdef __cplusplus
}
#endif
void MainTask(void) {
  int i;
  U32 Time;

  FS_X_Log("Start\n");
  //
  // Initialize file system
  //
  FS_Init();
  //
  // Check if low-level format is required
  //
  (void)FS_FormatLLIfRequired(VOLUME_NAME);
  //
  // Check if volume needs to be high level formatted.
  //
  if (FS_IsHLFormatted(VOLUME_NAME) == 0) {
    FS_X_Log("High-level formatting\n");
    (void)FS_Format(VOLUME_NAME, NULL);
  }
  //
  // Prepare file names in advance.
  //
  for (i = 0; i < NUM_FILES; i++) {
    SEGGER_snprintf(_aacFileName[i], (int)sizeof(_aacFileName[0]), "file%.2d.txt", i);
  }
  //
  // Create and measure the time used to create the files with the cache enabled.
  //
  FS_X_Log("Cache disabled\n");
  _CreateFiles();
  //
  // Create and measure the time used to create the files.
  //
  (void)FS_AssignCache(VOLUME_NAME, _aCache, (int)sizeof(_aCache), FS_CACHE_RW);
  (void)FS_CACHE_SetMode(VOLUME_NAME, (int)FS_SECTOR_TYPE_MASK_ALL, (int)FS_CACHE_MODE_WB);
  FS_X_Log("Cache enabled\n");
  _CreateFiles();
  Time = FS_X_OS_GetTime();
  (void)FS_CACHE_Clean(VOLUME_NAME);
  Time = FS_X_OS_GetTime() - Time;
  SEGGER_snprintf(_ac, (int)sizeof(_ac), "Cache flush took: %d ms\n", Time);
  FS_X_Log(_ac);
  //
  // Create and measure the time used to create the files with the cache disabled.
  //
  FS_X_Log("Cache disabled\n");
  (void)FS_AssignCache(VOLUME_NAME, NULL, 0, FS_CACHE_NONE);
  _CreateFiles();
  FS_X_Log("Finished\n");
  for(;;) {
    ;
  }
}

/*************************** End of file ****************************/

File buffer

emFile comes with support for file buffer. A file buffer is a small memory area assigned to an opened file where the file system can store frequently accessed file data. Using a file buffer can greatly increase the performance especially when the application has to access small amounts of data.

The file buffer can be configured in different access modes. In read mode, that is only the data that is read by the application from the file is stored to file buffer or in read / write mode where the data read as well as the data written by the application is stored to file buffer. The access modes can be changed at runtime each time the file is opened via FS_SetFileBufferFlags() or FS_SetFileBuffer().

The size of the file buffer is configurable either globally for all opened files via FS_ConfigFileBufferDefault() or individually for each opened file via FS_SetFileBuffer().

Device drivers

This chapter describes the file system components that provide access to a storage device.

General information

emFile has been designed to operate with any kind of storage device. To use a specific type of storage device with emFile, a device driver for that specific storage device is required. A device driver is a file system component that provides block access to a storage device. The device driver consists of basic I/O functions for accessing the storage device and a global table that holds pointers to these functions.

The following table lists the device drivers available in emFile. The two-letter combination “RO” in the driver identifier indicates that the driver is not able to perform any write operations.

Driver name Acronym Identifier Volume name
File Disk driver FILEDISK FS_FILEDISK_Driver “file:”
CompactFlash card and IDE driver IDE FS_IDE_Driver “ide:”
SPI MMC/SD driver MMC_SPI FS_MMC_SPI_Driver “mmc:”
Card Mode MMC/SD driver MMC_CM FS_MMC_CM_Driver “mmc:”
Card Mode MMC/SD driver MMC_CM_RO FS_MMC_CM_RO_Driver “mmc:”
SLC1 NAND driver NAND FS_NAND_Driver “nand:”
Universal NAND driver NAND_UNI FS_NAND_UNI_Driver “nand:”
Universal NAND driver NAND_UNI_RO FS_NAND_UNI_RO_Driver “nand:”
Sector Map NOR driver NOR FS_NOR_Driver “nor:”
Block Map NOR driver NOR_BM FS_NOR_BM_Driver “nor:”
Block Map NOR driver NOR_BM_RO FS_NOR_BM_RO_Driver “nor:”
System RAM Disk driver RAMDISK FS_RAMDISK_Driver “ram:”
Universal RAM Disk driver RAMDISK_UNI FS_RAMDISK_UNI_Driver “ram:”
Windows Drive driver WINDRIVE FS_WINDRIVE_Driver “win:”
Windows Drive driver WINDRIVE_RO FS_WINDRIVE_RO_Driver “win:”

By default, the file system is not configured to access any particular storage device. A device driver has to be added by the application by calling FS_AddDevice() in FS_X_AddDevices(). The file system calls FS_X_AddDevices() during the initialization to allow the application to configure the file system. FS_AddDevice() takes as parameter a pointer to a the function table of the particular device driver as specified in the “Identifier” column in the table above. It is possible to add more than one device driver to the file system if more than one storage device is present in the system or if the system uses one storage device that is partitioned.

The file system assigns a volume to each device driver added by the application. A volume is an internal structure that contains information about organization of the storage device and how to access it. The application uses the volume name as specified in the “Volume name” column in the table above to select a particular storage device. The names of the volumes are fixed and cannot be changed by the application.

If the same device driver is added to file system more than once, an unit number is used to differentiate between them. The unit number is an optional part of the volume name and it can be used by the application to access a specific storage device. Most device driver functions as well as most of the underlying hardware functions receive the unit number as the first parameter. If there are for example tow NAND flash drivers which operate as two different NAND flash devices, the first one is identified as unit 0, the second one as unit 1. If there is just a single instance (as in most systems), the unit number parameter can be ignored by the underlying hardware functions.

Hardware layer

Most of the device drivers require functions to access the hardware. This set of functions is called hardware layer. The implementation of the hardware layer is user responsibility. emFile comes with template and sample hardware layers that can be used as a starting point in developing a new one.

The hardware layer can be implemented in two different ways:

Polled mode

In the polled mode the software actively queries the completion of the I/O operation. No operating system is required to implement the device driver in this way. The following example to demonstrate the fundamentals of an polled-driven hardware layer.

#include "FS.h"

/*********************************************************************
*
*       _HW_Write
*
*  Function description
*    FS hardware layer function. Writes a specified number of bytes
*    to storage device via DMA.
*/
static int _HW_Write(U8 Unit, const U8 * pData, int NumBytes) {
  int r;

  //
  // Start transmission using DMA.
  //
  _StartDMAWrite(Unit, pData, NumBytes);
  //
  // Wait for the DMA operation to complete.
  //
  while (1) {
    if (_IsDMAOperationCompleted()) {
      r = 0;          // OK, success.
      break;
    }
    if (_IsDMAError()) {
      r = 1;          // Error, could not write data via DMA.
      break;
    }
  }
  return r;
}

Interrupt-driven mode

In the interrupt-driven mode the completion of an I/O operation is signaled through an interrupt. This operating mode requires the support of an operating system. The following example demonstrates the fundamentals of an interrupt-driven hardware layer.

#include "FS.h"
#include "FS_OS.h"

/**********************************************************
*
*       _IRQ_Handler
*
*  Function description
*    Handles the hardware interrupt. Has to be registered
*    as interrupt service routine.
*/
static void _IRQ_Handler(void) {
  //
  // Disable further interrupts.
  //
  _DisableInterrupts();
  //
  // Signal (wake) the waiting task.
  //
  FS_X_OS_Signal();
}
/*********************************************************************
*
*       _HW_Write
*
*  Function description
*    FS hardware layer function. Writes a specified number of bytes
*    to storage device via DMA.
*/
static int _HW_Write(U8 Unit, const U8 * pData, int NumBytes) {
  //
  // Start transmission using DMA.
  //
  _StartDMAWrite(Unit, pData, NumBytes);
  //
  // Wait for the DMA operation to complete.
  //
  while (1) {
    if (_IsDMAOperationCompleted()) {
      r = 0;          // OK, success.
      break;
    }
    if (_IsDMAError()) {
      r = 1;          // Error, could not write data via DMA.
      break;
    }
    //
    // Wait for IRQ to signal the event and wake up the task.
    //
    r = FS_X_OS_Wait(TIMEOUT);
    if (r) {
      break;          // Error, timeout expired.
    }
  }
}

RAM Disk driver

General information

The RAM disk driver supports the use of any type of volatile and non-volatile RAM as storage. This includes the system memory as well as any RAM devices connected serially via an SPI or I2C bus using FRAM, MRAM or any other type of storage technology.

Two drivers for RAM storage are provided:

A file system configuration that uses the system memory as storage is suitable for getting started using emFile because it does not require any hardware access functions to be implemented. The RAM Disk driver is also useful for testing the file system on a PC simulation.

Theory of operation

The RAM Disk driver stores the data of the logical sectors it receives from file system without modification to the memory region configured by the application via FS_RAMDISK_Configure(). The byte offset at which the data is stored is calculated by multiplying the index of the logical sector by the size of a logical sector. For example, the data of the logical sector with the index 7 is stored at the byte offset 7 * 512 = 3584 assuming that the size of the logical sector is 512 bytes.

Fail-safe operation

Typically, all the file system data lost in case of an unexpected power loss if a volatile RAM device or the system memory without battery backup is used as storage. battery backup. For this reason, the fail-safety is relevant only for file system configurations that use a non-volatile RAM as storage.

Unexpected reset

In case of an unexpected reset the data will be preserved. However, if the unexpected reset interrupts a write operation, the data of the sector may contain partially invalid data.

Power failure

A power failure causes an unexpected reset and has the same effects.

Wear leveling

Typically, a RAM storage does now wear out therefore the RAM Disk driver does not perform any wear leveling.

Formatting

The storage used by the RAM Disk driver has to be formatted after each each startup of the system because its contents is typically lost. Exceptions to this are file system configurations that use as storage a system memory that is backed up via a battery or a non-volatile RAM device connected serially to the MCU.

The application has to format the storage via FS_Format() before it can store data on it. If the application adds only one RAM Disk driver to file system, FS_Format() can be called with an empty string as volume name. For example, FS_Format(“”, NULL). If more than one RAM Disk driver is added to file system, a the volume name has to be specified. For example, FS_Format(“ram:0:”, NULL) for the first storage device and FS_Format(“ram:1:”, NULL) for the second.

System RAM Disk driver

This section describes the RAM Disk driver that can use the system memory as storage.

Supported hardware

The System RAM Disk driver can be used on any target hardware that has sufficient system memory to be used as storage.

Configuring the driver

The application has to add the System RAM Disk driver to the file system before using it. This is done by calling FS_AddDevice() in FS_X_AddDevices() with the parameter set to the function table of the System RAM Disk driver FS_RAMDISK_Driver.

The maximum number of System RAM Disk driver instances that can be added to file system can be configured a compile-time using the FS_RAMDISK_MAX_NUM_UNITS configuration define. By default, a maximum number of four System RAM Disk driver instances can be added to file system.

The application has to call FS_RAMDISK_Configure() for each driver instance to configure the range of the system memory to be used as storage. The specified memory range can be located on any system memory that is accessible to the CPU.

Example

#include <FS.h>

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE          0x1100    // Memory pool for the file system in bytes
#define NUM_SECTORS         16        // Number of sectors on the RAM storage
#define BYTES_PER_SECTOR    512       // Size of a sector in bytes

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
//
// Memory pool used for semi-dynamic allocation.
//
static U32 _aMemBlock[ALLOC_SIZE / 4];
//
// Memory to be used as storage.
//
static U32 _aRAMDisk[(NUM_SECTORS * BYTES_PER_SECTOR) / 4];

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*    It is supposed to add all devices, using primarily FS_AddDevice().
*
*  Note
*    (1) Other API functions may NOT be called, since this function is called
*        during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the driver.
  //
  FS_AddDevice(&FS_RAMDISK_Driver);
  FS_RAMDISK_Configure(0, _aRAMDisk, BYTES_PER_SECTOR, NUM_SECTORS);
#if FS_SUPPORT_FILE_BUFFER
  //
  // Enable the file buffer to increase the performance
  // when reading/writing a small number of bytes.
  //
  FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
Compile-time configuration

The compile time configuration is realized via preprocessor defines that have to be added to the FS_Conf.h file which is the main configuration file of emFile. For detailed information about the configuration of emFile and of the configuration define types, refer to Configuration of emFile The System RAM disk driver does not require any hardware access functions. The following table lists the configuration defines supported by the RAM Disk driver.

Define Default value Type Description
FS_RAMDISK_NUM_UNITS 4 N Maximum number of driver instances.
FS_RAMDISK_NUM_UNITS

This define specifies the maximum number of driver instances that can be created by the application. The memory for each driver instance is allocated dynamically.

Runtime configuration

This section describes the functions that can be used to configure an instance of the System RAM Disk driver.

Function Description
FS_RAMDISK_Configure() Configures an instance of a System RAM disk driver.
FS_RAMDISK_Configure()

Description

Configures an instance of a System RAM disk driver.

Prototype

void FS_RAMDISK_Configure(U8     Unit,
                          void * pData,
                          U16    BytesPerSector,
                          U32    NumSectors);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pData Memory area to be used as storage. It cannot be NULL.
BytesPerSector Number of bytes in a logical sector.
NumSectors Number of logical sectors in the storage.

Additional information

The application has to call this function for each instance of the System RAM disk driver it adds to file system. Unit identifies the instance of the System RAM disk driver. The instance of the RAM disk driver added first to file system has the index 0, the second instance has the index 1, and so on.

pData has to point to a memory region that is at least BytesPerSector * NumSectors bytes large. The memory region can by located on any system memory that is accessible by CPU.

BytesPerSector has to be a power of 2 value.

Example

#include <FS.h>

#define NUM_SECTORS         16        // Number of sectors on the RAM storage
#define BYTES_PER_SECTOR    512       // Size of a sector in bytes

static U32 _aRAMDisk[(NUM_SECTORS * BYTES_PER_SECTOR) / 4]; // Memory to be used as storage.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Basic file system configuration...
  //

  //
  // Add and configure the driver.
  //
  FS_AddDevice(&FS_RAMDISK_Driver);
  FS_RAMDISK_Configure(0, _aRAMDisk, BYTES_PER_SECTOR, NUM_SECTORS);

  //
  // Additional file system configuration...
  //
}
Performance and resource usage
ROM usage

The ROM usage depends on the compiler options, the compiler version and the used CPU. The memory requirements of the System RAM Disk driver were measured as described in the section Test procedure.

Usage: 500 bytes

Static RAM usage

Static RAM usage refers to the amount of RAM required by the System RAM Disk driver internally for all the driver instances. The number of bytes can be seen in the compiler list file of the FS_RAMDisk.c file.

Usage: 40 bytes

Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the driver at runtime. Each instance of the System RAM Disk driver requires the following number of bytes:

Usage: 10 bytes

Performance

These performance measurements are in no way complete, but they give an approximation of the length of time required for common operations on various targets. The tests have been performed as described in the section Performance. All values are given in Mbytes/sec.

CPU type Write speed Read speed
Atmel AT91SAM9261 (200 MHz) 128 128
LogicPD LH79520 (51 MHz) 20 20

Universal RAM Disk driver

This section describes the RAM Disk driver that can use the system memory as well as a serial RAM device a storage.

Supported hardware

The Universal RAM Disk driver can be used on any target hardware that has sufficient system memory to be used as storage. In addition, the driver can be used with volatile and non-volatile RAM devices that are connected to MCU via a serial bus such as SPI or I2C.

The following table shows the serial RAM devices that were tested by SEGGER or are known to be compatible with a tested device.

Device name Storage capacity Device type Supported extra features
Fujitsu
MB85RC64TA 64 Kibit I2C
MB85RS128TY 128 Kibit SPI
MB85RS1MT 1 Mibit SPI
MB85RS256TY 256 Kibit SPI
MB85RS512T 512 Kibit SPI
Infineon
CY15B104QSN 4096 Mibit SPI extended SPI, DTR
FM24CL64B 64 Mibit I2C
FM24V01A 128 Mibit I2C
FM24V02A 256 Mibit I2C
FM25V02A 256 Mibit SPI
FM25V05 512 Mibit SPI
FM25V10 1 Mibit SPI
Configuring the driver

The application has to add the Universal RAM Disk driver to the file system before using it. This is done by calling FS_AddDevice() in FS_X_AddDevices() with the parameter set to the function table of the Universal RAM Disk driver FS_RAMDISK_UNI_Driver.

The maximum number of Universal RAM Disk driver instances that can be added to file system can be configured a compile-time using the FS_RAMDISK_MAX_NUM_UNITS configuration define. By default, a maximum number of four Universal RAM Disk driver instances can be added to file system.

In addition, the application has to configure the RAMDISK physical layer to be used for accessing the storage and if required the RAMDISK hardware layer to be used for the data transfer with the RAM device.

Example

The following configuration example uses the system memory as storage.

#include <FS.h>

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE          0x1100    // Memory pool for the file system in bytes.
#define NUM_SECTORS         16        // Number of sectors on the RAM storage.
#define BYTES_PER_SECTOR    512       // Size of a sector in bytes.

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
//
// Memory pool used for semi-dynamic allocation.
//
static U32 _aMemBlock[ALLOC_SIZE / 4];
//
// Memory to be used as storage.
//
static U32 _aRAMDisk[(NUM_SECTORS * BYTES_PER_SECTOR) / 4];

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*    It is supposed to add all devices, using primarily FS_AddDevice().
*
*  Note
*    (1) Other API functions may NOT be called, since this function is called
*        during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the driver.
  //
  FS_AddDevice(&FS_RAMDISK_UNI_Driver);
  FS_RAMDISK_UNI_SetPhyType(0, &FS_RAMDISK_PHY_System);
  FS_RAMDISK_UNI_SetSectorSize(0, BYTES_PER_SECTOR);
  FS_RAMDISK_SYS_SetMemBlock(0, _aRAMDisk, sizeof(_aRAMDisk));
#if FS_SUPPORT_FILE_BUFFER
  //
  // Enable the file buffer to increase the performance
  // when reading/writing a small number of bytes.
  //
  FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}

The following configuration example uses as storage a RAM device connected via I2C.

#include <FS.h>
#include "FS_RAMDISK_HW_I2C_GPIO_Template.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE          0x1100    // Memory pool for the file system in bytes.
#define NUM_SECTORS         16        // Number of sectors on the RAM storage.
#define BYTES_PER_SECTOR    512       // Size of a sector in bytes.
#define DEVICE_ADDRESS      0x50      // I2C address of the device.
#define DEVICE_SIZE         8192      // Capacity of the device in bytes.

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
//
// Memory pool used for semi-dynamic allocation.
//
static U32 _aMemBlock[ALLOC_SIZE / 4];

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*    It is supposed to add all devices, using primarily FS_AddDevice().
*
*  Note
*    (1) Other API functions may NOT be called, since this function is called
*        during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the driver.
  //
  FS_AddDevice(&FS_RAMDISK_UNI_Driver);
  FS_RAMDISK_UNI_SetPhyType(0, &FS_RAMDISK_PHY_I2C);
  FS_RAMDISK_UNI_SetSectorSize(0, BYTES_PER_SECTOR);
  FS_RAMDISK_I2C_SetDeviceAddress(0, DEVICE_ADDRESS);
  FS_RAMDISK_I2C_SetDeviceSize(0, DEVICE_SIZE);
  FS_RAMDISK_I2C_SetHWType(0, &FS_RAMDISK_HW_I2C_GPIO_Template);
#if FS_SUPPORT_FILE_BUFFER
  //
  // Enable the file buffer to increase the performance
  // when reading/writing a small number of bytes.
  //
  FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}

The following configuration example uses as storage a RAM device connected via SPI.

#include <FS.h>
#include "FS_RAMDISK_HW_SPI_Template.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE            0x1100    // Memory pool for the file system in bytes.
#define BYTES_PER_SECTOR      512       // Size of a sector in bytes.

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for semi-dynamic allocation. 

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*    It is supposed to add all devices, using primarily FS_AddDevice().
*
*  Note
*    (1) Other API functions may NOT be called, since this function is called
*        during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the driver.
  //
  FS_AddDevice(&FS_RAMDISK_UNI_Driver);
  FS_RAMDISK_UNI_SetPhyType(0, &FS_RAMDISK_PHY_SPI);
  FS_RAMDISK_UNI_SetSectorSize(0, BYTES_PER_SECTOR);
  FS_RAMDISK_SPI_SetHWType(0, &FS_RAMDISK_HW_SPI_Template);
  FS_RAMDISK_SPI_SetDeviceList(0, &FS_RAMDISK_SPI_DeviceListAll);
  FS_RAMDISK_SPI_Allow2bitMode(0, 1);
  FS_RAMDISK_SPI_Allow4bitMode(0, 1);
#if FS_SUPPORT_FILE_BUFFER
  //
  // Enable the file buffer to increase the performance
  // when reading/writing a small number of bytes.
  //
  FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
Compile-time configuration

The compile time configuration is realized via preprocessor defines that have to be added to the FS_Conf.h file which is the main configuration file of emFile. For detailed information about the configuration of emFile and of the configuration define types, refer to Configuration of emFile The RAM disk driver does not require any hardware access functions. The following table lists the configuration defines supported by the RAM Disk driver.

Define Default value Type Description
FS_RAMDISK_DATA_BUFFER_SIZE 32 N Number of bytes to be reserved for the data buffers used for internal operations.
FS_RAMDISK_NUM_READ_RETRIES 10 N Configures the number of retries in case of a read error.
FS_RAMDISK_NUM_UNITS 4 N Maximum number of driver instances.
FS_RAMDISK_VERIFY_WRITE 0 B Enables or disables the support for checking if the write operation was successful.
FS_RAMDISK_DATA_BUFFER_SIZE

This define can be used to specify the size of the buffers used by the Universal RAM Disk driver for internal operations such as verifying if the write operation was successful. All these buffers are allocated on the stack therefore increasing the value of FS_RAMDISK_DATA_BUFFER_SIZE increases the stack usage while providing a better performance. FS_RAMDISK_DATA_BUFFER_SIZE has to be a non-zero value that is a multiple of 4.

FS_RAMDISK_NUM_READ_RETRIES

FS_RAMDISK_NUM_READ_RETRIES can be used to specify the maximum number of times the Universal RAM Disk driver repeats a read operation in case of an error. A read retry is performed each time the read function of the RAMDISK physical layer reports an error.

FS_RAMDISK_NUM_UNITS

This define specifies the maximum number of driver instances that can be created by the application. The memory for each driver instance is allocated dynamically.

FS_RAMDISK_VERIFY_WRITE

This define can be used to activate the write verification of the Universal RAM Disk driver. The write verification is performed after each write operation by reading back the modified data from storage and by comparing it with the data requested to be written. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_RAMDISK_UNI_SetWriteVerification().

Note

Activating the write verification can negatively affect the write performance.

Runtime configuration

This section describes the functions that can be used to configure an instance of the RAM Disk driver.

Function Description
FS_RAMDISK_UNI_SetPhyType() Configures the physical layer type.
FS_RAMDISK_UNI_SetByteRange() Configures the range of memory to be used as storage.
FS_RAMDISK_UNI_SetSectorSize() Configures the size of the logical sector used by the driver.
FS_RAMDISK_UNI_SetWriteVerification() Enables or disables the checking of the data write operation.
FS_RAMDISK_UNI_SetPhyType()

Description

Configures the physical layer type.

Prototype

int FS_RAMDISK_UNI_SetPhyType(      U8                    Unit,
                              const FS_RAMDISK_PHY_TYPE * pPhyType);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pPhyType Type of physical layer. It cannot be NULL.

Return value

= 0 OK, physical layer configured successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function is mandatory and it has to be called once in FS_X_AddDevices() for each instance of the RAMDisk driver created by the application. Different instances of the RAMDisk driver are identified by the Unit parameter.

Permitted values for the pPhyType parameter are:

Identifier Description
FS_RAMDISK_PHY_System System memory.
FS_RAMDISK_PHY_I2C External RAM device connected via I2C.
FS_RAMDISK_PHY_SPI External RAM device connected via SPI.
FS_RAMDISK_UNI_SetByteRange()

Description

Configures the range of memory to be used as storage.

Prototype

int FS_RAMDISK_UNI_SetByteRange(U8  Unit,
                                U32 StartOff,
                                U32 NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
StartOff Offset of the first byte to be used as storage (0-based).
NumBytes Number of bytes to be used as storage.

Return value

= 0 OK, memory range configured successfully.
≠ 0 Error code indicating the failure reason.

Additional information

StartOff is rounded up to a multiple while NumBytes is rounded down to a multiple of logical sector size.

If NumBytes is set to 0 then the memory region used as storage starts at byte offset StartOff and extends to the end of the storage device.

FS_RAMDISK_UNI_SetSectorSize()

Description

Configures the size of the logical sector used by the driver.

Prototype

int FS_RAMDISK_UNI_SetSectorSize(U8       Unit,
                                 unsigned BytesPerSector);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BytesPerSector Logical sector size in bytes.

Return value

= 0 OK, memory range configured successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. If the size of the logical sector is not explicitly configured via FS_RAMDISK_UNI_SetSectorSize() then the file system uses the maximum logical sector size set via FS_SetMaxSectorSize(). FS_RAMDISK_UNI_SetSectorSize() can be called only in FS_X_AddDevices().

BytesPerSector has to be a power of 2 value.

FS_RAMDISK_UNI_SetWriteVerification()

Description

Enables or disables the checking of the data write operation.

Prototype

int FS_RAMDISK_UNI_SetWriteVerification(U8 Unit,
                                        U8 OnOff);

Parameters

Parameter Description
Unit Index of the Universal RAM Disk driver (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked.

Return value

= 0 OK, write verification configured successfully.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. It can be used to enable the checking of the written data. This is done by reading back the contents of the written data and by comparing it with the data requested to be written. Enabling this feature can negatively impact the write performance of Universal RAM Disk driver.

The write verification feature is active only when the Universal RAM Disk driver is compiled with the FS_RAMDISK_VERIFY_WRITE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

Additional driver functions

The functions documented in this section are optional. They can be used to get information about the status of the Universal RAM Disk driver or to directly access the data stored on a RAM device.

FunctionDescription
FS_RAMDISK_UNI_GetDiskInfo() Gets information about the storage device.
FS_RAMDISK_UNI_ReadOff() Reads a specified number of bytes from storage device.
FS_RAMDISK_UNI_WriteOff() Writes a specified number of bytes to storage device.
FS_RAMDISK_UNI_GetDiskInfo()

Description

Gets information about the storage device.

Prototype

int FS_RAMDISK_UNI_GetDiskInfo(U8                         Unit,
                               FS_RAMDISK_UNI_DISK_INFO * pDiskInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pDiskInfo  out  Storage device information. It cannot be NULL.

Return value

= 0 OK, information returned successfully.
≠ 0 Error code indicating the failure reason.
FS_RAMDISK_UNI_ReadOff()

Description

Reads a specified number of bytes from storage device.

Prototype

int FS_RAMDISK_UNI_ReadOff(U8     Unit,
                           U32    Off,
                           void * pData,
                           U32    NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
Off Byte offset to read from.
pData  out  Data read from storage device. It cannot be NULL.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read successfully.
≠ 0 Error code indicating the failure reason.

Additional information

Off has to be specified in bytes and is relative to the beginning of the storage partition configured via FS_RAMDISK_UNI_SetByteRange().

FS_RAMDISK_UNI_WriteOff()

Description

Writes a specified number of bytes to storage device.

Prototype

int FS_RAMDISK_UNI_WriteOff(      U8     Unit,
                                  U32    Off,
                            const void * pData,
                                  U32    NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
Off Byte offset to write to.
pData  out  Data to be written to the storage device. It cannot be NULL.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written successfully.
≠ 0 Error code indicating the failure reason.

Additional information

Off has to be specified in bytes and is relative to the beginning of the storage partition configured via FS_RAMDISK_UNI_SetByteRange().

FS_RAMDISK_UNI_DISK_INFO

Description

Management information maintained by the Universal RAM Disk driver.

Type definition

typedef struct {
  U32  NumBytes;
  U16  BytesPerSector;
} FS_RAMDISK_UNI_DISK_INFO;

Structure members

Member Description
NumBytes Capacity of the storage device in bytes.
BytesPerSector Size of the logical sector used by the driver in bytes.
Performance and resource usage
ROM usage

The ROM usage depends on the compiler options, the compiler version and the used CPU. The memory requirements of the Universal RAM Disk driver were measured as described in the section Test procedure.

Usage: 600 bytes

Static RAM usage

Static RAM usage refers to the amount of RAM required by the Universal RAM Disk driver internally for all the driver instances. The number of bytes can be seen in the compiler list file of the FS_RAMDISK_UNI_Drv.c file.

Usage: 16 bytes

Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the driver at runtime. Each instance of the Universal RAM Disk driver requires the following number of bytes:

Usage: 25 bytes

Performance

These performance measurements are in no way complete, but they give an approximation of the length of time required for common operations on various targets. The tests have been performed as described in the section Performance. All values are given in Mbytes/sec.

CPU type RAM device Write speed Read speed
ST STM32H743 (480 MHz) Infineon CY15B104QSN (48 MHz, quad DTR) 48 64

RAMDISK physical layer

General information

The table below lists the RAMDISK physical layers that ship with emFile. Refer to Configuring the driver and Configuring the driver for more information about how to add and configure a physical layer in an application.

Physical layer identifier Hardware layer type
FS_RAMDISK_PHY_I2C FS_RAMDISK_HW_TYPE_I2C
FS_RAMDISK_PHY_SPI FS_RAMDISK_HW_TYPE_SPI
FS_RAMDISK_PHY_System Not required.

The following sections provide information about the usage and the implementation of a RAMDISK physical layer.

I2C physical layer

This physical layer supports any RAM device connected to the MCU via I2C.

The physical layer has to be configured at runtime. The following section describes how this can be done in the application.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the System physical layer. The application can call these function only at the file system initialization in FS_X_AddDevices().

Function Description
FS_RAMDISK_I2C_SetDeviceAddress() Configures the I2C address of the storage device.
FS_RAMDISK_I2C_SetDeviceSize() Configures the capacity of the storage device.
FS_RAMDISK_I2C_SetHWType() Configures the HW layer for the device access.
FS_RAMDISK_I2C_SetDeviceAddress()

Description

Configures the I2C address of the storage device.

Prototype

int FS_RAMDISK_I2C_SetDeviceAddress(U8       Unit,
                                    unsigned Addr);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based).
Addr I2C address to be configured.

Return value

= 0 OK, device address configured.
≠ 0 Error code indicating the failure reason.

Additional information

It is mandatory to call this function once for each configured I2C RAMDisk physical layer. The application must call it in FS_X_AddDevices().

FS_RAMDISK_I2C_SetDeviceSize()

Description

Configures the capacity of the storage device.

Prototype

int FS_RAMDISK_I2C_SetDeviceSize(U8  Unit,
                                 U32 NumBytes);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based).
NumBytes Device capacity to be configured.

Return value

= 0 OK, device capacity configured.
≠ 0 Error code indicating the failure reason.

Additional information

It is mandatory to call this function once for each configured I2C RAMDisk physical layer. The application must call it in FS_X_AddDevices().

FS_RAMDISK_I2C_SetHWType()

Description

Configures the HW layer for the device access.

Prototype

int FS_RAMDISK_I2C_SetHWType(      U8                       Unit,
                             const FS_RAMDISK_HW_TYPE_I2C * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based).
pHWType  in  HW layer to be used. It cannot be NULL.

Return value

= 0 OK, HW layer configured.
≠ 0 Error code indicating the failure reason.

Additional information

It is mandatory to call this function once for each configured I2C RAMDisk physical layer. The application must call it in FS_X_AddDevices().

SPI physical layer

This physical layer supports any RAM device connected to the MCU via single dual, quad and octal SPI.

The physical layer has to be configured at runtime. The following section describes how this can be done in the application.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the System physical layer. The application can call these function only at the file system initialization in FS_X_AddDevices().

Function Description
FS_RAMDISK_SPI_Allow2bitMode() Specifies if the physical layer is permitted to exchange data via two data lines.
FS_RAMDISK_SPI_Allow4bitMode() Specifies if the physical layer is permitted to exchange data via four data lines.
FS_RAMDISK_SPI_AllowDTRMode() Specifies if the physical layer is permitted to exchange data on both clock edges.
FS_RAMDISK_SPI_SetDeviceList() Configures the type of handled serial RAM devices.
FS_RAMDISK_SPI_SetHWType() Configures the HW layer for the device access.
FS_RAMDISK_SPI_SetMemAddr() Configures the address in the system memory where the device is mapped.
FS_RAMDISK_SPI_Allow2bitMode()

Description

Specifies if the physical layer is permitted to exchange data via two data lines.

Prototype

int FS_RAMDISK_SPI_Allow2bitMode(U8 Unit,
                                 U8 OnOff);

Parameters

Parameter Description
Unit Index of the physical layer (0-based).
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Return value

= 0 OK, 2 bit mode configured.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. By default the data is exchanged via one data line (standard SPI). The data transfer via two data lines is used only if this type of data transfer is supported by the serial RAM device. In dual mode two bits of data are transferred with each clock period which helps improve the performance. If the serial RAM device does not support the dual mode then the data is transferred in standard mode (one data bit per clock period).

The application is permitted to call this function only at the file system initialization in FS_X_AddDevices().

FS_RAMDISK_SPI_Allow4bitMode()

Description

Specifies if the physical layer is permitted to exchange data via four data lines.

Prototype

int FS_RAMDISK_SPI_Allow4bitMode(U8 Unit,
                                 U8 OnOff);

Parameters

Parameter Description
Unit Index of the physical layer (0-based).
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Return value

= 0 OK, 4 bit mode configured.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. By default the data is exchanged via one data line (standard SPI). The data transfer via four data lines is used only if this type of data transfer is supported by the serial RAM device. In quad mode four bits of data are transferred on each clock period which helps improve the performance. If the serial RAM device does not support the quad mode then the data is transferred in dual mode if enabled and supported or in standard mode (one bit per clock period).

The application is permitted to call this function only at the file system initialization in FS_X_AddDevices().

FS_RAMDISK_SPI_AllowDTRMode()

Description

Specifies if the physical layer is permitted to exchange data on both clock edges.

Prototype

int FS_RAMDISK_SPI_AllowDTRMode(U8 Unit,
                                U8 OnOff);

Parameters

Parameter Description
Unit Index of the physical layer (0-based).
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Return value

= 0 OK, DTR mode configured.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. By default the data is exchanged only on one of the clock edges (SDR mode). In DTR mode the data is transferred on each edge of the clock which helps improve the performance. The SPI RAMDISK physical layer transfers the data in DTR mode only if the used serial RAM device supports it.

The application is permitted to call this function only at the file system initialization in FS_X_AddDevices().

FS_RAMDISK_SPI_SetDeviceList()

Description

Configures the type of handled serial RAM devices.

Prototype

int FS_RAMDISK_SPI_SetDeviceList(      U8                           Unit,
                                 const FS_RAMDISK_SPI_DEVICE_LIST * pDeviceList);

Parameters

Parameter Description
Unit Index of the physical layer (0-based).
pDeviceList List of serial RAM devices the physical layer can handle.

Return value

= 0 OK, device list successfully configured.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. By default the physical layer is configured to handle Infineon (Ramtron) serial FRAM devices. Handling of serial RAM devices from other manufacturers has to be explicitly enabled via this function.

Permitted values for the pDeviceList parameter are:

Identifier Description
FS_NOR_SPI_DeviceListAll Enables handling of serial RAM devices from all supported manufacturers.
FS_NOR_SPI_DeviceListDefault Enables handling of Infineon (Ramtron) serial RAM devices.
FS_NOR_SPI_DeviceListFujitsu Enables handling of Fujitsu serial RAM devices.
FS_NOR_SPI_DeviceListInfineon Enables handling of Infineon serial RAM devices.

The application can save ROM space by setting FS_RAMDISK_DEVICE_LIST_DEFAULT to NULL at compile time and by calling at runtime FS_RAMDISK_SPI_SetDeviceList() with the actual list of serial RAM devices that have to be handled.

The application is permitted to call this function only at the file system initialization in FS_X_AddDevices().

FS_RAMDISK_SPI_SetHWType()

Description

Configures the HW layer for the device access.

Prototype

int FS_RAMDISK_SPI_SetHWType(      U8                       Unit,
                             const FS_RAMDISK_HW_TYPE_SPI * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based).
pHWType  in  HW layer to be used. It cannot be NULL.

Return value

= 0 OK, HW layer configured.
≠ 0 Error code indicating the failure reason.

Additional information

It is mandatory to call this function once for each configured SPI RAMDisk physical layer. The application must call it in FS_X_AddDevices().

FS_RAMDISK_SPI_SetMemAddr()

Description

Configures the address in the system memory where the device is mapped.

Prototype

int FS_RAMDISK_SPI_SetMemAddr(U8  Unit,
                              U32 Addr);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based).
Addr Address in the system memory.

Return value

= 0 OK, address successfully configured.
≠ 0 Error code indicating the failure reason.

Additional information

This function has to be called only in FS_X_AddDevices().

RAMDISK HW layer flags

Description

Additional options for data exchanged by the SPI RAMDISK hardware layer.

Definition

#define FS_RAMDISK_HW_FLAG_DTR_DATA      (1uL << 0)
#define FS_RAMDISK_HW_FLAG_DTR_ADDR      (1uL << 1)
#define FS_RAMDISK_HW_FLAG_DTR_CMD       (1uL << 2)
#define FS_RAMDISK_HW_FLAG_DQS_ACTIVE    (1uL << 3)
#define FS_RAMDISK_HW_FLAG_MODE_8BIT     (1uL << 4)

Symbols

Definition Description
FS_RAMDISK_HW_FLAG_DTR_DATA Exchange the data on each clock transition.
FS_RAMDISK_HW_FLAG_DTR_ADDR Send the address on each clock transition.
FS_RAMDISK_HW_FLAG_DTR_CMD Send the command on each clock transition.
FS_RAMDISK_HW_FLAG_DQS_ACTIVE Enable the data strobe signal.
FS_RAMDISK_HW_FLAG_MODE_8BIT Send eight mode bits after the data address.
System physical layer

This physical layer supports any system memory.

The physical layer has to be configured at runtime. The following section describes how this can be done in the application.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the System physical layer. The application can call these function only at the file system initialization in FS_X_AddDevices().

Function Description
FS_RAMDISK_SYS_SetMemBlock() Configures the memory block to be used as storage.
FS_RAMDISK_SYS_SetMemBlock()

Description

Configures the memory block to be used as storage.

Prototype

int FS_RAMDISK_SYS_SetMemBlock(U8     Unit,
                               void * pData,
                               U32    NumBytes);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based).
pData Memory area to be used as storage. It cannot be NULL.
NumBytes Number of bytes to be used as storage.

Return value

= 0 OK, memory block configured.
≠ 0 Error code indicating the failure reason.

Additional information

The application has to call this function for each instance of the RAM disk physical layer that is added to the file system. Unit identifies the instance of the RAM disk physical layer.

pData has to point to a memory region that is at least NumBytes bytes large. The memory region can by located on any system memory that is accessible by CPU.

Physical layer API

The physical layers that come with emFile provide support most of the popular RAM device and target MCU types. Therefore, there is typically no need to modify any of the provided RAMDISK physical layers. In most of the cases, only the RAMDISK hardware layer has to be adapted to a specific target hardware. However, when none of the provided RAMDISK physical layers are compatible with the target hardware a new RAMDISK physical layer implementation is required. This section provides information about the API of the RAMDISK physical layer that helps to create a new physical layer from scratch or to modify an existing one.

The API of the physical layer is implemented as a structure of type FS_RAMDISK_PHY_TYPE that contains pointers to functions. The following sections describe these functions in detail together with the data structure passed to these functions as parameters.

FS_RAMDISK_PHY_TYPE

Description

RAMDISK physical layer API.

Type definition

typedef struct {
  FS_RAMDISK_PHY_TYPE_INIT_GET_DEVICE_INFO * pfInitGetDeviceInfo;
  FS_RAMDISK_PHY_TYPE_READ_OFF             * pfReadOff;
  FS_RAMDISK_PHY_TYPE_WRITE_OFF            * pfWriteOff;
  FS_RAMDISK_PHY_TYPE_DEINIT               * pfDeInit;
} FS_RAMDISK_PHY_TYPE;

Structure members

Member Description
pfInitGetDeviceInfo Initializes the instance of the RAM physical layer and returns the information about the RAM device.
pfReadOff Reads data from the RAM device.
pfWriteOff Writes data to the RAM device.
pfDeInit Frees the resources allocated by the RAM physical layer instance.
FS_RAMDISK_PHY_TYPE_INIT_GET_DEVICE_INFO

Description

Initializes the physical layer.

Type definition

typedef int FS_RAMDISK_PHY_TYPE_INIT_GET_DEVICE_INFO(U8                       Unit,
                                                     FS_RAMDISK_DEVICE_INFO * pDeviceInfo);

Parameters

Parameter Description
Unit Index of the RAMDISK physical layer instance (0-based)
pDeviceInfo  out  Information about the NAND flash device.

Return value

= 0 OK, physical layer successfully initialized.
≠ 0 An error occurred.

Additional information

This function is a member of the RAMDISK physical layer API. It has to be implemented by all the RAMDISK physical layers. This is the first function of the physical layer API that is called by the Universal RAM Disk driver when the RAM device is mounted.

This function has to perform the initialization of the hardware layer, and the identification of the RAM device. If the RAM device can be handled, then the function has to fill pDevInfo with information about the organization of the RAM device.

FS_RAMDISK_PHY_TYPE_READ_OFF

Description

Reads data from a RAM device.

Type definition

typedef int FS_RAMDISK_PHY_TYPE_READ_OFF(U8     Unit,
                                         U32    Off,
                                         void * pData,
                                         U32    NumBytes);

Parameters

Parameter Description
Unit Index of the RAMDISK physical layer instance (0-based)
Off Byte offset to read from.
pData  out  Data read from RAM device.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the RAMDISK physical layer API. It has to be implemented by all the RAMDISK physical layers.

FS_RAMDISK_PHY_TYPE_WRITE_OFF

Description

Writes data to a RAM device.

Type definition

typedef int FS_RAMDISK_PHY_TYPE_WRITE_OFF(      U8     Unit,
                                                U32    Off,
                                          const void * pData,
                                                U32    NumBytes);

Parameters

Parameter Description
Unit Index of the RAMDISK physical layer instance (0-based)
Off Byte offset to write to.
pData  in  Data to be written to the RAM device.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is a member of the RAMDISK physical layer API. It has to be implemented by all the RAMDISK physical layers.

FS_RAMDISK_PHY_TYPE_DEINIT

Description

Releases the allocated resources.

Type definition

typedef void FS_RAMDISK_PHY_TYPE_DEINIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the RAMDISK physical layer instance (0-based)

Additional information

This function is a member of the RAMDISK physical layer API. It has to be implemented by the all the RAMDISK physical layers that allocate resources dynamically during the initialization such as memory for the physical layer instance.

The RAMDISK driver calls this function when the file system is unmounted.

FS_RAMDISK_DEVICE_INFO

Description

Information about a RAM device.

Type definition

typedef struct {
  U32  NumBytes;
} FS_RAMDISK_DEVICE_INFO;

Structure members

Member Description
NumBytes Capacity of the storage device in bytes.
Resource usage

This section describes the ROM and RAM usage of the RAMDISK physical layers.

ROM usage

The ROM usage depends on the compiler options, the compiler version, and the used CPU. The memory requirements of the RAMDISK physical layers were measured as described in the section Test procedure. The following table lists the ROM usage of all the available RAMDISK physical layers.

Name ROM usage(Kbytes)
I2C 0.5
SPI 1
System 0.1
Static RAM usage

Static RAM usage is the amount of RAM required by the driver for static variables inside the driver. The number of bytes can be seen in a compiler list file. The next table lists the static RAM usage of all the available RAMDISK physical layers.

Name RAM usage (bytes)
I2C 16
SPI 16
System 16
Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the physical layer at runtime. The amount of RAM required depends on the compile time and runtime configuration. The following table lists the the dynamic RAM usage of the available RAMDISK physical layers.

Name RAM usage (bytes)
I2C 11
SPI 20
System 8

RAMDISK hardware layer

General information

The RAMDISK hardware layer provides functionality for accessing a RAM device via the target hardware such as GPIO, SPI, I2C, etc. The functions of the RAMDISK hardware layer are called by the RAMDISK physical layer to exchange commands and data with a RAM device. These functions are hardware dependent and therefore they have to be implemented in the application. emFile comes with template hardware layers and sample implementations for popular evaluation boards that can be used as starting point for implementing new hardware layers. The relevant files are located in the /Sample/FS/Driver/RAM folder of the emFile shipment.

The functions of the RAMDISK hardware layer are organized in a function table implemented as a C structure. Different hardware layer types are provided to support different ways of interfacing a RAM device. The type of hardware layer an application has to use depends on the type RAMDISK physical layer configured. The following table shows what hardware layer is required by each physical layer.

RAMDISK hardware layer RAMDISK physical layer
FS_RAMDISK_HW_TYPE_I2C FS_RAMDISK_PHY_I2C
FS_RAMDISK_HW_TYPE_SPI FS_RAMDISK_PHY_SPI
Hardware layer API - FS_RAMDISK_HW_TYPE_I2C

This hardware layer supports serial RAM devices that are interfaced via I2C. The functions of this hardware layer are grouped in a structure of type FS_RAMDISK_HW_TYPE_I2C. The following sections describe these functions in detail.

FS_RAMDISK_HW_TYPE_I2C

Description

HW layer for RAM devices connected via I2C.

Type definition

typedef struct {
  FS_RAMDISK_HW_TYPE_I2C_INIT  * pfInit;
  FS_RAMDISK_HW_TYPE_I2C_START * pfStart;
  FS_RAMDISK_HW_TYPE_I2C_STOP  * pfStop;
  FS_RAMDISK_HW_TYPE_I2C_READ  * pfRead;
  FS_RAMDISK_HW_TYPE_I2C_WRITE * pfWrite;
} FS_RAMDISK_HW_TYPE_I2C;

Structure members

Member Description
pfInit Initializes the I2C hardware.
pfStart Generates a START condition on the I2C bus.
pfStop Generates a STOP condition on the I2C bus.
pfRead Transfers data from I2C device to MCU.
pfWrite Transfers data from MCU to I2C device.
FS_RAMDISK_HW_TYPE_I2C_INIT

Description

Initializes the HW layer.

Type definition

typedef int FS_RAMDISK_HW_TYPE_I2C_INIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).

Return value

= 0 OK, HW layer successfully initialized.
≠ 0 An error occurred.
FS_RAMDISK_HW_TYPE_I2C_START

Description

Start an I2C transaction.

Type definition

typedef int FS_RAMDISK_HW_TYPE_I2C_START(U8       Unit,
                                         unsigned Addr,
                                         int      IsRead);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
Addr Address of the device to be accessed.
IsRead Type of operation to be executed. 0 - Write operation. 1 - Read operation.

Return value

= 0 OK, transaction successfully started.
≠ 0 An error occurred.

Additional information

This function is a member of the I2C RAMDISK hardware layer API. It has to be implemented by all the hardware layers.

FS_RAMDISK_HW_TYPE_I2C_STOP

Description

Ends an I2C transaction.

Type definition

typedef int FS_RAMDISK_HW_TYPE_I2C_STOP(U8 Unit);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).

Return value

= 0 OK, transaction successfully ended.
≠ 0 An error occurred.

Additional information

This function is a member of the I2C RAMDISK hardware layer API. It has to be implemented by all the hardware layers.

FS_RAMDISK_HW_TYPE_I2C_READ

Description

Transfers data from I2C device to MCU.

Type definition

typedef int FS_RAMDISK_HW_TYPE_I2C_READ(U8   Unit,
                                        U8 * pData,
                                        U32  NumBytes);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pData  out  Data read from I2C device.
NumBytes Number of bytes to transfer.

Return value

= 0 OK, data successfully transferred.
≠ 0 An error occurred.

Additional information

This function is a member of the I2C RAMDISK hardware layer API. It has to be implemented by all the hardware layers.

The function has to send a NAK after the last byte transferred.

FS_RAMDISK_HW_TYPE_I2C_WRITE

Description

Transfers data from MCU to I2C device.

Type definition

typedef int FS_RAMDISK_HW_TYPE_I2C_WRITE(      U8   Unit,
                                         const U8 * pData,
                                               U32  NumBytes);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pData  in  Data written to I2C device.
NumBytes Number of bytes to transfer.

Return value

= 0 OK, data successfully transferred.
≠ 0 An error occurred.

Additional information

This function is a member of the I2C RAMDISK hardware layer API. It has to be implemented by all the hardware layers.

Sample implementation

The following sample implementation uses the GPIOs of an ST STM32H743 MCU to interface with a I2C RAM device. This RAMDISK hardware layer was tested on the SGGER QSPI Flash Evaluator board (https://www.segger.com/evaluate-our-software/segger/qspi-flash-evaluator/)

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator.c
Purpose : Hardware layer for SEGGER QSPI Flash Evaluator
          with RAM device connected via I2C.
Literature:
  [1] RM0433 Reference manual STM32H7x3 advanced ARM-based 32-bit MCUs
  [2] STM32H753xI Errata sheet STM32H753xI rev Y device limitations
Additional information:
  The value of RAM_NUM_DELAY_LOOPS was determined by testing with
  different I2C RAM devices. The resulting maximum SCL frequency
  for a stable data transfer is about 100 kHz which is relatively
  slow compared with the 1 MHz clock frequency supported by most
  of the I2C RAM devices.
  The reason for this limitation is that the HW layer is using
  the internal pull-up resistors of the GPIO ports for the SCL
  and SDA signals. According to the datasheet of STM32H7 device
  the value of the internal pull-up resistors is about 40 kOhm.
  The frequency of SCL signal can be greatly improved by using
  external pull-up resistors of about 4.7 kOhm.

  The device select address signals (A0-2) are set to logic low.
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/
#include "FS.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define RAM_NUM_DELAY_LOOPS       500   // Number of software cycles required
                                        // to generate a delay of at least
                                        // 4.7 us if the I2C device supports
                                        // standard-mode (400kHz) or of at least
                                        // 1.3 us if the I2C device support
                                        // fast-mode (1MHz).

/*********************************************************************
*
*       RAM_SET_SCL
*
*  Description
*    Sets the logic level of SCL signal to high.
*/
#define RAM_SET_SCL()             GPIOF_BSRR = 1uL << RAM_SCL_BIT

/*********************************************************************
*
*       RAM_CLR_SCL
*
*  Description
*    Sets the logic level of SCL signal to low.
*/
#define RAM_CLR_SCL()             GPIOF_BSRR = 1uL << (RAM_SCL_BIT + 16)

/*********************************************************************
*
*       RAM_SET_SDA
*
*  Description
*    Sets the logic level of SDA signal to high.
*/
#define RAM_SET_SDA()             GPIOF_BSRR = 1uL << RAM_SDA_BIT

/*********************************************************************
*
*       RAM_CLR_SDA
*
*  Description
*    Sets the logic level of SDA signal to high.
*/
#define RAM_CLR_SDA()             GPIOF_BSRR = 1uL << (RAM_SDA_BIT + 16)

/*********************************************************************
*
*       RAM_SET_SDA_TO_INPUT
*
*  Description
*    Configures the direction of the SDA signal to input.
*/
#define RAM_SET_SDA_TO_INPUT()    GPIOF_MODER &= ~(MODER_MASK << (RAM_SDA_BIT << 1));

/*********************************************************************
*
*       RAM_SET_SDA_TO_OUTPUT
*
*  Description
*    Configures the direction of the SDA signal to output.
*/
#define RAM_SET_SDA_TO_OUTPUT()   GPIOF_MODER |= MODER_OUT << (RAM_SDA_BIT << 1)

/*********************************************************************
*
*       RAM_GET_SDA
*
*  Description
*    Returns the logic level of the SDA signal.
*/
#define RAM_GET_SDA()             (GPIOF_IDR & (1uL << RAM_SDA_BIT))

/*********************************************************************
*
*       Defines, fixed
*
**********************************************************************
*/

/*********************************************************************
*
*       RAM_DELAY
*
*  Description
*    Blocks the execution for a fixed period of time.
*/
#if RAM_NUM_DELAY_LOOPS
  #define RAM_DELAY()             _Delay()
#else
  #define RAM_DELAY()
#endif

/*********************************************************************
*
*       Port B registers
*/
#define GPIOB_BASE_ADDR           0x58020400uL
#define GPIOB_MODER               (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x00))
#define GPIOB_OTYPE               (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x04))
#define GPIOB_OSPEEDR             (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x08))
#define GPIOB_PUPDR               (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x0C))
#define GPIOB_IDR                 (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x10))
#define GPIOB_ODR                 (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x14))
#define GPIOB_BSRR                (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x18))
#define GPIOB_AFRL                (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x20))

/*********************************************************************
*
*       Port F registers
*/
#define GPIOF_BASE_ADDR           0x58021400uL
#define GPIOF_MODER               (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x00))
#define GPIOF_OTYPE               (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x04))
#define GPIOF_OSPEEDR             (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x08))
#define GPIOF_PUPDR               (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x0C))
#define GPIOF_IDR                 (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x10))
#define GPIOF_ODR                 (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x14))
#define GPIOF_BSRR                (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x18))
#define GPIOF_AFRL                (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x20))
#define GPIOF_AFRH                (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x24))

/*********************************************************************
*
*       Reset and clock control
*/
#define RCC_BASE_ADDR             0x58024400uL
#define RCC_AHB3RSTR              (*(volatile U32*)(RCC_BASE_ADDR + 0x7C))
#define RCC_AHB3ENR               (*(volatile U32*)(RCC_BASE_ADDR + 0xD4))
#define RCC_AHB4ENR               (*(volatile U32*)(RCC_BASE_ADDR + 0xE0))

/*********************************************************************
*
*       GPIO bit positions of SPI signals
*/
#define RAM_SCL_BIT               10  // Port F
#define RAM_SDA_BIT               8   // Port F
#define RAM_A0_BIT                6   // Port B
#define RAM_A1_BIT                9   // Port F
#define RAM_A2_BIT                7   // Port F
#define RAM_WP_BIT                6   // Port F

/*********************************************************************
*
*       GPIO bits and masks
*/
#define OSPEEDR_HIGH              2uL
#define OSPEEDR_MASK              0x3uL
#define MODER_MASK                0x3uL
#define MODER_OUT                 1uL
#define MODER_ALT                 2uL
#define AFR_MASK                  0xFuL
#define PUPDR_MASK                0x3uL
#define PUPDR_PULLUP              0x1uL

/*********************************************************************
*
*       Masks for the peripheral enable bits
*/
#define AHB1ENR_GPIOBEN_BIT       1
#define AHB1ENR_GPIOFEN_BIT       5

/*********************************************************************
*
*        Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _Delay
*
*  Function description
*    Blocks the execution for a specified time.
*
*  Additional information
*    The delay time is specified via RAM_NUM_DELAY_LOOPS.
*/
static void _Delay(void) {
  volatile int i;

  for (i = 0; i < RAM_NUM_DELAY_LOOPS; ++i) {
    ;
  }
}

/*********************************************************************
*
*       _WriteByte
*
*  Function description
*    Transfers 8 bits of data from MCU to I2C device.
*
*  Parameters
*    Data    8-bit value to be transferred.
*
*  Return value
*    ==0      Data accepted by the I2C device (ACK/NACK bit set to 0)
*    !=0      Data rejected by the I2C device (ACK/NACK bit set to 1)
*/
static int _WriteByte(U8 Data) {
  int r;
  int i;

  //
  // Send data bits with MSB first.
  //
  for (i = 0; i < 8; ++i) {
    if ((Data & (1 << 7)) != 0) {
      RAM_SET_SDA();
    } else {
      RAM_CLR_SDA();
    }
    Data <<= 1;
    RAM_DELAY();          // Wait tLOW
    RAM_SET_SCL();
    RAM_DELAY();          // Wait tHIGH
    RAM_CLR_SCL();
  }
  //
  // Receive ACK/NACK.
  //
  RAM_SET_SDA_TO_INPUT();
  RAM_DELAY();            // Wait tLOW
  RAM_SET_SCL();
  RAM_DELAY();            // Wait tHIGH
  r = RAM_GET_SDA();
  RAM_CLR_SCL();
  RAM_DELAY();            // Wait tLOW
  RAM_SET_SDA_TO_OUTPUT();
  return r;
}

/*********************************************************************
*
*       _ReadByte
*
*  Function description
*    Transfers 8 bits of data from I2C device to MCU.
*
*  Parameters
*    AckNack      Value of the ACK/NACK bit.
*                 * 0 - More data will be transferred (ACK/NACK is set to 0)
*                 * 1 - Last data to be transferred (ACK/NACK is set to 1)
*
*  Return value
*    Transferred 8-bit value.
*/
static U8 _ReadByte(int AckNack) {
  U8 Value;
  int i;

  //
  // Receive data bits with MSB first.
  //
  RAM_SET_SDA_TO_INPUT();
  RAM_DELAY();            // Wait tLOW
  Value = 0;
  for (i = 0; i < 8; ++i) {
    RAM_SET_SCL();
    RAM_DELAY();          // Wait tHIGH
    Value <<= 1;
    if (RAM_GET_SDA() != 0) {
      Value |= 1u;
    }
    RAM_CLR_SCL();
    RAM_DELAY();          // Wait tLOW
  }
  //
  // Send ACK/NACK.
  //
  if (AckNack != 0) {
    RAM_CLR_SDA();
  } else {
    RAM_SET_SDA();
  }
  RAM_SET_SDA_TO_OUTPUT();
  RAM_SET_SCL();
  RAM_DELAY();            // Wait tHIGH
  RAM_CLR_SCL();
  return Value;
}

/*********************************************************************
*
*        Static code (public via callback)
*
**********************************************************************
*/

/*********************************************************************
*
*       _HW_Init
*
*  Function description
*    Initializes the HW layer.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*
*  Return value
*    ==0      OK, HW layer successfully initialized.
*    !=0      An error occurred.
*/
static int _HW_Init(U8 Unit) {
  FS_USE_PARA(Unit);
  //
  // Enable the clocks of GPIO peripherals.
  //
  RCC_AHB4ENR  |= 0
               | (1uL << AHB1ENR_GPIOBEN_BIT)
               | (1uL << AHB1ENR_GPIOFEN_BIT)
               ;
  //
  // Clock signal (SCL).
  //
  GPIOF_MODER   &= ~(MODER_MASK   <<  (RAM_SCL_BIT << 1));
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_SCL_BIT - 8) << 2));
  GPIOF_PUPDR   &= ~(PUPDR_MASK   <<  (RAM_SCL_BIT << 1));
  GPIOF_PUPDR   |=   PUPDR_PULLUP <<  (RAM_SCL_BIT << 1);
  GPIOF_BSRR    =    1uL          <<   RAM_SCL_BIT;               // Set to high logic level.
  GPIOF_OTYPE   |=   1uL          <<   RAM_SCL_BIT;               // Set to open-drain.
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK <<  (RAM_SCL_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    <<  (RAM_SCL_BIT << 1);
  //
  // Data signal (SDA).
  //
  GPIOF_MODER   &= ~(MODER_MASK   <<  (RAM_SDA_BIT << 1));
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_SDA_BIT - 8) << 2));
  GPIOF_PUPDR   &= ~(PUPDR_MASK   <<  (RAM_SDA_BIT << 1));
  GPIOF_PUPDR   |=   PUPDR_PULLUP <<  (RAM_SDA_BIT << 1);
  GPIOF_BSRR    =    1uL          <<   RAM_SDA_BIT;               // Set to high logic level.
  GPIOF_OTYPE   |=   1uL          <<   RAM_SDA_BIT;               // Set to open-drain.
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK <<  (RAM_SDA_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    <<  (RAM_SDA_BIT << 1);
  //
  // Address pin 0 (A0).
  //
  GPIOB_MODER   &= ~(MODER_MASK   <<  (RAM_A0_BIT << 1));
  GPIOB_AFRL    &= ~(AFR_MASK     <<  (RAM_A0_BIT << 2));
  GPIOB_BSRR    =    1uL          <<  (RAM_A0_BIT + 16);          // Set to low logic level.
  GPIOB_OSPEEDR &= ~(OSPEEDR_MASK <<  (RAM_A0_BIT << 1));
  GPIOB_MODER   |=   MODER_OUT    <<  (RAM_A0_BIT << 1);
  //
  // Address pin 1 (A1).
  //
  GPIOF_MODER   &= ~(MODER_MASK   <<  (RAM_A1_BIT << 1));
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_A1_BIT - 8) << 2));
  GPIOF_BSRR    =    1uL          <<  (RAM_A1_BIT + 16);          // Set to low logic level.
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK <<  (RAM_A1_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    <<  (RAM_A1_BIT << 1);
  //
  // Address pin 2 (A2).
  //
  GPIOF_MODER   &= ~(MODER_MASK   <<  (RAM_A2_BIT << 1));
  GPIOF_AFRL    &= ~(AFR_MASK     <<  (RAM_A2_BIT << 2));
  GPIOF_BSRR    =    1uL          <<  (RAM_A2_BIT + 16);          // Set to low logic level.
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK <<  (RAM_A2_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    <<  (RAM_A2_BIT << 1);
  //
  // Write protect pin (WP).
  //
  GPIOF_MODER   &= ~(MODER_MASK   <<  (RAM_WP_BIT << 1));
  GPIOF_AFRL    &= ~(AFR_MASK     <<  (RAM_WP_BIT << 2));
  GPIOF_BSRR    =    1uL          <<  (RAM_WP_BIT + 16);          // Set to low logic level to disable the write protection.
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK <<  (RAM_WP_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    <<  (RAM_WP_BIT << 1);
  return 0;
}

/*********************************************************************
*
*       _HW_Start
*
*  Function description
*    Start an I2C transaction.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    Addr           Address of the device to be accessed.
*    IsRead         Type of operation to be executed.
*                   * 0 - Write operation.
*                   * 1 - Read operation.
*
*  Return value
*    ==0      OK, transaction successfully started.
*    !=0      An error occurred.
*/
static int _HW_Start(U8 Unit, unsigned Addr, int IsRead) {
  int r;
  U8  AddrByte;

  FS_USE_PARA(Unit);
  AddrByte = (U8)(Addr << 1);
  if (IsRead != 0) {
    AddrByte |= 1u;
  }
  RAM_SET_SDA();
  RAM_SET_SCL();
  RAM_DELAY();            // Wait tBUF
  RAM_CLR_SDA();
  RAM_DELAY();            // Wait tHD;STA
  RAM_CLR_SCL();
  r = _WriteByte(AddrByte);
  if (r != 0) {
    return 1;
  }
  return 0;
}

/*********************************************************************
*
*       _HW_Stop
*
*  Function description
*    Ends an I2C transaction.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*
*  Return value
*    ==0      OK, transaction successfully ended.
*    !=0      An error occurred.
*/
static int _HW_Stop(U8 Unit) {
  FS_USE_PARA(Unit);
  RAM_CLR_SDA();
  RAM_DELAY();            // Wait tLOW
  RAM_SET_SCL();
  RAM_DELAY();            // Wait tSU;STO
  RAM_SET_SDA();
  return 0;
}

/*********************************************************************
*
*       _HW_Read
*
*  Function description
*    Transfers data from I2C device to MCU.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pData          [OUT] Data read from I2C device.
*    NumBytes       Number of bytes to transfer.
*
*  Return value
*    ==0      OK, data successfully transferred.
*    !=0      An error occurred.
*/
static int _HW_Read(U8 Unit, U8 * pData, U32 NumBytes) {
  FS_USE_PARA(Unit);
  if (NumBytes != 0u) {
    --NumBytes;
    if (NumBytes != 0) {
      do {
        *pData++ = _ReadByte(1);
      } while (--NumBytes != 0u);
    }
    *pData = _ReadByte(0);
  }
  return 0;
}

/*********************************************************************
*
*       _HW_Write
*
*  Function description
*    Transfers data from MCU to I2C device.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pData          [IN] Data written to I2C device.
*    NumBytes       Number of bytes to transfer.
*
*  Return value
*    ==0      OK, data successfully transferred.
*    !=0      An error occurred.
*/
static int _HW_Write(U8 Unit, const U8 * pData, U32 NumBytes) {
  int r;

  FS_USE_PARA(Unit);
  r = 0;                  // Set to indicate success.
  if (NumBytes != 0u) {
    do {
      r = _WriteByte(*pData++);
      if (r != 0) {
        break;
      }
    } while (--NumBytes != 0u);
  }
  return r;
}

/*********************************************************************
*
*       Public data
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator
*/
const FS_RAMDISK_HW_TYPE_I2C FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator = {
  _HW_Init,
  _HW_Start,
  _HW_Stop,
  _HW_Read,
  _HW_Write
};

/*************************** End of file ****************************/
Hardware layer API - FS_RAMDISK_HW_TYPE_SPI

This hardware layer supports serial RAM devices that are interfaced via SPI. The functions of this hardware layer are grouped in a structure of type FS_RAMDISK_HW_TYPE_SPI. The following sections describe these functions in detail.

FS_RAMDISK_HW_TYPE_SPI

Description

HW layer for RAM devices connected via SPI (single, dual, quad or octal).

Type definition

typedef struct {
  FS_RAMDISK_HW_TYPE_SPI_INIT    * pfInit;
  FS_RAMDISK_HW_TYPE_SPI_UNMAP   * pfUnmap;
  FS_RAMDISK_HW_TYPE_SPI_MAP     * pfMap;
  FS_RAMDISK_HW_TYPE_SPI_CONTROL * pfControl;
  FS_RAMDISK_HW_TYPE_SPI_READ    * pfRead;
  FS_RAMDISK_HW_TYPE_SPI_WRITE   * pfWrite;
  FS_RAMDISK_HW_TYPE_SPI_LOCK    * pfLock;
  FS_RAMDISK_HW_TYPE_SPI_UNLOCK  * pfUnlock;
} FS_RAMDISK_HW_TYPE_SPI;

Structure members

Member Description
pfInit Initializes the hardware.
pfUnmap Configures the hardware for direct access to serial RAM device.
pfMap Configures the hardware for access to serial RAM device via system memory.
pfControl Sends a command to serial RAM device that does not transfer any data.
pfRead Transfers data from serial RAM device to MCU.
pfWrite Transfers data from MCU to serial RAM device.
pfLock Requests exclusive access to SPI bus.
pfUnlock Releases the exclusive access to SPI bus.
FS_RAMDISK_HW_TYPE_SPI_INIT

Description

Initializes the SPI hardware.

Type definition

typedef int FS_RAMDISK_HW_TYPE_SPI_INIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).

Return value

> 0 OK, frequency of the SPI clock in Hz.
= 0 An error occurred.

Additional information

This function is a member of the SPI RAMDISK hardware layer API. It has to be implemented by all the hardware layers.

This function is called by the SPI RAMDISK physical layer before any other function of the hardware layer each time the file system mounts the serial RAM deice. FS_RAMDISK_HW_TYPE_SPI_INIT has to perform the initialization of clock signals, GPIO ports, SPI controller, etc.

FS_RAMDISK_HW_TYPE_SPI_UNMAP

Description

Configures the hardware for direct access to serial RAM device.

Type definition

typedef int FS_RAMDISK_HW_TYPE_SPI_UNMAP(U8 Unit);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).

Return value

= 0 OK, direct mode configured successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the SPI RAMDISK hardware layer API. It has to be implemented by all the hardware layers.

The physical layer calls this function before it starts sending commands directly to the serial RAM device. Typically, the SPI hardware can operate in two modes: command and memory. In command mode the physical layer can access the serial RAM device directly by sending commands to it. In the memory mode the SPI hardware translates read accesses to an assigned memory region to serial RAM device read commands. In this way, the contents of the contents of the serial RAM device is mapped into this memory region.

If the command and memory mode are mutually exclusive, FS_NOR_HW_TYPE_SPIFI_UNMAP has to disable the memory mode.

FS_RAMDISK_HW_TYPE_SPI_MAP

Description

Configures the hardware for access to serial RAM device via system memory.

Type definition

typedef int FS_RAMDISK_HW_TYPE_SPI_MAP(      U8       Unit,
                                       const U8     * pCmd,
                                             unsigned NumBytesCmd,
                                       const U8     * pPara,
                                             unsigned NumBytesPara,
                                             unsigned NumBytesAddr,
                                             U16      BusWidth,
                                             unsigned Flags);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pCmd  in  Code of the command to be used for reading the data. Cannot be NULL.
NumBytesCmd Number of bytes in the command code. Cannot be 0.
pPara  in  Command parameters (address and dummy bytes). Can be NULL.
NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
NumBytesAddr Number of address bytes to be send. Can be 0.
BusWidth Number of data lines to be used for the data transfer.
Flags Options for the data exchange.

Return value

= 0 OK, memory mode configured successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the SPI RAMDISK hardware layer API. The implementation of this function is mandatory if the SPI hardware supports the access to RAM device via system memory. If FS_RAMDISK_HW_TYPE_SPI_MAP is not provided then the SPI RAMDISK physical layer accesses the RAM device in command mode.

Flags is a bitwise-or combination of RAMDISK HW layer flags.

FS_RAMDISK_HW_TYPE_SPI_CONTROL

Description

Sends a command to serial RAM device that does not transfer any data.

Type definition

typedef int FS_RAMDISK_HW_TYPE_SPI_CONTROL(      U8       Unit,
                                           const U8     * pCmd,
                                                 unsigned NumBytesCmd,
                                                 U8       BusWidth,
                                                 unsigned Flags);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pCmd  in  Code of the command to be sent. Cannot be NULL.
NumBytesCmd Number of bytes in the command code. Cannot be 0.
BusWidth Number of data lines to be used for sending the command.
Flags Options for the data exchange.

Return value

= 0 OK, command transferred successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the SPI RAMDISK hardware layer API. The implementation of this function is mandatory.

Flags is a bitwise-or combination of RAMDISK HW layer flags.

The value of BusWidth is not encoded as is the case with the other functions of this physical layer. The value specified via BusWith is the actual number of data lines that have to be used for the data transfer of the command code. Permitted values are 1, 2, 4 and 8.

FS_RAMDISK_HW_TYPE_SPI_READ

Description

Transfers data from serial RAM device to MCU.

Type definition

typedef int FS_RAMDISK_HW_TYPE_SPI_READ(      U8       Unit,
                                        const U8     * pCmd,
                                              unsigned NumBytesCmd,
                                        const U8     * pPara,
                                              unsigned NumBytesPara,
                                              unsigned NumBytesAddr,
                                              U8     * pData,
                                              unsigned NumBytesData,
                                              U16      BusWidth,
                                              unsigned Flags);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pCmd  in  Code of the command to be sent. Cannot be NULL.
NumBytesCmd Number of bytes in the command code. Cannot be 0.
pPara  in  Command parameters (address and dummy bytes). Can be NULL.
NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
NumBytesAddr Number of address bytes to be send. Can be 0.
pData  out  Data read from the serial RAM device. Can be NULL.
NumBytesData Number of bytes to read from the serial RAM device. Can be 0.
BusWidth Number of data lines to be used for the data transfer.
Flags Options for the data exchange.

Return value

= 0 OK, data transferred successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the SPI RAMDISK hardware layer API. The implementation of this function is mandatory.

The first address byte is stored at *pPara. NumBytesAddr is always smaller than or equal to NumBytesPara. If NumBytesAddr is equal to NumBytesPara then neither mode nor dummy bytes have to be sent. The number of dummy bytes to be generated can be calculated as NumBytesPara - NumBytesAddr. If the hardware generates dummy cycles instead of bytes then the number of dummy bytes has to converted to clock cycles by taking into account the number of data lines used for the data transfer of the address.

Flags is a bitwise-or combination of RAMDISK HW layer flags.

FS_RAMDISK_HW_TYPE_SPI_WRITE

Description

Transfers data from MCU to serial RAM device.

Type definition

typedef int FS_RAMDISK_HW_TYPE_SPI_WRITE(      U8       Unit,
                                         const U8     * pCmd,
                                               unsigned NumBytesCmd,
                                         const U8     * pPara,
                                               unsigned NumBytesPara,
                                               unsigned NumBytesAddr,
                                         const U8     * pData,
                                               unsigned NumBytesData,
                                               U16      BusWidth,
                                               unsigned Flags);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pCmd  in  Code of the command to be sent. Cannot be NULL.
NumBytesCmd Number of bytes in the command code. Cannot be 0.
pPara  in  Command parameters (address and dummy bytes). Can be NULL.
NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
NumBytesAddr Number of address bytes to be send. Can be 0.
pData  in  Data to be sent to the serial RAM device. Can be NULL.
NumBytesData Number of bytes to be written the serial RAM device. Can be 0.
BusWidth Number of data lines to be used for the data transfer.
Flags Options for the data exchange.

Return value

= 0 OK, data transferred successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the SPI RAMDISK hardware layer API. The implementation of this function is mandatory.

The first address byte is stored at *pPara. NumBytesAddr is always smaller than or equal to NumBytesPara.

Flags is a bitwise-or combination of RAMDISK HW layer flags.

FS_RAMDISK_HW_TYPE_SPI_LOCK

Description

Requests exclusive access to SPI bus.

Type definition

typedef void FS_RAMDISK_HW_TYPE_SPI_LOCK(U8 Unit);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).

Additional information

This function is a member of the SPIFI NOR hardware layer API. The implementation of this function is optional.

The NOR physical layer calls this function to indicate that it needs exclusive to access the NOR flash device via the SPI bus. It is guaranteed that the NOR physical layer does not attempt to exchange any data with the serial NOR flash device via the SPI bus before calling this function first. It is also guaranteed that FS_RAMDISK_HW_TYPE_SPI_LOCK and FS_RAMDISK_HW_TYPE_SPI_UNLOCK are called in pairs. Typically, this function is used for synchronizing the access to SPI bus when the SPI bus is shared between the serial NOR flash and other SPI devices.

A possible implementation would make use of an OS semaphore that is acquired in FS_RAMDISK_HW_TYPE_SPI_LOCK and released in FS_RAMDISK_HW_TYPE_SPI_UNLOCK.

FS_RAMDISK_HW_TYPE_SPI_UNLOCK

Description

Requests exclusive access to SPI bus.

Type definition

typedef void FS_RAMDISK_HW_TYPE_SPI_UNLOCK(U8 Unit);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).

Additional information

This function is a member of the SPIFI NOR hardware layer API. The implementation of this function is optional.

The NOR physical layer calls this function when it no longer needs to access the serial NOR flash device via the SPI bus. It is guaranteed that the NOR physical layer does not attempt to exchange any data with the serial NOR flash device via the SPI bus before calling FS_RAMDISK_HW_TYPE_SPI_LOCK. It is also guaranteed that FS_RAMDISK_HW_TYPE_SPI_UNLOCK and FS_RAMDISK_HW_TYPE_SPI_LOCK are called in pairs.

FS_RAMDISK_HW_TYPE_SPI_UNLOCK and FS_RAMDISK_HW_TYPE_SPI_LOCK can be used to synchronize the access to the SPI bus when other devices than the serial NOR flash are connected to it. A possible implementation would make use of an OS semaphore that is acquired FS_RAMDISK_HW_TYPE_SPI_LOCK and released in FS_RAMDISK_HW_TYPE_SPI_UNLOCK.

Sample implementation

The following sample implementation uses the QUADSPI controller of an ST STM32H743 MCU to interface with a SPI RAM device. This RAMDISK hardware layer was tested on the SGGER QSPI Flash Evaluator board (https://www.segger.com/evaluate-our-software/segger/qspi-flash-evaluator/)

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator.c
Purpose : Hardware layer for SEGGER QSPI Flash Evaluator
          with RAM device connected via SPI.
Literature:
  [1] RM0433 Reference manual STM32H7x3 advanced ARM-based 32-bit MCUs
  [2] STM32H753xI Errata sheet STM32H753xI rev Y device limitations
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/
#include "FS.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#ifndef   FS_RAMDISK_HW_PER_CLK_HZ
  #define FS_RAMDISK_HW_PER_CLK_HZ              240000000     // Clock of Quad-SPI unit.
#endif

#ifndef   FS_RAMDISK_HW_RAM_CLK_HZ
  #define FS_RAMDISK_HW_RAM_CLK_HZ              48000000      // Frequency of the clock supplied to RAM device.
#endif

#ifndef   FS_RAMDISK_HW_QUADSPI_MEM_ADDR
  #define FS_RAMDISK_HW_QUADSPI_MEM_ADDR        0x90000000    // This is the start address of the memory region used by the file system
                                                              // to read the data from the serial RAM device. The hardware layer
                                                              // uses this address to invalidate the data cache.
#endif

#ifndef   FS_RAMDISK_HW_USE_QUAD_MODE
  #define FS_RAMDISK_HW_USE_QUAD_MODE           1             // Enables/disables the support for quad mode.
#endif

#ifndef   FS_RAMDISK_HW_USE_MEM_MAP_MODE
  #define FS_RAMDISK_HW_USE_MEM_MAP_MODE        1             // Enables or disables the access to the RAM device data via system memory.
#endif

#ifndef   FS_RAMDISK_HW_RESET_TIME_MS
  #define FS_RAMDISK_HW_RESET_TIME_MS           10            // Number milliseconds to keep the reset line low.
#endif

/*********************************************************************
*
*       Defines, fixed
*
**********************************************************************
*/

/*********************************************************************
*
*       QSPI registers
*/
#define QUADSPI_BASE_ADDR       0x52005000uL
#define QUADSPI_CR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x00))
#define QUADSPI_DCR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x04))
#define QUADSPI_SR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x08))
#define QUADSPI_FCR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x0C))
#define QUADSPI_DLR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x10))
#define QUADSPI_CCR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x14))
#define QUADSPI_AR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x18))
#define QUADSPI_ABR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x1C))
#define QUADSPI_DR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_DR_BYTE         (*(volatile U8  *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_PSMKR           (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x24))
#define QUADSPI_PSMAR           (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x28))
#define QUADSPI_PIR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x2C))
#define QUADSPI_LPTR            (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x30))

/*********************************************************************
*
*       Port B registers
*/
#define GPIOB_BASE_ADDR         0x58020400uL
#define GPIOB_MODER             (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x00))
#define GPIOB_OSPEEDR           (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x08))
#define GPIOB_PUPDR             (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x0C))
#define GPIOB_ODR               (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x14))
#define GPIOB_AFRL              (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x20))

/*********************************************************************
*
*       Port F registers
*/
#define GPIOF_BASE_ADDR         0x58021400uL
#define GPIOF_MODER             (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x00))
#define GPIOF_OSPEEDR           (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x08))
#define GPIOF_PUPDR             (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x0C))
#define GPIOF_ODR               (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x14))
#define GPIOF_BSRR              (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x18))
#define GPIOF_AFRL              (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x20))
#define GPIOF_AFRH              (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x24))

/*********************************************************************
*
*       Reset and clock control
*/
#define RCC_BASE_ADDR           0x58024400uL
#define RCC_AHB3RSTR            (*(volatile U32*)(RCC_BASE_ADDR + 0x7C))
#define RCC_AHB3ENR             (*(volatile U32*)(RCC_BASE_ADDR + 0xD4))
#define RCC_AHB4ENR             (*(volatile U32*)(RCC_BASE_ADDR + 0xE0))

/*********************************************************************
*
*       System Control Block
*/
#define SCB_BASE_ADDR           0xE000E000uL
#define SCB_CCR                 (*(volatile U32 *)(SCB_BASE_ADDR + 0xD14))    // Configuration Control Register

/*********************************************************************
*
*       Memory protection unit
*/
#define MPU_BASE_ADDR           0xE000ED90uL
#define MPU_TYPE                (*(volatile U32 *)(MPU_BASE_ADDR + 0x00))
#define MPU_CTRL                (*(volatile U32 *)(MPU_BASE_ADDR + 0x04))
#define MPU_RNR                 (*(volatile U32 *)(MPU_BASE_ADDR + 0x08))
#define MPU_RBAR                (*(volatile U32 *)(MPU_BASE_ADDR + 0x0C))
#define MPU_RASR                (*(volatile U32 *)(MPU_BASE_ADDR + 0x10))

/*********************************************************************
*
*       Masks for the peripheral enable bits
*/
#define AHB1ENR_GPIOBEN         1
#define AHB1ENR_GPIOFEN         5
#define AHB3ENR_QSPIEN          14

/*********************************************************************
*
*       GPIO bit positions of SPI signals
*/
#define RAM_BK1_NCS_BIT         6   // Port B
#define RAM_CLK_BIT             10  // Port F
#define RAM_BK1_D0_BIT          8   // Port F
#define RAM_BK1_D1_BIT          9   // Port F
#define RAM_BK1_D2_BIT          7   // Port F
#define RAM_BK1_D3_BIT          6   // Port F
#define RAM_MP6_BIT             3   // Port F
#define RAM_RST_BIT             11  // Port F

/*********************************************************************
*
*       GPIO bits and masks
*/
#define OSPEEDR_HIGH            2uL
#define OSPEEDR_MASK            0x3uL
#define MODER_MASK              0x3uL
#define MODER_OUT               1uL
#define MODER_ALT               2uL
#define AFR_MASK                0xFuL

/*********************************************************************
*
*       Quad-SPI control register
*/
#define CR_EN_BIT               0
#define CR_ABORT_BIT            1
#define CR_SSHIFT_BIT           4
#define CR_SMIE_BIT             19
#define CR_APMS_BIT             22
#define CR_PRESCALER_BIT        24
#define CR_PRESCALER_MAX        255

/*********************************************************************
*
*       Quad-SPI device configuration register
*/
#define DCR_CKMODE_BIT          0
#define DCR_FSIZE_BIT           16
#define DCR_FSIZE_MAX           0x1FuL

/*********************************************************************
*
*       Quad-SPI status register
*/
#define SR_TEF_BIT              0
#define SR_TCF_BIT              1
#define SR_SMF_BIT              3
#define SR_TOF_BIT              4
#define SR_BUSY_BIT             5
#define SR_FLEVEL_BIT           8
#define SR_FLEVEL_MASK          0x3FuL

/*********************************************************************
*
*       Quad-SPI communication configuration register
*/
#define CCR_INTRUCTION_BIT      0
#define CCR_IMODE_BIT           8
#define CCR_MODE_NONE           0
#define CCR_MODE_SINGLE         1uL
#define CCR_MODE_DUAL           2uL
#define CCR_MODE_QUAD           3uL
#define CCR_ADMODE_BIT          10
#define CCR_ADSIZE_BIT          12
#define CCR_ADSIZE_MASK         0x03uL
#define CCR_ABMODE_BIT          14
#define CCR_ABSIZE_BIT          16
#define CCR_ABSIZE_MASK         0x03uL
#define CCR_DCYC_BIT            18
#define CCR_DMODE_BIT           24
#define CCR_FMODE_BIT           26
#define CCR_FMODE_WRITE         0x0uL
#define CCR_FMODE_READ          0x1uL
#define CCR_FMODE_POLL          0x2uL
#define CCR_FMODE_MMAP          0x3uL
#define CCR_FMODE_MASK          0x3uL
#define CCR_DDRM_BIT            31

/*********************************************************************
*
*       MPU defines
*/
#define CTRL_ENABLE_BIT         0
#define CTRL_PRIVDEFENA_BIT     2
#define RNR_REGION_MASK         0xFF
#define RASR_ENABLE_BIT         0
#define RASR_SIZE_BIT           1
#define RASR_TEX_BIT            19
#define RASR_AP_BIT             24
#define RASR_XN_BIT             28
#define RASR_AP_FULL            0x3uL
#define TYPE_DREGION_BIT        8
#define TYPE_DREGION_MASK       0xFFuL
#define RBAR_REGION_BIT         0
#define RBAR_REGION_MASK        0x1FuL
#define RBAR_VALID_BIT          5

/*********************************************************************
*
*       Misc. defines
*/
#define NUM_BYTES_FIFO          32
#define CCR_DC_BIT              16
#define QUADSPI_MEM_SIZE_SHIFT  28                // Size of the memory region reserved for QUADSPI (256 MB)
#define QUADSPI_PRIO            15
#define CYCLES_PER_MS           150000            // Depends on the CPU clock frequency.
#define WAIT_TIMEOUT_MS         500
#define WAIT_TIMEOUT_CYCLES     (WAIT_TIMEOUT_MS * CYCLES_PER_MS)

/*********************************************************************
*
*      Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _CalcClockDivider
*
*  Function description
*    Calculates the divider for the clock supplied to RAM device.
*/
static U8 _CalcClockDivider(U32 * pFreq_Hz) {
  U8  Div;
  U32 Freq_Hz;
  U32 MaxFreq_Hz;

  Div        = 0;
  MaxFreq_Hz = *pFreq_Hz;
  for (;;) {
    Freq_Hz = FS_RAMDISK_HW_PER_CLK_HZ / (Div + 1);
    if (Freq_Hz <= MaxFreq_Hz) {
      break;
    }
    ++Div;
    if (Div == CR_PRESCALER_MAX) {
      break;
    }
  }
  *pFreq_Hz = Freq_Hz;
  return Div;
}

/*********************************************************************
*
*       _GetMode
*
*  Function description
*    Returns the transfer mode for the QUADSPI peripheral.
*/
static U32 _GetMode(unsigned BusWidth, U32 NumBytes) {
  U32 Mode;

  Mode = CCR_MODE_NONE;
  if (NumBytes) {
    switch (BusWidth) {
    case 1:
      Mode = CCR_MODE_SINGLE;
      break;
    case 2:
      Mode = CCR_MODE_DUAL;
      break;
    case 4:
      Mode = CCR_MODE_QUAD;
      break;
    default:
      break;
    }
  }
  return Mode;
}

/*********************************************************************
*
*       _CalcNumCycles
*
*  Function description
*    Calculates the number of clock cycles required to transfer a specified number of bytes.
*/
static U32 _CalcNumCycles(unsigned BusWidth, U32 NumBytes, int IsDTRMode) {
  U32 NumCycles;

  NumCycles = 0;
  if (NumBytes != 0) {
    NumCycles = NumBytes << 3;        // Assume 8-bits per byte.
    switch (BusWidth) {
    case 2:
      NumCycles >>= 1;
      break;
    case 4:
      NumCycles >>= 2;
      break;
    default:
      break;
    }
    if (IsDTRMode != 0) {
      NumCycles >>= 1;                // The data is sent on both clock edges.
    }
  }
  return NumCycles;
}

/*********************************************************************
*
*       _ClearFlags
*
*  Function description
*    Clears the status flags of QUADSPI peripheral.
*/
static int _ClearFlags(void) {
  U32 TimeOut;
  int r;

  QUADSPI_FCR = 0
              | (1uL << SR_TEF_BIT)
              | (1uL << SR_TCF_BIT)
              | (1uL << SR_SMF_BIT)
              | (1uL << SR_TOF_BIT)
              ;
  //
  // Wait for the flags to be cleared.
  //
  r       = 0;
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & ((1uL << SR_TEF_BIT) |
                       (1uL << SR_TCF_BIT) |
                       (1uL << SR_SMF_BIT) |
                       (1uL << SR_TOF_BIT))) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                    // Error, could not clear flags.
      break;
    }
  }
  return r;
}

/*********************************************************************
*
*       _Cancel
*
*  Function description
*    Interrupts an ongoing data transfer.
*/
static int _Cancel(void) {
  U32 TimeOut;
  int r;

  r       = 0;
  TimeOut = WAIT_TIMEOUT_CYCLES;
  QUADSPI_CR |= 1uL << CR_ABORT_BIT;
  for (;;) {
    if ((QUADSPI_CR & (1uL << CR_ABORT_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                    // Error, could not cancel data transfer.
      break;
    }
  }
  return r;
}

/*********************************************************************
*
*       _DisableDCache
*
*  Function description
*    Disables the data cache for the memory region where the RAM device is mapped.
*/
static void _DisableDCache(void) {
  U32 NumRegions;
  U32 iRegion;
  U32 Mask;

  if (SCB_CCR & (1uL << CCR_DC_BIT)) {      // Is data cache enabled?
    NumRegions = (MPU_TYPE >> TYPE_DREGION_BIT) & TYPE_DREGION_MASK;
    //
    // Find the next free region.
    //
    for (iRegion = 0; iRegion < NumRegions; ++iRegion) {
      MPU_RNR = iRegion;
      if ((MPU_RASR & (1uL << RASR_ENABLE_BIT)) == 0) {
        break;            // Found a free region.
      }
      //
      // Check if we already configured the MPU.
      //
      Mask = 0uL
           | (RBAR_REGION_MASK << RBAR_REGION_BIT)
           | (1uL              << RBAR_VALID_BIT)
           ;
      if ((MPU_RBAR & ~Mask) == FS_RAMDISK_HW_QUADSPI_MEM_ADDR) {
        iRegion = NumRegions;
        break;            // Already configured.
      }
    }
    if (iRegion < NumRegions) {
      //
      // Use MPU to disable the data cache on the memory region assigned to QSPI.
      //
      MPU_CTRL &= ~(1uL << CTRL_ENABLE_BIT);      // Disable MPU first.
      MPU_RNR   = iRegion & RNR_REGION_MASK;
      MPU_RBAR  = FS_RAMDISK_HW_QUADSPI_MEM_ADDR;
      MPU_RASR  = 0
                | (1uL                          << RASR_XN_BIT)
                | (RASR_AP_FULL                 << RASR_AP_BIT)
                | (1uL                          << RASR_TEX_BIT)
                | ((QUADSPI_MEM_SIZE_SHIFT - 1) << RASR_SIZE_BIT)
                | (1uL                          << RASR_ENABLE_BIT)
                ;
      //
      // Enable MPU.
      //
      MPU_CTRL |= 0
               | (1uL << CTRL_PRIVDEFENA_BIT)
               | (1uL << CTRL_ENABLE_BIT)
               ;
    }
  }
}

/*********************************************************************
*
*      Static code (public via callback)
*
**********************************************************************
*/

/*********************************************************************
*
*       _HW_Init
*
*  Function description
*    Initializes the SPI hardware.
*
*  Parameters
*    Unit       Index of the hardware layer (0-based).
*
*  Return value
*    > 0      OK, frequency of the SPI clock in Hz.
*    ==0      An error occurred.
*/
static int _HW_Init(U8 Unit) {
  U32 Div;
  U32 Freq_Hz;

  FS_USE_PARA(Unit);
  //
  // Enable the clocks of peripherals and reset them.
  //
  RCC_AHB4ENR  |= 0
               | (1uL << AHB1ENR_GPIOBEN)
               | (1uL << AHB1ENR_GPIOFEN)
               ;
  RCC_AHB3ENR  |=   1uL << AHB3ENR_QSPIEN;
  RCC_AHB3RSTR |=   1uL << AHB3ENR_QSPIEN;
  RCC_AHB3RSTR &= ~(1uL << AHB3ENR_QSPIEN);
  //
  // Wait for the unit to exit reset.
  //
  for (;;) {
    if ((RCC_AHB3RSTR & (1uL << AHB3ENR_QSPIEN)) == 0) {
      break;
    }
  }
  //
  // Disable the cache on the memory region assigned to QSPI.
  //
  _DisableDCache();
  //
  // NCS of bank 1 is an output signal and is controlled by the QUADSPI unit.
  //
  GPIOB_MODER   &= ~(MODER_MASK   << (RAM_BK1_NCS_BIT << 1));
  GPIOB_MODER   |=   MODER_ALT    << (RAM_BK1_NCS_BIT << 1);
  GPIOB_AFRL    &= ~(AFR_MASK     << (RAM_BK1_NCS_BIT << 2));
  GPIOB_AFRL    |=   0xAuL        << (RAM_BK1_NCS_BIT << 2);
  GPIOB_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_NCS_BIT << 1));
  GPIOB_OSPEEDR |=   OSPEEDR_HIGH << (RAM_BK1_NCS_BIT << 1);
  //
  // CLK is an output signal controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_CLK_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (RAM_CLK_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_CLK_BIT - 8) << 2));
  GPIOF_AFRH    |=   0x9uL        << ((RAM_CLK_BIT - 8) << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_CLK_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (RAM_CLK_BIT << 1);
  //
  // D0 of bank 1 is an input/output signal controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_BK1_D0_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (RAM_BK1_D0_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_BK1_D0_BIT - 8) << 2));
  GPIOF_AFRH    |=   0xAuL        << ((RAM_BK1_D0_BIT - 8) << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D0_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (RAM_BK1_D0_BIT << 1);
  //
  // D1 of bank 1 is an input/output signal controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_BK1_D1_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (RAM_BK1_D1_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_BK1_D1_BIT - 8) << 2));
  GPIOF_AFRH    |=   0xAuL        << ((RAM_BK1_D1_BIT - 8) << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D1_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (RAM_BK1_D1_BIT << 1);
#if FS_RAMDISK_HW_USE_QUAD_MODE
  //
  // D2 of bank 1 is an input/output signal and is controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_BK1_D2_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (RAM_BK1_D2_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (RAM_BK1_D2_BIT << 2));
  GPIOF_AFRL    |=   0x9uL        << (RAM_BK1_D2_BIT << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D2_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (RAM_BK1_D2_BIT << 1);
  //
  // D3 of bank 1 is an output signal and is controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_BK1_D3_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (RAM_BK1_D3_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (RAM_BK1_D3_BIT << 2));
  GPIOF_AFRL    |=   0x9uL        << (RAM_BK1_D3_BIT << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D3_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (RAM_BK1_D3_BIT << 1);
#else
  //
  // D2 and D3 are used as WP and HOLD signals when the quad mode
  // is disabled in the RAM device. We set these signals to
  // logic high here so that the data transfer works correctly
  // in single and dual mode.
  //
  GPIOF_BSRR    = 1uL << RAM_BK1_D2_BIT;
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_BK1_D2_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    << (RAM_BK1_D2_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (RAM_BK1_D2_BIT << 2));
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D2_BIT << 1));
  GPIOF_BSRR    = 1uL << RAM_BK1_D3_BIT;
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_BK1_D3_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    << (RAM_BK1_D3_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (RAM_BK1_D3_BIT << 2));
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D3_BIT << 1));
#endif // FS_RAMDISK_HW_USE_QUAD_MODE
  //
  // The MP6 is the signal connected to the pin 6 of the RAM device
  // which is used by some dual stack devices as the chip select signal
  // for the second stack. We have to disable the second stack
  // by setting the MP6 signal to high in order to prevent that the
  // second stack is accidentally activated.
  //
  GPIOF_BSRR    = 1uL << RAM_MP6_BIT;
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_MP6_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    << (RAM_MP6_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (RAM_MP6_BIT << 2));
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_MP6_BIT << 1));
  //
  // Set the RST signal to high to make sure that the RAM
  // device is not accidentally reset during the data transfer.
  //
  GPIOF_BSRR    = 1uL << RAM_RST_BIT;
  GPIOF_MODER   &= ~(MODER_MASK   << (RAM_RST_BIT << 1));
  GPIOF_MODER   |=   MODER_OUT    << (RAM_RST_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((RAM_RST_BIT - 8) << 2));
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_RST_BIT << 1));
  //
  // Initialize the Quad-SPI controller.
  //
  Freq_Hz = FS_RAMDISK_HW_RAM_CLK_HZ;
  Div = (U32)_CalcClockDivider(&Freq_Hz);
  QUADSPI_CR  = 0
              | (1uL << CR_EN_BIT)                        // Enable the Quad-SPI unit.
              | (Div << CR_PRESCALER_BIT)
              ;
  QUADSPI_DCR = 0
              | (1uL           << DCR_CKMODE_BIT)         // CLK signal stays HIGH when the RAM device is not selected.
              | (DCR_FSIZE_MAX << DCR_FSIZE_BIT)          // We set the size of the RAM device to maximum because the actual capacity is not known at this stage.
              ;
#if FS_RAMDISK_HW_RESET_TIME_MS
  {
    volatile U32 NumCycles;

    GPIOF_BSRR = 1uL << (RAM_RST_BIT + 16);               // Put the RAM device into reset state by setting the signal to low.
    NumCycles = FS_RAMDISK_HW_RESET_TIME_MS * CYCLES_PER_MS;
    do {
      ;
    } while (--NumCycles != 0u);
    GPIOF_BSRR = 1uL << RAM_RST_BIT;                      // Release the RAM device from the reset state by setting reset signal to high.
    NumCycles = FS_RAMDISK_HW_RESET_TIME_MS * CYCLES_PER_MS;
    do {
      ;
    } while (--NumCycles != 0u);
  }
#endif // FS_RAMDISK_HW_RESET_TIME_MS
  return (int)Freq_Hz;
}

/*********************************************************************
*
*       _HW_Unmap
*
*  Function description
*    Enables the direct access to RAM device.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*
*  Return value
*    ==0      OK, command mode configured successfully.
*    !=0      An error occurred.
*
*  Additional information
*    This function disables the memory-mapped mode.
*/
static int _HW_Unmap(U8 Unit) {
  int r;

  FS_USE_PARA(Unit);            // This device has only one HW unit.
  r = 0;
  //
  // Restore the default sampling mode.
  //
  QUADSPI_CR &= ~(1uL << CR_SSHIFT_BIT);
  //
  // Cancel the memory mode so that the BUSY bit goes to 0
  // and we can write to QUADSPI_CCR register.
  //
  if ((QUADSPI_CCR & (CCR_FMODE_MASK << CCR_FMODE_BIT)) == (CCR_FMODE_MMAP << CCR_FMODE_BIT)) {
    r = _Cancel();
  }
  return r;
}

#if FS_RAMDISK_HW_USE_MEM_MAP_MODE

/*********************************************************************
*
*       _HW_Map
*
*  Function description
*    Configures the hardware for access to serial RAM device via system memory.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pCmd           [IN] Code of the command to be used for reading the data. Cannot be NULL.
*    NumBytesCmd    Number of bytes in the command code. Cannot be 0.
*    pPara          [IN] Command parameters (address and dummy bytes). Can be NULL.
*    NumBytesPara   Total number of address and dummy bytes to be sent. Can be 0.
*    NumBytesAddr   Number of address bytes to be send. Can be 0.
*    BusWidth       Number of data lines to be used for the data transfer.
*    Flags          Options for the data exchange.
*
*  Return value
*    ==0      OK, memory mode configured successfully.
*    !=0      An error occurred.
*/
static int _HW_Map(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara,
                   unsigned NumBytesPara, unsigned NumBytesAddr, U16 BusWidth, unsigned Flags) {
  U32 CfgReg;
  U32 CmdMode;
  U32 AddrMode;
  U32 DataMode;
  U32 NumDummyCycles;
  U32 AddrSize;
  U32 IsDTR;
  U32 AltMode;
  U32 AltSize;
  U32 NumBytesAlt;
  U32 NumBytes;
  U32 AltReg;
  int r;
  U32 TimeOut;

  FS_USE_PARA(Unit);                                                                // This MCU has only one QSPI controller.
  FS_USE_PARA(pPara);
  FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u);                              // The QSPI controller is able to handle only 1-byte commands.
  //
  // Fill local variables.
  //
  r           = 0;
  AltReg      = 0;
  NumBytesAlt = NumBytesPara - NumBytesAddr;
  //
  // Calculate the transfer mode.
  //
  IsDTR = 0;
  if (   ((Flags & FS_RAMDISK_HW_FLAG_DTR_ADDR) != 0u)
      || ((Flags & FS_RAMDISK_HW_FLAG_DTR_DATA) != 0u)) {
    IsDTR = 1;
  }
  //
  // Encode the mode and dummy bytes.
  //
  NumDummyCycles = 0;
  if (NumBytesAlt != 0) {
    NumBytes = NumBytesAlt;
    //
    // Check if a mode byte has to be sent and if yes encode its value.
    //
    if ((Flags & FS_RAMDISK_HW_FLAG_MODE_8BIT) != 0u) {
      NumBytes    = NumBytesAlt - 1u;
      NumBytesAlt = 1;                                                              // We never send more than one mode byte.
      if (pPara != NULL) {
        AltReg = (U32)*pPara;
      } else {
        AltReg = 0xFFuL;
      }
    } else {
      NumBytesAlt = 0;
    }
    if (NumBytes != 0u) {
      //
      // The remaining alternate bytes are not sent. Instead, we generate dummy cycles.
      //
      NumDummyCycles = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytes, IsDTR);
    }
  }
  //
  // It seems that QUADSPI is driving the data lines one half of the clock
  // cycle longer than required. This can cause that a wrong value is
  // sampled immediately after a data line is switched from output to input.
  // For this reason we configure QUADSPI to sample the data later than default.
  //
  if ((IsDTR == 0) && (NumBytesAlt != 0) && (NumDummyCycles == 0) ) {
    QUADSPI_CR |= 1uL << CR_SSHIFT_BIT;
  }
  //
  // Calculate the number of data lines to be used for the transfer.
  //
  CmdMode  = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
  AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
  AltMode  = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAlt);
  DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), 1);                           // We always read at least one byte.
  //
  // Calculate the number of bytes in each command phase.
  //
  AddrSize = 0;
  if (NumBytesAddr) {
    AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
  }
  AltSize = 0;
  if (NumBytesAlt) {
    AltSize = (NumBytesAlt - 1) & CCR_ABSIZE_MASK;
  }
  //
  // Configure the operation.
  //
  CfgReg = 0
         | (CCR_FMODE_MMAP << CCR_FMODE_BIT)
         | (DataMode       << CCR_DMODE_BIT)
         | (AddrSize       << CCR_ADSIZE_BIT)
         | (AddrMode       << CCR_ADMODE_BIT)
         | (AltSize        << CCR_ABSIZE_BIT)
         | (AltMode        << CCR_ABMODE_BIT)
         | (NumDummyCycles << CCR_DCYC_BIT)
         | (IsDTR          << CCR_DDRM_BIT)
         | (CmdMode        << CCR_IMODE_BIT)
         | (*pCmd          << CCR_INTRUCTION_BIT)
         ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                                                        // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  r = _ClearFlags();
  if (r != 0) {
    goto Done;                                                                      // Error, could not clear status flags.
  }
  QUADSPI_ABR = AltReg;
  QUADSPI_CCR = CfgReg;
Done:
  return r;
}

#endif // FS_RAMDISK_HW_USE_MEM_MAP_MODE

/*********************************************************************
*
*       _HW_Control
*
*  Function description
*    Sends a command to serial RAM device that does not transfer any data.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pCmd           [IN] Code of the command to be sent. Cannot be NULL.
*    NumBytesCmd    Number of bytes in the command code. Cannot be 0.
*    BusWidth       Number of data lines to be used for sending the command.
*    Flags          Options for the data exchange.
*
*  Return value
*    ==0      OK, command transferred successfully.
*    !=0      An error occurred.
*/
static int _HW_Control(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, U8 BusWidth, unsigned Flags) {
  U32 CfgReg;
  U32 CmdMode;
  U32 TimeOut;
  int r;

  FS_USE_PARA(Unit);                                        // This MCU has only one QSPI controller.
  FS_USE_PARA(Flags);
  FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u);      // The QSPI controller is able to handle only 1-byte commands.
  //
  // Fill local variables.
  //
  r       = 0;
  CmdMode = _GetMode(BusWidth, NumBytesCmd);
  CfgReg  = 0
          | (CCR_FMODE_WRITE << CCR_FMODE_BIT)
          | (CmdMode         << CCR_IMODE_BIT)
          | (*pCmd           << CCR_INTRUCTION_BIT)
          ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                                // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // Execute the command.
  //
  r = _ClearFlags();
  if (r != 0) {
    goto Done;                                              // Error, could not clear status flags.
  }
  QUADSPI_DLR = 0;
  QUADSPI_ABR = 0;
  QUADSPI_CCR = CfgReg;
  //
  // Wait until the command has been completed.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                                // Error, QUADSPI is not ready.
      break;
    }
  }
Done:
  return r;
}

/*********************************************************************
*
*       _HW_Read
*
*  Function description
*    Transfers data from serial RAM device to MCU.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pCmd           [IN] Code of the command to be sent. Cannot be NULL.
*    NumBytesCmd    Number of bytes in the command code. Cannot be 0.
*    pPara          [IN] Command parameters (address and dummy bytes). Can be NULL.
*    NumBytesPara   Total number of address and dummy bytes to be sent. Can be 0.
*    NumBytesAddr   Number of address bytes to be send. Can be 0.
*    pData          [OUT] Data read from the serial RAM device. Can be NULL.
*    NumBytesData   Number of bytes to read from the serial RAM device. Can be 0.
*    BusWidth       Number of data lines to be used for the data transfer.
*    Flags          Options for the data exchange.
*
*  Return value
*    ==0      OK, data transferred successfully.
*    !=0      An error occurred.
*/
static int _HW_Read(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara, unsigned NumBytesPara,
                    unsigned NumBytesAddr, U8 * pData, unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
  U32 AddrReg;
  U32 AltReg;
  U32 CfgReg;
  U32 DataMode;
  U32 AddrMode;
  U32 AltMode;
  U32 CmdMode;
  U32 DataReg;
  U32 AltSize;
  U32 AddrSize;
  U32 NumBytesAvail;
  U32 NumBytes;
  U32 NumBytesAlt;
  U32 IsDTR;
  U32 NumDummyCycles;
  U32 TimeOut;
  int r;

  FS_USE_PARA(Unit);                                                                // This MCU has only one QSPI controller.
  FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u);                              // The QSPI controller is able to handle only 1-byte commands.
  //
  // Fill local variables.
  //
  r           = 0;
  AddrReg     = 0;
  AltReg      = 0;
  NumBytesAlt = NumBytesPara - NumBytesAddr;
  //
  // Calculate the transfer mode.
  //
  IsDTR = 0;
  if (   ((Flags & FS_RAMDISK_HW_FLAG_DTR_ADDR) != 0u)
      || ((Flags & FS_RAMDISK_HW_FLAG_DTR_DATA) != 0u)) {
    IsDTR = 1;
  }
  //
  // Encode the address.
  //
  if (NumBytesAddr) {
    NumBytes = NumBytesAddr;
    do {
      AddrReg <<= 8;
      AddrReg  |= (U32)(*pPara++);
    } while (--NumBytes);
  }
  //
  // Encode the mode and dummy bytes.
  //
  NumDummyCycles = 0;
  if (NumBytesAlt != 0) {
    NumBytes = NumBytesAlt;
    //
    // Check if a mode byte has to be sent and if yes encode its value.
    //
    if ((Flags & FS_RAMDISK_HW_FLAG_MODE_8BIT) != 0u) {
      NumBytes    = NumBytesAlt - 1u;
      NumBytesAlt = 1;                                                              // We never send more than one mode byte.
      if (pPara != NULL) {
        AltReg = (U32)*pPara;
      } else {
        AltReg = 0xFFuL;
      }
    } else {
      NumBytesAlt = 0;
    }
    if (NumBytes != 0u) {
      //
      // The remaining alternate bytes are not sent. Instead, we generate dummy cycles.
      //
      NumDummyCycles = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytes, IsDTR);
    }
  }
  //
  // Calculate the number of data lines to be used for the transfer.
  //
  CmdMode  = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
  AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
  AltMode  = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAlt);
  DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
  //
  // Calculate the number of bytes in each command phase.
  //
  AddrSize = 0;
  if (NumBytesAddr) {
    AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
  }
  AltSize = 0;
  if (NumBytesAlt) {
    AltSize = (NumBytesAlt - 1) & CCR_ABSIZE_MASK;
  }
  //
  // Configure the operation.
  //
  CfgReg = 0
         | (CCR_FMODE_READ << CCR_FMODE_BIT)
         | (DataMode       << CCR_DMODE_BIT)
         | (AltSize        << CCR_ABSIZE_BIT)
         | (AltMode        << CCR_ABMODE_BIT)
         | (AddrSize       << CCR_ADSIZE_BIT)
         | (AddrMode       << CCR_ADMODE_BIT)
         | (NumDummyCycles << CCR_DCYC_BIT)
         | (IsDTR          << CCR_DDRM_BIT)
         | (CmdMode        << CCR_IMODE_BIT)
         | (*pCmd          << CCR_INTRUCTION_BIT)
         ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // It seems that QUADSPI is driving the data lines one half of the clock
  // cycle longer than required. This can cause that a wrong value is
  // sampled immediately after a data line is switched from output to input.
  // For this reason we configure QUADSPI to sample the data later than default.
  //
  if ((IsDTR == 0) && (NumBytesAlt != 0) && (NumDummyCycles == 0) ) {
    QUADSPI_CR |= 1uL << CR_SSHIFT_BIT;
  }
  //
  // Execute the command.
  //
  r = _ClearFlags();
  if (r != 0) {
    goto Done;                            // Error, could not clear status flags.
  }
  if (NumBytesData != 0) {
    QUADSPI_DLR = NumBytesData - 1;       // 0 means "read 1 byte".
  }
  QUADSPI_ABR = AltReg;
  QUADSPI_CCR = CfgReg;
  if (NumBytesAddr != 0) {
    QUADSPI_AR = AddrReg;
  }
  //
  // Read data from RAM device.
  //
  if (NumBytesData != 0) {
    do {
      //
      // Wait for the data to be received.
      //
      TimeOut = WAIT_TIMEOUT_CYCLES;
      for (;;) {
        NumBytesAvail = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
        if ((NumBytesAvail >= 4) || (NumBytesAvail >= NumBytesData)) {
          break;
        }
        if (--TimeOut == 0u) {
          r = 1;                          // Error, no data received.
          goto Done;
        }
      }
      //
      // Read data and store it to destination buffer.
      //
      if (NumBytesData < 4) {
        //
        // Read single bytes.
        //
        do {
          *pData++ = QUADSPI_DR_BYTE;
        } while (--NumBytesData != 0);
      } else {
        //
        // Read 4 bytes at a time.
        //
        DataReg = QUADSPI_DR;
        *pData++ = (U8)DataReg;
        *pData++ = (U8)(DataReg >> 8);
        *pData++ = (U8)(DataReg >> 16);
        *pData++ = (U8)(DataReg >> 24);
        NumBytesData -= 4;
      }
    } while (NumBytesData != 0);
  }
  //
  // Wait until the data transfer has been completed.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, transaction not completed.
      break;
    }
  }
Done:
  //
  // Restore the default sampling mode.
  //
  QUADSPI_CR &= ~(1uL << CR_SSHIFT_BIT);
  return r;
}

/*********************************************************************
*
*       _HW_Write
*
*  Function description
*    Transfers data from MCU to serial RAM device.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pCmd           [IN] Code of the command to be sent. Cannot be NULL.
*    NumBytesCmd    Number of bytes in the command code. Cannot be 0.
*    pPara          [IN] Command parameters (address and dummy bytes). Can be NULL.
*    NumBytesPara   Total number of address and dummy bytes to be sent. Can be 0.
*    NumBytesAddr   Number of address bytes to be send. Can be 0.
*    pData          [IN] Data to be sent to the serial RAM device. Can be NULL.
*    NumBytesData   Number of bytes to be written the serial RAM device. Can be 0.
*    BusWidth       Number of data lines to be used for the data transfer.
*    Flags          Options for the data exchange.
*
*  Return value
*    ==0      OK, data transferred successfully.
*    !=0      An error occurred.
*/
static int _HW_Write(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara, unsigned NumBytesPara,
                     unsigned NumBytesAddr, const U8 * pData, unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
  U32 AddrReg;
  U32 AltReg;
  U32 CfgReg;
  U32 DataMode;
  U32 AddrMode;
  U32 AltMode;
  U32 CmdMode;
  U32 DataReg;
  U32 AddrSize;
  U32 AltSize;
  U32 NumBytes;
  U32 NumBytesAlt;
  U32 NumBytesFree;
  U32 IsDTR;
  U32 TimeOut;
  int r;

  FS_USE_PARA(Unit);                                        // This MCU has only one QSPI controller.
  FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u);      // The QSPI controller is able to handle only 1-byte commands.
  //
  // Fill local variables.
  //
  r           = 0;
  AddrReg     = 0;
  AltReg      = 0;
  NumBytesAlt = NumBytesPara - NumBytesAddr;
  //
  // Calculate the transfer mode.
  //
  IsDTR = 0;
  if (   ((Flags & FS_RAMDISK_HW_FLAG_DTR_ADDR) != 0u)
      || ((Flags & FS_RAMDISK_HW_FLAG_DTR_DATA) != 0u)) {
    IsDTR = 1;
  }
  //
  // Encode the address.
  //
  if (NumBytesAddr) {
    NumBytes = NumBytesAddr;
    do {
      AddrReg <<= 8;
      AddrReg  |= (U32)(*pPara++);
    } while (--NumBytes);
  }
  //
  // Encode additional information.
  //
  if (NumBytesPara > NumBytesAddr) {
    NumBytes = NumBytesAlt;
    do {
      AltReg <<= 8;
      AltReg  |= (U32)(*pPara++);
    } while (--NumBytes);
  }
  //
  // Calculate the number of data lines to be used for the transfer.
  //
  CmdMode     = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
  AddrMode    = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
  AltMode     = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAlt);
  DataMode    = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
  //
  // Calculate the number of bytes in each command phase.
  //
  AddrSize = 0;
  if (NumBytesAddr) {
    AddrSize = NumBytesAddr - 1;
  }
  AltSize = 0;
  if (NumBytesAlt) {
    AltSize = NumBytesAlt - 1;
  }
  //
  // Configure the operation.
  //
  CfgReg = 0
         | (CCR_FMODE_WRITE << CCR_FMODE_BIT)
         | (DataMode        << CCR_DMODE_BIT)
         | (AltSize         << CCR_ABSIZE_BIT)
         | (AltMode         << CCR_ABMODE_BIT)
         | (AddrSize        << CCR_ADSIZE_BIT)
         | (AddrMode        << CCR_ADMODE_BIT)
         | (IsDTR           << CCR_DDRM_BIT)
         | (CmdMode         << CCR_IMODE_BIT)
         | (*pCmd           << CCR_INTRUCTION_BIT)
         ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // Execute the command.
  //
  r = _ClearFlags();
  if (r != 0) {
    goto Done;                            // Error, could not clear status flags.
  }
  if (NumBytesData != 0) {
    QUADSPI_DLR = NumBytesData - 1;       // 0 means "read 1 byte".
  }
  QUADSPI_ABR = AltReg;
  QUADSPI_CCR = CfgReg;
  if (NumBytesAddr != 0) {
    QUADSPI_AR = AddrReg;
  }
  //
  // Write data to RAM device.
  //
  if (NumBytesData != 0) {
    do {
      //
      // Wait for free space in FIFO.
      //
      TimeOut = WAIT_TIMEOUT_CYCLES;
      for (;;) {
        NumBytesFree = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
        NumBytesFree = NUM_BYTES_FIFO - NumBytesFree;
        if ((NumBytesFree >= 4) || (NumBytesFree >= NumBytesData)) {
          break;
        }
        if (--TimeOut == 0u) {
          r = 1;                          // Error, no free space in FIFO.
          goto Done;
        }
      }
      //
      // Get the data from source buffer and write it.
      //
      if (NumBytesData < 4) {
        //
        // Write single bytes.
        //
        do {
          QUADSPI_DR_BYTE = *pData++;
        } while (--NumBytesData != 0);
      } else {
        //
        // Write 4 bytes at a time if possible.
        //
        DataReg  = (U32)*pData++;
        DataReg |= (U32)*pData++ << 8;
        DataReg |= (U32)*pData++ << 16;
        DataReg |= (U32)*pData++ << 24;
        NumBytesData -= 4;
        QUADSPI_DR = DataReg;
      }
    } while (NumBytesData != 0);
  }
  //
  // Wait until the data transfer has been completed.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, transfer not completed.
      break;
    }
  }
Done:
  return r;
}

/*********************************************************************
*
*       Global data
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator
*/
const FS_RAMDISK_HW_TYPE_SPI FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator = {
  _HW_Init,
  _HW_Unmap,
#if FS_RAMDISK_HW_USE_MEM_MAP_MODE
  _HW_Map,
#else
  NULL,
#endif // FS_RAMDISK_HW_USE_MEM_MAP_MODE
  _HW_Control,
  _HW_Read,
  _HW_Write,
  NULL,
  NULL
};

/*************************** End of file ****************************/

NAND flash driver

General information

emFile supports the use of unmanaged NAND flash devices as data storage. Two drivers for NAND flash devices also known as flash translation layers are provided:

Selecting the correct NAND driver

The first factor to be considered is the type of storage device used. Microchip / Atmel and Adesto DataFlash devices are currently supported only by the SLC1 NAND driver while NAND flash devices are typically supported by both NAND drivers. The bit error correction requirement of the NAND flash device is the next factor. It indicates how many bit errors the error correcting code (ECC) have to be able to detect and correct. If the NAND flash devices requires only 1-bit correction capability then the SLC1 NAND driver can be used. The SLC1 NAND driver performs the bit error detection and correction in the software. For an correction capability larger than 1 bit the Universal NAND driver has to be used instead. The Universal NAND driver is able to calculated the ECC either in the hardware using the ECC integrated into the NAND flash device or MCU or in the software using an ECC library such as SEGGER emLib-ECC (https://www.segger.com/products/security-iot/emlib/variations/ecc/)

You can always get in contact with us if you are not sure what type of NAND driver to choose.

Multiple driver configurations

Both NAND drivers store management information to spare area of a page. The layout and the content of this information is different for each NAND driver which means that data written using one NAND driver cannot be accessed with the other one and vice versa. For example, if an application uses the SLC1 NAND driver to store data to a NAND flash device than it cannot use the Universal NAND driver to access it. The Universal NAND driver reports in this case that the NAND flash device is not properly formatted. For applications that have to support different types of NAND flash devices that require the usage of both NAND drivers it is possible to select the correct NAND driver by checking the device id of the connected NAND flash device. The description of the FS_NAND_PHY_ReadDeviceId() function provides an example showing how to a NAND flash device can be identified at the configuration of the file system.

Software structure

The NAND driver is organized into different layers that contains from top to bottom:

It is possible to use the NAND driver with custom hardware. If port pins or a simple memory controller are used for accessing the flash memory, only the hardware layer needs to be ported, normally no changes to the physical layer are required. If the NAND driver should be used with a special memory controller (for example special FPGA implementations), the physical layer needs to be adapted. In this case, the hardware layer is not required, because the memory controller manages the hard- ware access.

Bad block management

Bad block management is supported in the driver. Blocks marked as defective are skipped and are not used for data storage. The block is recognized as defective when the first byte in the spare area of the first or second page is different than 0xFF. The driver marks blocks as defective in the following cases:

Garbage collection

The driver performs the garbage collection automatically during the write operations. If no empty NAND blocks are available to store the data, new empty NAND blocks are created by erasing the data of the NAND blocks marked as invalid. This involves a NAND block erase operation which, depending on the characteristics of the NAND flash, can potentially take a long time to complete, and therefor reduces the write throughput. For applications which require maximum write throughput, the garbage collection can be done in the application. Typically, this operation can be performed when the file system is idle. Two API functions are provided: FS_STORAGE_Clean() and FS_STORAGE_CleanOne(). They can be called directly from the task which is performing the write or from a background task. The FS_STORAGE_Clean() function blocks until all the invalid NAND blocks are converted to free NAND blocks. A write operation following the call to this function runs at maximum speed. The other function, FS_STORAGE_CleanOne(), converts a single invalid NAND block. Depending on the number of invalid NAND blocks, several calls to this function are required to clean up the entire NAND flash.

Fail-safe operation

The NAND drivers are fail-safe which means that the drivers make only atomic operations and guarantee that the file system data is always valid. If an unexpected power loss or reset interrupts a a write operation, then the old data is kept while the new corrupted data is discarded. The fail-safe operation can only be guaranteed if the NAND flash device is able to fully complete the last command it received from the MCU. The picture below is an oscilloscope capture which shows how a power down sequence should look like in order to meet the requirements needed for a fail-safe operation of a NAND driver. The labels in the picture have the following meaning:

Power loss

Wear leveling

Wear leveling is supported by the NAND drivers. The procedure makes sure that the number of times a NAND block is erased remains approximately equal for all the NAND blocks. This is realized by maintaining an erase count for each NAND block. The maximum allowed erase count difference is configurable at compile time via FS_NAND_MAX_ERASE_CNT_DIFF as well as at runtime via FS_NAND_SetMaxEraseCntDiff() for the SLC1 NAND driver and FS_NAND_UNI_SetMaxEraseCntDiff() for the Universal NAND driver.

Read disturb errors

Read disturb errors are bit errors that occur when a large number of read operations (a few hundred thousand to one million) are preformed on a NAND flash block without an erase operation taking place in between. These bit errors can be avoided by simply rewriting the sector data. This can be realized by calling in the application the FS_STORAGE_RefreshSectors() storage layer API function that is able to refresh multiple sectors in a single call.

Low-level format

Before using a NAND flash device for the first time, the application has to initialize it by performing a low-level format operation on it. Refer to FS_FormatLow() and FS_FormatLLIfRequired() for detailed information about this.

NAND flash organization

A NAND flash device is a serial-type memory device that uses the I/O pins for both address and data transfer as well as for command inputs. A NAND flash device consist of a number of individual storage blocks. Every block contains a number of pages, typically 64. The pages can be written to individually, one at a time. When writing to a page, bits can only be changed from 1 to 0. Only entire blocks (all pages in the block) can be erased. Erasing means bringing all memory bits in all pages of the block to logical 1. The erase and program operations are executed automatically by the NAND flash device.

NAND organization

Small NAND flashes (up to 256 Mbytes) have a page size of 528 bytes, that is 512 bytes for storing file system data and 16 bytes, called the spare area, for storing management information (ECC, etc.).

Large NAND devices (256 Mbytes or more) have a page size of 2112 bytes with 2048 bytes used for storing file system data data and with 64 bytes of spare area.

Pin description - parallel NAND flash device

This type of devices uses 8 or 16 I/O signals to exchange the data with the MCU an additional set of signals that are used to control the data transfer.

Signal name Description
CE Chip Enable - The CE signal enables the device. This signal is active low. If the signal is inactive, device is in standby mode.
WE Write Enable - The WE signal controls the transfer of data from MCU to NAND flash device. This signal is active low. Commands, address and data are latched on the rising edge of the WE pulse.
RE Read Enable - The RE signal controls the transfer of data from NAND flash device to MCU. This signal is active low. When active the NAND flash device outputs data.
CLE Command Latch Enable - The CLE signal controls the activating path for commands sent to NAND flash device. This signal is active high. When active, command data sent via the I/O signals is latched by the NAND flash device into the internal command register on the rising edge of the WE signal.
ALE Address Latch Enable - The ALE signal controls the activating path for address to the internal address registers. This signal is active high. Address data is latched on the rising edge of WE with ALE high.
WP Write Protect - The WP signal controls if data can be stored to NAND flash device. This signal is active low and is typically connected to VCC (recommended), but may also be connected to port pin.
R/B Ready/Busy - The R/B signal indicates the status of the NAND flash device operation to MCU. When low, it indicates that a program, erase or read operation is in process. The signal returns to high when the operation is completed. It is an open drain output that should be connected to a port pin with pull-up. If available, a port pin which can trigger an interrupt can be connected to this signal.
I/O0-I/O7 Data Input/Output - The data I/O signals are used to input command, address and data, and to output data during read operations.
I/O8-I/O15 Data Input/Output - Additional data I/O signals.
Pin description - DataFlash device

DataFlash devices are commonly used when low pin count and easy data transfer are required. DataFlash devices use the following pins:

Signal name Description
CS Chip Select - This signal selects the DataFlash device. The device is selected, when CS pin is driven low.
SCLK Serial Clock - The SCLK signal is used to control the flow of data to and from the DataFlash. Data is always clocked into the device on the rising edge of SCLK and clocked out of the device on the falling edge of SCLK.
SI Serial Data In - The SI signal is used to transfer data to the DataFlash device. It is used for all data input including opcodes and address sequences.
SO Serial Data Out - The SO signal is used to transfer data serially out of the DataFlash device.

Additionally, the host system has to comply with the following requirements:

SLC1 NAND driver

SLC1 NAND driver is an extremely efficient and low footprint driver that can be used to access the data stored on a raw NAND flash device. The driver is designed to support one or multiple Single Level Cell (SLC) NAND flash devices that require 1-bit error correction capability. The SLC1 NAND flash driver can also be used to access the data stored on Microchip / Atmel and Adesto DataFlash devices. Different sector sizes are supported to help reduce the RAM usage of the file system.

Supported hardware

the SLC1 NAND driver supports almost all SLC NAND flash devices. This includes NAND flash devices with page sizes of 512 + 16 and 2048 + 64 bytes.

Tested and compatible NAND flash devices

The table below lists the NAND flash devices that have been tested or are compatible with a tested device. In addition the NAND flash driver fully supports the Dialog Semiconductor / Adesto / Atmel DataFlash devices with capacities up to 128 MBit.

Device name Page size Number of blocks Storage capacity Bus width
ATO
AFND1G08U3 2048+64 byte 1024 128 MiB 16 bit
Dialog Semiconductor/Adesto/Atmel
AT25PE16 512+16 byte 512 2 MiB 1 bit
AT45BR3214B 512+16 byte 1024 4 MiB 1 bit
AT45DB011B 256+8 byte 64 128 KiB 1 bit
AT45DB021B 256+8 byte 128 256 KiB 1 bit
AT45DB041B 256+8 byte 256 512 KiB 1 bit
AT45DB081B 256+8 byte 512 1 MiB 1 bit
AT45DB1282 1024+32 byte 2048 16 MiB 1 bit
AT45DB161B 512+16 byte 512 2 MiB 1 bit
AT45DB161E 512+16 byte 512 2 MiB 1 bit
AT45DB321C 512+16 byte 1024 4 MiB 1 bit
AT45DB321E 512+16 byte 1024 4 MiB 1 bit
AT45DB641E 256+8 byte 4096 8 MiB 1 bit
AT45DB642D 1024+32 byte 1024 8 MiB 1 bit
AT45DCB002 512+16 byte 512 2 MiB 1 bit
AT45DCB004 512+16 byte 1024 4 MiB 1 bit
AT45DCB008 1024+32 byte 1024 8 MiB 1 bit
Hynix
HY27SA081G1M 512+16 byte 8192 512 MiB 8 bit
HY27SS08121M 512+16 byte 4096 512 MiB 8 bit
HY27SS08561M 512+16 byte 2048 256 MiB 8 bit
HY27UA081G1M 512+16 byte 8192 512 MiB 8 bit
HY27UF081G2A 2048+64 byte 1024 128 MiB 8 bit
HY27UF081G2M 2048+64 byte 1024 128 MiB 8 bit
HY27UF082G2M 2048+64 byte 2048 256 MiB 8 bit
HY27UF084G2M 2048+64 byte 4096 512 MiB 8 bit
HY27UG084G2M 2048+64 byte 4096 512 MiB 8 bit
HY27UG084GDM 2048+64 byte 4096 512 MiB 8 bit
HY27US08121M 512+16 byte 4096 512 MiB 8 bit
HY27US08281A 512+16 byte 1024 128 MiB 8 bit
HY27US08561M 512+16 byte 2048 256 MiB 8 bit
Kioxia/Toshiba
TC5816BFT 256+8 byte 512 2 MiB 8 bit
TC582562A 512+8 byte 2048 32 MiB 8 bit
TC58256AFT 512+8 byte 2048 32 MiB 8 bit
TC58512FT 512+8 byte 4096 64 MiB 8 bit
TC58V32AFT 512+8 byte 512 4 MiB 8 bit
TC58V64BFT 512+8 byte 1024 8 MiB 8 bit
TH58100FT 512+8 byte 8192 128 MiB 8 bit
Micron
MT29F2G08AAB 2048+64 byte 2048 256 MiB 8 bit
MT29F2G08ABD 2048+64 byte 2048 256 MiB 8 bit
MT29F2G16AAD 2048+64 byte 2048 256 MiB 16 bit
MT29F4G08AAA 2048+64 byte 4096 512 MiB 8 bit
MT29F4G08BAB 2048+64 byte 4096 512 MiB 8 bit
STMicroelectronics
NAND01GR3A 512+16 byte 8192 1 GiB 8 bit
NAND01GR3B 2048+64 byte 1024 128 MiB 8 bit
NAND01GW3A 512+16 byte 8192 1 GiB 8 bit
NAND01GW3B 2048+64 byte 1024 128 MiB 8 bit
NAND02GR3B 2048+64 byte 2048 256 MiB 8 bit
NAND02GW3B 2048+64 byte 2048 256 MiB 8 bit
NAND04GW3B 2048+64 byte 4096 512 MiB 8 bit
NAND128R3A 512+16 byte 1024 128 MiB 8 bit
NAND128W3A 512+16 byte 1024 128 MiB 8 bit
NAND256R3A 512+16 byte 2048 256 MiB 8 bit
NAND256W3A 512+16 byte 2048 256 MiB 8 bit
NAND512R3A 512+16 byte 4096 512 MiB 8 bit
NAND512W3A 512+16 byte 4096 512 MiB 8 bit
Samsung
K9F1208B0B 512+16 byte 4096 64 MiB 8 bit
K9F1208R0B 512+16 byte 4096 64 MiB 8 bit
K9F1208U0B 512+16 byte 4096 64 MiB 8 bit
K9F1G08R0A 2048+64 byte 1024 128 MiB 8 bit
K9F1G08U0A 2048+64 byte 1024 128 MiB 8 bit
K9F1G08U0C 2048+64 byte 1024 128 MiB 8 bit
K9F2808Q0B 512+16 byte 1024 16 MiB 8 bit
K9F2808U0B 512+16 byte 1024 16 MiB 8 bit
K9F2G08U0M 2048+64 byte 2048 256 MiB 8 bit
K9F4G08U0A 2048+64 byte 4096 512 MiB 8 bit
K9F4G08U0M 2048+64 byte 4096 512 MiB 8 bit
K9F5608B0D 512+16 byte 2048 32 MiB 8 bit
K9F5608R0D 512+16 byte 2048 32 MiB 8 bit
K9F5608U0D 512+16 byte 2048 32 MiB 8 bit
K9F6408Q0C 512+16 byte 1024 8 MiB 8 bit
K9F6408U0C 512+16 byte 1024 8 MiB 8 bit
K9F8G08U0M 2048+128 byte 4096 1 GiB 8 bit
K9K1G08B0B 512+16 byte 8192 128 MiB 8 bit
K9K1G08R0B 512+16 byte 8192 128 MiB 8 bit
K9K1G08U0B 512+16 byte 8192 128 MiB 8 bit
K9K1G08U0M 512+16 byte 8192 128 MiB 8 bit
K9K2G08R0A 2048+64 byte 2048 256 MiB 8 bit
K9K2G08U0M 2048+64 byte 2048 256 MiB 8 bit
SkyHigh/Cypress
S34ML01G100TFI000 2048+64 byte 1024 128 MiB 8 bit
S34ML04G100TFI000 2048+64 byte 4096 512 MiB 8 bit
S34MS02G100TFI000 2048+64 byte 2048 256 MiB 8 bit
Winbond
W29N08GVSIAA 2048+64 byte 8192 1 GiB 8 bit

Support for devices not in this list

Most other NAND flash devices are compatible with one of the supported devices. Thus, the driver can be used with these devices or may only need a little modification, which can be easily done. Get in touch with us, if you have questions about support for devices not in this list.

Note

DataFlash devices with a page size that is a power of 2 are not supported by the SLC1 NAND driver.

Theory of operation

NAND flash devices are divided into physical blocks and physical pages. One physical block is the smallest erasable unit; one physical page is the smallest writable unit. Small block NAND flashes contain multiple pages. One block contain typically 16 / 32 / 64 pages per block. Every page has a size of 528 bytes (512 data bytes + 16 spare bytes). Large block NAND Flash devices contain blocks made up of 64 pages, each page containing 2112 bytes (2048 data bytes + 64 spare bytes). The driver uses the spare bytes for the following purposes:

Error correction using ECC

The SLC1 NAND driver is highly speed optimized and offers a better error detection and correction than a standard memory controller ECC. The ECC is capable of single bit error correction and 2-bit random detection. When a block for which the ECC is calculated has 2 or more bit errors, the data cannot be corrected. Standard memory controllers calculate an ECC for the complete block size (512 / 2048 bytes). The ECC routines of the SLC1 NAND driver calculates the ECC for data chunks of 256 bytes (e.g. a page with 2048 bytes is divided into 8 parts of 256 bytes), therefore the probability to detect and also correct data errors is much higher. This enhancement is realized with a very good performance. The ECC computation of the SLC1 NAND driver is highly optimized, so that a performance of 18 Mbytes/second can be achieved with an ARM7 based MCU running at 48 MHz. We suggest the use of the SLC1 NAND driver without enabling the hardware ECC of the memory controller, because the performance of the driver is very high and the error correction is much better.

Partial write operations

Most NAND devices allow a write operation to change an arbitrary number of bytes starting from any byte offset inside a page. A write operation that does not change all the bytes in page is called partial write or partial programming. The driver makes extensive use of this feature to increase the write speed and to reduce the RAM usage. But there is a limitation of this method imposed by the NAND technology. The manufacturer does not guarantee the integrity of the data if a page is partially written more than a number of times without an intermediate erase operation. The maximum number of partial writes is usually four. Exceeding the maximum number of partial writes does not lead automatically to the corruption of data in that page but it can increase the probability of bit errors. The driver is be able to correct single bit errors using ECC. For some combinations of logical sector size and NAND page size the driver might exceed the limit for the number of partial write operations. The table below summarizes the maximum number of partial writes performed by the SLC1 NAND driver for different logical sector sizes:

NAND page size (bytes) Logical sector size (bytes) Maximum number of partial write operations
512 512 4
2048 2048 4
2048 1024 5
2048 512 8
Configuring the driver

This section describes how to configure the file system to make use of the SLC1 NAND driver.

Compile time configuration

The SLC1 NAND driver can optionally be configured at compile time. Typically, this step can be omitted because the SLC1 NAND driver provides reasonable default values that work for most of the target applications. The compile time configuration is realized via preprocessor defines that have to be added to the FS_Conf.h file which is the main configuration file of emFile. For detailed information about the configuration of emFile and of the configuration define types, refer to Configuration of emFile The following table lists the configuration defines supported by the SLC1 NAND driver.

Define Default value Type Description
FS_NAND_ENABLE_STATS 0 or 1 B Enables or disables the support for statistical counters.
FS_NAND_NUM_READ_RETRIES 10 N Configures the number of retries in case of a read error.
FS_NAND_NUM_WRITE_RETRIES 10 N Configures the number of retries in case of a write error.
FS_NAND_NUM_UNITS 4 N Configures the maximum number of driver instances.
FS_NAND_VERIFY_ERASE 0 B Enables or disables the verification of the erase operation.
FS_NAND_VERIFY_WRITE 0 B Enables or disables the verification of the write operation.
FS_NAND_ENABLE_STATS

This define can be used to enable the support for statistical counters. The statistical counters provide information about the number of operations performed internally by the SLC1 NAND driver that can be useful for debugging. The statistical counters can be queried via FS_NAND_GetStatCounters(). By default FS_NAND_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NAND_NUM_READ_RETRIES

Number of times the SLC1 NAND driver reties the operation in case of a read error (device error or uncorrectable bit error). NumReadRetries of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.

FS_NAND_NUM_WRITE_RETRIES

Number of times the SLC1 NAND driver reties the operation in case of a write error. A write error occurs when the NAND flash device is not able to write the data to memory array. This condition is typically reported via a flag in the status register of the NAND flash device that is queried by the NAND physical layer after each write operation. NumWriteRetries of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.

FS_NAND_NUM_UNITS

This define specifies the maximum number of driver instances of the SLC1 NAND driver the application is allowed create. Four bytes of static RAM are reserved for each instance. If the maximum number of driver instances is smaller than the default then FS_NAND_NUM_UNITS can be set to the to that value in order to reduce the RAM usage.

FS_NAND_VERIFY_ERASE

This define can be used to activate the erase verification of the SLC1 NOR driver. The erase verification is performed after each erase operation by reading back the entire data of the erase block and by comparing each byte in the block with 0xFF. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NAND_SetEraseVerification().

Note

Activating the erase verification may negatively affect the write performance.

FS_NAND_VERIFY_WRITE

This define can be used to activate the write verification of the SLC1 NAND driver. The write verification is performed after each write operation by reading back the modified data and by comparing it with the data requested to be written. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NAND_SetWriteVerification().

Note

Activating the write verification may negatively affect the write performance.

Runtime configuration

The driver must be added to the file system by calling FS_AddDevice() with the driver identifier set to the address of FS_NAND_Driver. This function call together with other function calls that configure the driver operation have to be added to FS_X_AddDevices() as demonstrated in the following example.

Example

#include <FS.h>
#include "FS_NAND_HW_Template.h"

#define ALLOC_SIZE      0x9000          // Memory pool for the file system in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for semi-dynamic allocation.

void FS_X_AddDevices(void) {
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add the driver to file system.
  //
  FS_AddDevice(&FS_NAND_Driver);
  //
  // Set the physical interface of the NAND flash.
  //
  FS_NAND_SetPhyType(0, &FS_NAND_PHY_x8);
  //
  // Skip 2 blocks (256 Kbytes in case of 2K device)
  // The size of the configured area is 128 blocks.
  // For 2K devices, this means 2 Kbytes * 64 * 128 = 16 Mbytes
  //
  FS_NAND_SetBlockRange(0, 2, 128);
  //
  // Configure the HW access routines.
  //
  FS_NAND_x8_SetHWType(0, &FS_NAND_HW_Template);
#if FS_SUPPORT_FILE_BUFFER
  //
  // Enable the file buffer to increase the performance
  // when reading/writing a small number of bytes.
  //
  FS_ConfigFileBufferDefault(512, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}

The API functions listed in the next table can be used by the application to configure the behavior of the SLC1 NAND driver. The application can call them only at the file system initialization in FS_X_AddDevices().

FunctionDescription
FS_NAND_SetBlockRange() Specifies which NAND flash blocks can used as data storage.
FS_NAND_SetCleanThreshold() Specifies the minimum number sectors that the driver should keep available for fast write operations.
FS_NAND_SetEraseVerification() Enables or disables the checking of the block erase operation.
FS_NAND_SetMaxEraseCntDiff() Configures the threshold of the wear leveling procedure.
FS_NAND_SetNumWorkBlocks() Sets number of work blocks the SLC1 NAND driver uses for write operations.
FS_NAND_SetOnFatalErrorCallback() Registers a function to be called by the driver when a fatal error occurs.
FS_NAND_SetPhyType() Configures NAND flash access functions.
FS_NAND_SetWriteVerification() Enables or disables the checking of each page write operation.
FS_NAND_SetBlockRange()

Description

Specifies which NAND flash blocks can used as data storage.

Prototype

void FS_NAND_SetBlockRange(U8  Unit,
                           U16 FirstBlock,
                           U16 MaxNumBlocks);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
FirstBlock Index of the first NAND flash block to be used as storage (0-based).
MaxNumBlocks Maximum number of NAND flash blocks to be used as storage.

Additional information

This function is optional. By default, the SLC1 NAND driver uses all blocks of the NAND flash as data storage. FS_NAND_SetBlockRange() is useful when a part of the NAND flash has to be used for another purpose, for example to store the application program used by a boot loader, and therefore it cannot be managed by the SLC1 NAND driver. Limiting the number of blocks used by the SLC1 NAND driver can also help reduce the RAM usage.

FirstBlock is the index of the first physical NAND block were 0 is the index of the first block of the NAND flash device. MaxNumBlocks can be larger that the actual number of available NAND blocks in which case the SCL1 NAND driver silently truncates the value to reflect the actual number of NAND blocks available.

The SLC1 NAND driver uses the first NAND block in the range to store management information at low-level format. If the first NAND block happens to be marked as defective, then the next usable NAND block is used.

The read optimization of the FS_NAND_PHY_2048x8 physical layer has to be disabled when this function is used to partition the NAND flash device in order to ensure data consistency. The read cache can be disabled at runtime using FS_NAND_2048x8_DisableReadCache().

If the FS_NAND_SetBlockRange() is used to subdivide the same physical NAND flash device into two or more partitions than the application has to make sure that they do not overlap.

Example

Sample configuration showing how to reserve the first 16 blocks of the NAND flash.

#include <FS.h>

void FS_X_AddDevices(void) {
  //
  // Basic file system configuration...
  //

  //
  // Add and configure the SLC1 NAND driver.
  // Only the NAND blocks with the physical
  // indexes 16-143 are used for storage.
  //
  FS_AddDevice(&FS_NAND_Driver);
  FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
  FS_NAND_SetBlockRange(0, 16, 128);

  //
  // Additional file system configuration...
  //
}

Sample configuration showing how to partition the same NAND flash device.

#include <FS.h>

void FS_X_AddDevices(void) {
  //
  // Basic file system configuration...
  //

  //
  // Add and configure the first SLC1 NAND driver.
  // The blocks 16 blocks are used for storage,
  // that is the NAND blocks with the physical
  // indexes 0-15.
  //
  FS_AddDevice(&FS_NAND_Driver);
  FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
  FS_NAND_SetBlockRange(0, 0, 16);

  //
  // Add and configure the second SLC1 NAND driver.
  // The blocks 64 blocks are used for storage,
  // that is the NAND blocks with the physical
  // indexes 16-79.
  //
  FS_AddDevice(&FS_NAND_Driver);
  FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
  FS_NAND_SetBlockRange(0, 16, 64);

  //
  // Additional file system configuration...
  //
}
FS_NAND_SetCleanThreshold()

Description

Specifies the minimum number sectors that the driver should keep available for fast write operations.

Prototype

int FS_NAND_SetCleanThreshold(U8       Unit,
                              unsigned NumBlocksFree,
                              unsigned NumSectorsFree);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
NumBlocksFree Number of blocks to be kept free.
NumSectorsFree Number of sectors to be kept free on each block.

Return value

= 0 OK, threshold set.
≠ 0 An error occurred.

Additional information

Typically, used for allowing the NAND flash to write data fast to a file on a sudden reset. At the startup, the application reserves free space, by calling the function with NumBlocksFree and NumSectorsFree set to a value different than 0. The number of free sectors depends on the number of bytes written and on how the file system is configured. When the unexpected reset occurs, the application tells the driver that it can write to the free sectors, by calling the function with NumBlocksFree and NumSectorsFree set to 0. Then, the application writes the data to file and the NAND driver stores it to the free space. Since no erase or copy operation is required, the data is written as fastest as the NAND flash device permits it.

The NAND flash device will wear out faster than normal if sectors are reserved in a work block (NumSectors > 0).

FS_NAND_SetEraseVerification()

Description

Enables or disables the checking of the block erase operation.

Prototype

void FS_NAND_SetEraseVerification(U8 Unit,
                                  U8 OnOff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The erase operation is not checked. ≠0 The erase operation is checked.

Additional information

This function is optional. The result of a block erase operation is normally checked by evaluating the error bits maintained by the NAND flash device in a internal status register. FS_NAND_SetEraseVerification() can be used to enable additional verification of the block erase operation that is realized by reading back the contents of the entire erased physical block and by checking that all the bytes in it are set to 0xFF. Enabling this feature can negatively impact the write performance of SLC1 NAND driver.

The block erase verification feature is active only when the SLC1 NAND driver is compiled with the FS_NAND_VERIFY_ERASE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NAND_SetMaxEraseCntDiff()

Description

Configures the threshold of the wear leveling procedure.

Prototype

void FS_NAND_SetMaxEraseCntDiff(U8  Unit,
                                U32 EraseCntDiff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
EraseCntDiff Maximum allowed difference between the erase counts of any two NAND blocks.

Additional information

This function is optional. It can be used to control how the SLC1 NAND driver performs the wear leveling. The wear leveling procedure makes sure that the NAND blocks are equally erased to meet the life expectancy of the storage device by keeping track of the number of times a NAND block has been erased (erase count). The SLC1 NAND driver executes this procedure when a new empty NAND block is required for data storage. The wear leveling procedure works by first choosing the next available NAND block. Then the difference between the erase count of the chosen block and the NAND block with lowest erase count is computed. If this value is greater than EraseCntDiff the NAND block with the lowest erase count is freed and made available for use.

The same threshold can also be configured at compile time via the FS_NAND_MAX_ERASE_CNT_DIFF configuration define.

Example

#include <FS.h>

void FS_X_AddDevices(void) {
  //
  // Basic file system configuration...
  //

  //
  // Add and configure the SLC1 NAND driver.
  //
  FS_AddDevice(&FS_NAND_Driver);
  FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
  FS_NAND_SetMaxEraseCntDiff(0, 5000);

  //
  // Additional file system configuration...
  //
}
FS_NAND_SetNumWorkBlocks()

Description

Sets number of work blocks the SLC1 NAND driver uses for write operations.

Prototype

void FS_NAND_SetNumWorkBlocks(U8  Unit,
                              U32 NumWorkBlocks);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
NumWorkBlocks Number of work blocks.

Additional information

This function is optional. It can be used to change the default number of work blocks according to the requirements of the application. Work blocks are physical NAND blocks that the SLC1 NAND driver uses to temporarily store the data written to NAND flash device. The SLC1 NAND driver calculates at low-level format the number of work blocks based on the total number of blocks available on the NAND flash device.

By default, the NAND driver allocates 10% of the total number of NAND blocks used as storage, but no more than 10 NAND blocks. The minimum number of work blocks allocated by default depends on whether journaling is used or not. If the journal is active 4 work blocks are allocated, else SLC1 NAND driver allocates 3 work blocks. The currently allocated number of work blocks can be checked via FS_NAND_GetDiskInfo(). The value is returned in the NumWorkBlocks member of the FS_NAND_DISK_INFO structure.

Increasing the number of work blocks can help increase the write performance of the SLC1 NAND driver. At the same time the RAM usage of the SLC1 NAND driver increases since each configured work block requires a certain amount of RAM for the data management. This is a trade-off between write performance and RAM usage.

The new value take effect after the NAND flash device is low-level formatted via FS_FormatLow() or FS_NAND_FormatLow() API functions.

Example

#include <FS.h>

void FS_X_AddDevices(void) {
  //
  // Basic file system configuration...
  //

  //
  // Add and configure the SLC1 NAND driver.
  //
  FS_AddDevice(&FS_NAND_Driver);
  FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
  FS_NAND_SetNumWorkBlocks(0, 5);

  //
  // Additional file system configuration...
  //
}
FS_NAND_SetOnFatalErrorCallback()

Description

Registers a function to be called by the driver when a fatal error occurs.

Prototype

void FS_NAND_SetOnFatalErrorCallback
                                (FS_NAND_ON_FATAL_ERROR_CALLBACK * pfOnFatalError);

Parameters

Parameter Description
pfOnFatalError Pointer to callback function.

Additional information

This function is optional. If no callback function is registered the SLC1 NAND driver behaves as if the callback function returned 1. This means that the NAND flash remains writable after the occurrence of the fatal error. emFile versions previous to 4.04b behave differently and mark the NAND flash as read-only in this case. For additional information refer to FS_NAND_ON_FATAL_ERROR_CALLBACK.

Typically, the SLC1 NAND driver reports a fatal error when an uncorrectable bit error occurs, that is when the ECC is not able to correct the bit errors. A fatal error can also be reported on other events such the failure to erase a NAND block. The type of error is indicated to the callback function via the ErrorType member of the FS_NAND_FATAL_ERROR_INFO structure.

All instances of the SLC1 NAND driver share the same callback function. The Unit member of the FS_NAND_FATAL_ERROR_INFO structure passed as parameter to the pfOnFatalError callback function can be used to determine which driver instance triggered the fatal error.

FS_NAND_SetPhyType()

Description

Configures NAND flash access functions.

Prototype

void FS_NAND_SetPhyType(      U8                 Unit,
                        const FS_NAND_PHY_TYPE * pPhyType);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)
pPhyType  in  Physical layer to be used to access the NAND flash device.

Additional information

This function is mandatory and it has to be called in FS_X_AddDevices() once for each instance of the SLC1 NAND driver. The driver instance is identified by the Unit parameter. First SLC1 NAND driver instance added to the file system via a FS_AddDevice(&FS_NAND_Driver) call has the unit number 0, the SLC1 NAND driver added by a second call to FS_AddDevice() has the unit number 1 and so on.

FS_NAND_SetWriteVerification()

Description

Enables or disables the checking of each page write operation.

Prototype

void FS_NAND_SetWriteVerification(U8 Unit,
                                  U8 OnOff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked.

Additional information

This function is optional. The result of a page write operation is normally checked by evaluating the error bits maintained by the NAND flash device in a internal status register. FS_NAND_SetWriteVerification() can be used to enable additional verification of the page write operation that is realized by reading back the contents of the written page and by checking that all the bytes are matching the data requested to be written. Enabling this feature can negatively impact the write performance of SLC1 NAND driver.

The page write verification feature is active only when the SLC1 NAND driver is compiled with the FS_NAND_VERIFY_WRITE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NAND_ON_FATAL_ERROR_CALLBACK

Description

The type of the callback function invoked by the NAND driver when a fatal error occurs.

Type definition

typedef int FS_NAND_ON_FATAL_ERROR_CALLBACK(FS_NAND_FATAL_ERROR_INFO * pFatalErrorInfo);

Parameters

Parameter Description
pFatalErrorInfo Information about the fatal error.

Return value

= 0 The NAND driver has to mark the NAND flash device as read only.
≠ 0 The NAND flash device has to remain writable.

Additional information

If the callback function returns a 0 the NAND driver marks the NAND flash device as read-only and it remains in this state until the NAND flash device is low-level formatted. In this state all further write operations are rejected with an error by the NAND driver.

The application is responsible for handling the fatal error for example by checking the consistency of the file system via FS_CheckDisk(). The callback function is not allowed to invoke any other FS API functions therefore the handling of the error has to be done after the FS API function that triggered the error returns.

Depending on the type of NAND driver used, the fatal error handler can be registered either via FS_NAND_SetOnFatalErrorCallback() or FS_NAND_UNI_SetOnFatalErrorCallback().

FS_NAND_FATAL_ERROR_INFO

Description

Information passed to callback function when a fatal error occurs.

Type definition

typedef struct {
  U8   Unit;
  U8   ErrorType;
  U32  ErrorSectorIndex;
} FS_NAND_FATAL_ERROR_INFO;

Structure members

Member Description
Unit Instance of the NAND driver that generated the fatal error.
ErrorType Type of fatal error.
ErrorSectorIndex Index of the physical sector where the error occurred. Not applicable for all type of errors.
Additional driver functions

The following functions are optional and can be used by the application to perform operations directly on the NAND flash device.

FunctionDescription
FS_NAND_Clean() Makes sectors available for fast write operations.
FS_NAND_EraseBlock() Sets all the bytes in a NAND block to 0xFF.
FS_NAND_EraseFlash() Erases the entire NAND partition.
FS_NAND_FormatLow() Performs a low-level format of the NAND flash device.
FS_NAND_GetBlockInfo() Returns information about a specified NAND block.
FS_NAND_GetDiskInfo() Returns information about the NAND partition.
FS_NAND_GetStatCounters() Returns the actual values of statistical counters.
FS_NAND_IsBlockBad() Checks if a NAND block is marked as defective.
FS_NAND_IsLLFormatted() Checks if the NAND flash is low-level formatted.
FS_NAND_ReadPageRaw() Reads data from a page without ECC.
FS_NAND_ReadPhySector() This function reads a physical sector from NAND flash.
FS_NAND_ResetStatCounters() Sets the values of statistical counters to 0.
FS_NAND_TestBlock() Fills all the pages in a block (including the spare area) with the specified pattern and verifies if the data was written correctly.
FS_NAND_WritePage() Stores data to a page of a NAND flash with ECC.
FS_NAND_WritePageRaw() Stores data to a page of a NAND flash without ECC.
FS_NAND_Clean()

Description

Makes sectors available for fast write operations.

Prototype

int FS_NAND_Clean(U8       Unit,
                  unsigned NumBlocksFree,
                  unsigned NumSectorsFree);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
NumBlocksFree Number of blocks to be kept free.
NumSectorsFree Number of sectors to be kept free on each block.

Return value

= 0 OK
≠ 0 An error occurred

Additional information

This function is optional. It can be used to free space on the NAND flash device for data that the application has to write as fast as possible. FS_NAND_UNI_Clean() performs two internal operations: (1) Converts all work blocks that have less free sectors than NumSectorsFree into data blocks. (2) If required, convert work blocks until at least NumBlocksFree are available.

FS_NAND_EraseBlock()

Description

Sets all the bytes in a NAND block to 0xFF.

Prototype

int FS_NAND_EraseBlock(U8       Unit,
                       unsigned BlockIndex);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the NAND flash block to be erased.

Return value

= 0 OK, block erased.
≠ 0 An error occurred.

Additional information

This function is optional. FS_NAND_EraseBlock() function does not check if the block is marked as defective before erasing it.

FS_NAND_EraseFlash()

Description

Erases the entire NAND partition.

Prototype

int FS_NAND_EraseFlash(U8 Unit);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).

Return value

≥ 0 Number of blocks which failed to erase.
< 0 An error occurred.

Additional information

This function is optional. After the call to FS_NAND_EraseFlash() all the bytes in the NAND partition are set to 0xFF.

This function has to be used with care, since it also erases blocks marked as defective and therefore the information about the block status will be lost. FS_NAND_EraseFlash() can be used without this side effect on storage devices that are guaranteed to not have any bad blocks, such as DataFlash devices.

FS_NAND_FormatLow()

Description

Performs a low-level format of the NAND flash device.

Prototype

int FS_NAND_FormatLow(U8 Unit);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).

Return value

= 0 OK, NAND flash device is low-level formatted.
≠ 0 An error occurred.

Additional information

This function is optional. It is recommended that application use FS_FormatLow() to initialize the NAND flash device instead of FS_NAND_FormatLow().

After the low-level format operation all data that was stored on the NAND flash device is lost. A low-level format has to be performed only once before using the NAND flash device for the first time. The application can check if the NAND flash device is low-level formatted by calling FS_IsLLFormated() or alternatively FS_NAND_IsLLFormated().

FS_NAND_GetBlockInfo()

Description

Returns information about a specified NAND block.

Prototype

int FS_NAND_GetBlockInfo(U8                   Unit,
                         U32                  PhyBlockIndex,
                         FS_NAND_BLOCK_INFO * pBlockInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PhyBlockIndex Index of the physical block to get information about.
pBlockInfo  out  Information about the NAND block.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

This function is not required for the functionality of the SLC1 NAND driver and is typically not linked in in production builds.

Example

#include <stdio.h>
#include "FS.h"

void SampleNANDGetBlockInfo(void) {
  FS_NAND_BLOCK_INFO BlockInfo;
  char               ac[100];

  FS_X_Log("Get information about block 1 of the first SLC1 NAND driver instance\n");
  FS_NAND_GetBlockInfo(0, 1, &BlockInfo);
  SEGGER_snprintf(ac, sizeof(ac), "  sType:                    %s\n", BlockInfo.sType);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  EraseCnt:                 0x%.8x\n", BlockInfo.EraseCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  LBI:                      %lu\n", BlockInfo.lbi);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsBlank:          %d\n", BlockInfo.NumSectorsBlank);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsECCCorrectable: %d\n", BlockInfo.NumSectorsECCCorrectable);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsErrorInECC:     %d\n", BlockInfo.NumSectorsErrorInECC);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsECCError:       %d\n", BlockInfo.NumSectorsECCError);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsInvalid:        %d\n", BlockInfo.NumSectorsInvalid);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsValid:          %d\n", BlockInfo.NumSectorsValid);
}
FS_NAND_GetDiskInfo()

Description

Returns information about the NAND partition.

Prototype

int FS_NAND_GetDiskInfo(U8                  Unit,
                        FS_NAND_DISK_INFO * pDiskInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pDiskInfo  out  Information about the NAND partition.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

This function is not required for the functionality of the SLC1 NAND driver and is typically not linked in production builds.

Example

#include <stdio.h>
#include "FS.h"

void SampleNANDGetDiskInfo(void) {
  FS_NAND_DISK_INFO DiskInfo;
  char              ac[100];

  memset(&DiskInfo, 0, sizeof(DiskInfo));
  FS_X_Log("Get information about the first SLC1 NAND driver instance:\n");
  FS_NAND_GetDiskInfo(0, &DiskInfo);
  SEGGER_snprintf(ac, sizeof(ac), "  NumPhyBlocks:       %lu\n", DiskInfo.NumPhyBlocks);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumLogBlocks:       %lu\n", DiskInfo.NumLogBlocks);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumPagesPerBlock:   %lu\n", DiskInfo.NumPagesPerBlock);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumSectorsPerBlock: %lu\n", DiskInfo.NumSectorsPerBlock);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  BytesPerPage:       %lu\n", DiskInfo.BytesPerPage);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  BytesPerSector:     %lu\n", DiskInfo.BytesPerSector);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumUsedPhyBlocks:   %lu\n", DiskInfo.NumUsedPhyBlocks);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  NumBadPhyBlocks:    %lu\n", DiskInfo.NumBadPhyBlocks);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  EraseCntMin:        %lu\n", DiskInfo.EraseCntMin);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  EraseCntMax:        %lu\n", DiskInfo.EraseCntMax);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  EraseCntAvg:        %lu\n", DiskInfo.EraseCntAvg);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  IsWriteProtected:   %d\n", DiskInfo.IsWriteProtected);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  HasFatalError:      %d\n", DiskInfo.HasFatalError);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  ErrorType:          %d\n", DiskInfo.ErrorType);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  ErrorSectorIndex:   %lu\n", DiskInfo.ErrorSectorIndex);
  FS_X_Log(ac);
}
FS_NAND_GetStatCounters()

Description

Returns the actual values of statistical counters.

Prototype

void FS_NAND_GetStatCounters(U8                      Unit,
                             FS_NAND_STAT_COUNTERS * pStat);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)
pStat  out  Values of statistical counters.

Additional information

This function is optional. It is active only when the file system is compiled with FS_DEBUG_LEVEL set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.

The statistical counters can be cleared via FS_NAND_ResetStatCounters().

FS_NAND_IsBlockBad()

Description

Checks if a NAND block is marked as defective.

Prototype

int FS_NAND_IsBlockBad(U8       Unit,
                       unsigned BlockIndex);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the NAND flash block to be checked.

Return value

1 Block is defective
0 Block is not defective

Additional information

This function is optional.

FS_NAND_IsLLFormatted()

Description

Checks if the NAND flash is low-level formatted.

Prototype

int FS_NAND_IsLLFormatted(U8 Unit);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).

Return value

= 1 NAND flash device is low-level formatted.
= 0 NAND flash device is not low-level formatted.
< 0 An error occurred.

Additional information

This function is optional.

FS_NAND_ReadPageRaw()

Description

Reads data from a page without ECC.

Prototype

int FS_NAND_ReadPageRaw(U8         Unit,
                        U32        PageIndex,
                        void     * pData,
                        unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PageIndex Index of the page to be read.
pData  out  Data to be written.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read.
≠ 0 An error occurred.

Additional information

This function is optional.

The data is read beginning from byte offset 0 in the page. If more data is requested than the page + spare area size, typ. 2 Kbytes + 64 bytes, the function does not modify the remaining bytes in pData.

FS_NAND_ReadPhySector()

Description

This function reads a physical sector from NAND flash.

Prototype

int FS_NAND_ReadPhySector(U8         Unit,
                          U32        PhySectorIndex,
                          void     * pData,
                          unsigned * pNumBytesData,
                          void     * pSpare,
                          unsigned * pNumBytesSpare);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PhySectorIndex Physical sector index.
pData Pointer to a buffer to store read data.
pNumBytesData  in  Pointer to variable storing the size of the data buffer.  out  The number of bytes that were stored in the data buffer.
pSpare Pointer to a buffer to store read spare data.
pNumBytesSpare  in  Pointer to variable storing the size of the spare data buffer.  out  The number of bytes that were stored in the spare data buffer.

Return value

< 0 OK, all bytes are set to 0xFF in the physical sector.
= 0 OK, no bit errors.
= 1 OK, one bit error found and corrected.
= 2 OK, one bit error found in the ECC.
= 3 Error, more than 1 bit errors occurred.
= 4 Error, could not read form NAND flash device.
= 5 Error, internal operation.

Additional information

This function is optional.

FS_NAND_ResetStatCounters()

Description

Sets the values of statistical counters to 0.

Prototype

void FS_NAND_ResetStatCounters(U8 Unit);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)

Additional information

This function is optional. It is active only when the file system is compiled with FS_DEBUG_LEVEL set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.

The statistical counters can be queried via FS_NAND_GetStatCounters().

FS_NAND_TestBlock()

Description

Fills all the pages in a block (including the spare area) with the specified pattern and verifies if the data was written correctly.

Prototype

int FS_NAND_TestBlock(U8                  Unit,
                      unsigned            BlockIndex,
                      U32                 Pattern,
                      FS_NAND_TEST_INFO * pInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the NAND block to be tested.
Pattern Data pattern to be written during the test.
pInfo  out  Optional information about the test result.

Return value

FS_NAND_TEST_RETVAL_OK OK, no bit errors.
FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR OK, correctable bit errors found. The number of bit errors is returned in NumErrorsCorrectable of pResult.
FS_NAND_TEST_RETVAL_FATAL_ERROR Fatal error, uncorrectable bit error found. The page index is returned in PageIndexFatalError of pResult.
FS_NAND_TEST_RETVAL_BAD_BLOCK Bad block, skipped.
FS_NAND_TEST_RETVAL_ERASE_FAILURE Erase operation failed. The block has been marked as defective.
FS_NAND_TEST_RETVAL_WRITE_FAILURE Write operation failed. The block has been marked as defective.
FS_NAND_TEST_RETVAL_READ_FAILURE Read operation failed.
FS_NAND_TEST_RETVAL_INTERNAL_ERROR NAND flash access error.

Additional information

This function is optional. It can be used by the application to test the data reliability of a NAND block. BlockIndex is relative to the beginning of the NAND partition where the first block has the index 0.

Example

#include <stdio.h>
#include "FS.h"

void _SampleNANDTestBlock(void) {
  int               r;
  U32               NumPhyBlocks;
  U32               iBlock;
  FS_NAND_DISK_INFO DiskInfo;
  FS_NAND_TEST_INFO TestInfo;
  char              ac[100];

  memset(&DiskInfo, 0, sizeof(DiskInfo));
  memset(&TestInfo, 0, sizeof(TestInfo));
  FS_NAND_GetDiskInfo(0, &DiskInfo);
  NumPhyBlocks = DiskInfo.NumPhyBlocks;
  for (iBlock = 0; iBlock < NumPhyBlocks; ++iBlock) {
    r = FS_NAND_TestBlock(0, iBlock, 0xAA5500FFuL, &TestInfo);
    switch (r) {
    case FS_NAND_TEST_RETVAL_OK:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: OK.\n", iBlock);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: %lu correctable error(s).\n", 
        iBlock, TestInfo.BitErrorCnt);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_FATAL_ERROR:
      SEGGER_snprintf(ac, sizeof(ac), 
        "Block %lu: %lu correctable error(s), fatal error on page %lu.\n", 
        iBlock, TestInfo.BitErrorCnt, TestInfo.PageIndex);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_BAD_BLOCK:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Bad. Skipped.\n", iBlock);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_ERASE_FAILURE:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Erase failure. Marked as bad.\n", iBlock);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_WRITE_FAILURE:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Write failure on page %lu. Marked as bad.\n", 
        iBlock, TestInfo.PageIndex);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_READ_FAILURE:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Read failure on page %lu.\n", 
        iBlock, TestInfo.PageIndex);
      FS_X_Log(ac);
      break;
    default:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Internal error.\n", iBlock);
      FS_X_Log(ac);
      break;
    }
  }
}
FS_NAND_WritePage()

Description

Stores data to a page of a NAND flash with ECC.

Prototype

int FS_NAND_WritePage(      U8         Unit,
                            U32        PageIndex,
                      const void     * pData,
                            unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PageIndex Index of the page to be written.
pData  in  Data to be written.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is optional.

The data is written beginning with the byte offset 0 in the page. If more data is written than the size of the page, typically 2 KB + 64 bytes, the excess bytes are discarded. Data in the area reserved for ECC cannot be written using this function and it will be overwritten.

FS_NAND_WritePageRaw()

Description

Stores data to a page of a NAND flash without ECC.

Prototype

int FS_NAND_WritePageRaw(      U8         Unit,
                               U32        PageIndex,
                         const void     * pData,
                               unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PageIndex Index of the page to be written.
pData  in  Data to be written.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is optional.

The data is written beginning at the byte offset 0 in the page. If more data is written than the size of the page + spare area, typically 2 Kbytes + 64 bytes, the excess bytes are ignored.

FS_NAND_DISK_INFO

Description

Information about the NAND partition.

Type definition

typedef struct {
  U32  NumPhyBlocks;
  U32  NumLogBlocks;
  U32  NumUsedPhyBlocks;
  U32  NumBadPhyBlocks;
  U32  NumPagesPerBlock;
  U32  NumSectorsPerBlock;
  U32  BytesPerPage;
  U32  BytesPerSpareArea;
  U32  BytesPerSector;
  U32  EraseCntMin;
  U32  EraseCntMax;
  U32  EraseCntAvg;
  U8   BadBlockMarkingType;
  U8   IsWriteProtected;
  U8   HasFatalError;
  U8   ErrorType;
  U32  ErrorSectorIndex;
  U16  BlocksPerGroup;
  U32  NumWorkBlocks;
  U8   IsFormatted;
} FS_NAND_DISK_INFO;

Structure members

Member Description
NumPhyBlocks Total number of blocks in the NAND partition.
NumLogBlocks Total number of NAND blocks that can be used to store data.
NumUsedPhyBlocks Number of NAND blocks that store valid data.
NumBadPhyBlocks Number of NAND blocks that are marked as defective.
NumPagesPerBlock Number of pages in a NAND block.
NumSectorsPerBlock Number of logical sectors stored in a NAND block.
BytesPerPage Number of bytes in the main area of a NAND page.
BytesPerSpareArea Number of bytes in the spare area of a NAND page.
BytesPerSector Number of bytes is a logical sector.
EraseCntMin Minimum value of the erase counts in the NAND partition.
EraseCntMax Maximum value of the erase counts in the NAND partition.
EraseCntAvg Average value of the erase counts of all the NAND blocks in the NAND partition.
BadBlockMarkingType Type of the bad block marking.
IsWriteProtected Set to 1 if the NAND flash device cannot be written.
HasFatalError Set to 1 if the SLC1 NAND driver reported a fatal error.
ErrorType Type of fatal error that has occurred.
ErrorSectorIndex Sector index on which a fatal error occurred.
BlocksPerGroup Number of NAND blocks in a group.
NumWorkBlocks Number of work blocks used by the SLC1 NAND driver.
IsFormatted Set to 1 if the NAND partition has been low-level formatted.

Additional information

Refer to Bad block marking types for a list of permitted values for BadBlockMarkingType.

FS_NAND_BLOCK_INFO

Description

Information about a NAND block.

Type definition

typedef struct {
  U32          EraseCnt;
  U32          lbi;
  U16          NumSectorsBlank;
  U16          NumSectorsValid;
  U16          NumSectorsInvalid;
  U16          NumSectorsECCError;
  U16          NumSectorsECCCorrectable;
  U16          NumSectorsErrorInECC;
  U8           IsDriverBadBlock;
  U8           BadBlockErrorType;
  U16          BadBlockErrorBRSI;
  U8           Type;
  const char * sType;
} FS_NAND_BLOCK_INFO;

Structure members

Member Description
EraseCnt Number of times the block has been erased
lbi Logical block index assigned to queried physical block.
NumSectorsBlank Sectors are not used yet.
NumSectorsValid Sectors contain correct data.
NumSectorsInvalid Sectors have been invalidated.
NumSectorsECCError Sectors have incorrect ECC.
NumSectorsECCCorrectable Sectors have correctable ECC error.
NumSectorsErrorInECC Sectors have error in ECC.
IsDriverBadBlock Set to 1 if the block has been marked as bad by the driver.
BadBlockErrorType Type of the error that caused the block to be marked as defective.
BadBlockErrorBRSI Block-relative sector index on which the fatal error occurred that caused the block to be marked as defective.
Type Type of data stored in the block.
sType Zero-terminated string holding the block type.

Additional information

Refer to NAND block types for a list of permitted values for Type.

IsDriverBadBlock is valid only when Type is set to FS_NAND_BLOCK_TYPE_BAD.

Performance and resource usage

This section provides information about the ROM and RAM usage as well as the performance of the SLC1 NAND driver. Each SLC1 NAND driver instance requires one instance of one NAND physical layer in order to operate. The resource usage of the used NAND physical layer has to be taken into account when calculating the total resource usage of the SLC1 NAND driver.

ROM usage

The ROM usage depends on the compiler options, the compiler version and the used CPU. The memory requirements of the SLC1 NAND driver were measured as described in the section Test procedure.

Usage: 4.5 Kbytes

Static RAM usage

Static RAM usage refers to the amount of RAM required by the SLC1 NAND driver internally for all the driver instances. The number of bytes can be seen in the compiler list file of the {FS_NAND_Drv.c} file.

Usage: 32 bytes

Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the driver at runtime. The amount RAM required depends on the runtime configuration and on the characteristics of the used NAND flash device. The approximate RAM usage of the SLC1 NAND driver can be calculated as follows:

MemAllocated = 160 + 2 * NumberOfUsedBlocks + 4 * SectorsPerBlock
               + 1.04 * MaxSectorSize
Parameter Description
MemAllocated Number of bytes allocated for one instance of the NAND driver
NumberOfUsedBlocks Number of NAND blocks used for data storage
SectorsPerBlock Number of logical sectors that can be stored in a NAND block
MaxSectorSize Size of a logical sector in bytes

Example 1

2 GBit NAND flash with 2K pages, 2048 blocks used, 512-byte sectors, one NAND block consists of 64 pages, each page holds 4 sectors of 512 bytes.

SectorsPerBlock    = 256
NumberOfUsedBlocks = 2048
MaxSectorSize      = 512
RAM usage          = (160 + 2 * 2048 + 4 * 256 + 1.04 * 512) bytes
RAM usage          = 5813 bytes

Example 2

2 GBit NAND flash with 2K pages, 2048 blocks used, 2048-byte sectors, one block consists of 64 pages, each page holds 1 sector of 2048 bytes.

SectorsPerBlock    = 64
NumberOfUsedBlocks = 2048
MaxSectorSize      = 2048
RAM usage          = (160 + 2 * 2048 + 4 * 64 + 1.04 * 2048) bytes
RAM usage          = 6642 bytes

Example 3

512 MBit NAND flash with 512 pages, 4096 blocks used, 512-byte sectors, one block consists of 64 pages, each page holds 1 sector of 512 bytes.

SectorsPerBlock    = 32
NumberOfUsedBlocks = 8192
MaxSectorSize      = 512
RAM usage          = (160 + 2 * 4096 + 4 * 32 + 1.04 * 512) bytes
RAM usage          = 9013 bytes
Performance

The following performance measurements are in no way complete, but they give a good approximation of time required for common operations on various target hardware. The tests were performed as described in the section Performance. All values are given in Mbytes/sec.

CPU type NAND flash device Write speed Read speed
Atmel AT91SAM7S (48 MHz) NAND flash with 512 bytes per page using port mode. 0.8 2.0
Atmel AT91SAM7S (48 MHz) NAND flash with 2048 bytes per page and a sector size of 512 bytes using Port mode. 0.7 2.0
Atmel AT91SAM7S (48 MHz) NAND flash with 2048 bytes per page and a sector size of 2048 bytes using the built-in NAND controller/external bus-interface. 1.3 2.3
Atmel AT91SAM7SE (48 MHz) NAND flash with 2048 bytes per page and a sector size of 512 bytes using the built-in NAND controller/external bus-interface. 1.6 3.1
Atmel AT91SAM7SE (48 MHz) NAND flash with 2048 bytes per page and a sector size of 2048 bytes using the built-in NAND controller/external bus-interface. 3.8 5.9
Atmel AT91SAM9261 (200 MHz) NAND flash with 2048 bytes per page and a sector size of 512 bytes using the built-in NAND controller/external bus-interface. 2.3 6.5
Atmel AT91SAM9261 (200 MHz) NAND flash with 2048 bytes per page and a sector size of 2048 bytes using the built-in NAND controller/external bus-interface. 5.1 9.8
Atmel AT91SAM9G45 (384 MHz) NAND flash with 2048 bytes per page and a sector size of 2048 bytes using the built-in NAND controller/external bus-interface. 4.7 12.4
Atmel AT91SAM3U (96 MHz) NAND flash with 2048 bytes per page and a sector size of 2048 bytes using the built-in NAND controller/external bus-interface. 5.0 5.9
Atmel AT91SAM3U (96 MHz) NAND flash with 2048 bytes per page and a sector size of 512 bytes using the built-in NAND controller/external bus-interface. 2.3 4.7
Atmel AT91SAM9261 (200 MHz) AT45DB64 DataFlash with a sector size of 1024 bytes using the SPI interface. 0.16 0.67

Universal NAND driver

Universal NAND driver is a very efficient device driver that was designed to support NAND flash devices that are using Single-Level Cell (SLC) as well Multi-Level Cell (MLC) technology. It requires a relatively small amount of RAM to operate and it can correct multiple bit errors by using the internal ECC of a NAND flash device or by calling ECC calculation routines provided by the application. The ECC protects the sector data and the driver management data stored in the spare area of a page which provides better data reliability. The Universal NAND driver uses a logical sector size that is equal to page size of the used NAND flash device. The NAND flash device must have a page of least 2048 bytes. Smaller logical sector sizes can be used with the help of an additional file system layer such as Sector Size Adapter driver.

Supported hardware

In general, the Universal NAND driver supports almost all popular Single-Level Cell NAND flashes (SLC) with a page size larger than 2048+64 bytes. The table below shows the NAND flash devices that have been tested or are compatible with a tested device:

Device name Page size Number of blocks Storage capacity Bus width HW ECC Supported extra features
ATO
AFND1G08U3 2048+64 byte 1024 128 MiB 16 bit No
Alliance Memory
AS5F32G04SND 2048+128 byte 2048 256 MiB 1 bit Yes
AS5F34G04SND 2048+128 byte 4096 512 MiB 1 bit Yes
AS5F38G04SND 4096+256 byte 4096 1 GiB 1 bit Yes
AS9F31G08SA 2048+64 byte 1024 1 GiB 8 bit No
AS9F32G08SA 2048+128 byte 2048 2 GiB 8 bit No
AS9F34G08SA 2048+128 byte 4096 4 GiB 8 bit No
AS9F38G08SA 2048+128 byte 8192 8 GiB 8 bit No
GigaDevice
GD5F1GQ4UF 2048+64 byte 1024 128 MiB 1 bit Yes
GD5F2GQ5UE 2048+128 byte 2048 256 MiB 1 bit Yes
GD9FU1G8F2A 2048+128 byte 1024 128 MiB 8 bit No
GD9FU4G8F2A 2048+128 byte 4096 512 MiB 8 bit Yes
Hynix
HY27UF081G2A 2048+64 byte 1024 128 MiB 8 bit No
HY27UF081G2M 2048+64 byte 1024 128 MiB 8 bit No
HY27UF082G2M 2048+64 byte 2048 256 MiB 8 bit No
HY27UF084G2M 2048+64 byte 4096 512 MiB 8 bit No
HY27UG084G2M 2048+64 byte 4096 512 MiB 8 bit No
HY27UG084GDM 2048+64 byte 4096 512 MiB 8 bit No
ISSI
IS34ML01G081 2048+64 byte 1024 128 MiB 8 bit No
IS34ML01G084 2048+64 byte 1024 128 MiB 8 bit No
IS34ML02G084 2048+64 byte 2048 256 MiB 8 bit No
IS34ML04G081 2048+64 byte 4096 512 MiB 8 bit No
IS34ML04G084 2048+64 byte 4096 512 MiB 8 bit No
IS34ML04G088 4096+256 byte 2048 512 MiB 8 bit No
IS35ML02G081 2048+64 byte 2048 256 MiB 8 bit No
IS37SML01G1 2048+64 byte 1024 128 MiB 1 bit Yes
IS38SML01G1 2048+64 byte 1024 128 MiB 1 bit Yes
Kioxia/Toshiba
TC58BVG0S3HTAI0 2048+64 byte 1024 128 MiB 8 bit Yes
TC58BVG1S3HTA00 2048+64 byte 2048 256 MiB 8 bit Yes
TC58BYG0S3HBAI6 2048+64 byte 1024 128 MiB 8 bit Yes
TC58CVG0S3HRAIJ 2048+64 byte 1024 128 MiB 1 bit Yes
TC58CVG1S3HRAIF 2048+128 byte 2048 256 MiB 1 bit Yes
TC58CVG1S3HRAIG 2048+64 byte 2048 256 MiB 1 bit Yes
TC58CVG1S3HRAIJ 2048+64 byte 2048 256 MiB 1 bit Yes
TC58CVG2S0HRAIJ 4096+128 byte 2048 512 MiB 1 bit Yes
TC58CYG0S3HRAIJ 2048+64 byte 1024 128 MiB 1 bit Yes
TC58CYG1S3HRAIJ 2048+64 byte 2048 256 MiB 1 bit Yes
TC58CYG2S0HRAIG 4096+128 byte 2048 512 MiB 1 bit Yes
TC58CYG2S0HRAIJ 4096+128 byte 2048 512 MiB 1 bit Yes
TH58BYG3S0HBAI6 4096+128 byte 4096 1 GiB 8 bit Yes
TH58CVG3S0HRAIJ 4096+128 byte 4096 1 GiB 1 bit Yes
TH58CYG3S0HRAIJ 4096+128 byte 4096 1 GiB 1 bit Yes
Macronix
MX30LF1G18AC 2048+64 byte 1024 128 MiB 8 bit No
MX30LF1G28AD 2048+128 byte 1024 128 MiB 8 bit No
MX30LF1GE8AB 2048+64 byte 1024 128 MiB 8 bit Yes
MX30LF2G28AD 2048+128 byte 2048 256 MiB 8 bit No
MX30LF2GE8AB 2048+64 byte 2048 256 MiB 8 bit Yes
MX30LF4G28AD 4096+256 byte 2048 512 MiB 8 bit No
MX30LF4GE8AB 2048+64 byte 4096 512 MiB 8 bit Yes
MX35LF1G24AD 2048+128 byte 1024 128 MiB 1 bit No
MX35LF1GE4AB 2048+64 byte 1024 128 MiB 1 bit Yes
MX35LF2G24AD 2048+128 byte 2048 256 MiB 1 bit No
MX35LF2GE4AD 2048+64 byte 2048 256 MiB 1 bit Yes
MX35LF4G24AD 4096+256 byte 2048 512 MiB 1 bit No
MX35LF4GE4AD 4096+128 byte 2048 512 MiB 1 bit Yes
MX60LF8G28AB 2048+112 byte 8192 1 GiB 8 bit No
MX60LF8G28AD 4096+256 byte 4096 1 GiB 8 bit No
Micron
MT29F1G01AAADD 2048+64 byte 1024 128 MiB 1 bit Yes
MT29F1G01ABAFD 2048+128 byte 1024 128 MiB 1 bit Yes
MT29F1G01ABBFD 2048+128 byte 1024 128 MiB 1 bit Yes
MT29F1G08ABADA 2048+64 byte 1024 128 MiB 8 bit Yes
MT29F1G08ABAEA 2048+64 byte 1024 128 MiB 8 bit No
MT29F1G08ABAFA 2048+128 byte 1024 128 MiB 8 bit Yes
MT29F2G01AAAED 2048+64 byte 2048 256 MiB 1 bit Yes
MT29F2G01ABAGD 2048+128 byte 2048 256 MiB 1 bit Yes
MT29F2G08AAB 2048+64 byte 2048 256 MiB 8 bit No
MT29F2G08ABABA 2048+64 byte 2048 256 MiB 8 bit No
MT29F2G08ABAEA 2048+64 byte 2048 256 MiB 8 bit Yes
MT29F2G08ABAGA 2048+128 byte 2048 256 MiB 8 bit Yes
MT29F2G08ABD 2048+64 byte 2048 256 MiB 8 bit No
MT29F2G16AAD 2048+64 byte 2048 256 MiB 16 bit No
MT29F2G16ABAEA 2048+64 byte 2048 256 MiB 16 bit Yes
MT29F4G01AAADD 2048+64 byte 4096 512 MiB 1 bit Yes
MT29F4G01ABAFD 4096+256 byte 4096 512 MiB 1 bit Yes
MT29F4G01ABBFD 4096+256 byte 2048 512 MiB 1 bit Yes
MT29F4G08AAA 2048+64 byte 4096 512 MiB 8 bit No
MT29F4G08ABADA 2048+64 byte 4096 512 MiB 8 bit Yes
MT29F4G08BAB 2048+64 byte 4096 512 MiB 8 bit No
MT29F8G01ADAFD 4096+256 byte 4096 1 GiB 1 bit Yes
MT29F8G01ADBFD 4096+256 byte 4096 1 GiB 1 bit Yes
MT29F8G08ABABA 4096+224 byte 2048 1 GiB 8 bit No
MT29F8G08ABACA 4096+224 byte 4096 1 GiB 8 bit No
STMicroelectronics
NAND01GR3B 2048+64 byte 1024 128 MiB 8 bit No
NAND01GW3B 2048+64 byte 1024 128 MiB 8 bit No
NAND02GR3B 2048+64 byte 2048 256 MiB 8 bit No
NAND02GW3B 2048+64 byte 2048 256 MiB 8 bit No
NAND04GW3B 2048+64 byte 4096 512 MiB 8 bit No
Samsung
K9F1G08R0A 2048+64 byte 1024 128 MiB 8 bit No
K9F1G08U0A 2048+64 byte 1024 128 MiB 8 bit No
K9F1G08U0C 2048+64 byte 1024 128 MiB 8 bit No
K9F1G08U0F 2048+64 byte 1024 128 MiB 8 bit Yes
K9F2G08U0M 2048+64 byte 2048 256 MiB 8 bit No
K9F4G08U0A 2048+64 byte 4096 512 MiB 8 bit No
K9F4G08U0M 2048+64 byte 4096 512 MiB 8 bit No
K9F8G08U0M 2048+128 byte 4096 1 GiB 8 bit No
K9K2G08R0A 2048+64 byte 2048 256 MiB 8 bit No
K9K2G08U0M 2048+64 byte 2048 256 MiB 8 bit No
SkyHigh/Cypress
S34ML01G100TFI000 2048+64 byte 1024 128 MiB 8 bit No
S34ML01G300TFI013 2048+64 byte 1024 128 MiB 8 bit Yes
S34ML04G100TFI000 2048+64 byte 4096 512 MiB 8 bit No
S34ML04G200TFI000 2048+128 byte 4096 512 MiB 8 bit No
S34ML04G300TFI000 2048+128 byte 4096 512 MiB 8 bit Yes
S34ML04G300TFI100 4096+256 byte 2048 512 MiB 8 bit Yes
S34ML08G201TFI000 2048+128 byte 8192 1 GiB 8 bit No
S34ML08G301TFI000 2048+128 byte 8192 1 GiB 8 bit Yes
S34ML16G202TFI200 2048+128 byte 16384 2 GiB 8 bit No
S34ML16G303TFI000 2048+128 byte 16384 2 GiB 8 bit Yes
S34MS02G100TFI000 2048+64 byte 2048 256 MiB 8 bit No
Winbond
W25M02GVZEIT 2048+64 byte 2048 256 MiB 1 bit Yes
W25N01GVZEIG 2048+64 byte 1024 128 MiB 1 bit Yes
W25N01JWSFIT 2048+64 byte 1024 128 MiB 1 bit Yes DTR
W25N02JWZEIF 2048+64 byte 2048 256 MiB 1 bit Yes DTR
W25N02KVZEIU 2048+128 byte 2048 256 MiB 1 bit Yes
W25N04KVZEIR 2048+128 byte 4096 512 MiB 1 bit Yes
W25N512GVEIG 2048+64 byte 512 64 MiB 1 bit Yes
W29N02GZSIBF 2048+64 byte 2048 256 MiB 8 bit No
W29N08GVSIAA 2048+64 byte 8192 1 GiB 8 bit No
XTX
XT27G02BTSIG 2048+64 byte 2048 256 MiB 8 bit Yes

Support for devices not in the list

Most other NAND flash devices are compatible with one of the supported devices. Thus, the driver can be used with these devices or may only need a little modification, which can be easily done. Get in touch with us, if you have questions about support for devices not in this list.

Theory of operation

NAND flash devices are divided into physical blocks and physical pages. One physical block is the smallest erasable unit while one physical page is the smallest writable unit. Large block NAND Flash devices contain blocks made up of 64 pages, each page containing 2112 bytes (2048 data bytes + 64 spare bytes). The Universal NAND driver reserves the first page of a block for management data such as erase count. The Universal NAND driver uses the spare bytes for the following purposes:

Support for custom hardware

It is possible to use the Universal NAND driver with a custom hardware. If port pins or a simple memory controller are used for accessing the flash memory, only the hardware layer needs to be ported and normally no changes to the physical layer are required. If the NAND driver has to be used with a special memory controller (for example special FPGA implementations), the physical layer needs to be adapted. In this case, the hardware layer is not required, because the memory controller manages all the hardware accesses.

Partial write operations

The Universal NAND driver writes only once in any page of the NAND flash between two erase operations of the NAND block that contain that page. Therefore, the number of partial write operation is one which makes the driver compatible with any SLC and MLC NAND flash device.

High-reliability operation

The Universal NAND driver supports a feature that can be used to increase the reliability of the data stored to a NAND flash device. It works by checking the number of bit errors corrected by the ECC during each page read operation. If the number of bit errors is equal to or greater than a configured threshold the Universal NAND driver copies the contents of the NAND block containing the read page to an other location. This prevents the accumulation of bit errors that may cause ECC correction errors. An ECC correction error occurs when the number of bit errors is larger than the number of bit errors the ECC is able to correct. Typically, a correction error leads to a data loss.

This feature requires support for the FS_NAND_PHY_TYPE_GET_ECC_RESULT function in the NAND physical layer. By default, the feature is disabled for performance reasons and has to be explicitly enabled at compile time by setting FS_NAND_MAX_BIT_ERROR_CNT to a value greater than 0. This value can be modified at runtime by calling FS_NAND_UNI_SetMaxBitErrorCnt().

Note

Enabling the high-reliability operation may reduce the specified lifetime of the NAND flash due to the increased number of erase cycles.

Configuring the driver

This section describes how to configure the file system to make use of the Universal NAND driver.

Compile time configuration

The Universal NAND driver can optionally be configured at compile time. Typically, this step can be omitted because the Universal NAND driver provides reasonable default values that work for most of the target applications. The compile time configuration is realized via preprocessor defines that have to be added to the FS_Conf.h file which is the main configuration file of emFile. For detailed information about the configuration of emFile and of the configuration define types, refer to Configuration of emFile The following table lists the configuration defines supported by the Universal NAND driver.

Define Default value Type Description
FS_NAND_ECC_HOOK_DEFAULT &FS_NAND_ECC_SW_1BIT R Configures the default ECC algorithm.
FS_NAND_ENABLE_ERROR_RECOVERY 0 B Enables or disables the bit error recovery via RAID driver.
FS_NAND_ENABLE_STATS 0 or 1 B Enables or disables the support for statistical counters.
FS_NAND_ENABLE_STATS_SECTOR_STATUS 1 B Enables or disables the collection of statistical information about the number of valid logical sectors.
FS_NAND_FILL_READ_BUFFER 0 or 1 B Enables or disables the filling of invalid sectors with predefined data.
FS_NAND_MAX_BIT_ERROR_CNT 0 N Configures the number of bit errors that trigger a block relocation.
FS_NAND_MAX_PAGE_SIZE 0 N Configures the size of the main area buffer.
FS_NAND_MAX_SPARE_AREA_SIZE 0 N Configures the size of the spare area buffer.
FS_NAND_NUM_READ_RETRIES 10 N Configures the number of retries in case of a read error.
FS_NAND_NUM_WRITE_RETRIES 10 N Configures the number of retries in case of a write error.
FS_NAND_NUM_UNITS 4 N Configures the maximum number of driver instances.
FS_NAND_OPTIMIZE_SPARE_AREA_READ 0 B Enables or disables the optimization related to reading data from the spare area.
FS_NAND_READ_BUFFER_FILL_PATTERN 0xFF N Configures the value to fill an invalid logical sector contents.
FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS 0 B Configures how the blocks marked as defective are handled at low-level format.
FS_NAND_STAT_MAX_BIT_ERRORS 1 N Configures the number of statistical counters for bit errors.
FS_NAND_SUPPORT_BLOCK_GROUPING 1 B Enables or disables the block grouping feature.
FS_NAND_SUPPORT_FAIL_SAFE_ERASE 0 B Enables or disables the fail-safe erase feature.
FS_NAND_VERIFY_ERASE 0 B Enables or disables the verification of the erase operation.
FS_NAND_VERIFY_WRITE 0 B Enables or disables the verification of the write operation.
FS_NAND_ECC_HOOK_DEFAULT

The FS_NAND_ECC_HOOK_DEFAULT can be used to specify default ECC calculation routines. For a file system configuration that has support for calculating the ECC in the hardware FS_NAND_ECC_HOOK_DEFAULT can be set to NULL to reduce the ROM usage. In this case it is mandatory that the application specifies at runtime a different ECC algorithm via FS_NAND_UNI_SetECCHook().

FS_NAND_ENABLE_ERROR_RECOVERY

This define can be used to enable the support for error recovery in the Universal NAND driver. The error recovery is performed by getting corrected data from a redundant partition via one of the RAID components of the file system. Refer to RAID1 driver and RAID5 driver for more information about this.

FS_NAND_ENABLE_STATS

This define can be used to enable the support for statistical counters. The statistical counters provide information about the number of operations performed internally by the Universal NAND driver. This information can be useful for analyzing the performance. The statistical counters can be queried via FS_NAND_UNI_GetStatCounters(). By default FS_NAND_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NAND_ENABLE_STATS_SECTOR_STATUS

This define can be used to configure if the Universal NAND driver has to collect information about the number of valid logical sectors. Enabling this operation may negatively affect the performance of the low-level mount operation because the the Universal NAND driver has to check the status of all logical sectors. FS_NAND_ENABLE_STATS_SECTOR_STATUS takes effect only if FS_NAND_ENABLE_STATS is set to 1.

FS_NAND_FILL_READ_BUFFER

FS_NAND_FILL_READ_BUFFER can be used to configure if the read buffer that receives the contents of an invalid logical sector has to be initialized with predefined data. The byte pattern that has to be used for filling the buffer contents can be specified via FS_NAND_READ_BUFFER_FILL_PATTERN. By default this feature is enabled only if no file system layer is used (both FS_SUPPORT_FAT and FS_SUPPORT_EFS set to 0), because the file system layer does not rely on this feature.

FS_NAND_MAX_BIT_ERROR_CNT

This define can be used to configure the monitoring of bit errors in the Universal NAND driver. The assigned value specifies the maximum number of correctable bit errors that are allowed to occur in a page before the block that contains that page is copied to another location. This is done in order to reduce the probability of a data loss as a result of an ECC correction error by keeping the number of bit errors below the bit error correction capability of the ECC algorithm. The value of FS_NAND_MAX_BIT_ERROR_CNT has to be smaller than or equal to the bit error correction capability that is required by the NAND flash device. The bit error monitoring is disabled if FS_NAND_MAX_BIT_ERROR_CNT is set to 0. The maximum number of bit errors can also be changed at runtime via FS_NAND_UNI_SetMaxBitErrorCnt(). Enabling this feature increases the data reliability but it may negatively affect the performance.

FS_NAND_MAX_PAGE_SIZE

FS_NAND_MAX_PAGE_SIZE can be used to configure the the size of the internal buffer that the Universal NAND driver uses for reading and writing the data of the main area of a page. If FS_NAND_MAX_PAGE_SIZE is set to 0 then the Universal NAND driver allocates a buffer with a size equal to the logical sector of the file system. In addition, the size of the buffer can be configured at runtime via FS_NAND_UNI_SetMaxPageSize().

FS_NAND_MAX_SPARE_AREA_SIZE

FS_NAND_MAX_SPARE_AREA_SIZE can be used to configure the size of the internal buffer that the Universal NAND driver uses for reading and writing the data of the spare area of a page. If FS_NAND_MAX_SPARE_AREA_SIZE is set to 0 then the Universal NAND driver allocates a buffer that is 1/32 of the internal buffer allocated for the main area of a page. For example, 64 bytes are allocated if the size of the buffer used for the main area of a page is 2048 bytes. If the ratio between the size of the main and spare area of the page is different than 1/32 then FS_NAND_MAX_SPARE_AREA_SIZE has to be set to the number of bytes in the spare area of the NAND flash device. In addition, the size of the buffer can be configured a runtime via FS_NAND_UNI_SetMaxSpareAreaSize().

FS_NAND_NUM_READ_RETRIES

FS_NAND_NUM_READ_RETRIES can be used to specify the number of times the Universal NAND driver reties the operation in case of a read error (device error or uncorrectable bit error). NumReadRetries of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.

FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS

FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS can be used to configure the behavior of the Universal NAND driver during the low-level format operation with regards to the NAND blocks marked as defective. If FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS is set to 1 then the NAND blocks marked as defective by the Universal NAND driver are erased during the low-level format operation. If FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS is set to 0 then the low-level format operation does not erase the NAND blocks marked as defective by the Universal NAND driver. This is the default behavior. Setting FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS to 1 is useful during the development of a NAND physical or hardware layer when NAND blocks may be marked as defective by mistake. These blocks can then be easily erased via a low-level format operation. The NAND blocks marked as defective by the manufacturer are never erased. In addition, these NAND blocks are never used for data storage.

FS_NAND_NUM_WRITE_RETRIES

FS_NAND_NUM_WRITE_RETRIES can be used to specify the number of times the Universal NAND driver reties the operation in case of a write error. A write error occurs when the NAND flash device is not able to write the data to memory array. This condition is typically reported via a flag in the status register of the NAND flash device that is queried by the NAND physical layer after each write operation. NumWriteRetries of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.

FS_NAND_NUM_UNITS

This define specifies the maximum number of driver instances of the Universal NAND driver the application is allowed create. Four bytes of static RAM are reserved for each instance. If the maximum number of driver instances is smaller than the default then FS_NAND_NUM_UNITS can be set to the to that value in order to reduce the RAM usage.

FS_NAND_OPTIMIZE_SPARE_AREA_READ

This configuration define can be used to enable an optimization that reduces the amount of data transferred by the Universal NAND driver from the spare area from a page to the MCU. With FS_NAND_OPTIMIZE_SPARE_AREA_READ set to 0 the entire spare are of a page is transferred to MCU each time the Universal NAND driver has to evaluate the management data of that page. If FS_NAND_OPTIMIZE_SPARE_AREA_READ set to 1 then only the regions of the spare area that store the management data are transferred to the MCU. This may help improve the performance when the NAND flash device is connected to the MCU via a relatively slow interface such as SPI.

FS_NAND_READ_BUFFER_FILL_PATTERN

The Universal NAND driver uses the byte value assigned to FS_NAND_READ_BUFFER_FILL_PATTERN to fill the read buffer that receives the contents of a logical sector that does not contain any valid data. The contents of a logical sector becomes valid when the file system layer writes any data to it. After a low-level format operation the contents of all logical sectors is invalid. The contents of a logical sector can be explicitly invalidated via a sector free operation. FS_NAND_READ_BUFFER_FILL_PATTERN takes effect only if FS_NAND_FILL_READ_BUFFER is set to 1.

FS_NAND_STAT_MAX_BIT_ERRORS

FS_NAND_STAT_MAX_BIT_ERRORS defines how many bit error counters the Universal NAND driver has to maintain. Each counter keeps track of the number of times a certain number of bit errors occurred at the same time during one page read operation. The first counter keeps track of the number of 1 bit errors, the second counter keeps track of the number of 2 bit errors and so on. The bit error counters can be read via FS_NAND_UNI_GetStatCounters(). FS_NAND_ENABLE_STATS_SECTOR_STATUS takes effect only if FS_NAND_ENABLE_STATS is set to 1.

FS_NAND_SUPPORT_BLOCK_GROUPING

FS_NAND_SUPPORT_BLOCK_GROUPING can be used to specify if the Universal NAND driver is able to handle of two or more adjacent NAND blocks as a single block. The number of blocks in the group has to be configured at runtime via FS_NAND_UNI_SetNumBlocksPerGroup(). The RAM usage of the Universal NAND driver depends on the number of NAND blocks it has to manage. Therefore, enabling the block grouping feature can help reduce the RAM usage because the the number of blocks decreases. If the block grouping feature is not required by the application then FS_NAND_SUPPORT_BLOCK_GROUPING can be set to 0 in order to reduce the RAM and ROM usage of the Universal NAND driver.

FS_NAND_SUPPORT_FAIL_SAFE_ERASE

FS_NAND_SUPPORT_FAIL_SAFE_ERASE can be used to enable or disable the detection of interrupted block erase operations. This feature works by invalidating the management data of the block before the erase operation and by storing a valid erase count to the block after a successful erase operation. In this way, the driver is able to identify and erase again these blocks during the low-level mount operation. With the support for the fail-safe erase operation enabled, the target hardware is no longer required to meet the timing requirements described in Fail-safe operation. Instead, the target hardware will have to make sure that a write page operation completes successfully. Typically, such an operation takes about 250 us to complete.

FS_NAND_VERIFY_ERASE

This define can be used to activate the erase verification of the Universal NOR driver. The erase verification is performed after each erase operation by reading back the entire data of the erased block and by comparing each byte in the block with 0xFF. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NAND_UNI_SetEraseVerification().

Note

Activating the erase verification may negatively affect the write performance.

FS_NAND_VERIFY_WRITE

This define can be used to activate the write verification of the Universal NAND driver. The write verification is performed after each write operation by reading back the modified data and by comparing it with the data requested to be written. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NAND_UNI_SetWriteVerification().

Note

Activating the write verification may negatively affect the write performance.

Runtime configuration

The driver must be added to the file system by calling FS_AddDevice() with the driver identifier set to the address of FS_NAND_UNI_Driver. This function call together with other function calls that configure the driver operation have to be added to FS_X_AddDevices() as demonstrated in the following example.

Example

#include "FS.h"
#include "FS_NAND_HW_Template.h"

#define ALLOC_SIZE      0x9000          // Memory pool for the file system in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for semi-dynamic allocation.

void FS_X_AddDevices(void) {
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add the NAND flash driver to file system. Volume name: "nand:0:".
  //
  FS_AddDevice(&FS_NAND_UNI_Driver);
  //
  // Set the physical interface of the NAND flash.
  //
  FS_NAND_UNI_SetPhyType(0, &FS_NAND_PHY_ONFI);
  //
  // Configure the driver to use the internal ECC of NAND flash for error correction.
  //
  FS_NAND_UNI_SetECCHook(0, &FS_NAND_ECC_HW_NULL);
  //
  // Configure the HW access routines.
  //
  FS_NAND_ONFI_SetHWType(0, &FS_NAND_HW_Template);
#if FS_SUPPORT_FILE_BUFFER
  //
  // Enable the file buffer to increase the performance
  // when reading/writing a small number of bytes.
  //
  FS_ConfigFileBufferDefault(512, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}

The API functions listed in the next table can be used by the application to configure the behavior of the Universal NAND driver. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_UNI_AllowBlankUnusedSectors() Configures if the data of unused sectors has to be initialized.
FS_NAND_UNI_AllowReadErrorBadBlocks() Configures if a block is marked as defective on read fatal error.
FS_NAND_UNI_SetBlockRange() Specifies which NAND blocks the driver can use to store the data.
FS_NAND_UNI_SetBlockReserve() Configures the number of NAND flash blocks to be reserved as replacement for the NAND flash blocks that become defective.
FS_NAND_UNI_SetCleanThreshold() Specifies the minimum number sectors that the driver should keep available for fast write operations.
FS_NAND_UNI_SetDriverBadBlockReclamation() Configures if the bad blocks marked as defective by the driver have to be erased at low-level format or not.
FS_NAND_UNI_SetECCHook() Configures the ECC algorithm to be used for the correction of bit errors.
FS_NAND_UNI_SetEraseVerification() Enables or disables the checking of the block erase operation.
FS_NAND_UNI_SetMaxBitErrorCnt() Configures the number of bit errors that trigger the relocation of the data stored in a NAND block.
FS_NAND_UNI_SetMaxEraseCntDiff() Configures the threshold of the wear leveling procedure.
FS_NAND_UNI_SetMaxPageSize() Configures the maximum handled page size.
FS_NAND_UNI_SetMaxSpareAreaSize() Configures the maximum handled spare area size.
FS_NAND_UNI_SetNumBlocksPerGroup() Specifies the number of physical NAND blocks in a virtual block.
FS_NAND_UNI_SetNumWorkBlocks() Sets number of work blocks the Universal NAND driver uses for write operations.
FS_NAND_UNI_SetOnFatalErrorCallback() Registers a function to be called by the driver when a fatal error occurs.
FS_NAND_UNI_SetPhyType() Configures NAND flash access functions.
FS_NAND_UNI_SetWriteDisturbHandling() Configures if the bit errors caused by write operations are handled or not.
FS_NAND_UNI_SetWriteVerification() Enables or disables the checking of each page write operation.
FS_NAND_UNI_AllowBlankUnusedSectors()

Description

Configures if the data of unused sectors has to be initialized.

Prototype

void FS_NAND_UNI_AllowBlankUnusedSectors(U8 Unit,
                                         U8 OnOff);

Parameters

Parameter Description
Unit Index of driver instance (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 Sector data is filled with 0s. ≠0 Sector data is not initialized (all bytes remain set to 0xFF).

Additional information

This function is optional. The default behavior of the Universal NAND driver is to fill the data of unused logical sectors with 0s. This done in order to reduce the chance of a bit error caused by an unwanted transition from 1 to 0 of the value stored to these memory cells.

Some NAND flash devices may wear out faster than expected if excessive number of bytes are set to 0. This limitation is typically documented in the data sheet of the corresponding NAND flash. For such devices it is recommended configure the Universal NAND driver to do not initialize the unused sectors with 0s. This can be realized by calling FS_NAND_UNI_AllowBlankUnusedSectors() with the OnOff parameter set to 1 in FS_X_AddDevices().

FS_NAND_UNI_AllowReadErrorBadBlocks()

Description

Configures if a block is marked as defective on read fatal error.

Prototype

void FS_NAND_UNI_AllowReadErrorBadBlocks(U8 Unit,
                                         U8 OnOff);

Parameters

Parameter Description
Unit Index of driver instance (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The block is not marked as defective. ≠0 The block is marked as defective.

Additional information

This function is optional. The default behavior of the Universal NAND driver is to mark a block as defective if a read error or and uncorrectable bit error occurs while reading data from a page of that block.

FS_NAND_UNI_SetBlockRange()

Description

Specifies which NAND blocks the driver can use to store the data.

Prototype

void FS_NAND_UNI_SetBlockRange(U8  Unit,
                               U16 FirstBlock,
                               U16 MaxNumBlocks);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
FirstBlock Index of the first NAND flash block to be used as storage (0-based).
MaxNumBlocks Maximum number of NAND flash blocks to be used as storage.

Additional information

This function is optional. By default, the Universal NAND driver uses all blocks of the NAND flash as data storage. FS_UNI_NAND_SetBlockRange() is useful when a part of the NAND flash has to be used for another purpose, for example to store the application program used by a boot loader, and therefore it cannot be managed by the Universal NAND driver. Limiting the number of blocks used by the Universal NAND driver can also help reduce the RAM usage.

FirstBlock is the index of the first physical NAND block were 0 is the index of the first block of the NAND flash device. MaxNumBlocks can be larger that the actual number of available NAND blocks in which case the Universal NAND driver silently truncates the value to reflect the actual number of NAND blocks available.

The Universal NAND driver uses the first NAND block in the range to store management information at low-level format. If the first NAND block happens to be marked as defective, then the next usable NAND block is used.

If the FS_UNI_NAND_SetBlockRange() is used to subdivide the same physical NAND flash device into two or more partitions than the application has to make sure that the created partitions do not overlap.

The read optimization of the FS_NAND_PHY_2048x8 physical layer has to be disabled when this function is used to partition the NAND flash device in order to ensure data consistency. The read cache can be disabled at runtime via FS_NAND_2048x8_DisableReadCache().

FS_NAND_UNI_SetBlockReserve()

Description

Configures the number of NAND flash blocks to be reserved as replacement for the NAND flash blocks that become defective.

Prototype

void FS_NAND_UNI_SetBlockReserve(U8       Unit,
                                 unsigned pctOfBlocks);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pctOfBlocks Number of NAND flash blocks to be reserved as percentage of the total number of NAND flash blocks.

Additional information

This function is optional. The Universal NAND driver reserves by default about 3% of the total number of NAND flash blocks which is sufficient for most applications. Reserving more NAND flash blocks can increase the lifetime of the NAND flash device. The NAND flash device has to be low-level formatted after changing the number of reserved blocks.

FS_NAND_UNI_SetCleanThreshold()

Description

Specifies the minimum number sectors that the driver should keep available for fast write operations.

Prototype

int FS_NAND_UNI_SetCleanThreshold(U8       Unit,
                                  unsigned NumBlocksFree,
                                  unsigned NumSectorsFree);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
NumBlocksFree Number of blocks to be kept free.
NumSectorsFree Number of sectors to be kept free on each block.

Return value

= 0 OK, threshold has been set.
≠ 0 An error occurred.

Additional information

This function is optional. It can be used by the application to prepare the NAND flash device to write data as fast as possible once when an event occurs such an unexpected reset. At the startup, the application reserves free space, by calling the function with NumBlocksFree and NumSectorsFree set to a value different than 0. The number of free sectors depends on the number of bytes written and on how the file system is configured. When the unexpected reset occurs, the application tells the driver that it can write to the free sectors, by calling the function with NumBlocksFree and NumSectorsFree set to 0. Then, the application writes the data to file and the NAND driver stores it to the free space. Since no erase or copy operation is required, the data is written as fastest as the NAND flash device permits it.

The NAND flash device will wear out faster than normal if sectors are reserved in a work block (NumSectors > 0).

Example

The following sample code demonstrates how to determine the threshold parameters.

#include <stdio.h>
#include "FS.h"

void SampleNAND_UNISetCleanThreshold(void) {
  unsigned             NumPhyBlocks;
  unsigned             NumWorkBlocks;
  FS_FILE            * pFile;
  FS_NAND_DISK_INFO    DiskInfo;
  FS_NAND_BLOCK_INFO   BlockInfo;
  U32                  BlockIndex;
  unsigned             MaxNumSectors;
  unsigned             NumSectorsValid;
  char                 ac[100];
  
  //
  // Get information about the storage.
  //
  memset(&DiskInfo, 0, sizeof(DiskInfo));
  FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
  NumPhyBlocks  = DiskInfo.NumPhyBlocks;
  NumWorkBlocks = DiskInfo.NumWorkBlocks;
  //
  // Make sure that all work blocks are converted to data blocks.
  //
  FS_NAND_UNI_Clean(0, NumWorkBlocks, 0);
  //
  // Create a test file, write to file the data
  // to be saved on sudden reset then close it.
  //
  pFile = FS_FOpen("Test.txt", "w");
  FS_Write(pFile, "Reset", 5);
  FS_FClose(pFile);
  //
  // Calculate how many work blocks were written
  // and the maximum number of sectors written in a work block.
  //
  NumWorkBlocks = 0;
  BlockIndex    = 0;
  MaxNumSectors = 0;
  do {
    memset(&BlockInfo, 0, sizeof(BlockInfo));
    FS_NAND_UNI_GetBlockInfo(0, BlockIndex++, &BlockInfo);
    if (BlockInfo.Type == FS_NAND_BLOCK_TYPE_WORK) {
      ++NumWorkBlocks;
      NumSectorsValid = BlockInfo.NumSectorsValid;
      if (MaxNumSectors < NumSectorsValid) {
        MaxNumSectors = NumSectorsValid;
      }
    }
  } while (--NumPhyBlocks);
  //
  // Clean up: remove the test file.
  //
  FS_Remove("Test.txt");
  //
  // Show the calculated values.
  // NumWorkBlocks and MaxNumSectors can be passed as 2nd and 3rd
  // argument in the call to FS_NAND_UNI_SetWorkBlockReserve().
  //
  SEGGER_snprintf(ac, sizeof(ac), "Number of work blocks used:  %u\n", NumWorkBlocks);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "Max. number of used sectors: %u\n", MaxNumSectors);
  FS_X_Log(ac);
}

Sample output

Number of work blocks used:  1
Max. number of used sectors: 5
FS_NAND_UNI_SetDriverBadBlockReclamation()

Description

Configures if the bad blocks marked as defective by the driver have to be erased at low-level format or not.

Prototype

void FS_NAND_UNI_SetDriverBadBlockReclamation(U8 Unit,
                                              U8 OnOff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
OnOff Configures if the feature has to be enable or disabled. =1 Defective blocks marked as such by the driver are erased at low-level format. =0 Defective blocks marked as such by the driver are not erased at low-level format.

Additional information

This function is active only when the option FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS is set to 1. The default behavior is to erase the blocks marked as defective by the driver.

FS_NAND_UNI_SetECCHook()

Description

Configures the ECC algorithm to be used for the correction of bit errors.

Prototype

void FS_NAND_UNI_SetECCHook(      U8                 Unit,
                            const FS_NAND_ECC_HOOK * pECCHook);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)
pECCHook  in  ECC algorithm.

Additional information

This function is optional. By default, the Universal NAND driver uses an software algorithm that is capable of correcting 1 bit errors and of detecting 2 bit errors. If the NAND flash device requires a better error correction, the application has to specify an different ECC algorithm via FS_NAND_UNI_SetECCHook().

The ECC algorithms can be either implemented in the software or the calculation routines can take advantage of any dedicated ECC HW available on the target system.

The following ECC algorithms are supported:

Type Description
FS_NAND_ECC_HW_NULL This is a pseudo ECC algorithm that requests the Universal NAND driver to use the internal HW ECC of a NAND flash device.
FS_NAND_ECC_HW_4BIT This is a pseudo ECC algorithm that requests the Universal NAND driver to use HW 4 bit error correction. It can be used for example with dedicated a NAND flash controller that comes with a configurable HW ECC.
FS_NAND_ECC_HW_8BIT This is a pseudo ECC algorithm that requests the Universal NAND driver to use HW 8 bit error correction. It can be used for example with dedicated a NAND flash controller that comes with a configurable HW ECC.
FS_NAND_ECC_SW_1BIT This is an software algorithm that is able to correct 1 bit errors and detect 2 bit errors. More specifically it can correct a 1 bit error per 256 bytes of data and a 1 bit error per 4 bytes of spare area.

Additional software algorithms with error correction capabilities greater than 1 are supported via the SEGGER emLib ECC component (www.segger.com/products/security-iot/emlib/variations/ecc/).

FS_NAND_UNI_SetEraseVerification()

Description

Enables or disables the checking of the block erase operation.

Prototype

void FS_NAND_UNI_SetEraseVerification(U8 Unit,
                                      U8 OnOff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The erase operation is not checked. ≠0 The erase operation is checked.

Additional information

This function is optional. The result of a block erase operation is normally checked by evaluating the error bits maintained by the NAND flash device in a internal status register. FS_NAND_UNI_SetEraseVerification() can be used to enable additional verification of the block erase operation that is realized by reading back the contents of the entire erased physical block and by checking that all the bytes in it are set to 0xFF. Enabling this feature can negatively impact the write performance of Universal NAND driver.

The block erase verification feature is active only when the Universal NAND driver is compiled with the FS_NAND_VERIFY_ERASE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NAND_UNI_SetMaxBitErrorCnt()

Description

Configures the number of bit errors that trigger the relocation of the data stored in a NAND block.

Prototype

void FS_NAND_UNI_SetMaxBitErrorCnt(U8       Unit,
                                   unsigned BitErrorCnt);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BitErrorCnt Number of physical bit errors.

Additional information

This function is optional and is active only when the file system is compiled with FS_NAND_MAX_BIT_ERROR_CNT set to a value greater than 0.

FS_NAND_UNI_SetMaxBitErrorCnt() can be used to configure when the Universal NAND Driver has to copy the contents of a NAND block to another location in order to prevent the accumulation of bit errors. BitErrorCnt has to be smaller than or equal to the bit error correction requirement of the NAND flash device. The feature can be disabled by calling FS_NAND_UNI_SetMaxBitErrorCnt() with BitErrorCnt set to 0.

The lifetime of the NAND flash device can be negatively affected if this feature is enabled due to the increased number of block erase operations.

FS_NAND_UNI_SetMaxEraseCntDiff()

Description

Configures the threshold of the wear leveling procedure.

Prototype

void FS_NAND_UNI_SetMaxEraseCntDiff(U8  Unit,
                                    U32 EraseCntDiff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
EraseCntDiff Maximum allowed difference between the erase counts of any two NAND blocks.

Additional information

This function is optional. It can be used to control how the Universal NAND driver performs the wear leveling. The wear leveling procedure makes sure that the NAND blocks are equally erased to meet the life expectancy of the storage device by keeping track of the number of times a NAND block has been erased (erase count). The Universal NAND driver executes this procedure when a new empty NAND block is required for data storage. The wear leveling procedure works by first choosing the next available NAND block. Then the difference between the erase count of the chosen block and the NAND block with lowest erase count is computed. If this value is greater than EraseCntDiff the NAND block with the lowest erase count is freed and made available for use.

The same threshold can also be configured at compile time via the FS_NAND_MAX_ERASE_CNT_DIFF configuration define.

FS_NAND_UNI_SetMaxPageSize()

Description

Configures the maximum handled page size.

Prototype

void FS_NAND_UNI_SetMaxPageSize(unsigned NumBytes);

Parameters

Parameter Description
NumBytes NAND page size in bytes.

Additional information

This function can be used at runtime to configure the size of the internal buffer used by the Universal NAND driver to read the data from a NAND page. This buffer is shared by all instances of the Universal NAND driver. If the application does not call FS_NAND_UNI_SetMaxPageSize() then the size of the internal page buffer is set to FS_NAND_MAX_PAGE_SIZE if FS_NAND_MAX_PAGE_SIZE is different than 0 or to the logical sector size of the file system if FS_NAND_MAX_PAGE_SIZE is set to 0.

FS_NAND_UNI_SetMaxPageSize() is for example useful when the application is using two NAND flash devices with different page sizes. In this case, the application has to call FS_NAND_UNI_SetMaxPageSize() with the NumBytes parameter set to the largest of the two page sizes.

FS_NAND_UNI_SetMaxPageSize() is available only if the file system is built with FS_NAND_MAX_PAGE_SIZE set to a value different than 0. The function has to be called in FS_X_AddDevices() before any instance of the Universal NAND driver is created.

NumBytes has to be a power of 2 value.

FS_NAND_UNI_SetMaxSpareAreaSize()

Description

Configures the maximum handled spare area size.

Prototype

void FS_NAND_UNI_SetMaxSpareAreaSize(unsigned NumBytes);

Parameters

Parameter Description
NumBytes Spare area size of the NAND page in bytes.

Additional information

This function can be used at runtime to configure the size of the internal buffer used by the Universal NAND driver to read the data from a spare area of a NAND page. This buffer is shared by all instances of the Universal NAND driver. If the application does not call FS_NAND_UNI_SetMaxSpareAreaSize() then the size of the internal spare area buffer is set to FS_NAND_MAX_SPARE_AREA_SIZE if FS_NAND_MAX_SPARE_AREA_SIZE is different than 0 or to 1/32 of the logical sector size of the file system if FS_NAND_MAX_SPARE_AREA_SIZE is set to 0.

FS_NAND_UNI_SetMaxSpareAreaSize() is for example useful when NAND flash device has a spare area that is larger than 1/32 of the page size. In this case, the application has to call FS_NAND_UNI_SetMaxSpareAreaSize() with the NumBytes parameter set to the spare area size specified in the data sheet of the NAND flash device.

FS_NAND_UNI_SetMaxSpareAreaSize() is available only if the file system is built with FS_NAND_MAX_SPARE_AREA_SIZE set to a value different than 0. The function has to be called in FS_X_AddDevices() before any instance of the Universal NAND driver is created.

FS_NAND_UNI_SetNumBlocksPerGroup()

Description

Specifies the number of physical NAND blocks in a virtual block.

Prototype

int FS_NAND_UNI_SetNumBlocksPerGroup(U8       Unit,
                                     unsigned BlocksPerGroup);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlocksPerGroup Number of physical blocks in a virtual block. The value must be a power of 2.

Return value

= 0 OK, value configured.
≠ 0 Error code indicating the failure reason.

Additional information

This function is optional. It can be used to specify how many physical NAND blocks are grouped together to form a virtual block. Grouping physical blocks helps reduce the RAM usage of the driver when the NAND flash device contains a large number of physical blocks. For example, the dynamic RAM usage of the Universal NAND driver using a NAND flash device with 8196 blocks and a page size of 2048 bytes is about 20 KB. The dynamic RAM usage is reduced to about 7 KB if 4 physical blocks are grouped together.

The FS_NAND_SUPPORT_BLOCK_GROUPING configuration define has to be set to 1 in order to enable this function. The FS_NAND_SUPPORT_BLOCK_GROUPING configuration define is set to 1 by default. When set to 0 the function returns an error if called in the application.

FS_NAND_UNI_SetNumBlocksPerGroup() is optional and may be called only from FS_X_AddDevices(). Changing the block grouping requires a low-level format of the NAND flash device.

FS_NAND_UNI_SetNumWorkBlocks()

Description

Sets number of work blocks the Universal NAND driver uses for write operations.

Prototype

void FS_NAND_UNI_SetNumWorkBlocks(U8  Unit,
                                  U32 NumWorkBlocks);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
NumWorkBlocks Number of work blocks.

Additional information

This function is optional. It can be used to change the default number of work blocks according to the requirements of the application. Work blocks are physical NAND blocks that the Universal NAND driver uses to temporarily store the data written to NAND flash device. The Universal NAND driver calculates at low-level format the number of work blocks based on the total number of blocks available on the NAND flash device.

By default, the NAND driver allocates 10% of the total number of NAND blocks used as storage, but no more than 10 NAND blocks. The minimum number of work blocks allocated by default depends on whether journaling is used or not. If the journal is active 4 work blocks are allocated, else Universal NAND driver allocates 3 work blocks. The currently allocated number of work blocks can be checked via FS_NAND_UNI_GetDiskInfo(). The value is returned in the NumWorkBlocks member of the FS_NAND_DISK_INFO structure.

Increasing the number of work blocks can help increase the write performance of the Universal NAND driver. At the same time the RAM usage of the Universal NAND driver increases since each configured work block requires a certain amount of RAM for the data management. This is a trade-off between write performance and RAM usage.

The new value take effect after the NAND flash device is low-level formatted via the FS_FormatLow() API function.

FS_NAND_UNI_SetOnFatalErrorCallback()

Description

Registers a function to be called by the driver when a fatal error occurs.

Prototype

void FS_NAND_UNI_SetOnFatalErrorCallback
                                (FS_NAND_ON_FATAL_ERROR_CALLBACK * pfOnFatalError);

Parameters

Parameter Description
pfOnFatalError Function to be called when a fatal error occurs.

Additional information

This function is optional. The application can use this function to register a routine to be called by the file system when a fatal error occurs. Typically, a fatal error occurs when the ECC is not able to correct all the bit errors in a page and is an indication that some data was lost. A data loss leads in most of the cases to a damage of the file system structure.

FS_NAND_UNI_SetPhyType()

Description

Configures NAND flash access functions.

Prototype

void FS_NAND_UNI_SetPhyType(      U8                 Unit,
                            const FS_NAND_PHY_TYPE * pPhyType);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)
pPhyType  in  Physical layer to be used to access the NAND flash device.

Additional information

This function is mandatory and it has to be called in FS_X_AddDevices() once for each instance of the Universal NAND driver. The driver instance is identified by the Unit parameter. First Universal NAND driver instance added to the file system via a FS_AddDevice(&FS_NAND_UNI_Driver) call has the unit number 0, the Universal NAND driver added by a second call to FS_AddDevice() has the unit number 1 and so on.

FS_NAND_UNI_SetWriteDisturbHandling()

Description

Configures if the bit errors caused by write operations are handled or not.

Prototype

void FS_NAND_UNI_SetWriteDisturbHandling(U8 Unit,
                                         U8 OnOff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
OnOff Activation status of the feature. =0 Write disturb errors are not handled (default). ≠0 Write disturb errors are handled.

Additional information

This function is optional and is active only when the file system is compiled with FS_NAND_MAX_BIT_ERROR_CNT set to a value greater than 0.

A write operation can cause bit errors in the pages located on the same NAND block with the page being currently written. Normally, these bit errors are corrected later when the data of the NAND block is copied internally by the Universal NAND driver to another location on the NAND flash device during a wear leveling, a garbage collection or a write operation. This is the default behavior of the Universal NAND driver.

The Universal NAND driver is also able to check for and correct any bit errors right a after the write operation in order to reduce the accumulation of bit errors that can lead to a data loss. This error handling mode can be enabled by calling FS_NAND_UNI_SetWriteDisturbHandling() with the OnOff parameter set to 1. In this error handling mode if the number of bit errors in any page in the checked NAND block is greater than or equal to the value configured via FS_NAND_UNI_SetMaxBitErrorCnt() then the NAND block is copied to another location on the NAND flash device in order to correct the bit errors.

The lifetime of the NAND flash device can be negatively affected if this feature is enabled due to the increased number of block erase operations. The write performance can be negatively affected as well.

FS_NAND_UNI_SetWriteVerification()

Description

Enables or disables the checking of each page write operation.

Prototype

void FS_NAND_UNI_SetWriteVerification(U8 Unit,
                                      U8 OnOff);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked.

Additional information

This function is optional. The result of a page write operation is normally checked by evaluating the error bits maintained by the NAND flash device in a internal status register. FS_NAND_UNI_SetWriteVerification() can be used to enable additional verification of the page write operation that is realized by reading back the contents of the written page and by checking that all the bytes are matching the data requested to be written. Enabling this feature can negatively impact the write performance of Universal NAND driver.

The page write verification feature is active only when the Universal NAND driver is compiled with the FS_NAND_VERIFY_WRITE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NAND_ECC_HOOK

Description

ECC calculation algorithm.

Type definition

typedef struct {
  FS_NAND_ECC_HOOK_CALC  * pfCalc;
  FS_NAND_ECC_HOOK_APPLY * pfApply;
  U8                       NumBitsCorrectable;
  U8                       ldBytesPerBlock;
  U8                       NumBitsCorrectableSpare;
} FS_NAND_ECC_HOOK;

Structure members

Member Description
pfCalc Calculates the ECC of specified data.
pfApply Verifies and corrects bit errors using ECC.
NumBitsCorrectable Number of bits the ECC algorithm is able to correct in the data block and 4 bytes of spare area.
ldBytesPerBlock Number of bytes in the data block given as power of 2 exponent.
NumBitsCorrectableSpare Number of bits the ECC algorithm is able to correct in the 4 bytes of the spare area.

Additional information

This structure contains pointers to API functions and attributes related to an ECC calculation algorithm.

ldBytesPerBlock is typically set to 9 which indicates a block size of 512 bytes. The size of the ECC block is imposed by the specifications of the NAND flash device. If the value is set to 0 the Universal NAND driver assumes that the ECC block is 512 bytes large.

NumBitsCorrectable is used by the Universal NAND driver to check if the ECC algorithm is capable of correcting the number of bit errors required by the used NAND flash device.

NumBitsCorrectableSpare is used by the Universal NAND driver to activate an optimization related to reading the data from the spare area. If NumBitsCorrectableSpare is set to a value different than 0 than the Universal NAND driver assumes that the 4 bytes of management data stored in the spare area of the NAND page are protected by a dedicated ECC. This enables the Universal NAND driver to read only the spare area instead of the entire NAND page when only the management data has to be evaluated which can help increase the performance of specific operations such as the mounting of NAND flash device.

FS_NAND_ECC_HOOK_CALC

Description

Calculates the parity bits of the specified data using ECC.

Type definition

typedef void FS_NAND_ECC_HOOK_CALC(const U32 * pData,
                                         U8  * pSpare);

Parameters

Parameter Description
pData  in  Data to be written to the main area of the page.
pSpare  in  Data to be written to the spare area of the page.  out  The calculated parity bits.

Additional information

FS_NAND_ECC_HOOK_CALC is called by the Universal NAND driver before it writes the data to the NAND flash device to calculate the parity check bits. The parity check bits are stored together with the data to NAND flash device. They are used by FS_NAND_ECC_HOOK_CALC to correct eventual bit errors.

This function has to calculate the parity bits of pData and of four bytes of pSpare. That is the calculated parity bits are used to protect the data stored in pData as well as pSpare. The number of bytes in pData to be protected by ECC is specified via ldBytesPerBlock in FS_NAND_ECC_HOOK. The data in pSpare to be protected by ECC is located at byte offset four. The calculated parity bits must be stored to pSpare at byte offset eight. The byte order of the stored parity bits is not relevant for the Universal NAND driver. pSpare is organized as follows:

Byte range Description
0-3 Not protected by ECC
4-7 Data to be protected by ECC
8-N Parity check bits calculated via the ECC algorithm

FS_NAND_ECC_HOOK_CALC is not allowed to store more than N - 8 + 1 parity check bytes at byte offset eight to pSpare. N depends on the size of the main and spare are of the NAND flash and on ldBytesPerBlock and can be calculate using this formula:

N = ((BytesPerSpareArea / (BytesPerPage >> ldBytesPerBlock)) - 8) - 1
Parameter Description
BytesPerSpareArea Number of bytes in the spare area of the NAND flash device
BytesPerPage Number of bytes in the spare area of the NAND flash device
ldBytesPerBlock Value specified in FS_NAND_ECC_HOOK
FS_NAND_ECC_HOOK_APPLY

Description

Checks and corrects bit errors in the specified data using ECC.

Type definition

typedef int FS_NAND_ECC_HOOK_APPLY(U32 * pData,
                                   U8  * pSpare);

Parameters

Parameter Description
pData  in  Data read from the main area of the page.  out  Corrected main area data.
pSpare  in  Data read from the spare area of the page.  out  Corrected spare area data.

Return value

< 0 Uncorrectable bit errors detected.
≥ 0 Number of bit errors detected and corrected.

Additional information

FS_NAND_ECC_HOOK_APPLY is called by the Universal NAND driver after it reads data with from the NAND flash device to verify that the data is not corrupted. If the function detects bit errors then it uses the parity check bits to correct them. The correction has to be performed in place that is directly in pData and pSpare. The parity check bits are located at byte offset eight in pSpare. They protect all the bytes in pData and four bytes of pSpare. Refer to FS_NAND_ECC_HOOK_CALC for a description of pSpare data layout. FS_NAND_ECC_HOOK_APPLY function has to also correct the bit errors that occurred in the parity check.

For backwards compatibility the return value is interpreted differently by the Universal NAND driver if ldBytesPerBlock is set to 0 as follows:

Value Description
0 No error detected.
1 Bit errors corrected. Data is OK.
2 Error in ECC detected. Data is OK.
3 Uncorrectable bit error. Data is corrupted.

The Universal NAND driver can possibly call this function with pData set to NULL when it needs to check only the data stored in the spare area of a NAND page if NumBitsCorrectableSpare in FS_NAND_ECC_HOOK is set to a value different than 0.

Additional driver functions

The following functions are optional and can be used by the application to perform operations directly on the NAND flash device.

Function Description
FS_NAND_UNI_Clean() Makes storage space available for fast write operations.
FS_NAND_UNI_EraseBlock() Sets all the bytes in a NAND block to 0xFF.
FS_NAND_UNI_EraseFlash() Erases the entire NAND partition.
FS_NAND_UNI_GetBlockInfo() Returns information about the specified NAND block.
FS_NAND_UNI_GetBlockInfoEx() Returns information about the specified NAND block.
FS_NAND_UNI_GetDiskInfo() Returns information about the NAND partition.
FS_NAND_UNI_GetStatCounters() Returns the actual values of statistical counters.
FS_NAND_UNI_IsBlockBad() Checks if a NAND block is marked as defective.
FS_NAND_UNI_Mount() Mounts the NAND flash device.
FS_NAND_UNI_ReadLogSectorPartial() Reads a specified number of bytes from a logical sector.
FS_NAND_UNI_ReadPageRaw() Reads data from a page without ECC.
FS_NAND_UNI_ReadPhySector() This function reads a physical sector from NAND flash.
FS_NAND_UNI_ResetStatCounters() Sets the values of statistical counters to 0.
FS_NAND_UNI_TestBlock() Fills all the pages in a block (including the spare area) with the specified pattern and verifies if the data was written correctly.
FS_NAND_UNI_WritePage() Stores data to a page of a NAND flash with ECC.
FS_NAND_UNI_WritePageRaw() Stores data to a page of a NAND flash without ECC.
FS_NAND_UNI_Clean()

Description

Makes storage space available for fast write operations.

Prototype

int FS_NAND_UNI_Clean(U8       Unit,
                      unsigned NumBlocksFree,
                      unsigned NumSectorsFree);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
NumBlocksFree Number of blocks to be kept free.
NumSectorsFree Number of sectors to be kept free on each block.

Return value

= 0 OK, space has been made available.
≠ 0 An error occurred.

Additional information

This function is optional. It can be used to free space on the NAND flash device for data that the application has to write as fast as possible. FS_NAND_UNI_Clean() performs two internal operations: (1) Converts all work blocks that have less free sectors than NumSectorsFree into data blocks. (2) If required, convert work blocks until at least NumBlocksFree are available.

FS_NAND_UNI_EraseBlock()

Description

Sets all the bytes in a NAND block to 0xFF.

Prototype

int FS_NAND_UNI_EraseBlock(U8       Unit,
                           unsigned BlockIndex);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the NAND flash block to be erased.

Return value

= 0 OK, block erased
≠ 0 An error occurred

Additional information

This function is optional. FS_NAND_UNI_EraseBlock() function does not check if the block is marked as defective before erasing it.

FS_NAND_UNI_EraseFlash()

Description

Erases the entire NAND partition.

Prototype

int FS_NAND_UNI_EraseFlash(U8 Unit);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).

Return value

≥ 0 . Number of blocks which failed to erase.
< 0 An error occurred.

Additional information

This function is optional. After the call to this function all the bytes in the NAND partition are set to 0xFF.

This function has to be used with care, since it also erases blocks marked as defective and therefore the information about the block status will be lost. FS_NAND_EraseFlash() can be used without this side effect on storage devices that are guaranteed to not have any bad blocks, such as DataFlash devices.

FS_NAND_UNI_GetBlockInfo()

Description

Returns information about the specified NAND block.

Prototype

int FS_NAND_UNI_GetBlockInfo(U8                   Unit,
                             U32                  BlockIndex,
                             FS_NAND_BLOCK_INFO * pBlockInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the physical block to get information about.
pBlockInfo  out  Information about the NAND block.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

This function is not required for the functionality of the driver and will typically not be linked in production builds.

FS_NAND_UNI_GetBlockInfo() has to read the contents of the entire NAND block in order to collect all the information which may take a relatively long time to complete. If the application does not require the information about the block status or about the status of the logical sectors stored in the NAND block it can call FS_NAND_UNI_GetBlockInfoEx() instead.

FS_NAND_UNI_GetBlockInfoEx()

Description

Returns information about the specified NAND block.

Prototype

int FS_NAND_UNI_GetBlockInfoEx(U8                   Unit,
                               U32                  BlockIndex,
                               FS_NAND_BLOCK_INFO * pBlockInfo,
                               unsigned             Flags);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the physical block to get information about.
pBlockInfo  out  Information about the NAND block.
Flags Specifies the information to be returned.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

This function is not required for the functionality of the driver and will typically not be linked in production builds.

Flags is a bitwise-or combination of Block info flags.

The FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS flag specifies if the information about the block status has to be returned via the members IsDriverBadBlock, BadBlockErrorType, BadBlockErrorBRSI of FS_NAND_BLOCK_INFO. If FS_NAND_UNI_GetBlockInfoEx() is called on a NAND block marked as defective with the FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS flag cleared than the member Type of FS_NAND_BLOCK_INFO is set to NAND_BLOCK_TYPE_UNKNOWN.

The FS_NAND_BLOCK_INFO_FLAG_SECTOR_STATUS flag specifies if FS_NAND_UNI_GetBlockInfoEx() has to return information about the logical sectors stored in the NAND block. This information is returned via the members NumSectorsBlank, NumSectorsValid, NumSectorsInvalid, NumSectorsECCError, NumSectorsECCCorrectable, NumSectorsErrorInECC of FS_NAND_BLOCK_INFO

FS_NAND_UNI_GetDiskInfo()

Description

Returns information about the NAND partition.

Prototype

int FS_NAND_UNI_GetDiskInfo(U8                  Unit,
                            FS_NAND_DISK_INFO * pDiskInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pDiskInfo  out  Information about the NAND partition.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

FS_NAND_UNI_GetDiskInfo() can be used to get information about the NAND flash device and about the instance of the Universal NAND driver that is used to access it. If the NAND flash device is formatted then FS_NAND_UNI_GetDiskInfo() also returns statistical information about the usage of NAND blocks. If this information is not relevant to the application FS_NAND_UNI_Mount() can be called instead which typically requires less time to complete.

FS_NAND_UNI_GetDiskInfo() mounts the NAND flash device if required and leaves it in this state upon return.

This function is not required for the functionality of the Universal NAND driver and is typically not linked in production builds.

FS_NAND_UNI_GetStatCounters()

Description

Returns the actual values of statistical counters.

Prototype

void FS_NAND_UNI_GetStatCounters(U8                      Unit,
                                 FS_NAND_STAT_COUNTERS * pStat);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)
pStat  out  Values of statistical counters.

Additional information

This function is optional. It is active only when the file system is compiled with FS_DEBUG_LEVEL set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.

The statistical counters can be cleared via FS_NAND_UNI_ResetStatCounters().

FS_NAND_UNI_IsBlockBad()

Description

Checks if a NAND block is marked as defective.

Prototype

int FS_NAND_UNI_IsBlockBad(U8       Unit,
                           unsigned BlockIndex);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the NAND flash block to be checked.

Return value

1 Block is defective
0 Block is not defective

Additional information

This function is optional.

FS_NAND_UNI_Mount()

Description

Mounts the NAND flash device.

Prototype

int FS_NAND_UNI_Mount(U8                   Unit,
                      FS_NAND_MOUNT_INFO * pMountInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
pMountInfo  out  Information about the mounted NAND flash device. Can be set to NULL.

Return value

= 0 OK, NAND flash device successfully mounted.
≠ 0 Error, could not mount NAND flash device.

Additional information

FS_NAND_UNI_Mount() can be used to explicitly mount the NAND flash device and to get information about it. This function returns a subset of the information returned by FS_NAND_UNI_GetDiskInfo() and therefore can be used instead of it if the application does not require statistical information about the usage of the NAND blocks. Typically, FS_NAND_UNI_Mount() requires less time to complete than FS_NAND_UNI_GetDiskInfo().

This function is not required for the functionality of the Universal NAND driver and is typically not linked in production builds.

FS_NAND_UNI_ReadLogSectorPartial()

Description

Reads a specified number of bytes from a logical sector.

Prototype

int FS_NAND_UNI_ReadLogSectorPartial(U8         Unit,
                                     U32        LogSectorIndex,
                                     void     * pData,
                                     unsigned   Off,
                                     unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
LogSectorIndex Index of the logical sector to read from.
pData  out  Data read from NAND flash.
Off Byte offset to read from (relative to beginning of the sector).
NumBytes Number of bytes to be read.

Return value

≠ 0 Number of bytes read.
= 0 An error occurred.

Additional information

This function is optional.

For NAND flash devices with internal HW ECC only the specified number of bytes is transferred and not the entire sector. Typ. used by the applications that access the NAND flash directly (that is without a file system) to increase the read performance.

FS_NAND_UNI_ReadPageRaw()

Description

Reads data from a page without ECC.

Prototype

int FS_NAND_UNI_ReadPageRaw(U8         Unit,
                            U32        PageIndex,
                            void     * pData,
                            unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PageIndex Index of the page to be read.
pData  out  Data to be written.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read.
≠ 0 An error occurred.

Additional information

This function is optional.

The data is read from byte offset 0 relative to the beginning of the page. If more data is requested than the page size (main + spare area, typically 2048 + 64 bytes) the function does not modify excess bytes in pData.

FS_NAND_UNI_ReadPageRaw() does not work correctly on NAND flash devices with HW ECC that cannot be disabled.

FS_NAND_UNI_ReadPhySector()

Description

This function reads a physical sector from NAND flash.

Prototype

int FS_NAND_UNI_ReadPhySector(U8         Unit,
                              U32        PhySectorIndex,
                              void     * pData,
                              unsigned * pNumBytesData,
                              void     * pSpare,
                              unsigned * pNumBytesSpare);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PhySectorIndex Physical sector index.
pData Pointer to a buffer to store read data.
pNumBytesData  in  Pointer to variable storing the size of the data buffer.  out  The number of bytes that were stored in the data buffer.
pSpare Pointer to a buffer to store read spare data.
pNumBytesSpare  in  Pointer to variable storing the size of the spare data buffer.  out  The number of bytes that were stored in the spare data buffer.

Return value

≥ 0 OK, sector data read.
< 0 An error occurred.

Additional information

This function is optional.

FS_NAND_UNI_ResetStatCounters()

Description

Sets the values of statistical counters to 0.

Prototype

void FS_NAND_UNI_ResetStatCounters(U8 Unit);

Parameters

Parameter Description
Unit Index of the driver instance (0-based)

Additional information

This function is optional. It is active only when the file system is compiled with FS_DEBUG_LEVEL set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.

The statistical counters can be queried via FS_NAND_UNI_GetStatCounters().

FS_NAND_UNI_TestBlock()

Description

Fills all the pages in a block (including the spare area) with the specified pattern and verifies if the data was written correctly.

Prototype

int FS_NAND_UNI_TestBlock(U8                  Unit,
                          unsigned            BlockIndex,
                          U32                 Pattern,
                          FS_NAND_TEST_INFO * pInfo);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
BlockIndex Index of the NAND block to be tested.
Pattern Data pattern to be written during the test.
pInfo Additional parameters and information about the test.

Return value

FS_NAND_TEST_RETVAL_OK OK, no bit errors.
FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR OK, correctable bit errors found. The number of bit errors is returned in NumErrorsCorrectable of pResult.
FS_NAND_TEST_RETVAL_FATAL_ERROR Fatal error, uncorrectable bit error found. The page index is returned in PageIndexFatalError of pResult.
FS_NAND_TEST_RETVAL_BAD_BLOCK Bad block, skipped.
FS_NAND_TEST_RETVAL_ERASE_FAILURE Erase operation failed. The block has been marked as defective.
FS_NAND_TEST_RETVAL_WRITE_FAILURE Write operation failed. The block has been marked as defective.
FS_NAND_TEST_RETVAL_READ_FAILURE Read operation failed.
FS_NAND_TEST_RETVAL_INTERNAL_ERROR NAND flash access error.

Additional information

This function is optional. It can be used by the application to test the data reliability of a NAND block. BlockIndex is relative to the beginning of the NAND partition where the first block has the index 0.

Example

The following sample code demonstrates how FS_NAND_UNI_TestBlock() can be used to check all the blocks of a NAND flash device. The function does not work correctly on NAND flash devices with HW ECC that cannot be disabled.

#include <stdio.h>
#include "FS.h"

void SampleNAND_UNITestBlocks(void) {
  int               r;
  U32               NumPhyBlocks;
  U32               iBlock;
  FS_NAND_DISK_INFO DiskInfo;
  FS_NAND_TEST_INFO TestInfo;
  char              ac[100];

  memset(&DiskInfo, 0, sizeof(DiskInfo));
  memset(&TestInfo, 0, sizeof(TestInfo));
  FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
  NumPhyBlocks = DiskInfo.NumPhyBlocks;
  TestInfo.NumBitsCorrectable = 1;
  TestInfo.BytesPerSpare      = (U16)DiskInfo.BytesPerSpareArea;
  for (iBlock = 0; iBlock < NumPhyBlocks; ++iBlock) {
    r = FS_NAND_UNI_TestBlock(0, iBlock, 0xAA5500FFuL, &TestInfo);
    switch (r) {
    case FS_NAND_TEST_RETVAL_OK:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: OK.\n", iBlock);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: %lu correctable error(s).\n", 
        iBlock, TestInfo.BitErrorCnt);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_FATAL_ERROR:
      SEGGER_snprintf(ac, sizeof(ac), 
        "Block %lu: %lu correctable error(s), fatal error on page %lu.\n",
        iBlock, TestInfo.BitErrorCnt, TestInfo.PageIndex);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_BAD_BLOCK:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Bad. Skipped.\n", iBlock);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_ERASE_FAILURE:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Erase failure. Marked as bad.\n", iBlock);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_WRITE_FAILURE:
      SEGGER_snprintf(ac, sizeof(ac), 
        "Block %lu: Write failure on page %lu. Marked as bad.\n",
        iBlock, TestInfo.PageIndex);
      FS_X_Log(ac);
      break;
    case FS_NAND_TEST_RETVAL_READ_FAILURE:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Read failure on page %lu.\n", 
        iBlock, TestInfo.PageIndex);
      FS_X_Log(ac);
      break;
    default:
      SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Internal error.\n", iBlock);
      FS_X_Log(ac);
      break;
    }
  }
}
FS_NAND_UNI_WritePage()

Description

Stores data to a page of a NAND flash with ECC.

Prototype

int FS_NAND_UNI_WritePage(      U8         Unit,
                                U32        PageIndex,
                          const void     * pData,
                                unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PageIndex Index of the page to be written.
pData  in  Data to be written.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is optional.

The data is written at byte offset 0 relative to the beginning of the page. If more data is written than the size of the page (main + spare area, typically 2048 + 64 bytes) then the excess bytes are discarded. The data in the area reserved for ECC cannot be modified using this function.

FS_NAND_UNI_WritePageRaw()

Description

Stores data to a page of a NAND flash without ECC.

Prototype

int FS_NAND_UNI_WritePageRaw(      U8         Unit,
                                   U32        PageIndex,
                             const void     * pData,
                                   unsigned   NumBytes);

Parameters

Parameter Description
Unit Index of the driver instance (0-based).
PageIndex Index of the page to be written.
pData  in  Data to be written.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is optional.

The data is written at the byte offset 0 relative to the beginning of the page. If more data is written than the size of the page (main + spare area, typically 2048 + 64 bytes) the excess bytes are discarded.

FS_NAND_UNI_WritePageRaw() does not work correctly on NAND flash devices with HW ECC that cannot be disabled.

Bad block marking types

Description

Methods to mark a block as defective.

Definition

#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FSPS     0
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FPS      1
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPS     2
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FSLPS    3
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPMS    4

Symbols

Definition Description
FS_NAND_BAD_BLOCK_MARKING_TYPE_FSPS The block is marked as defective in the spare area of the first and second page of the block.
FS_NAND_BAD_BLOCK_MARKING_TYPE_FPS The block is marked as defective in the spare area of the first page of the block.
FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPS The block is marked as defective in the spare area of first and last page of the block.
FS_NAND_BAD_BLOCK_MARKING_TYPE_FSLPS The block is marked as defective in the spare area of first, second and last page of the block.
FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPMS The block is marked as defective in the main and spare area of first and last page of the block.
Block info flags

Description

Flags that control the information returned by FS_NAND_UNI_GetBlockInfoEx().

Definition

#define FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS       0x01u
#define FS_NAND_BLOCK_INFO_FLAG_SECTOR_STATUS    0x02u

Symbols

Definition Description
FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS Return information about the status of the NAND block (defective or not)
FS_NAND_BLOCK_INFO_FLAG_SECTOR_STATUS Return information about the status of all logical sectors in the NAND block.

Additional information

These flags can be passed as Flags parameter to FS_NAND_UNI_GetBlockInfoEx() in order to specify the type of information that has to be returned.

ECC correction status

Description

Result of the bit error correction.

Definition

#define FS_NAND_CORR_NOT_APPLIED    0u
#define FS_NAND_CORR_APPLIED        1u
#define FS_NAND_CORR_FAILURE        2u

Symbols

Definition Description
FS_NAND_CORR_NOT_APPLIED No bit errors detected.
FS_NAND_CORR_APPLIED Bit errors were detected and corrected.
FS_NAND_CORR_FAILURE Bit errors were detected but not corrected.
FS_NAND_MOUNT_INFO

Description

Information about the mounted NAND flash device.

Type definition

typedef struct {
  U32  NumPhyBlocks;
  U32  NumLogBlocks;
  U32  NumPagesPerBlock;
  U32  NumSectorsPerBlock;
  U32  BytesPerPage;
  U32  BytesPerSpareArea;
  U32  BytesPerSector;
  U8   BadBlockMarkingType;
  U8   IsWriteProtected;
  U8   HasFatalError;
  U8   ErrorType;
  U32  ErrorSectorIndex;
  U16  BlocksPerGroup;
  U32  NumWorkBlocks;
} FS_NAND_MOUNT_INFO;

Structure members

Member Description
NumPhyBlocks Total number of blocks in the NAND partition.
NumLogBlocks Total number of NAND blocks that can be used to store data.
NumPagesPerBlock Number of pages in a NAND block.
NumSectorsPerBlock Number of logical sectors stored in a NAND block.
BytesPerPage Number of bytes in the main area of a NAND page.
BytesPerSpareArea Number of bytes in the spare area of a NAND page.
BytesPerSector Number of bytes is a logical sector.
BadBlockMarkingType Type of the bad block marking.
IsWriteProtected Set to 1 if the NAND flash device cannot be written.
HasFatalError Set to 1 if the SLC1 NAND driver reported a fatal error.
ErrorType Type of fatal error that has occurred.
ErrorSectorIndex Sector index on which a fatal error occurred.
BlocksPerGroup Number of NAND blocks in a group.
NumWorkBlocks Number of work blocks used by the SLC1 NAND driver.
FS_NAND_STAT_COUNTERS

Description

Statistical counters of NAND flash driver.

Type definition

typedef struct {
  U32  NumFreeBlocks;
  U32  NumBadBlocks;
  U32  EraseCnt;
  U32  ReadDataCnt;
  U32  ReadSpareCnt;
  U32  ReadSectorCnt;
  U32  NumReadRetries;
  U32  WriteDataCnt;
  U32  WriteSpareCnt;
  U32  WriteSectorCnt;
  U32  NumWriteRetries;
  U32  ConvertViaCopyCnt;
  U32  ConvertInPlaceCnt;
  U32  NumValidSectors;
  U32  CopySectorCnt;
  U32  BlockRelocationCnt;
  U32  ReadByteCnt;
  U32  WriteByteCnt;
  U32  BitErrorCnt;
  U32  aBitErrorCnt[];
} FS_NAND_STAT_COUNTERS;

Structure members

Member Description
NumFreeBlocks Number of NAND blocks not used for data.
NumBadBlocks Number of NAND blocks marked as defective.
EraseCnt Number of block erase operation performed.
ReadDataCnt Number of times the NAND driver read from the main area of a page.
ReadSpareCnt Number of times the NAND driver read from the spare area of a page.
ReadSectorCnt Number of logical sectors read from the NAND flash.
NumReadRetries Number of times a read operation has been retried because of an error.
WriteDataCnt Number of times the NAND driver wrote to the main area of a page.
WriteSpareCnt Number of times the NAND driver wrote to the spare area of a page.
WriteSectorCnt Number of logical sectors wrote to the NAND flash.
NumWriteRetries Number of times a write operation has been retried because of an error.
ConvertViaCopyCnt Number of block conversions via copy.
ConvertInPlaceCnt Number of block conversions in place.
NumValidSectors Number of logical sectors that contain valid data.
CopySectorCnt Number of times the NAND driver copied a logical sector to another location.
BlockRelocationCnt Number of times the NAND driver relocated a NAND block due to errors.
ReadByteCnt Number of bytes read from NAND flash.
WriteByteCnt Number of bytes written to NAND flash.
BitErrorCnt Number of bit errors detected and corrected.
aBitErrorCnt Number of times a specific number of bit errors occurred.

Additional information

This structure can be used to get statistical information about the operation of the Universal as well as SLC1 NAND driver via the function FS_NAND_UNI_GetStatCounters() and FS_NAND_GetStatCounters() respectively.

aBitErrorCnt[0] stores the number of 1 bit error occurrences, aBitErrorCnt[1] stores the number of 2 bit error occurrences, and so on.

Example

Refer to FS_NAND_UNI_GetStatCounters() and FS_NAND_GetStatCounters() for a sample usage.

FS_NAND_TEST_INFO

Description

Additional information passed to test routine.

Type definition

typedef struct {
  U8   NumBitsCorrectable;
  U8   OffSpareECCProt;
  U8   NumBytesSpareECCProt;
  U16  BytesPerSpare;
  U32  BitErrorCnt;
  U32  PageIndex;
} FS_NAND_TEST_INFO;

Structure members

Member Description
NumBitsCorrectable Number of bits the ECC can correct in the data and spare area (typically 4)
OffSpareECCProt Offset in the spare area of the first byte protected by ECC (typically 4).
NumBytesSpareECCProt Number of bytes in the spare area protected by ECC (typically 4 bytes)
BytesPerSpare Total number of bytes in the spare area. When set to 0 the default value of 1/32 of page size is used.
BitErrorCnt Number of bit errors detected and corrected.
PageIndex Index of the physical page where the error happened.

Additional information

The test routine returns information about what went wrong during a test via FS_NAND_UNI_TestBlock() and FS_NAND_TestBlock().

Example

Refer to FS_NAND_UNI_TestBlock() and FS_NAND_TestBlock() for a sample usage.

NAND block types

Description

Type of data stored to a NAND block.

Definition

#define FS_NAND_BLOCK_TYPE_UNKNOWN    0u
#define FS_NAND_BLOCK_TYPE_BAD        1u
#define FS_NAND_BLOCK_TYPE_EMPTY      2u
#define FS_NAND_BLOCK_TYPE_WORK       3u
#define FS_NAND_BLOCK_TYPE_DATA       4u

Symbols

Definition Description
FS_NAND_BLOCK_TYPE_UNKNOWN The type of the block cannot be determined.
FS_NAND_BLOCK_TYPE_BAD The block marked as defective.
FS_NAND_BLOCK_TYPE_EMPTY The block does not store any data.
FS_NAND_BLOCK_TYPE_WORK The block that stores data temporarily.
FS_NAND_BLOCK_TYPE_DATA The block that stores data permanently.
NAND test return values

Description

Return values of the NAND block test functions.

Definition

#define FS_NAND_TEST_RETVAL_OK                   0
#define FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR    1
#define FS_NAND_TEST_RETVAL_FATAL_ERROR          2
#define FS_NAND_TEST_RETVAL_BAD_BLOCK            3
#define FS_NAND_TEST_RETVAL_ERASE_FAILURE        4
#define FS_NAND_TEST_RETVAL_WRITE_FAILURE        5
#define FS_NAND_TEST_RETVAL_READ_FAILURE         6
#define FS_NAND_TEST_RETVAL_INTERNAL_ERROR       (-1)

Symbols

Definition Description
FS_NAND_TEST_RETVAL_OK The test was successful.
FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR Bit errors occurred that were corrected via ECC.
FS_NAND_TEST_RETVAL_FATAL_ERROR Bit errors occurred that the ECC was not able to correct.
FS_NAND_TEST_RETVAL_BAD_BLOCK The tested block was marked as defective.
FS_NAND_TEST_RETVAL_ERASE_FAILURE An error occurred during the block erase operation.
FS_NAND_TEST_RETVAL_WRITE_FAILURE An error occurred while writing the data to the NAND block.
FS_NAND_TEST_RETVAL_READ_FAILURE An error occurred while reading the data from the NAND block.
FS_NAND_TEST_RETVAL_INTERNAL_ERROR An internal processing error occurred.
Performance and resource usage

This section provides information about the ROM and RAM usage as well as the performance of the Universal NAND driver. Please note that a Universal NAND driver instance requires one instance of one NAND physical layer in order to operate. The resource usage of the used NAND physical layer has to be taken into account when calculating the total resource usage of the Universal NAND driver.

ROM usage

The ROM usage depends on the compiler options, the compiler version and the used CPU. The memory requirements of the Universal NAND driver were measured as described in the section Test procedure.

Usage: 7.9 Kbytes

Static RAM usage

Static RAM usage refers to the amount of RAM required by the Universal NAND driver internally for all the driver instances. The number of bytes can be seen in the compiler list file of the {FS_NAND_UNI_Drv.c} file.

Usage: 32 bytes

Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the driver at runtime. The amount required depends on the runtime configuration and the characteristics of the used NAND flash device. The approximate RAM usage of the Universal NAND driver can be calculated as follows:

MemAllocated = 148 + 2 * NumBlocks
             + ((PagesPerBlock - 1) + 18) * NumWorkBlocks
             + 1.04 * PageSize
Parameter Description
MemAllocated Number of bytes allocated for one instance of the NAND driver.
NumBlocks Number of blocks in the NAND flash device.
NumWorkBlocks Number of blocks the driver reserves as temporary storage for the written data. By default, 3 blocks are reserved. The number of work blocks can be specified at runtime via FS_NAND_UNI_SetNumWorkBlocks().
PageSize Number of bytes in a page.

Example

This example uses a 2 GBit NAND flash device with 2Kbyte pages and 2048 blocks. One block consists of 64 pages and each page holds 1 sector of 2048 bytes.

PagesPerBlock = 64
NumBlocks     = 2048
NumWorkBlocks = 4
PageSize      = 2048
MemAllocated  = 148 + 2 * 2048 + (64 - 1 + 18) * 4 + 1.04 * 2048
              = 148 + 4096 + 324 + 2129
              = 6397 bytes
Performance

The following performance measurements are in no way complete, but they give a good approximation of time required for common operations on various target hardware. The tests were performed as described in the section Performance. All values are given in Mbytes/sec.

CPU type NAND flash device Write speed Read speed
NXP LPC4322 (180 MHz) Serial NAND flash with 2048 bytes per page connected to a quad SPI controller via 4 data lines transferring data at 60 MHz. 4.1 12.2
NXP LPC4322 (180 MHz) Serial NAND flash with 2048 bytes per page connected to a standard SPI controller transferring data at 60 MHz. 3.9 7.7
ST STM32MP157 (650 MHz) Parallel NAND flash with 4096 bytes per page connected to external memory controller via an 8-bit data bus. The 8-bit ECC is calculated using SEGGER emFile-ECC. 10.8 22.2
Atmel AT91SAM3U (96 MHz) Parallel NAND flash with 2048 bytes per page and a sector size of 2048 bytes with internal ECC enabled using the built in NAND controller/external bus-interface. 2.6 7.5

NAND physical layer

General information

The NAND physical layer provides the basic functionality for accessing a NAND flash device such as device identification, block erase operation, page read and write operations, etc. Every instance of the Universal or SLC1 NAND driver requires an instance of a NAND physical layer in order to be able to operate. A NAND physical layer instance is automatically allocated either statically or dynamically at the first call to one of its API functions. Each instance is identified by a unit number that is identical with the unit number of the NAND driver that uses that instance of the NAND physical layer. The type of the NAND physical layer assigned to an instance of a Universal or SLC1 NAND driver is configured via FS_NAND_UNI_SetPhyType() and FS_NAND_SetPhyType() respectively.

The table below lists the NAND physical layers that ship with emFile. Refer to Configuring the driver and Configuring the driver for detailed information about how to add and configure a physical layer in an application.

Physical layer identifier Works with Universal NAND driver? Works with SLC1 NAND driver? Hardware layer type
FS_NAND_PHY_512x8 no yes FS_NAND_HW_TYPE
FS_NAND_PHY_2048x8 yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_2048x8_TwoPlane yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_2048x8_Small yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_2048x16 yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_4096x8 yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_DataFlash no yes FS_NAND_HW_TYPE_DF
FS_NAND_PHY_ONFI yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_ONFI_RO yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_ONFI_Small yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_QSPI yes no FS_NAND_HW_TYPE_QSPI
FS_NAND_PHY_SPI yes no FS_NAND_HW_TYPE_SPI
FS_NAND_PHY_x yes yes FS_NAND_HW_TYPE
FS_NAND_PHY_x8 yes yes FS_NAND_HW_TYPE

The following sections provide information about the usage and the implementation of a NAND physical layer.

512x8 physical layer

This NAND physical layer supports any NAND flash device with a page size of 512 bytes and a spare area of 16 bytes that is connected to MCU via an 8-bit data bus. It works only with the SLC1 NAND driver because the size of the spare area is not sufficiently large for the amount of management data required by the Universal NAND driver. The instances of this physical layer are allocated statically. The maximum number of instances can be configured at compile time via FS_NAND_NUM_UNITS.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the 512x8 physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_512x8_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_512x8.
FS_NAND_512x8_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_512x8.

Prototype

void FS_NAND_512x8_SetHWType(      U8                Unit,
                             const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_512x8.

2048x8 physical layer

This NAND physical layer supports any NAND flash device with a page size of 2048 bytes and a spare area larger than or equal to 64 bytes that is connected to MCU via an 8-bit data bus. The instances of this physical layer are allocated dynamically. The maximum number of instances can be configured at compile time via FS_NAND_NUM_UNITS.

Compile time configuration

The 2048x8 physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_2048X8_DEVICE_LIST_DEFAULT &FS_NAND_2048X8_DeviceListDefault R List of parallel NAND flash devices that can be handled by the physical layer.
FS_NAND_SUPPORT_READ_CACHE 0 B Specifies if the internal page register of the NAND flash device should be used as read cache.
FS_NAND_2048X8_DEVICE_LIST_DEFAULT

FS_NAND_2048X8_DEVICE_LIST_DEFAULT specifies the list of parallel NAND flash devices that can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage if not all the devices included in FS_NAND_2048X8_DeviceListDefault have to be handled. In this case it is mandatory that the application configures a list of devices via FS_NAND_2048X8_SetDeviceList().

FS_NAND_SUPPORT_READ_CACHE

With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track of the index of the last page read from NAND flash device. If the same page is read again then the physical layer omits the operation that transfers the page data from the memory array to the internal page register of the NAND flash device. In this case only a data transfer from the internal page register to host is executed which helps improve the performance.

Note

This feature cannot be used if the NAND flash device is partitioned via either FS_NAND_SetBlockRange() or FS_NAND_UNI_SetBlockRange() and the created partitions are accessed via the file system.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the 2048x8 physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_2048x8_DisableReadCache() Deactivates the page read optimization.
FS_NAND_2048x8_EnableReadCache() Activates the page read optimization.
FS_NAND_2048X8_SetDeviceList() Specifies the list of NAND flash devices that require special handling.
FS_NAND_2048x8_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_2048x8.
FS_NAND_2048x8_DisableReadCache()

Description

Deactivates the page read optimization.

Prototype

void FS_NAND_2048x8_DisableReadCache(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)

Additional information

This function is optional and is available only when the file system is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default. The optimization can be enabled at runtime via FS_NAND_2048x8_EnableReadCache().

Refer to FS_NAND_2048x8_EnableReadCache() for more information about how the page read optimization works

FS_NAND_2048x8_EnableReadCache()

Description

Activates the page read optimization.

Prototype

void FS_NAND_2048x8_EnableReadCache(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)

Additional information

This function is optional and is available only when the file system is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default. Activating the read cache can increase the overall performance of the NAND driver especially when using the SLC1 NAND driver with a logical sector size smaller than the page of the used NAND flash device.

The optimization takes advantage of how the NAND flash device implements the read page operation. A NAND page read operation consists of two steps. In the first step, the page data is read from the memory array to internal page register of the NAND flash device. In the second step, the data is transferred from the internal page register of NAND flash device to MCU. With the optimization enabled the first step is skipped whenever possible.

The optimization is enabled by default and has to be disabled if two or more instances of the NAND driver are configured to access the same physical NAND flash device. At runtime, the optimization can be disabled via FS_NAND_2048x8_DisableReadCache().

FS_NAND_2048X8_SetDeviceList()

Description

Specifies the list of NAND flash devices that require special handling.

Prototype

void FS_NAND_2048X8_SetDeviceList(      U8                           Unit,
                                  const FS_NAND_2048X8_DEVICE_LIST * pDeviceList);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
pDeviceList  in  List of NAND flash devices.

Additional information

NAND flash devices that do not require special handling such as devices without HW ECC are always enabled. The special handling is required for example to determine if the HW ECC of the NAND flash device can be enabled and disabled at runtime.

By default, only special handling for NAND flash devices from Samsung and Toshiba is enabled (FS_NAND_ONFI_DeviceListDefault). The correct operation of NAND flash device from a manufacturer not included in the configured list of devices is not guaranteed if the the NAND flash device requires special handling.

Permitted values for the pDeviceList parameter are:

Identifier Description
FS_NAND_2048X8_DeviceListAll Enables the handling for all supported NAND flash devices.
FS_NAND_2048X8_DeviceListDefault Enables the handling of standard NAND flash devices and the special handling of Samsung and Toshiba NAND flashes.
FS_NAND_2048X8_DeviceListStandard Enables the handling of NAND flash devices that do not have any special features such as HW ECC.
FS_NAND_2048X8_DeviceListSamsung Enables the special handling of Samsung NAND flash devices.
FS_NAND_2048X8_DeviceListToshiba Enables the special handling of Toshiba NAND flash devices.
FS_NAND_2048x8_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_2048x8.

Prototype

void FS_NAND_2048x8_SetHWType(      U8                Unit,
                              const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_2048x8.

Two plane 2048x8 physical layer

This NAND physical layer supports any NAND flash device with a page size of 2048 bytes and a spare area larger than or equal to 64 bytes that is connected to MCU via an 8-bit data bus. In addition, the NAND flash device has to be organized in two planes and provide support for executing an operation on both planes simultaneously. The instances of this physical layer are allocated dynamically. The maximum number of instances can be configured at build time via FS_NAND_NUM_UNITS.

FS_NAND_PHY_2048x8_TwoPlane uses the same runtime functions and compile time configuration defines as FS_NAND_PHY_2048x8.

Small 2048x8 physical layer

This physical layer is a variant of FS_NAND_PHY_2048x8 with reduced ROM usage. FS_NAND_PHY_2048x8_Small supports the same NAND flash devices as FS_NAND_PHY_2048x8 but it does not provide support for the NAND internal page copy operation and for the reading the ECC correction result. FS_NAND_PHY_2048x8_Small provides read as well as write access to NAND flash device. The instances of this physical layer are allocated statically.

FS_NAND_PHY_2048x8_Small uses the same runtime functions and compile time configuration defines as FS_NAND_PHY_2048x8.

2048x16 physical layer

This physical layer supports NAND flash devices with page size of 2048 bytes and a spare area larger than or equal to 64 bytes that is connected to MCU via an 16-bit data bus. The instances of this physical layer are allocated statically. The maximum number of instances can be configured at build time via FS_NAND_NUM_UNITS.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the 2048x16 physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_2048x16_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_2048x16.
FS_NAND_2048x16_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_2048x16.

Prototype

void FS_NAND_2048x16_SetHWType(      U8                Unit,
                               const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_2048x16.

4096x8 physical layer

This NAND physical layer supports any NAND flash device with a page size of 4096 bytes and a spare area larger than or equal to 128 bytes that is connected to MCU via an 8-bit data bus. The instances of this physical layer are allocated statically. The maximum number of instances can be configured at build time via FS_NAND_NUM_UNITS.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the 4096x8 physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_4096x8_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_4096x8.
FS_NAND_4096x8_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_4096x8.

Prototype

void FS_NAND_4096x8_SetHWType(      U8                Unit,
                              const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_4096x8.

DataFlash physical layer

This physical layer supports Dialog Semiconductor / Adesto / Atmel DataFlash storage devices. The devices are accessed via SPI using a hardware layer of type FS_NAND_HW_TYPE_DF. FS_NAND_PHY_DataFlash works only with the SLC1 NAND driver because the size of the spare area is not sufficiently large for the amount of management data required by the Universal NAND driver. The instances of this physical layer are allocated statically.

Compile time configuration

The DataFlash physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_BLOCK_TYPE 2 N Specifies the size of the erase unit.
FS_NAND_SUPPORT_READ_CACHE 0 B Specifies if the internal page register of the DataFlash device should be used as read cache.
FS_NAND_BLOCK_TYPE

FS_NAND_BLOCK_TYPE can be used to specify the size of the erase unit used by the DataFlash physical layer. The following erase unit sizes are supported: 1 block large (FS_NAND_BLOCK_TYPE = 0), 8 blocks large (FS_NAND_BLOCK_TYPE = 1) and 1 sector large (FS_NAND_BLOCK_TYPE = 2). By default FS_NAND_BLOCK_TYPE is set 2 because it ensures the maximum performance.

Note

The physical layer is not fail-safe when FS_NAND_BLOCK_TYPE is set to 1 because more than one erase operation has to be performed in order to erase the entire block.

FS_NAND_SUPPORT_READ_CACHE

With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track of the index of the last page read from DataFlash flash device. If the same page is read again then the physical layer omits the operation that transfers the page data from the memory array to the internal page register of the DataFlash flash device. In this case only a data transfer from the internal page register to host is executed which helps improve the performance.

Note

This feature cannot be used if the DataFlash device is partitioned via FS_NAND_SetBlockRange() and the created partitions are accessed via the file system.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the DataFlash physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_DF_EraseChip() Erases the entire device.
FS_NAND_DF_SetMinPageSize() Configures the required minimum page size.
FS_NAND_DF_SetHWType() Configures the hardware access routines.
FS_NAND_DF_EraseChip()

Description

Erases the entire device.

Prototype

void FS_NAND_DF_EraseChip(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)

Additional information

This function is optional. It sets all the bits of the DataFlash memory to 1. All the data stored on the DataFlash memory is lost.

FS_NAND_DF_SetMinPageSize()

Description

Configures the required minimum page size.

Prototype

void FS_NAND_DF_SetMinPageSize(U8  Unit,
                               U32 NumBytes);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
NumBytes Page size in bytes.

Additional information

This function is optional. The application can use it to request a minimum page size to work with. If the size of the physical page is smaller than the specified value then then adjacent physical pages are grouped together into one virtual page that is presented as a single page to the SLC1 NAND driver. This is required when the size of a physical page is smaller than 512 bytes which is the minimum sector size the SLC1 NAND driver can work with. NumBytes has to be a power of 2 value.

FS_NAND_DF_SetHWType()

Description

Configures the hardware access routines.

Prototype

void FS_NAND_DF_SetHWType(      U8                   Unit,
                          const FS_NAND_HW_TYPE_DF * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
pHWType Table of hardware routines.

Additional information

This function is mandatory and it has to be called once for each used instance of the physical layer.

ONFI physical layer

This physical layer supports NAND flash devices that are compliant to ONFI specification. The organization of the NAND flash device such as page size and number of blocks is determined automatically by evaluating the parameters stored in the NAND flash device according to ONFI specification. The instances of this physical layer are allocated dynamically.

Compile time configuration

The ONFI physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_ONFI_DEVICE_LIST_DEFAULT &FS_NAND_ONFI_DeviceListDefault R List of parallel NAND flash devices that can be handled by the physical layer.
FS_NAND_SUPPORT_EXT_ONFI_PARA 0 B Specifies if the extended ONFI parameters have to be evaluated or not.
FS_NAND_ONFI_DEVICE_LIST_DEFAULT

FS_NAND_ONFI_DEVICE_LIST_DEFAULT specifies the list of parallel NAND flash devices that can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage if not all the devices included in FS_NAND_ONFI_DeviceListDefault have to be handled. In this case it is mandatory that the application configures a list of devices via FS_NAND_ONFI_SetDeviceList().

FS_NAND_SUPPORT_EXT_ONFI_PARA

FS_NAND_SUPPORT_EXT_ONFI_PARA can be used to enable the evaluation of extended ONFI parameters. By default the ONFI physical layer evaluates only the standard ONFI parameters. The extended ONFI parameters provide for example additional information about the bit error correction. Setting FS_NAND_SUPPORT_EXT_ONFI_PARA to 0 reduces the ROM usage.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the ONFI physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_ONFI_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_ONFI.
FS_NAND_ONFI_SetDeviceList() Specifies the list of ONFI NAND flash devices that require special handling.
FS_NAND_ONFI_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_ONFI.

Prototype

void FS_NAND_ONFI_SetHWType(      U8                Unit,
                            const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_ONFI.

FS_NAND_ONFI_SetDeviceList()

Description

Specifies the list of ONFI NAND flash devices that require special handling.

Prototype

void FS_NAND_ONFI_SetDeviceList(      U8                         Unit,
                                const FS_NAND_ONFI_DEVICE_LIST * pDeviceList);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
pDeviceList  in  List of ONFI NAND flash devices.

Additional information

NAND flash devices that do not require special handling such as devices without HW ECC are always enabled. The special handling is required for example to determine if the HW ECC of the NAND flash device can be enabled and disabled at runtime.

By default, only special handling for NAND flash devices from Micron and Macronix is enabled (FS_NAND_ONFI_DeviceListDefault). The correct operation of NAND flash device from a manufacturer not included in the configured list of devices is not guaranteed if the the NAND flash device requires special handling.

Permitted values for the pDeviceList parameter are:

Identifier Description
FS_NAND_ONFI_DeviceListAll Enables special handling for all supported NAND flash devices.
FS_NAND_ONFI_DeviceListAllianceMemory Enables special handling of Alliance Memory parallel NAND flash devices.
FS_NAND_ONFI_DeviceListDefault Enables special handling of NAND flash devices from Micron and Macronix.
FS_NAND_ONFI_DeviceListGigaDevice Enables special handling of GigaDevice parallel NAND flash devices.
FS_NAND_ONFI_DeviceListISSI Enables special handling of ISSI parallel NAND flash devices.
FS_NAND_ONFI_DeviceListMacronix Enables special handling of Macronix parallel NAND flash devices.
FS_NAND_ONFI_DeviceListMicron Enables special handling of Micron parallel NAND flash devices.
FS_NAND_ONFI_DeviceListSkyHigh Enables special handling of SkyHigh parallel NAND flash devices.
FS_NAND_ONFI_DeviceListWinbond Enables special handling of Winbond parallel NAND flash devices.
Read-only ONFI physical layer

This physical layer is a variant of FS_NAND_PHY_ONFI with read-only access. FS_NAND_PHY_ONFI_RO provides the same functionality as FS_NAND_PHY_ONFI except that it cannot modify any data stored on the NAND flash device only to read it. The erase and write functions of FS_NAND_PHY_ONFI_RO do nothing and return and error to NAND driver when called.

FS_NAND_PHY_ONFI_RO uses the same runtime configuration functions and compile time configuration defines as FS_NAND_PHY_ONFI.

Small ONFI physical layer

This physical layer is a variant of FS_NAND_PHY_ONFI with reduced ROM usage. FS_NAND_PHY_ONFI_Small supports the same NAND flash devices as FS_NAND_PHY_ONFI but it does not provide support for the internal page copy operation and for the reading the ECC correction result. FS_NAND_PHY_ONFI_Small provides read as well as write access to NAND flash device.

FS_NAND_PHY_ONFI_Small uses the same runtime configuration functions and compile time configuration defines as FS_NAND_PHY_ONFI.

Quad-SPI physical layer

This physical layer supports NAND flash devices interfaced via quad or dual SPI. The organization of the NAND flash device such as page size and number of blocks is determined automatically by evaluating the parameters stored in the NAND flash device. The instances of this physical layer are allocated dynamically.

Compile time configuration

The QSPI physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_DEVICE_OPERATION_TIMEOUT 500 N Timeout for a NAND flash device operation in milliseconds.
FS_NAND_RESET_TIME 2 N Time to wait for the device to become ready after reset in milliseconds.
FS_NAND_SPI_DEVICE_LIST_DEFAULT &FS_NAND_SPI_DeviceListAll R List of serial NAND flash devices that can be handled by the physical layer.
FS_NAND_SUPPORT_COMPATIBILITY_MODE 0 N Specifies the operating mode of the physical layer.
FS_NAND_SUPPORT_READ_CACHE 1 B Specifies if the internal page register of the NAND flash should be used as read cache.
FS_NAND_DEVICE_OPERATION_TIMEOUT

FS_NAND_DEVICE_OPERATION_TIMEOUT specifies the maximum time in milliseconds the physical layer has to wait for a NAND flash operation to complete. This timeout is used for the read, write and as well as erase operations. This value has to be set according to the timings specified in the data sheet of the NAND flash device.

FS_NAND_RESET_TIME

FS_NAND_RESET_TIME specifies the time in milliseconds the physical layer waits for the NAND flash device to become ready after a reset command. This value has to be set according to the timings specified in the data sheet of the NAND flash device.

FS_NAND_SPI_DEVICE_LIST_DEFAULT

FS_NAND_SPI_DEVICE_LIST_DEFAULT specifies the list of serial NAND flash devices that can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage if not all the devices included in FS_NAND_SPI_DeviceListDefault have to be handled. In this case it is mandatory that the application configures a list of devices via FS_NAND_QSPI_SetDeviceList().

FS_NAND_SUPPORT_COMPATIBILITY_MODE

emFile versions older than 4.06b wrongly stored the management data to a region of the spare area that was not protected by the HW ECC. This behavior affects only configurations that use the Micron MT29F1G01ABAFD NAND flash device. The correction of this behavior introduces a data compatibility that can be avoided by setting this define either to 1 or to 2. With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 1 the physical layer reads the management data from old location if at the new location no management data is present. With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 2 the physical layer updates the management data to old and new location in addition to trying to read it from both of these locations.

FS_NAND_SUPPORT_READ_CACHE

With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track of the index of the last page read from the serial NAND flash device. If the same page is read again then the physical layer omits the operation that transfers the page data from the memory array to the internal page register of the serial NAND flash device. In this case only a data transfer from the internal page register to host is executed which helps improve the performance.

Note

This feature cannot be used if the NAND flash device is partitioned via FS_NAND_UNI_SetBlockRange() and the created partitions are accessed via the file system.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the QSPI physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_QSPI_Allow2bitMode() Specifies if the physical layer can exchange data via 2 data lines.
FS_NAND_QSPI_Allow4bitMode() Specifies if the physical layer can exchange data via 4 data lines.
FS_NAND_QSPI_AllowDTRMode() Specifies if the physical layer is permitted to exchange data on both clock edges.
FS_NAND_QSPI_DisableReadCache() Deactivates the page read optimization.
FS_NAND_QSPI_EnableReadCache() Activates the page read optimization.
FS_NAND_QSPI_SetDeviceList() Specifies the list of enabled serial NAND flash devices.
FS_NAND_QSPI_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_QSPI.
FS_NAND_QSPI_Allow2bitMode()

Description

Specifies if the physical layer can exchange data via 2 data lines.

Prototype

void FS_NAND_QSPI_Allow2bitMode(U8 Unit,
                                U8 OnOff);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
OnOff Activation status of the option. 0 Data is exchanged via 1 data line. 1 Data is exchanged via 2 data lines.

Additional information

This function is optional. By default the data is exchanged via 1 data line (standard SPI mode).

FS_NAND_QSPI_Allow4bitMode()

Description

Specifies if the physical layer can exchange data via 4 data lines.

Prototype

void FS_NAND_QSPI_Allow4bitMode(U8 Unit,
                                U8 OnOff);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
OnOff Activation status of the option. 0 Data is exchanged via 1 data line or 2 data lines. 1 Data is exchanged via 4 data lines.

Additional information

This function is optional. By default the data is exchanged via 1 data line (standard SPI mode).

FS_NAND_QSPI_AllowDTRMode()

Description

Specifies if the physical layer is permitted to exchange data on both clock edges.

Prototype

void FS_NAND_QSPI_AllowDTRMode(U8 Unit,
                               U8 OnOff);

Parameters

Parameter Description
Unit Index of the physical layer (0-based).
OnOff Activation status of the option. 0 Disable the option. 1 Enable the option.

Additional information

This function is optional. By default the data is exchanged only on one of the clock edges (SDR mode). In DTR mode the data is transferred on each edge of the clock which helps improve the performance.

The application is permitted to call this function only at the file system initialization in FS_X_AddDevices().

The DTR mode is enabled only if the configured hardware layer implements the optional function FS_NAND_HW_TYPE_QSPI_READ_EX.

FS_NAND_QSPI_DisableReadCache()

Description

Deactivates the page read optimization

Prototype

void FS_NAND_QSPI_DisableReadCache(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)

Additional information

This function is optional and is available only when the file system is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default. The optimization can be enabled at runtime via FS_NAND_QSPI_EnableReadCache().

Refer to FS_NAND_QSPI_EnableReadCache() for more information about how the page read optimization works

FS_NAND_QSPI_EnableReadCache()

Description

Activates the page read optimization

Prototype

void FS_NAND_QSPI_EnableReadCache(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)

Additional information

This function is optional and is available only when the file system is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default. Activating the read cache can increase the overall performance of the NAND driver.

The optimization takes advantage of how the NAND flash device implements the read page operation. A NAND page read operation consists of two steps. In the first step, the page data is read from the memory array to internal page register of the NAND flash device. In the second step, the data is transferred from the internal page register of NAND flash device to MCU. With the optimization enabled the first step is skipped whenever possible.

The optimization is enabled by default and has to be disabled if two or more instances of the NAND driver are configured to access the same physical NAND flash device. At runtime, the optimization can be disabled via FS_NAND_QSPI_DisableReadCache().

FS_NAND_QSPI_SetDeviceList()

Description

Specifies the list of enabled serial NAND flash devices.

Prototype

void FS_NAND_QSPI_SetDeviceList(      U8                        Unit,
                                const FS_NAND_SPI_DEVICE_LIST * pDeviceList);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
pDeviceList  in  List of serial NAND flash devices.

Additional information

All supported serial NAND flash devices are enabled by default. Serial NAND flash devices that are not on the list are not recognized by the file system.

Permitted values for the pDeviceList parameter are:

Identifier Description
FS_NAND_SPI_DeviceListAll Enables handling of serial NAND flash devices from all manufacturers.
FS_NAND_SPI_DeviceListAllianceMemory Enables handling of Alliance Memory serial NAND flash devices.
FS_NAND_SPI_DeviceListDefault Enables handling of NAND flash devices from any other manufacturer.
FS_NAND_SPI_DeviceListGigaDevice Enables handling of GigaDevice serial NAND flash devices.
FS_NAND_SPI_DeviceListISSI Enables handling of ISSI serial NAND flash devices.
FS_NAND_SPI_DeviceListMacronix Enables handling of Macronix serial NAND flash devices.
FS_NAND_SPI_DeviceListMicron Enables handling of Micron serial NAND flash devices.
FS_NAND_SPI_DeviceListToshiba Enables handling of Kioxia/Toshiba serial NAND flash devices.
FS_NAND_SPI_DeviceListWinbond Enables handling of Winbond serial NAND flash devices.
FS_NAND_QSPI_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_QSPI.

Prototype

void FS_NAND_QSPI_SetHWType(      U8                     Unit,
                            const FS_NAND_HW_TYPE_QSPI * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_QSPI.

SPI physical layer

This physical layer supports NAND flash devices interfaced via standard SPI. The organization of the NAND flash device such as page size and number of blocks is determined automatically by evaluating the parameters stored in the NAND flash device. The instances of this physical layer are allocated dynamically.

Compile time configuration

The SPI physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_DEVICE_OPERATION_TIMEOUT 500 N Timeout for a NAND flash device operation in milliseconds.
FS_NAND_RESET_TIME 2 N Time to wait for the device to become ready after reset in milliseconds.
FS_NAND_SPI_DEVICE_LIST_DEFAULT &FS_NAND_SPI_DeviceListAll R List of serial NAND flash devices that can be handled by the physical layer.
FS_NAND_SUPPORT_COMPATIBILITY_MODE 0 N Specifies the operating mode of the physical layer.
FS_NAND_SUPPORT_READ_CACHE 1 B Specifies if the internal page register of the NAND flash should be used as read cache.
FS_NAND_DEVICE_OPERATION_TIMEOUT

FS_NAND_DEVICE_OPERATION_TIMEOUT specifies the maximum time in milliseconds the physical layer has to wait for a NAND flash operation to complete. This value has to be set according to the timings specified in the data sheet of the NAND flash device.

FS_NAND_RESET_TIME

FS_NAND_RESET_TIME specifies the time in milliseconds the physical layer waits for the NAND flash device to become ready after a reset command. This value has to be set according to the timings specified in the data sheet of the NAND flash device.

FS_NAND_SPI_DEVICE_LIST_DEFAULT

FS_NAND_SPI_DEVICE_LIST_DEFAULT specifies the list of serial NAND flash devices that can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage if not all the devices included in FS_NAND_SPI_DeviceListDefault have to be handled. In this case it is mandatory that the application configures a list of devices via FS_NAND_SPI_SetDeviceList().

FS_NAND_SUPPORT_COMPATIBILITY_MODE

emFile versions older than 4.06b wrongly stored the management data to a region of the spare area that was not protected by the HW ECC. This behavior affects only configurations that use the Micron MT29F1G01ABAFD NAND flash device. The correction of this behavior introduces a data compatibility that can be avoided by setting this define either to 1 or to 2. With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 1 the physical layer reads the management data from old location if at the new location no management data is present. With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 2 the physical layer updates the management data to old and new location in addition to trying to read it from both of these locations.

FS_NAND_SUPPORT_READ_CACHE

With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track of the index of the last page read from the serial NAND flash device. If the same page is read again then the physical layer omits the operation that transfers the page data from the memory array to the internal page register of the serial NAND flash device. In this case only a data transfer from the internal page register to host is executed which helps improve the performance.

Note

This feature cannot be used if the NAND flash device is partitioned via FS_NAND_UNI_SetBlockRange() and the created partitions are accessed via the file system.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the SPI physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_SPI_DisableReadCache() Deactivates the page read optimization.
FS_NAND_SPI_EnableReadCache() Activates the page read optimization.
FS_NAND_SPI_SetDeviceList() Specifies the list of enabled serial NAND flash devices.
FS_NAND_SPI_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_SPI.
FS_NAND_SPI_DisableReadCache()

Description

Deactivates the page read optimization

Prototype

void FS_NAND_SPI_DisableReadCache(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)

Additional information

This function is optional and is available only when the file system is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default. The optimization can be enabled at runtime via FS_NAND_SPI_EnableReadCache().

Refer to FS_NAND_SPI_EnableReadCache() for more information about how the page read optimization works

FS_NAND_SPI_EnableReadCache()

Description

Activates the page read optimization

Prototype

void FS_NAND_SPI_EnableReadCache(U8 Unit);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)

Additional information

This function is optional and is available only when the file system is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default. Activating the read cache can increase the overall performance of the NAND driver.

The optimization takes advantage of how the NAND flash device implements the read page operation. A NAND page read operation consists of two steps. In the first step, the page data is read from the memory array to internal page register of the NAND flash device. In the second step, the data is transferred from the internal page register of NAND flash device to MCU. With the optimization enabled the first step is skipped whenever possible.

The optimization is enabled by default and has to be disabled if two or more instances of the NAND driver are configured to access the same physical NAND flash device. At runtime, the optimization can be disabled via FS_NAND_SPI_DisableReadCache().

FS_NAND_SPI_SetDeviceList()

Description

Specifies the list of enabled serial NAND flash devices.

Prototype

void FS_NAND_SPI_SetDeviceList(      U8                        Unit,
                               const FS_NAND_SPI_DEVICE_LIST * pDeviceList);

Parameters

Parameter Description
Unit Index of the physical layer (0-based)
pDeviceList  in  List of serial NAND flash devices.

Additional information

All supported serial NAND flash devices are enabled by default. Serial NAND flash devices that are not on the list are not recognized by the file system.

Permitted values for the pDeviceList parameter are:

Identifier Description
FS_NAND_SPI_DeviceListAll Enables handling of serial NAND flash devices from all manufacturers.
FS_NAND_SPI_DeviceListDefault Enables handling of NAND flash devices from any other manufacturer.
FS_NAND_SPI_DeviceListISSI Enables handling of ISSI serial NAND flash devices.
FS_NAND_SPI_DeviceListMacronix Enables handling of Macronix serial NAND flash devices.
FS_NAND_SPI_DeviceListMicron Enables handling of Micron serial NAND flash devices.
FS_NAND_SPI_DeviceListToshiba Enables handling of Kioxia/Toshiba serial NAND flash devices.
FS_NAND_SPI_DeviceListWinbond Enables handling of Winbond serial NAND flash devices.
FS_NAND_SPI_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_SPI.

Prototype

void FS_NAND_SPI_SetHWType(      U8                    Unit,
                           const FS_NAND_HW_TYPE_SPI * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_SPI.

8/16-bit data bus physical layer

This physical layer supports all the NAND flash devices supported by the following NAND physical layers:

Compile time configuration

The 16/8-bit data bus physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_SUPPORT_AUTO_DETECTION 1 B Specifies if the parameters of the NAND flash device have to be automatically detected or not.
FS_NAND_SUPPORT_AUTO_DETECTION

By default, the 8-bit data bus physical layer tries to automatically detect the parameters of the NAND flash device such as the number of blocks and the number of pages in the block by evaluating the value returned as response to the READ ID (0x90) command. This behavior can be disabled by building the physical layer with FS_NAND_SUPPORT_AUTO_DETECTION set to 0. In this case, the application must call FS_NAND_x_Configure() in FS_X_AddDevices() to specify the parameters of the NAND flash device.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the 16/8-bit data bus physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_x_Configure() Configures the parameters of the NAND flash device for a NAND physical layer of type FS_NAND_PHY_x.
FS_NAND_x_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_x.
FS_NAND_x_Configure()

Description

Configures the parameters of the NAND flash device for a NAND physical layer of type FS_NAND_PHY_x.

Prototype

void FS_NAND_x_Configure(U8       Unit,
                         unsigned NumBlocks,
                         unsigned PagesPerBlock,
                         unsigned BytesPerPage,
                         unsigned BytesPerSpareArea,
                         unsigned DataBusWidth);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
NumBlocks Total number of blocks in the NAND flash device.
PagesPerBlock Total number of pages in a NAND block.
BytesPerPage Number of bytes in a page without the spare area.
BytesPerSpareArea Number of bytes in the spare area of a NAND page.
DataBusWidth Number of data lines used for data exchange.

Additional information

This function is mandatory only when the file system is built with FS_NAND_SUPPORT_AUTO_DETECTION set to 0 which is not the default. FS_NAND_x_Configure() has to be called once in FS_X_AddDevices() for each instance of the FS_NAND_PHY_x physical layer. FS_NAND_x_Configure() is not available if FS_NAND_SUPPORT_AUTO_DETECTION is set to 0.

By default, the FS_NAND_PHY_x physical layer identifies the parameters of the NAND flash device by evaluating the first and second byte of the reply returned by the NAND flash device to the READ ID (0x90) command. The identification operation is disabled if FS_NAND_SUPPORT_AUTO_DETECTION set to 0 and the application must specify the NAND flash parameters via this function.

FS_NAND_x_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_x.

Prototype

void FS_NAND_x_SetHWType(      U8                Unit,
                         const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory and has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_x.

8-bit data bus physical layer

This physical layer supports all the NAND flash devices supported by the following NAND physical layers:

Compile time configuration

The 8-bit data bus physical layer can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The following table provides a summary of the configuration defines supported by this physical layer.

Define Default value Type Description
FS_NAND_SUPPORT_AUTO_DETECTION 1 B Specifies if the parameters of the NAND flash device have to be automatically detected or not.
FS_NAND_SUPPORT_AUTO_DETECTION

By default, the 8-bit data bus physical layer tries to automatically detect the parameters of the NAND flash device such as the number of blocks and the number of pages in the block by evaluating the value returned as response to the READ ID (0x90) command. This behavior can be disabled by building the physical layer with FS_NAND_SUPPORT_AUTO_DETECTION set to 0. In this case, the application must call FS_NAND_x8_Configure() in FS_X_AddDevices() to specify the parameters of the NAND flash device.

Runtime configuration

The API functions listed in the following table can be used by the application to configure the behavior of the 8-bit data bus physical layer. The application can call them only at the file system initialization in FS_X_AddDevices().

Function Description
FS_NAND_x8_Configure() Configures the parameters of the NAND flash device for a NAND physical layer of type FS_NAND_PHY_x8.
FS_NAND_x8_SetHWType() Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_x8.
FS_NAND_x8_Configure()

Description

Configures the parameters of the NAND flash device for a NAND physical layer of type FS_NAND_PHY_x8.

Prototype

void FS_NAND_x8_Configure(U8       Unit,
                          unsigned NumBlocks,
                          unsigned PagesPerBlock,
                          unsigned BytesPerPage,
                          unsigned BytesPerSpareArea);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
NumBlocks Total number of blocks in the NAND flash device.
PagesPerBlock Total number of pages in a NAND block.
BytesPerPage Number of bytes in a page without the spare area.
BytesPerSpareArea Number of bytes in the spare area of a NAND page.

Additional information

This function is mandatory only when the file system is built with FS_NAND_SUPPORT_AUTO_DETECTION set to 0 which is not the default. FS_NAND_x_Configure() has to be called once in FS_X_AddDevices() for each instance of the FS_NAND_PHY_x8 physical layer. FS_NAND_x_Configure() is not available if FS_NAND_SUPPORT_AUTO_DETECTION is set to 0.

By default, the FS_NAND_PHY_x8 physical layer identifies the parameters of the NAND flash device by evaluating the first and second byte of the reply returned by the NAND flash device to the READ ID (0x90) command. The identification operation is disabled if FS_NAND_SUPPORT_AUTO_DETECTION set to 0 and the application must specify the NAND flash parameters via this function.

FS_NAND_x8_SetHWType()

Description

Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_x8.

Prototype

void FS_NAND_x8_SetHWType(      U8                Unit,
                          const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function has to be called once in FS_X_AddDevices() for every instance of a NAND physical layer of type FS_NAND_PHY_x8.

Physical layer API

The physical layers that come with emFile provide support most of the popular NAND flash device and target MCU types. Therefore, there is no need to modify any of the provided NAND physical layers. Typically, only the NAND hardware layer has to be adapted to a specific target hardware. However, when none of the provided NAND physical layers are compatible with the target hardware a new NAND physical layer implementation is required. This section provides information about the API of the NAND physical layer that helps to create a new physical layer from scratch or to modify an existing one.

The API of the physical layer is implemented as a structure of type FS_NAND_PHY_TYPE that contains pointers to functions. The following sections describe these functions in detail together with the data structure passed to these functions as parameters.

FS_NAND_PHY_TYPE

Description

NAND physical layer API.

Type definition

typedef struct {
  FS_NAND_PHY_TYPE_ERASE_BLOCK          * pfEraseBlock;
  FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO * pfInitGetDeviceInfo;
  FS_NAND_PHY_TYPE_IS_WP                * pfIsWP;
  FS_NAND_PHY_TYPE_READ                 * pfRead;
  FS_NAND_PHY_TYPE_READ_EX              * pfReadEx;
  FS_NAND_PHY_TYPE_WRITE                * pfWrite;
  FS_NAND_PHY_TYPE_WRITE_EX             * pfWriteEx;
  FS_NAND_PHY_TYPE_ENABLE_ECC           * pfEnableECC;
  FS_NAND_PHY_TYPE_DISABLE_ECC          * pfDisableECC;
  FS_NAND_PHY_TYPE_CONFIGURE_ECC        * pfConfigureECC;
  FS_NAND_PHY_TYPE_COPY_PAGE            * pfCopyPage;
  FS_NAND_PHY_TYPE_GET_ECC_RESULT       * pfGetECCResult;
  FS_NAND_PHY_TYPE_DEINIT               * pfDeInit;
  FS_NAND_PHY_TYPE_SET_RAW_MODE         * pfSetRawMode;
} FS_NAND_PHY_TYPE;

Structure members

Member Description
pfEraseBlock Erases a NAND block.
pfInitGetDeviceInfo Initializes the physical layer.
pfIsWP Checks the write protection status of NAND flash device.
pfRead Reads data from a NAND page.
pfReadEx Reads data from a NAND page.
pfWrite Writes data to a NAND page.
pfWriteEx Writes data to a NAND page.
pfEnableECC Enables the hardware ECC.
pfDisableECC Disables the hardware ECC.
pfConfigureECC Configures the hardware ECC.
pfCopyPage Copies a NAND page.
pfGetECCResult Returns the result of bit correction via ECC.
pfDeInit Frees allocated resources.
pfSetRawMode Enables or disables the raw operation mode.
FS_NAND_PHY_TYPE_ERASE_BLOCK

Description

Erases a NAND block.

Type definition

typedef int FS_NAND_PHY_TYPE_ERASE_BLOCK(U8  Unit,
                                         U32 PageIndex);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
PageIndex Index of the first page in the NAND block to be erased (0-based)

Return value

= 0 OK, the NAND block has been erased.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It is mandatory to be implemented by all the NAND physical layers. It is called by the NAND driver to set to 1 all the bits of a NAND block. A NAND block is the smallest erasable unit of a NAND flash device.

The index of the actual NAND block to be erased depends on the number of pages stored in a NAND block. For example if the NAND block contains 64 pages, then the PageIndex parameter passed by the NAND driver to the function has to be be interpreted as follows:

FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO

Description

Initializes the physical layer.

Type definition

typedef int FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO(U8                    Unit,
                                                  FS_NAND_DEVICE_INFO * pDevInfo);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
pDevInfo  out  Information about the NAND flash device.

Return value

= 0 OK, physical layer has been initialized.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It is mandatory to be implemented by all the NAND physical layers. It is the first function of the physical layer API that is called by the NAND driver when the NAND flash device is mounted.

This function initializes hardware layer, resets and tries to identify the NAND flash device. If the NAND flash device can be handled, the pDevInfo is filled with information about the organization and the ECC requirements of the NAND flash device.

FS_NAND_PHY_TYPE_IS_WP

Description

Checks if the NAND flash device is write protected.

Type definition

typedef int FS_NAND_PHY_TYPE_IS_WP(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)

Return value

= 0 Data stored on the NAND flash device can be modified.
≠ 0 Data stored on the NAND flash device cannot be modified.

Additional information

This function is a member of the NAND physical layer API. It is mandatory to be implemented by all the NAND physical layers.

The write protection status is checked by evaluating the bit 7 of the NAND status register. Typical reason for write protection is that either the supply voltage is too low or the /WP-pin is connected to ground.

FS_NAND_PHY_TYPE_READ

Description

Reads data from a NAND page.

Type definition

typedef int FS_NAND_PHY_TYPE_READ(U8       Unit,
                                  U32      PageIndex,
                                  void   * pData,
                                  unsigned Off,
                                  unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
PageIndex Index of the NAND page to read from (0-based).
pData  out  Data read from NAND page.
Off Byte offset to read from.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by all the NAND physical layers. The NAND driver uses FS_NAND_PHY_TYPE_READ to read data from the main as well as from the spare area of a page.

FS_NAND_PHY_TYPE_READ_EX

Description

Reads data from two different locations of a NAND page.

Type definition

typedef int FS_NAND_PHY_TYPE_READ_EX(U8       Unit,
                                     U32      PageIndex,
                                     void   * pData0,
                                     unsigned Off0,
                                     unsigned NumBytes0,
                                     void   * pData1,
                                     unsigned Off1,
                                     unsigned NumBytes1);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
PageIndex Index of the NAND page to read from (0-based).
pData0  out  Data read from Off0 of the NAND page.
Off0 Byte offset to read from for pData0.
NumBytes0 Number of bytes to be read.
pData1  out  Data read from Off1 of a NAND page.
Off1 Byte offset to read from for pData1.
NumBytes1 Number of bytes to be read from Off1.

Return value

= 0 OK, data read.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by all the NAND physical layers. FS_NAND_PHY_TYPE_READ_EX is typically used by the NAND driver to read the data from main and spare area of a page at the same time.

It is guaranteed that Off0 is always smaller than Off1 and that the region defined by Off0 and NumBytes0 does not overlap the region defined by Off1 and NumBytes1

FS_NAND_PHY_TYPE_WRITE

Description

Writes data to a NAND page.

Type definition

typedef int FS_NAND_PHY_TYPE_WRITE(      U8       Unit,
                                         U32      PageIndex,
                                   const void   * pData,
                                         unsigned Off,
                                         unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
PageIndex Index of the NAND page to write to (0-based).
pData  in  Data to be written to the NAND page.
Off Byte offset to write to.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented only by a NAND physical layer that works with the SLC1 NAND driver. The Universal NAND driver does not call this function. FS_NAND_PHY_TYPE_WRITE is used by the SLC1 NAND driver to write data to the main as well as to the spare area of a page.

FS_NAND_PHY_TYPE_WRITE_EX

Description

Writes data to two different locations of a NAND page.

Type definition

typedef int FS_NAND_PHY_TYPE_WRITE_EX(      U8       Unit,
                                            U32      PageIndex,
                                      const void   * pData0,
                                            unsigned Off0,
                                            unsigned NumBytes0,
                                      const void   * pData1,
                                            unsigned Off1,
                                            unsigned NumBytes1);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
PageIndex Index of the NAND page to write to (0-based).
pData0  in  Data to be written to the NAND page at Off0.
Off0 Byte offset to write to for pData0.
NumBytes0 Number of bytes to be written at Off0.
pData1  in  Data to be written to the NAND page at Off1.
Off1 Byte offset to write to for pData1.
NumBytes1 Number of bytes to be written at Off1.

Return value

= 0 OK, data written.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by all the NAND physical layers. The NAND driver uses FS_NAND_PHY_TYPE_WRITE_EX to write data to the main and spare area of a page at the same time.

It is guaranteed that Off0 is always smaller than Off1 and that the region defined by Off0 and NumBytes0 does not overlap the region defined by Off1 and NumBytes1

FS_NAND_PHY_TYPE_ENABLE_ECC

Description

Enables the hardware ECC.

Type definition

typedef int FS_NAND_PHY_TYPE_ENABLE_ECC(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)

Return value

= 0 OK, hardware ECC activated.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by the NAND physical layers that provide hardware support for bit error correction either on MCU via a dedicated NAND flash controller or via on-die ECC of the NAND flash device. FS_NAND_PHY_TYPE_ENABLE_ECC is called only by the Universal NAND driver.

After the call to this function the Universal NAND driver expects that FS_NAND_PHY_TYPE_READ and FS_NAND_PHY_TYPE_READ_EX return corrected data that is without bit errors. In addition, the Universal NAND driver expects that FS_NAND_PHY_TYPE_WRITE and FS_NAND_PHY_TYPE_WRITE_EX calculate and store the ECC to NAND flash device.

FS_NAND_PHY_TYPE_DISABLE_ECC

Description

Deactivates the hardware ECC.

Type definition

typedef int FS_NAND_PHY_TYPE_DISABLE_ECC(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)

Return value

= 0 OK, hardware ECC deactivated.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by the NAND physical layers that provide hardware support for bit error correction. FS_NAND_PHY_TYPE_DISABLE_ECC is called only by the Universal NAND driver.

After the call to this function the Universal NAND driver expects that FS_NAND_PHY_TYPE_READ and FS_NAND_PHY_TYPE_READ_EX return data that might contain bit errors. In addition, the Universal NADN driver expects that FS_NAND_PHY_TYPE_WRITE and FS_NAND_PHY_TYPE_WRITE_EX store the data without calculating the ECC.

FS_NAND_PHY_TYPE_CONFIGURE_ECC

Description

Configures the hardware ECC.

Type definition

typedef int FS_NAND_PHY_TYPE_CONFIGURE_ECC(U8  Unit,
                                           U8  NumBitsCorrectable,
                                           U16 BytesPerECCBlock);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
NumBitsCorrectable Maximum number of bit errors the hardware ECC has to be able to correct.
BytesPerECCBlock Number of consecutive data bytes protected by a single ECC.

Return value

= 0 OK, hardware ECC configured.
≠ 0 An error occurred.

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by the NAND physical layers that provide hardware support for bit error correction with configurable ECC strength. FS_NAND_PHY_TYPE_CONFIGURE_ECC is called only by the Universal NAND driver.

FS_NAND_PHY_TYPE_COPY_PAGE

Description

Copies the contents of an entire page to another page.

Type definition

typedef int FS_NAND_PHY_TYPE_COPY_PAGE(U8  Unit,
                                       U32 PageIndexSrc,
                                       U32 PageIndexDest);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
PageIndexSrc Index of the page to copy from.
PageIndexDest Index of the page to copy to.

Return value

= 0 OK, page copied.
≠ 0 An error occurred or operation not supported.

Additional information

This function is a member of the NAND physical layer API. It may be be implemented by the NAND physical layers that can provide a faster method of copying the contents of a page than by first reading the source page contents to MCU and then by writing the contents to the destination page. One such method is the internal page copy operation supported by some NAND flash device. FS_NAND_PHY_TYPE_COPY_PAGE is called only by the Universal NAND driver.

FS_NAND_PHY_TYPE_GET_ECC_RESULT

Description

Returns the error correction status of the last read page.

Type definition

typedef int FS_NAND_PHY_TYPE_GET_ECC_RESULT(U8                   Unit,
                                            FS_NAND_ECC_RESULT * pResult);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
pResult  out  Information about the correction status.

Return value

= 0 OK, information returned.
≠ 0 An error occurred or operation not supported.

Additional information

This function is a member of the NAND physical layer API. It may be implemented by the NAND physical layers that can provide information about the status of the bit correction operation and about the number of bit errors corrected. FS_NAND_PHY_TYPE_GET_ECC_RESULT is called only by the Universal NAND driver.

The information returned by FS_NAND_PHY_TYPE_GET_ECC_RESULT is used by the Universal NAND driver to decide when a NAND block has to be relocated in order to prevent bit correction errors. A bit correction error occurs when the number of bit errors is greater than the number of bit errors the ECC is able to correct. Typically, a bit correction error causes a data loss.

FS_NAND_PHY_TYPE_DEINIT

Description

Releases the allocated resources.

Type definition

typedef void FS_NAND_PHY_TYPE_DEINIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)

Additional information

This function is a member of the NAND physical layer API. It has to be implemented by the NAND physical layers that allocate resources dynamically during the initialization such as memory for the instance.

The NAND driver calls this function when the file system is unmounted.

FS_NAND_PHY_TYPE_SET_RAW_MODE

Description

Enables or disables the data translation.

Type definition

typedef int FS_NAND_PHY_TYPE_SET_RAW_MODE(U8 Unit,
                                          U8 OnOff);

Parameters

Parameter Description
Unit Index of the NAND physical layer instance (0-based)
OnOff Activation status of the feature.

Return value

= 0 OK, status changed.
≠ 0 An error occurred or operation not supported.

Additional information

This function is a member of the NAND physical layer API. It may be implemented by the NAND physical layers that store the data to NAND flash device using a different layout than the NAND driver. FS_NAND_PHY_TYPE_SET_RAW_MODE is not called by the NAND driver during the normal operation. It is called only by specific functions of the Universal NAND driver such as FS_NAND_UNI_WritePageRaw() and FS_NAND_UNI_ReadPageRaw().

FS_NAND_DEVICE_INFO

Description

Information about the NAND flash device.

Type definition

typedef struct {
  U8                BPP_Shift;
  U8                PPB_Shift;
  U16               NumBlocks;
  U16               BytesPerSpareArea;
  FS_NAND_ECC_INFO  ECC_Info;
  U8                DataBusWidth;
  U8                BadBlockMarkingType;
  U8                PPO_Shift;
} FS_NAND_DEVICE_INFO;

Structure members

Member Description
BPP_Shift Bytes per page as a power of two value.
PPB_Shift Pages per block as a power of two value.
NumBlocks Total number of blocks in the NAND flash device.
BytesPerSpareArea Number of bytes in the spare area.
ECC_Info Information about the ECC capability required by the NAND flash device.
DataBusWidth Number of lines used for exchanging the data with the NAND flash device.
BadBlockMarkingType Specifies how the blocks are marked as defective.
PPO_Shift Number of operations performed in parallel by the NAND physical layer.

Additional information

The initialization function of the physical layer FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO uses this structure to return information about the NAND flash device to the NAND driver.

Typical values for BPP_Shift are 9 and 11 for NAND flash devices with a page size (without the spare area) of 512 and 2048 bytes respectively.

BytesPerSpareArea is typically 1/32 of the page size (2^BPP_Shift) but some NAND flash devices have a spare area larger than this. For example Micron MT29F8G08ABABA has a spare area of 224 bytes for a page size of 4096 bytes.

DataBusWith can take the following values:

Refer to Bad block marking types for a list of permitted values for BadBlockMarkingType.

PPO_Shift (Planes Per Operation) has to be specified as a power of two value. Most of the NAND physical layers set this value to 0 to indicate that they do not support parallel operations. FS_NAND_PHY_2048x8_TwoPlane sets this value to 1 because it can read and write two NAND pages at once and it can erase two NAND blocks at once. This information is used by the Universal NAND driver to correctly identify and mark defective blocks.

FS_NAND_ECC_INFO

Description

Information about the ECC used to protect data stored on the NAND flash.

Type definition

typedef struct {
  U8  NumBitsCorrectable;
  U8  ldBytesPerBlock;
  U8  HasHW_ECC;
  U8  IsHW_ECCEnabledPerm;
} FS_NAND_ECC_INFO;

Structure members

Member Description
NumBitsCorrectable Maximum number of bit errors the ECC should be able to correct.
ldBytesPerBlock Number of bytes the ECC should protect as power of 2 exponent.
HasHW_ECC Set to 1 if the NAND flash device has internal HW ECC.
IsHW_ECCEnabledPerm Set to 1 if the internal HW ECC of the NAND flash device cannot be disabled.

Additional information

The value of IsHW_ECCEnabledPerm is valid only if the value of HasHW_ECC is different than 0.

ldBytesPerBlock is a power of 2 value. If HasHW_ECC is different than 0 ldBytesPerBlock represents the number of bytes in the main and spare area of a NAND page the internal HW ECC is able to protect against bit errors. More than one ECC is used to protect the data in a NAND page if the size of the NAND page is larger than ldBytesPerBlock. ldBytesPerBlock can never be larger than the size of a NAND page.

If HasHW_ECC is different than 0 than NumBitsCorrectable represents the maximum number of bit errors the internal HW ECC is able to correct.

FS_NAND_ECC_RESULT

Description

Information about the ECC number of bits corrected in an ECC block.

Type definition

typedef struct {
  U8  CorrectionStatus;
  U8  MaxNumBitsCorrected;
} FS_NAND_ECC_RESULT;

Structure members

Member Description
CorrectionStatus Indicates if the correction succeeded or failed.
MaxNumBitsCorrected Maximum number of bit errors detected and corrected in any ECC block of a page.

Additional information

This structure is filled by the FS_NAND_PHY_TYPE_GET_ECC_RESULT function of the NAND physical layer to return the result of the bit error correction operation.

Refer to ECC correction status for a list of permitted values for CorrectionStatus.

An ECC block is the number of bytes protected by a single ECC. Typically, the ECC block is 512 bytes large, therefor the number of ECC blocks in a 2 KByte page is 4. Most of the NAND flash devices report the number of bits corrected in each of the ECC blocks. The value stored to MaxNumBitsCorrected must be the maximum of these values.

Additional physical layer functions

The following functions are optional. They can be called to get information about the NAND flash device and to control additional functionality of physical layers.

FunctionDescription
FS_NAND_PHY_ReadDeviceId() Returns the id information stored in a NAND flash device.
FS_NAND_PHY_ReadONFIPara() Reads the ONFI parameters from a NAND flash.
FS_NAND_PHY_SetHWType() Configures the hardware access routines for FS_NAND_PHY_ReadDeviceId() and FS_NAND_PHY_ReadONFIPara().
FS_NAND_PHY_ReadDeviceId()

Description

Returns the id information stored in a NAND flash device.

Prototype

int FS_NAND_PHY_ReadDeviceId(U8    Unit,
                             U8  * pId,
                             U32   NumBytes);

Parameters

Parameter Description
Unit Index of HW layer connected to NAND flash.
pId  out  Identification data read from NAND flash.
NumBytes Number of bytes to read.

Return value

= 0 OK, id information read.
≠ 0 An error occurred.

Additional information

FS_NAND_PHY_ReadDeviceId() executes the READ ID command to read the id information from the NAND flash device. NumBytes specifies the number of bytes to be read. Refer to the data sheet of the NAND flash device for additional information about the meaning of the data returned by the NAND flash device. Typically, the first byte stores the manufactured id while the second byte provides information about the organization of the NAND flash device.

It is permitted to call FS_NAND_PHY_ReadONFIPara()from FS_X_AddDevices() since it does not require for the file system to be fully initialized and it invokes only functions of the NAND hardware layer. No instance of NAND driver is required to invoke this function.

Typical usage is to determine at runtime the type of NAND driver to be used for the connected NAND flash device.

Example

The following example shows how an application can select at runtime a different NAND drivers based on the type of the used NAND flash.

#include "FS.h"

#define ALLOC_SIZE            0x4000    // Memory pool for the file system in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*/
void FS_X_AddDevices(void) {
  U8 Id;

  FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
  //
  // Read the first byte of the identification array.
  // This byte stores the manufacturer type.
  //
  FS_NAND_PHY_SetHWType(0, &FS_NAND_HW_Default);
  FS_NAND_PHY_ReadDeviceId(0, &Id, sizeof(Id));
  if (Id == 0xEC) {
    //
    // Found a Samsung NAND flash. Use the SLC1 NAND driver.
    // ECC is performed by the NAND driver
    //
    FS_AddDevice(&FS_NAND_Driver);
    FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
    FS_NAND_2048x8_SetHWType(0, &FS_NAND_HW_Default);
  } else if (Id == 0x2C) {
    //
    // Found a Micron NAND flash. Use the Universal NAND driver.
    // The ECC is performed by the NAND flash.
    //
    FS_AddDevice(&FS_NAND_UNI_Driver);
    FS_NAND_UNI_SetPhyType(0, &FS_NAND_PHY_ONFI);
    FS_NAND_UNI_SetECCHook(0, &FS_NAND_ECC_HW_NULL);
    FS_NAND_ONFI_SetHWType(0, &FS_NAND_HW_Default);
  } else {
    //
    // NAND flash from another manufacturer, use auto-identification.
    //
    FS_AddDevice(&FS_NAND_Driver);
    FS_NAND_SetPhyType(0, &FS_NAND_PHY_x8);
    FS_NAND_x8_SetHWType(0, &FS_NAND_HW_Default);
  }
}
FS_NAND_PHY_ReadONFIPara()

Description

Reads the ONFI parameters from a NAND flash.

Prototype

int FS_NAND_PHY_ReadONFIPara(U8     Unit,
                             void * pPara);

Parameters

Parameter Description
Unit Index of HW layer connected to NAND flash.
pPara  out  Data of ONFI parameter page read from NAND flash. This parameter can be set to NULL.

Return value

= 0 ONFI parameters read.
≠ 0 ONFI is not supported by the NAND flash.

Additional information

Refer to the data sheet of the NAND flash device for a description of the data layout of the returned ONFI parameters.

This function can be used to read the ONFI parameter stored in a NAND flash. It is permitted to call FS_NAND_PHY_ReadONFIPara()from FS_X_AddDevices() since it does not require for the file system to be fully initialized and it invokes only functions of the NAND hardware layer. No instance of NAND driver is required to invoke this function.

FS_NAND_PHY_ReadONFIPara() can also be used to check if the NAND flash device is ONFI compliant by setting pPara to NULL.

The size of the buffer passed via pParam must be at least 256 bytes large.

Example

This example demonstrates how an application can configure at runtime different NAND driver based on the type of the NAND flash.

#include "FS.h"

#define ALLOC_SIZE            0x4000    // Memory pool for the file system in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*/
void FS_X_AddDevices(void) {
  int r;

  FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
  //
  // Check whether the NAND flash supports ONFI.
  //
  FS_NAND_PHY_SetHWType(0, &FS_NAND_HW_Default);
  r = FS_NAND_PHY_ReadONFIPara(0, NULL);
  if (r != 0) {
    //
    // Found a NAND flash which does not support ONFI.
    //
    FS_AddDevice(&FS_NAND_Driver);
    FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
  } else {
    //
    // Found a NAND flash which supports ONFI.
    //
    FS_AddDevice(&FS_NAND_UNI_Driver);
    FS_NAND_UNI_SetPhyType(0, &FS_NAND_PHY_ONFI);
    FS_NAND_UNI_SetECCHook(0, &FS_NAND_ECC_HW_NULL);
  }
}
FS_NAND_PHY_SetHWType()

Description

Configures the hardware access routines for FS_NAND_PHY_ReadDeviceId() and FS_NAND_PHY_ReadONFIPara().

Prototype

void FS_NAND_PHY_SetHWType(      U8                Unit,
                           const FS_NAND_HW_TYPE * pHWType);

Parameters

Parameter Description
Unit Index of the physical layer instance (0-based)
pHWType Type of the hardware layer to use. Cannot be NULL.

Additional information

This function is mandatory if the application calls either FS_NAND_PHY_ReadDeviceId() or FS_NAND_PHY_ReadONFIPara(). FS_NAND_PHY_SetHWType() has to be called once in FS_X_AddDevices() for every different Unit number passed to FS_NAND_PHY_ReadDeviceId() or FS_NAND_PHY_ReadONFIPara().

Resource usage

This section describes the ROM and RAM usage of the NAND physical layers.

ROM usage

The ROM usage depends on the compiler options, the compiler version, and the used CPU. The memory requirements of the NAND physical layers were measured as described in the section Test procedure. The following table lists the ROM usage of all the available NOR physical layers.

Name ROM usage(Kbytes)
512x8 1.3
2048x8 1.6
Two plane 2048x8 1.4
Small 2048x8 1.4
2048x16 1.2
4096x8 1.1
DataFlash 1.7
ONFI 3.8
Read-only ONFI 3.5
Small ONFI 3.6
QSPI 5.2
SPI 5.2
8/16-bit data bus 9.4
8-bit data bus 8.2
Static RAM usage

Static RAM usage is the amount of RAM required by the driver for static variables inside the driver. The number of bytes can be seen in a compiler list file. The next table lists the static RAM usage of all the available NOR physical layers.

Name RAM usage(bytes)
512x8 20
2048x8 16
Two plane 2048x8 16
Small 2048x8 16
2048x16 16
4096x8 16
DataFlash 64
ONFI 16
Read-only ONFI 16
Small ONFI 16
QSPI 16
SPI 16
8/16-bit data bus 16
8-bit data bus 16
Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the physical layer at runtime. The amount of RAM required depends on the compile time and runtime configuration. The following table lists the the dynamic RAM usage of the available NOR physical layers.

Name RAM usage(bytes)
512x8 0
2048x8 24
Two plane 2048x8 24
Small 2048x8 24
2048x16 0
4096x8 0
DataFlash 0
ONFI 28
Read-only ONFI 28
Small ONFI 28
QSPI 44
SPI 44
8/16-bit data bus 8
8-bit data bus 8

NAND hardware layer

General information

The NAND hardware layer provides functionality for accessing a NAND flash device via the target hardware such as external memory controller, GPIO, SPI, etc. The functions of the NAND hardware layer are called by the NAND physical layer to exchange commands and data with a NAND flash device. Since these functions are hardware dependent, they have to be implemented by the user. emFile comes with template hardware layers and sample implementations for popular evaluation boards that can be used as starting point for implementing new hardware layers. The relevant files are located in the /Sample/FS/Driver/NAND folder of the emFile shipment.

Hardware layer types

The functions of the NAND hardware layer are organized in a function table implemented a C structure. Different hardware layer types are provided to support different ways of interfacing a NAND flash device. The type of hardware layer an application has to use depends on the type NAND physical layer configured. The following table shows what hardware layer is required by each physical layer.

NAND hardware layer NAND physical layer
FS_NAND_HW_TYPE FS_NAND_PHY_512x8 FS_NAND_PHY_2048x8 FS_NAND_PHY_2048x16 FS_NAND_PHY_4096x8 FS_NAND_PHY_x FS_NAND_PHY_x8 FS_NAND_PHY_ONFI
FS_NAND_HW_TYPE_DF FS_NAND_PHY_DataFlash
FS_NAND_HW_TYPE_QSPI FS_NAND_PHY_QSPI
FS_NAND_HW_TYPE_SPI FS_NAND_PHY_SPI
Hardware layer API - FS_NAND_HW_TYPE

This NAND hardware layer supports NAND flash devices that can be accessed via an 8- or 16-bit data bus. The functions of this hardware layer are grouped in a structure of type FS_NAND_HW_TYPE. The following sections describe these functions in detail.

FS_NAND_HW_TYPE

Description

NAND hardware layer API for NAND flash devices connected via parallel I/O.

Type definition

typedef struct {
  FS_NAND_HW_TYPE_INIT_X8         * pfInit_x8;
  FS_NAND_HW_TYPE_INIT_X16        * pfInit_x16;
  FS_NAND_HW_TYPE_DISABLE_CE      * pfDisableCE;
  FS_NAND_HW_TYPE_ENABLE_CE       * pfEnableCE;
  FS_NAND_HW_TYPE_SET_ADDR_MODE   * pfSetAddrMode;
  FS_NAND_HW_TYPE_SET_CMD_MODE    * pfSetCmdMode;
  FS_NAND_HW_TYPE_SET_DATA_MODE   * pfSetDataMode;
  FS_NAND_HW_TYPE_WAIT_WHILE_BUSY * pfWaitWhileBusy;
  FS_NAND_HW_TYPE_READ_X8         * pfRead_x8;
  FS_NAND_HW_TYPE_WRITE_X8        * pfWrite_x8;
  FS_NAND_HW_TYPE_READ_X16        * pfRead_x16;
  FS_NAND_HW_TYPE_WRITE_X16       * pfWrite_x16;
} FS_NAND_HW_TYPE;

Structure members

Member Description
pfInit_x8 Initializes a NAND flash device with an 8-bit data interface.
pfInit_x16 Initializes a NAND flash device with a 16-bit data interface.
pfDisableCE Disables the NAND flash device.
pfEnableCE Enables the NAND flash device.
pfSetAddrMode Initiates the transfer of an address.
pfSetCmdMode Initiates the transfer of a command.
pfSetDataMode Initiates the transfer of data.
pfWaitWhileBusy Waits for the NAND flash device to become ready.
pfRead_x8 Reads a specified number of bytes from NAND flash device via the 8-bit data interface.
pfWrite_x8 Writes a specified number of bytes to NAND flash device via the 8-bit data interface.
pfRead_x16 Reads a specified number of bytes from NAND flash device via the 16-bit data interface.
pfWrite_x16 Writes a specified number of bytes to NAND flash device via the 16-bit data interface.
FS_NAND_HW_TYPE_INIT_X8

Description

Initializes the hardware for 8-bit mode access.

Type definition

typedef void FS_NAND_HW_TYPE_INIT_X8(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It has to be implemented by a NAND hardware layer that accesses a NAND flash device via an 8-bit data bus. FS_NAND_HW_TYPE_INIT_X8 is the first function of the hardware layer API that is called by a NAND physical layer during the mounting of the file system.

This function has to perform any initialization of the MCU hardware required to access the NAND flash device such as clocks, port pins, memory controllers, etc.

FS_NAND_HW_TYPE_INIT_X16

Description

Initializes the hardware for 16-bit mode access.

Type definition

typedef void FS_NAND_HW_TYPE_INIT_X16(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. The implementation of this function is optional for systems that interface to the NAND flash device via an 8-bit data bus. FS_NAND_HW_TYPE_INIT_X16 must be implemented for systems that have the NAND flash device connected to MCU via an 16-bit data bus.

FS_NAND_HW_TYPE_INIT_X16 is the first function of the hardware layer API that is called by the NAND physical layer when the NAND flash device is mounted.

FS_NAND_HW_TYPE_DISABLE_CE

Description

Disables the NAND flash device.

Type definition

typedef void FS_NAND_HW_TYPE_DISABLE_CE(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API and it is mandatory to be implemented. The implementation of this function can be left empty if the hardware is driving the Chip Enable (CE) signal. Typically, the NAND flash device is disabled by driving the CE signal to a logic low state level.

FS_NAND_HW_TYPE_ENABLE_CE

Description

Enables the NAND flash device.

Type definition

typedef void FS_NAND_HW_TYPE_ENABLE_CE(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It is mandatory to be implemented by all NAND hardware layers. The implementation of this function can be left empty if the hardware is driving the Chip Enable (CE) signal. Typically, the NAND flash device is enabled by driving the CE signal to a logic-high level.

FS_NAND_HW_TYPE_SET_ADDR_MODE

Description

Changes the data access to address mode.

Type definition

typedef void FS_NAND_HW_TYPE_SET_ADDR_MODE(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It is mandatory to be implemented by all NAND hardware layers.

After the call to this function the NAND hardware layer has to make sure that any data sent to NAND flash device is interpreted as address information. This can be achieved by setting the Address Latch Enable signal (ALE) signal to logic-high and the Command Latch Enable (CLE) signal to logic low state.

FS_NAND_HW_TYPE_SET_CMD_MODE

Description

Changes the data access to command mode.

Type definition

typedef void FS_NAND_HW_TYPE_SET_CMD_MODE(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers.

After the call to this function the NAND hardware layer has to make sure that any data sent to NAND flash device is interpreted as command information. This can be achieved by setting the Command Latch Enable (CLE) signal to logic-high and the Address Latch Enable signal (ALE) signal to logic low state.

FS_NAND_HW_TYPE_SET_DATA_MODE

Description

Changes the data access to data mode.

Type definition

typedef void FS_NAND_HW_TYPE_SET_DATA_MODE(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers.

After the call to this function the NAND hardware layer has to make sure that any data sent to NAND flash device is interpreted as data information. This can be achieved by setting the Command Latch Enable (CLE) and Address Latch Enable signals to logic low state.

FS_NAND_HW_TYPE_WAIT_WHILE_BUSY

Description

Waits for the NAND flash device to become ready.

Type definition

typedef int FS_NAND_HW_TYPE_WAIT_WHILE_BUSY(U8       Unit,
                                            unsigned us);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
us Maximum time to wait in microseconds.

Return value

= 0 The NAND flash device is ready.
≠ 0 The NAND flash device is busy or the operation is not supported.

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers.

A NAND hardware layer calls this function every time it checks the status of the NAND flash device. A typical implementation uses the status of the Ready/Busy (R/B) signal that is set to logic low state by the NAND flash device as long as it is busy and it cannot accept and other commands from MCU.

FS_NAND_HW_TYPE_WAIT_WHILE_BUSY must return 1 if the status of the NAND flash device cannot be queried via R/B signal. In this case, the NAND hardware layer checks the status via a read status command.

Typically, a NAND flash device does not set R/B signal to logic low state immediately after it accepts a command from MCU but only after a time interval labeled as tWB in the data sheet of the NAND flash device. This means that FS_NAND_HW_TYPE_WAIT_WHILE_BUSY has to wait for tWB time interval to elapse before it samples the R/B signal for the first time in order to make sure that it returns correct status information to the NAND physical layer.

FS_NAND_HW_TYPE_READ_X8

Description

Reads data from NAND flash device via 8-bit data bus.

Type definition

typedef void FS_NAND_HW_TYPE_READ_X8(U8       Unit,
                                     void   * pData,
                                     unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  out  Data read from NAND flash. It cannot be NULL.
NumBytes Number of bytes to be read. It cannot be 0.

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It has to be implemented by a NAND hardware layer that exchanges the data with the NAND flash device via an 8-bit data bus.

FS_NAND_HW_TYPE_READ_X8 is called by a NAND physical layer in data mode to transfer data from NAND flash device to MCU. It is not called in address and command data access modes.

The transfer of the data is controlled by the MCU using the Read Enable (RE) signal. If the NAND hardware layer exchanges the data via GPIO it has to make sure that the timing of the RE signal meets the specifications of the NAND flash device.

FS_NAND_HW_TYPE_WRITE_X8

Description

Writes data to NAND flash device via 8-bit data bus.

Type definition

typedef void FS_NAND_HW_TYPE_WRITE_X8(      U8       Unit,
                                      const void   * pData,
                                            unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  in  Data to be written to NAND flash. It cannot be NULL.
NumBytes Number of bytes to be read. It cannot be 0.

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It has to be implemented by a NAND hardware layer that exchanges the data with the NAND flash device via an 8-bit data bus.

FS_NAND_HW_TYPE_WRITE_X8 is called by a NAND physical layer in all data access modes to transfer data from MCU to NAND flash device.

The transfer of the data is controlled by the MCU using the Write Enable (WE) signal. If the NAND hardware layer exchanges the data via GPIO it has to make sure that the timing of the WE signal meets the specifications of the NAND flash device.

FS_NAND_HW_TYPE_READ_X16

Description

Reads data from NAND flash device via 16-bit data bus.

Type definition

typedef void FS_NAND_HW_TYPE_READ_X16(U8       Unit,
                                      void   * pData,
                                      unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  out  Data read from NAND flash. It cannot be NULL.
NumBytes Number of bytes to be read. It cannot be 0.

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It has to be implemented by a NAND hardware layer that exchanges the data with the NAND flash device via an 16-bit data bus.

FS_NAND_HW_TYPE_READ_X16 is called by a NAND physical layer in data mode to transfer data from NAND flash device to MCU. It is not called in address and command data access modes.

The transfer of the data is controlled by the MCU using the Read Enable (RE) signal. If the NAND hardware layer exchanges the data via GPIO it has to make sure that the timing of the RE signal meets the specifications of the NAND flash device.

pData is aligned to a half-word (2-byte) boundary.

FS_NAND_HW_TYPE_WRITE_X16

Description

Writes data to NAND flash device via 16-bit data bus.

Type definition

typedef void FS_NAND_HW_TYPE_WRITE_X16(      U8       Unit,
                                       const void   * pdata,
                                             unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  in  Data to be written to NAND flash. It cannot be NULL.
NumBytes Number of bytes to be read. It cannot be 0.

Additional information

This function is a member of the FS_NAND_PHY_TYPE NAND hardware layer API. It has to be implemented by a NAND hardware layer that exchanges the data with the NAND flash device via an 16-bit data bus.

FS_NAND_HW_TYPE_WRITE_X16 is called by a NAND physical layer in all data access modes to transfer data from MCU to NAND flash device.

The transfer of the data is controlled by the MCU using the Write Enable (WE) signal. If the NAND hardware layer exchanges the data via GPIO it has to make sure that the timing of the WE signal meets the specifications of the NAND flash device.

pData is aligned to a half-word (2-byte) boundary.

Sample implementation

The following sample implementation uses the GPIO ports of an NXP K66 MCU to interface with a NAND flash device. This NAND hardware layer was tested on the SGGER emPower board (https://www.segger.com/evaluate-our-software/segger/empower/)

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : FS_NAND_HW_K66_SEGGER_emPower.c
Purpose : NAND flash hardware layer header file for the SEGGER emPower
          V2 evaluation board.
Literature:
  [1] K66 Sub-Family Reference Manual
  [2] emPower Evaluation and prototyping platform for SEGGER software User Guide & Reference Manual
*/

/*********************************************************************
*
*       #include Section
*
**********************************************************************
*/
#include "FS.h"
#include "FS_NAND_HW_K66_SEGGER_emPower.h"
#include "MK66F18.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#ifndef   FS_NAND_HW_USE_OS
  #define FS_NAND_HW_USE_OS       0         // Enables / disables the
                                            // event-driven operation.
                                            //   0 - OS support disabled.
                                            //   1 - OS support enabled
                                            //       using the OS event of emFile.
                                            //   2 - OS support enabled using
                                            //       OS events of this HW layer.
#endif

/*********************************************************************
*
*       #include section, conditional
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
  #include "RTOS.h"
  #include "FS_OS.h"
#endif // FS_NAND_HW_USE_OS

/*********************************************************************
*
*        Defines, fixed
*
**********************************************************************
*/

/*********************************************************************
*
*        Port pins
*/
#define NAND_CS_PIN               0
#define NAND_WAIT_PIN             1
#define NAND_ALE_PIN              4
#define NAND_CLE_PIN              5
#define NAND_nOE_PIN              6
#define NAND_nWE_PIN              7
#define NAND_DATA_MASK            0xff
#define NAND_D0_SHIFT             8
#define NAND_D0_PIN               8
#define NAND_D1_PIN               9
#define NAND_D2_PIN               10
#define NAND_D3_PIN               11
#define NAND_D4_PIN               12
#define NAND_D5_PIN               13
#define NAND_D6_PIN               14
#define NAND_D7_PIN               15

/*********************************************************************
*
*        Macros for pin configuration
*/
#define SET_DATA2INPUT()          GPIOD_PDDR &= ~(NAND_DATA_MASK << NAND_D0_SHIFT)
#define SET_DATA2OUTPUT()         GPIOD_PDDR |=  (NAND_DATA_MASK << NAND_D0_SHIFT)

/*********************************************************************
*
*        Macros for pin control
*/
#define NAND_GET_DATA(Data)       Data = *((volatile U8 *)&GPIOD_PDIR + 0x1);
#define NAND_SET_DATA(Data)       *((volatile U8 *)&GPIOD_PDOR + 0x1) = Data;
#define NAND_SET_ALE()            GPIOD_PSOR = (1 << NAND_ALE_PIN);
#define NAND_CLR_ALE()            GPIOD_PCOR = (1 << NAND_ALE_PIN);
#define NAND_SET_CLE()            GPIOD_PSOR = (1 << NAND_CLE_PIN);
#define NAND_CLR_CLE()            GPIOD_PCOR = (1 << NAND_CLE_PIN);
#define NAND_SET_CE()             GPIOD_PSOR = (1 << NAND_CS_PIN);
#define NAND_CLR_CE()             GPIOD_PCOR = (1 << NAND_CS_PIN);
#define NAND_SET_RE()             GPIOD_PSOR = (1 << NAND_nOE_PIN);
#define NAND_CLR_RE()             GPIOD_PCOR = (1 << NAND_nOE_PIN);
#define NAND_SET_WE()             GPIOD_PSOR = (1 << NAND_nWE_PIN);
#define NAND_CLR_WE()             GPIOD_PCOR = (1 << NAND_nWE_PIN);
#define NAND_GET_BUSY()           (GPIOD_PDIR & (1 << NAND_WAIT_PIN))
#define NAND_NOP()                __asm("nop")

/*********************************************************************
*
*        Misc. defines
*/
#define PORTD_IRQ_PRIO            15
#define WAIT_TIMEOUT_MS           1000      // Maximum time to wait for the NAND
                                            // flash device to become ready.
#define NUM_LOOPS_TWB             17        // Delay for tWB time.

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
#if (FS_NAND_HW_USE_OS == 2)
  static U8         _IsEventInited = 0;
  static OS_EVENT   _Event;
#endif // FS_NAND_HW_USE_OS == 2

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS

/*********************************************************************
*
*       _WaitForEvent
*
*  Function description
*    Waits for the interrupt to wake up the task.
*
*  Parameters
*    TimeOut      Maximum time to wait for the event in milliseconds.
*
*  Return values
*    ==0      OK, event signaled.
*    !=0      An error occurred.
*/
static int _WaitForEvent(U32 TimeOut) {
  int r;

  PORTD_PCR1 |= PORT_PCR_IRQC(0xC);           // Generate an interrupt when the
                                              // the busy signal goes HIGH.
#if (FS_NAND_HW_USE_OS == 2)
  r = OS_EVENT_WaitTimed(&_Event, TimeOut);
#else
  r = FS_OS_Wait(TimeOut);
#endif
  if (r != 0) {
    PORTD_PCR1 &= ~PORT_PCR_IRQC_MASK;        // Disable the interrupt.
    PORTD_PCR1 |=  PORT_PCR_ISF_MASK;
  }
  return r;
}

#endif // FS_NAND_HW_USE_OS

/*********************************************************************
*
*       Static code (public via callback)
*
**********************************************************************
*/

/*********************************************************************
*
*       _HW_EnableCE
*
*  Function description
*    Enables the NAND flash device.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*/
static void _HW_EnableCE(U8 Unit) {
  FS_USE_PARA(Unit);
  NAND_CLR_CE();
}

/*********************************************************************
*
*       _HW_DisableCE
*
*  Function description
*    Disables the NAND flash device.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*/
static void _HW_DisableCE(U8 Unit) {
  FS_USE_PARA(Unit);
  NAND_SET_CE();
}

/*********************************************************************
*
*       _HW_SetDataMode
*
*  Function description
*    Changes the data access to data mode.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*/
static void _HW_SetDataMode(U8 Unit) {
  FS_USE_PARA(Unit);
  //
  // nCE low, CLE low, ALE low
  //
  NAND_CLR_CLE();
  NAND_CLR_ALE();
}

/*********************************************************************
*
*       _HW_SetCmdMode
*
*  Function description
*    Changes the data access to command mode.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*/
static void _HW_SetCmdMode(U8 Unit) {
  FS_USE_PARA(Unit);
  //
  // nCE low, CLE high, ALE low
  //
  NAND_SET_CLE();
  NAND_CLR_ALE();
}

/*********************************************************************
*
*       _HW_SetAddr
*
*  Function description
*    Changes the data access to address mode.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*/
static void _HW_SetAddrMode(U8 Unit) {
  FS_USE_PARA(Unit);
  //
  // nCE low, CLE low, ALE high
  //
  NAND_CLR_CLE();
  NAND_SET_ALE();
}

/*********************************************************************
*
*       _HW_Read_x8
*
*  Function description
*    Reads data from NAND flash device via 8-bit data bus.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*    pData        [OUT] Data read from NAND flash. It cannot be NULL.
*    NumBytes     Number of bytes to be read. It cannot be 0.
*/
static void _HW_Read_x8(U8 Unit, void * p, unsigned NumBytes) {
  U8 * pData;

  FS_USE_PARA(Unit);
  pData = (U8 *)p;
  SET_DATA2INPUT();
  do {
    NAND_CLR_RE();        // Enable RE (active low)
    //
    // Wait for the data to be available (tREA time).
    // Two NOPs should actually be sufficient but
    // it seems that the MCU requires some time to
    // synchronize the contents of the PDIR register
    // of the GPIO port.
    //
    NAND_NOP();
    NAND_NOP();
    NAND_NOP();
    NAND_NOP();
    NAND_NOP();
    NAND_NOP();
    NAND_NOP();
    NAND_NOP();
    NAND_GET_DATA(*pData++);
    NAND_SET_RE();        // Disable RE (active low)
  } while (--NumBytes);
}

/*********************************************************************
*
*       _HW_Write_x8
*
*  Function description
*    Writes data to NAND flash device via 8-bit data bus.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*    pData        [IN] Data to be written to NAND flash. It cannot be NULL.
*    NumBytes     Number of bytes to be read. It cannot be 0.
*/
static void _HW_Write_x8(U8 Unit, const void * p, unsigned NumBytes) {
  const U8 * pData;

  FS_USE_PARA(Unit);
  pData = (const U8 *)p;
  SET_DATA2OUTPUT();
  do {
    NAND_SET_DATA(*pData++);
    NAND_CLR_WE();        // Enable WE (active low)
    NAND_NOP();
    NAND_SET_WE();        // Disable WE (active low)
  } while (--NumBytes);
}

/*********************************************************************
*
*       _HW_Init_x8
*
*  Function description
*    Initializes the hardware for 8-bit mode access.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*/
static void _HW_Init_x8(U8 Unit) {
  FS_USE_PARA(Unit);
#if FS_NAND_HW_USE_OS
  //
  // Disable the interrupt.
  //
  NVIC_DisableIRQ(PORTD_IRQn);
  NVIC_SetPriority(PORTD_IRQn, PORTD_IRQ_PRIO);
#endif // FS_NAND_HW_USE_OS
  //
  // Add here the initialization of your NAND hardware
  //
  SIM_SCGC5   |= SIM_SCGC5_PORTD_MASK;                // Enable clock for Port D
  PORTD_PCR0   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR1   =  PORT_PCR_MUX(0x01)                  // Configure as GPIO
               |  PORT_PCR_PS_MASK                    // Enable the pull-up.
               |  PORT_PCR_PE_MASK
               ;
  PORTD_PCR4   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR5   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR6   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR7   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR8   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR9   =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR10  =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR11  =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR12  =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR13  =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR14  =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  PORTD_PCR15  =  PORT_PCR_MUX(0x01);                 // Configure as GPIO
  GPIOD_PDDR  |=  (1u << NAND_CS_PIN)
              |   (1u << NAND_ALE_PIN)
              |   (1u << NAND_CLE_PIN)
              |   (1u << NAND_nOE_PIN)
              |   (1u << NAND_nWE_PIN)
              ;
  GPIOD_PDDR  &=  ~(1 << NAND_WAIT_PIN);
  NAND_SET_RE();                                      // Disable RE
  NAND_SET_WE();                                      // Disable WE
  NAND_SET_CLE();                                     // Disable CLE
  NAND_SET_ALE();                                     // Disable ALE
  NAND_SET_CE();                                      // Disable CE
#if FS_NAND_HW_USE_OS
  //
  // Create the OS event and enable the interrupt.
  //
#if (FS_NAND_HW_USE_OS == 2)
  if (_IsEventInited == 0) {
    OS_EVENT_Create(&_Event);
    _IsEventInited = 1;
  }
#endif // FS_NAND_HW_USE_OS == 2
  NVIC_EnableIRQ(PORTD_IRQn);
#endif
}

/*********************************************************************
*
*       _HW_WaitWhileBusy
*
*  Function description
*    Waits for the NAND flash device to become ready.
*
*  Parameters
*    Unit         Index of the NAND hardware layer instance (0-based)
*    us           Maximum time to wait in microseconds.
*
*  Return value
*    ==0    The NAND flash device is ready.
*    !=0    The NAND flash device is busy or the operation is not supported.
*/
static int _HW_WaitWhileBusy(U8 Unit, unsigned us) {
  volatile int NumLoops;

  FS_USE_PARA(Unit);
  FS_USE_PARA(us);
  //
  // Make sure that we do not sample the busy signal too early.
  // In order to do so we have to wait here at least the time
  // specified at tWB in the data sheet of the NAND flash device.
  // Typically this time is about 100 ns. Assuming that the CPU
  // is running at 168 MHz then we have to wait here 100 / 5.9 = 16.9
  // that is about 17 cycles.
  //
  NumLoops = NUM_LOOPS_TWB;
  do {
    NAND_NOP();
  } while (--NumLoops != 0);
  for (;;) {
    if (NAND_GET_BUSY() != 0) {
      break;
    }
#if FS_NAND_HW_USE_OS
    (void)_WaitForEvent(WAIT_TIMEOUT_MS);
#else
    NAND_NOP();
#endif // FS_NAND_HW_USE_OS
  }
  return 0;
}

/*********************************************************************
*
*      Public code
*
**********************************************************************
*/

#if FS_NAND_HW_USE_OS

/*********************************************************************
*
*       PORTD_IRQHandler
*/
void PORTD_IRQHandler(void);
void PORTD_IRQHandler(void) {
  OS_EnterNestableInterrupt();
  PORTD_PCR1 &= ~PORT_PCR_IRQC_MASK;          // Disable the interrupt.
  PORTD_PCR1 |=  PORT_PCR_ISF_MASK;
#if (FS_NAND_HW_USE_OS == 2)
  OS_EVENT_Set(&_Event);
#else
  FS_OS_Signal();
#endif
  OS_LeaveNestableInterrupt();
}

#endif // FS_NAND_HW_USE_OS

/*********************************************************************
*
*       Public data
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_NAND_HW_K66_SEGGER_emPower
*/
const FS_NAND_HW_TYPE FS_NAND_HW_K66_SEGGER_emPower = {
  _HW_Init_x8,
  NULL,
  _HW_DisableCE,
  _HW_EnableCE,
  _HW_SetAddrMode,
  _HW_SetCmdMode,
  _HW_SetDataMode,
  _HW_WaitWhileBusy,
  _HW_Read_x8,
  _HW_Write_x8,
  NULL,
  NULL
};

/*************************** End of file ****************************/
Hardware layer API - FS_NAND_HW_TYPE_DF

This hardware layer supports Microchip / Atmel / Adesto DataFlash devices and is used by the FS_NAND_PHY_DataFlash physical layer to exchange data with a DataFlash device via a standard SPI interface. The functions of this hardware layer are grouped in the structure of type FS_NAND_HW_TYPE_DF. The following sections describe these functions in detail.

FS_NAND_HW_TYPE_DF

Description

NAND hardware layer API for DataFlash devices.

Type definition

typedef struct {
  FS_NAND_HW_TYPE_DF_INIT       * pfInit;
  FS_NAND_HW_TYPE_DF_ENABLE_CS  * pfEnableCS;
  FS_NAND_HW_TYPE_DF_DISABLE_CS * pfDisableCS;
  FS_NAND_HW_TYPE_DF_READ       * pfRead;
  FS_NAND_HW_TYPE_DF_WRITE      * pfWrite;
} FS_NAND_HW_TYPE_DF;

Structure members

Member Description
pfInit Initializes the hardware.
pfEnableCS Enables the DataFlash device.
pfDisableCS Disables the DataFlash device.
pfRead Transfers a specified number of bytes from DataFlash device to MCU.
pfWrite Transfers a specified number of bytes from MCU to DataFlash device.
FS_NAND_HW_TYPE_DF_INIT

Description

Initializes the hardware.

Type definition

typedef int FS_NAND_HW_TYPE_DF_INIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Return value

= 0 OK, initialization was successful.
≠ 0 An error occurred.

Additional information

This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type. FS_NAND_HW_TYPE_DF_INIT is the first function of the hardware layer API that is called by a NAND physical layer during the mounting of the file system.

This function has to perform any initialization of the MCU hardware required to access the DataFlash device such as clocks, port pins, memory controllers, etc.

A DataFlash requires that the SPI communication protocol meets the following requirements:

FS_NAND_HW_TYPE_DF_ENABLE_CS

Description

Enables the DataFlash device.

Type definition

typedef void FS_NAND_HW_TYPE_DF_ENABLE_CS(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The DataFlash device is enabled by driving the Chip Select (CS) signal to logic low state.

FS_NAND_HW_TYPE_DF_DISABLE_CS

Description

Disables the DataFlash device.

Type definition

typedef void FS_NAND_HW_TYPE_DF_DISABLE_CS(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The DataFlash device is disabled by driving the Chip Select (CS) signal to logic-high.

FS_NAND_HW_TYPE_DF_READ

Description

Transfers a specified number of bytes from DataFlash device to MCU.

Type definition

typedef void FS_NAND_HW_TYPE_DF_READ(U8   Unit,
                                     U8 * pData,
                                     int  NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  out  Data read from DataFlash device.
NumBytes Number of bytes to be read.

Additional information

This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

FS_NAND_HW_TYPE_DF_WRITE

Description

Transfers a specified number of bytes from MCU to DataFlash device.

Type definition

typedef void FS_NAND_HW_TYPE_DF_WRITE(      U8   Unit,
                                      const U8 * pData,
                                            int  NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  in  Data to be written to DataFlash device.
NumBytes Number of bytes to be written.

Additional information

This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

Sample implementation

The following sample implementation uses the SPI controller of a NXP LPC4322 MCU to interface with a DataFlash device. This NAND hardware layer was tested on a SGGER internal test board.

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : FS_NAND_HW_DF_LPC4322_SEGGER_QSPIFI_Test_Board.c
Purpose : DataFlash hardware layer for NXP LPC4322.
Literature:
  [1] UM10503 LPC43xx ARM Cortex-M4/M0 multi-core microcontroller
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/
#include "FS.h"

/*********************************************************************
*
*      Defines, configurable
*
**********************************************************************
*/
#define   PER_CLK_HZ            180000000uL     // Frequency of the clock supplied to SPI unit
#ifndef   SPI_CLK_HZ
  #define SPI_CLK_HZ            25000000uL      // Frequency of the clock supplied to DataFlash device
#endif
#define   RESET_DELAY_LOOPS     100000          // Number of software loops to wait for DataFlash to reset

/*********************************************************************
*
*       Defines, non-configurable
*
**********************************************************************
*/

/*********************************************************************
*
*       SPI unit
*/
#define SPI_BASE_ADDR         0x40100000
#define SPI_CR                (*(volatile U32*)(SPI_BASE_ADDR + 0x00))    // SPI Control Register
#define SPI_SR                (*(volatile U32*)(SPI_BASE_ADDR + 0x04))    // SPI Status Register
#define SPI_DR                (*(volatile U32*)(SPI_BASE_ADDR + 0x08))    // SPI Data Register
#define SPI_CCR               (*(volatile U32*)(SPI_BASE_ADDR + 0x0C))    // SPI Clock Counter Register
#define SPI_TCR               (*(volatile U32*)(SPI_BASE_ADDR + 0x10))    // SPI Test Control register
#define SPI_TSR               (*(volatile U32*)(SPI_BASE_ADDR + 0x14))    // SPI Test Status register
#define SPI_INT               (*(volatile U32*)(SPI_BASE_ADDR + 0x1C))    // SPI Interrupt Flag

/*********************************************************************
*
*       Clock generation unit
*/
#define CGU_BASE_ADDR         0x40050000
#define BASE_SPI_CLK          (*(volatile U32*)(CGU_BASE_ADDR + 0x0074))

/*********************************************************************
*
*       Clock control unit 1
*/
#define CCU1_BASE_ADDR        0x40051000
#define CLK_SPI_CFG           (*(volatile U32*)(CCU1_BASE_ADDR + 0x0A00))
#define CLK_SPI_STAT          (*(volatile U32*)(CCU1_BASE_ADDR + 0x0A04))

/*********************************************************************
*
*       System control unit
*/
#define SCU_BASE_ADDR         0x40086000
#define SFSP3_2               (*(volatile U32*)(SCU_BASE_ADDR + 0x188))     // Pin configuration register for pin P3_2
#define SFSP3_3               (*(volatile U32*)(SCU_BASE_ADDR + 0x18C))     // Pin configuration register for pin P3_3
#define SFSP3_6               (*(volatile U32*)(SCU_BASE_ADDR + 0x198))     // Pin configuration register for pin P3_6
#define SFSP3_7               (*(volatile U32*)(SCU_BASE_ADDR + 0x19C))     // Pin configuration register for pin P3_7
#define SFSP3_8               (*(volatile U32*)(SCU_BASE_ADDR + 0x1A0))     // Pin configuration register for pin P3_8

/*********************************************************************
*
*       GPIO unit
*/
#define GPIO_BASE_ADDR        0x400F4000
#define GPIO_DIR5             (*(volatile U32*)(GPIO_BASE_ADDR + 0x2014))   // Direction registers port 5
#define GPIO_SET5             (*(volatile U32*)(GPIO_BASE_ADDR + 0x2214))   // Set register for port 5
#define GPIO_CLR5             (*(volatile U32*)(GPIO_BASE_ADDR + 0x2294))   // Clear register for port 5

/*********************************************************************
*
*       Misc. defines
*/
#define CGU_IDIV_BIT            2
#define CGU_AUTOBLOCK_BIT       11
#define CGU_CLK_SEL_BIT         24
#define SFS_MODE_BIT            0
#define SFS_EPUN_BIT            4
#define SFS_EHS_BIT             5
#define SFS_EZI_BIT             6
#define SFS_ZIF_BIT             7
#define CLK_STAT_RUN_BIT        0
#define CLK_CFG_RUN_BIT         0
#define NOR_CS_BIT              11
#define CR_MSTR_BIT             5
#define SR_SPIF                 7
#define CCR_COUNTER_MAX         0xFE        // The actual maximum value is 0xFF but it has to be a multiple of 2
#define NOR_RESET_BIT           9

/*********************************************************************
*
*      Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _SetSpeed
*
*  Function description
*    Configures the speed of the clock supplied NOR flash device.
*
*  Return value
*    Frequency of the SPI clock in Hz.
*/
static U32 _SetSpeed(unsigned MaxFreq_Hz) {
  U32 Div;
  U32 Freq_Hz;

  //
  // According to [1] the clock divisor has to be >= 8 and a multiple of 2.
  //
  Div = 8;
  while (1) {
    Freq_Hz = PER_CLK_HZ / Div;
    if (Freq_Hz <= MaxFreq_Hz) {
      break;
    }
    Div += 2;
    if (Div >= CCR_COUNTER_MAX) {
      Div = CCR_COUNTER_MAX;
      Freq_Hz = PER_CLK_HZ / Div;
      break;
    }
  }
  SPI_CCR = Div;
  return Freq_Hz;
}

/*********************************************************************
*
*       _TransferByte
*
*  Function description
*    Exchanges 8 bits of data with the NOR flash.
*
*  Parameters
*    Data       Data to be sent to NOR flash.
*
*  Return value
*    The data received from NOR flash
*/
static U8 _Transfer8Bits(U8 Data) {
  SPI_DR = Data;
  while (1) {
    if (SPI_SR & (1uL << SR_SPIF)) {
      break;
    }
  }
  Data = SPI_DR;
  return Data;
}

/*********************************************************************
*
*      Public code (via callback)
*
**********************************************************************
*/

/*********************************************************************
*
*       _HW_Init
*
*  Function description
*    Initialize the hardware before accessing the device.
*
*  Parameters
*    Unit     Device index
*
*  Return Value
*    ==0      Hardware successfully initialized
*    !=0      An error occurred
*/
static int _HW_Init(U8 Unit) {
  unsigned NumLoops;

  FS_USE_PARA(Unit);    // This device has only one HW unit.
  BASE_SPI_CLK = 0
                 | 9uL  << CGU_CLK_SEL_BIT      // Use PLL1 as clock generator
                 | 1uL  << CGU_AUTOBLOCK_BIT
                 ;
  //
  // Enable the SPI clock if required.
  //
  if ((CLK_SPI_STAT & (1uL << CLK_STAT_RUN_BIT)) == 0) {
    CLK_SPI_CFG |= (1uL << CLK_CFG_RUN_BIT);
    while (1) {
      if (CLK_SPI_STAT & (1uL << CLK_CFG_RUN_BIT)) {
        ;
      }
    }
  }
  //
  // Clock pin (SPI_CLK).
  //
  SFSP3_3 = 0
          | (1uL << SFS_MODE_BIT)       // Controlled by SPI unit.
          | (1uL << SFS_EPUN_BIT)
          | (1uL << SFS_EHS_BIT)
          | (1uL << SFS_EZI_BIT)
          ;
  //
  // Master In Slave Out (SPI_MISO).
  //
  SFSP3_6 = 0
          | (1uL << SFS_MODE_BIT)       // Controlled by SPI unit.
          | (1uL << SFS_EPUN_BIT)
          | (1uL << SFS_EZI_BIT)
          ;
  //
  // Master Out Slave In (SPI_MOSI).
  //
  SFSP3_7 = 0
          | (1uL << SFS_MODE_BIT)       // Controlled by SPI unit.
          | (1uL << SFS_EPUN_BIT)
          | (1uL << SFS_EZI_BIT)
          ;
  //
  // Chip select pin (SPI_CS).
  //
  SFSP3_8 = 0
          | (4uL << SFS_MODE_BIT)       // GPIO controlled by the this hardware layer.
          | (1uL << SFS_EPUN_BIT)
          ;
  GPIO_DIR5 |= 1uL << NOR_CS_BIT;
  GPIO_SET5  = 1uL << NOR_CS_BIT;       // Set to idle state.
  //
  // Reset pin. Present only on 16-pin devices.
  //
  SFSP3_2 = 0
          | (4uL << SFS_MODE_BIT)                   // Controlled by this HW layer.
          | (1uL << SFS_EPUN_BIT)
          ;
  GPIO_DIR5 |= 1uL << NOR_RESET_BIT;
  //
  // Reset the NOR device.
  //
  GPIO_CLR5 = 1uL << NOR_RESET_BIT;                 // Assert reset signal (active low).
  NumLoops = RESET_DELAY_LOOPS;
  do {
    ;
  } while (--NumLoops);
  GPIO_SET5 = 1uL << NOR_RESET_BIT;                 // De-assert reset signal (active low).
  //
  // Configure the SPI unit.
  //
  SPI_CR = 0
         | (1uL << CR_MSTR_BIT)
         ;
  (void)_SetSpeed(SPI_CLK_HZ);
  return 0;
}

/*********************************************************************
*
*       _HW_EnableCS
*
*  Function description
*    Sets the device active using the chip select (CS) line.
*
*  Parameters
*    Unit     Device index
*/
static void _HW_EnableCS(U8 Unit) {
  FS_USE_PARA(Unit);
  GPIO_CLR5 = 1uL << NOR_CS_BIT;      // The CS signal is active low.
}

/*********************************************************************
*
*       _HW_DisableCS
*
*  Function description
*    Sets the device inactive using the chip select (CS) line.
*
*  Parameters
*    Unit     Device index
*/
static void _HW_DisableCS(U8 Unit) {
  FS_USE_PARA(Unit);
  GPIO_SET5 = 1uL << NOR_CS_BIT;      // The CS signal is active low.
}

/*********************************************************************
*
*       _HW_Read
*
*  Function description
*    Reads a specified number of bytes from device.
*
*  Parameters
*    Unit       Device index
*    pData      Pointer to a data buffer
*    NumBytes   Number of bytes
*/
static void _HW_Read(U8 Unit, U8 * pData, int NumBytes) {
  FS_USE_PARA(Unit);
  do {
    *pData++ = _Transfer8Bits(0xFF);
  } while (--NumBytes);
}

/*********************************************************************
*
*       _HW_Write
*
*  Function description
*    Writes a specified number of bytes from data buffer to device.
*
*  Parameters
*    Unit         Device index
*    pData        Pointer to a data buffer
*    NumBytes     Number of bytes
*/
static void _HW_Write(U8 Unit, const U8 * pData, int NumBytes) {
  FS_USE_PARA(Unit);
  do {
    (void)_Transfer8Bits(*pData++);
  } while (--NumBytes);
}

/*********************************************************************
*
*       Public data
*
**********************************************************************
*/
const FS_NAND_HW_TYPE_DF FS_NAND_HW_DF_LPC4322_SEGGER_QSPIFI_Test_Board = {
  _HW_Init,
  _HW_EnableCS,
  _HW_DisableCS,
  _HW_Read,
  _HW_Write
};

/*************************** End of file ****************************/
Hardware layer API - FS_NAND_HW_TYPE_QSPI

This hardware layer supports any serial NAND flash device with a standard, dual or quad SPI interface. It is used by the FS_NAND_PHY_QSPI physical layer to exchange data with a NAND flash device that supports such an interface. Typically, the implementation of FS_NAND_HW_TYPE_QSPI hardware layer makes use of a SPI controller that is able to exchange the data via two or four data lines. This kind of SPI controllers are found on most of the popular MCUs and they are typically used to execute code in-place from an external NOR flash device but they can be equally well used to exchange data with a serial NAND flash device.

The functions of this hardware layer are grouped in the structure of type FS_NAND_HW_TYPE_QSPI. The following sections describe these functions in detail.

FS_NAND_HW_TYPE_QSPI

Description

NAND hardware layer API for NAND flash devices connected via quad and dual SPI.

Type definition

typedef struct {
  FS_NAND_HW_TYPE_QSPI_INIT    * pfInit;
  FS_NAND_HW_TYPE_QSPI_CONTROL * pfExecCmd;
  FS_NAND_HW_TYPE_QSPI_READ    * pfReadData;
  FS_NAND_HW_TYPE_QSPI_WRITE   * pfWriteData;
  FS_NAND_HW_TYPE_QSPI_POLL    * pfPoll;
  FS_NAND_HW_TYPE_QSPI_DELAY   * pfDelay;
  FS_NAND_HW_TYPE_QSPI_LOCK    * pfLock;
  FS_NAND_HW_TYPE_QSPI_UNLOCK  * pfUnlock;
  FS_NAND_HW_TYPE_QSPI_READ_EX * pfReadEx;
} FS_NAND_HW_TYPE_QSPI;

Structure members

Member Description
pfInit Initializes the hardware.
pfExecCmd Executes a command without data transfer.
pfReadData Transfers data from NAND flash device to MCU.
pfWriteData Transfers data from MCU to NAND flash device.
pfPoll Sends a command repeatedly and checks the response data for a specified condition.
pfDelay Blocks the execution for the specified number of milliseconds.
pfLock Requests exclusive access to SPI bus.
pfUnlock Releases the exclusive access of SPI bus.
pfReadEx Transfers data from NAND flash device to MCU.
FS_NAND_HW_TYPE_QSPI_INIT

Description

Initializes the hardware.

Type definition

typedef int FS_NAND_HW_TYPE_QSPI_INIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Return value

Frequency of the QSPI clock in kHz.

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

This function has to configure anything necessary for the data transfer via QSPI such as clocks, port pins, QSPI peripheral, DMA, etc.

The frequency value returned by the function has to be greater than or equal to the actual clock frequency used to transfer the data via QSPI. The FS_NAND_PHY_QSPI physical layer uses this value to calculate the number of software cycles it has to wait for NAND flash device to finish an operation before a timeout error is reported. FS_NAND_HW_TYPE_QSPI_INIT must return 0 if the clock frequency is unknown. In this case, the FS_NAND_PHY_QSPI physical layer waits indefinitely for the end of a NAND flash operation and it never reports a timeout error.

FS_NAND_HW_TYPE_QSPI_CONTROL

Description

Executes a command without data transfer.

Type definition

typedef int FS_NAND_HW_TYPE_QSPI_CONTROL(U8 Unit,
                                         U8 Cmd,
                                         U8 BusWidth);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
Cmd Code of the command to be sent.
BusWidth Number of data lines to be used for sending the command code.

Return value

= 0 OK, command sent.
≠ 0 An error occurred.

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

FS_NAND_HW_TYPE_QSPI_CONTROL must to send a 8 bits to NAND flash device containing the value specified via Cmd.

BusWidth specifies the number of data lines to be used when sending the command code. Permitted values are:

Please note that this is not an encoded value such as the value passed via BusWidth in a call to FS_NAND_HW_TYPE_QSPI_READ, FS_NAND_HW_TYPE_QSPI_WRITE or FS_NAND_HW_TYPE_QSPI_POLL.

FS_NAND_HW_TYPE_QSPI_READ

Description

Transfers data from NAND flash device to MCU.

Type definition

typedef int FS_NAND_HW_TYPE_QSPI_READ(      U8       Unit,
                                            U8       Cmd,
                                      const U8     * pPara,
                                            unsigned NumBytesPara,
                                            unsigned NumBytesAddr,
                                            U8     * pData,
                                            unsigned NumBytesData,
                                            U16      BusWidth);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
Cmd Code of the command to be sent.
pPara Additional command parameters (can be NULL).
NumBytesPara Number of additional bytes to be sent after command. Can be 0 if pPara is NULL.
NumBytesAddr Number of address bytes to be sent. Can be 0 if pPara is NULL.
pData Data received from the NAND flash device.
NumBytesData Number of bytes to be received from the NAND flash device.
BusWidth Specifies the number of data lines to be used during the data transfer.

Return value

= 0 OK, data transferred.
≠ 0 An error occurred.

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The data has to be sent in this order: Cmd (1 byte) and pPara (NumBytesPara bytes). The first NumBytesAddr bytes in pPara represent the address bytes while the rest until NumBytesPara bytes are dummy bytes. These values are useful for QSPI hardware that can differentiate between address and dummy bytes. If NumBytesPara and NumBytesAddr are equal, no dummy bytes have to be sent. NumBytesPara is never be smaller than NumBytesAddr. The data received from NAND flash has to be stored to pData (NumBytesData bytes).

The number of data lines to be used during the data transfer is specified via BusWidth. The value is encoded with each nibble (4 bits) specifying the number of data lines for one part of the data transfer. The macros SPI bus width decoding can be used to decode the number of data lines of each part of the request (command and address) and of the response (data). The dummy bytes have to be sent using the number of data lines returned by FS_BUSWIDTH_GET_ADDR().

FS_NAND_HW_TYPE_QSPI_WRITE

Description

Transfers data from MCU to NAND flash device.

Type definition

typedef int FS_NAND_HW_TYPE_QSPI_WRITE(      U8       Unit,
                                             U8       Cmd,
                                       const U8     * pPara,
                                             unsigned NumBytesPara,
                                             unsigned NumBytesAddr,
                                       const U8     * pData,
                                             unsigned NumBytesData,
                                             U16      BusWidth);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
Cmd Code of the command to be sent.
pPara Additional command parameters (can be NULL).
NumBytesPara Number of additional bytes to be sent after command. Can be 0 if pPara is NULL.
NumBytesAddr Number of address bytes to be sent. Can be 0 if pPara is NULL.
pData Data to be sent to NAND flash device.
NumBytesData Number of data bytes to be sent to NAND flash device.
BusWidth Specifies the number of data lines to be used during the data transfer.

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The data has to be sent in this order: Cmd (1 byte), pPara (NumBytesPara bytes), pData (NumBytesData bytes). The first NumBytesAddr bytes in pPara represent the address bytes while the rest until NumBytesPara bytes are dummy bytes. These values are useful for QSPI hardware that can differentiate between address and dummy bytes. If NumBytesPara and NumBytesAddr are equal, no dummy bytes have to be sent. NumBytesPara will never be smaller than NumBytesAddr.

The number of data lines to be used during the data transfer is specified via BusWidth. The value is encoded with each nibble specifying the number of data lines for one part of the data transfer. The macros SPI bus width decoding can be used to decode the number of data lines of each part of the request (command, address and data). The dummy bytes have to be sent using the number of data lines returned by FS_BUSWIDTH_GET_ADDR().

FS_NAND_HW_TYPE_QSPI_POLL

Description

Sends a command repeatedly and checks the response data for a specified condition.

Type definition

typedef int FS_NAND_HW_TYPE_QSPI_POLL(      U8       Unit,
                                            U8       Cmd,
                                      const U8     * pPara,
                                            unsigned NumBytesPara,
                                            U8       BitPos,
                                            U8       BitValue,
                                            U32      Delay,
                                            U32      TimeOut_ms,
                                            U16      BusWidth);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
Cmd Code of the command to be sent.
pPara Additional command parameters (can be NULL).
NumBytesPara Number of additional bytes to be sent after command. Can be 0 if pPara is NULL.
BitPos Position of the bit inside response data that has to be checked (0-based, with 0 being LSB)
BitValue Bit value to wait for.
Delay_ms Time between two command executions.
TimeOut_ms Maximum time to wait for the bit at BitPos to be set to BitValue.
BusWidth Specifies how many data lines have to be used for sending the command and parameters and for reading the data.

Return value

> 0 Error, timeout occurred.
= 0 OK, bit set to specified value.
< 0 Error, feature not supported.

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. The implementation of this function is optional. FS_NAND_HW_TYPE_QSPI_POLL is called by the QSPI NAND physical layer when it has to wait for the NAND flash device to reach a certain status.

FS_NAND_HW_TYPE_QSPI_POLL has to read periodically a byte of data from the NAND flash device until the value of the bit at BitPos in the in the returned data byte is set to a value specified by BitValue. The data is read by sending a command with a code specified by Cmd followed by an optional number of additional bytes specified by pPara and NumBytesPara. Then 8 bits of data are transferred from NAND flash device to MCU and this the value stores the bit to be checked.

The number of data lines to be used during the data transfer is specified via BusWidth. The value is encoded with each nibble specifying the number of data lines for one part of the data transfer. The macros SPI bus width decoding can be used to decode the number of data lines of each part of the request (command, parameters and data). The pPara data has to be sent using the number of data lines returned by FS_BUSWIDTH_GET_ADDR().

The time FS_NAND_HW_TYPE_QSPI_POLL waits for the condition to be true shall not exceed the number of milliseconds specified by TimeOut_ms. Delay_ms specifies the number of milliseconds that can elapse between the execution of two consecutive commands.

FS_NAND_HW_TYPE_QSPI_DELAY

Description

Blocks the execution for the specified number of milliseconds.

Type definition

typedef void FS_NAND_HW_TYPE_QSPI_DELAY(U8  Unit,
                                        int ms);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
ms Number of milliseconds to wait.

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The time FS_NAND_HW_TYPE_QSPI_DELAY blocks does not have to be accurate. That is the function can block the execution longer that the number of specified milliseconds but no less than that.

FS_NAND_HW_TYPE_QSPI_LOCK

Description

Requests exclusive access to SPI bus.

Type definition

typedef void FS_NAND_HW_TYPE_QSPI_LOCK(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. The implementation of this function is optional.

The FS_NAND_PHY_QSPI physical layer calls this function to indicate that it needs exclusive to access the NAND flash device via the SPI bus. It is guaranteed that the FS_NAND_PHY_QSPI physical layer does not attempt to communicate via the SPI bus before calling this function first. It is also guaranteed that FS_NAND_HW_TYPE_QSPI_LOCK and FS_NAND_HW_TYPE_QSPI_UNLOCK are called in pairs.

FS_NAND_HW_TYPE_QSPI_UNLOCK and FS_NAND_HW_TYPE_QSPI_LOCK can be used to synchronize the access to the SPI bus when other devices than the NAND flash are connected to it. A possible implementation would make use of an OS semaphore that is acquired in this function and released in FS_NAND_HW_TYPE_QSPI_UNLOCK.

FS_NAND_HW_TYPE_QSPI_UNLOCK

Description

Releases the exclusive access of SPI bus.

Type definition

typedef void FS_NAND_HW_TYPE_QSPI_UNLOCK(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware layer API. The implementation of this function is optional.

The FS_NAND_PHY_QSPI physical layer calls this function when it no longer needs to access the NAND flash device via the SPI bus. It is guaranteed that the FS_NAND_PHY_QSPI physical layer does not attempt to communicate via the SPI bus before calling FS_NAND_HW_TYPE_QSPI_LOCK. It is also guaranteed that FS_NAND_HW_TYPE_QSPI_UNLOCK and FS_NAND_HW_TYPE_QSPI_LOCK are called in pairs.

FS_NAND_HW_TYPE_QSPI_UNLOCK and FS_NAND_HW_TYPE_QSPI_LOCK can be used to synchronize the access to the SPI bus when other devices than the NAND flash are connected to it. A possible implementation would make use of an OS semaphore that is acquired in this function and released in FS_NAND_HW_TYPE_QSPI_UNLOCK.

FS_NAND_HW_TYPE_QSPI_READ_EX

Description

Transfers data from serial NAND flash device to MCU.

Type definition

typedef int FS_NAND_HW_TYPE_QSPI_READ_EX(      U8       Unit,
                                         const U8     * pCmd,
                                               unsigned NumBytesCmd,
                                         const U8     * pPara,
                                               unsigned NumBytesPara,
                                               unsigned NumBytesAddr,
                                               U8     * pData,
                                               unsigned NumBytesData,
                                               U16      BusWidth,
                                               unsigned Flags);

Parameters

Parameter Description
Unit Index of the hardware layer (0-based).
pCmd  in  Code of the command to be sent. Cannot be NULL.
NumBytesCmd Number of bytes in the command code. Cannot be 0.
pPara  in  Command parameters (address and dummy bytes). Can be NULL.
NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
NumBytesAddr Number of address bytes to be send. Can be 0.
pData  out  Data read from the serial NOR flash device. Can be NULL.
NumBytesData Number of bytes to read from the serial NOR flash device. Can be 0.
BusWidth Number of data lines to be used for the data transfer.
Flags Options for the data exchange.

Return value

= 0 OK, data transferred successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the QSPI NAND hardware layer API. The implementation of this function is optional. The function has to be implemented only by hardware layers that have to be able to transfer the data in DTR mode. If the hardware layer does not implement this function then FS_NAND_HW_TYPE_QSPI_READ is called instead.

The first address byte is stored at *pPara. NumBytesAddr is always smaller than or equal to NumBytesPara. If NumBytesAddr is equal to NumBytesPara then no dummy bytes have to be sent. The number of dummy bytes to be generated can be calculated as NumBytesPara - NumBytesAddr. If the hardware generates dummy cycles instead of bytes then the number of dummy bytes has to converted to clock cycles by taking into account the number of data lines used for the data transfer of the address.

This function performs the same operation as FS_NAND_HW_TYPE_QSPI_READ with the difference that it can handle multi-byte commands and additional data transfer options specified via Flags. Flags is a bitwise-or combination of NAND HW layer flags. In addition, this function is able to report an error via the return value.

NAND HW layer flags

Description

Additional options for data exchanged via the QSPI NAND HW layer.

Definition

#define FS_NAND_HW_FLAG_DTR_DATA    (1uL << 0)
#define FS_NAND_HW_FLAG_DTR_ADDR    (1uL << 1)

Symbols

Definition Description
FS_NAND_HW_FLAG_DTR_DATA Exchange the data on each clock transition.
FS_NAND_HW_FLAG_DTR_ADDR Send the address on each clock transition.
SPI bus width decoding

Description

Macros for the handling of SPI bus width.

Definition

#define FS_BUSWIDTH_GET_CMD(BusWidth)     (((BusWidth) >> FS_BUSWIDTH_CMD_SHIFT)  & FS_BUSWIDTH_MASK)
#define FS_BUSWIDTH_GET_ADDR(BusWidth)    (((BusWidth) >> FS_BUSWIDTH_ADDR_SHIFT) & FS_BUSWIDTH_MASK)
#define FS_BUSWIDTH_GET_DATA(BusWidth)    (((BusWidth) >> FS_BUSWIDTH_DATA_SHIFT) & FS_BUSWIDTH_MASK)

Symbols

Definition Description
FS_BUSWIDTH_GET_CMD(BusWidth) Returns the number of data lines to be used for sending the command code.
FS_BUSWIDTH_GET_ADDR(BusWidth) Returns the number of data lines to be used for sending the data address.
FS_BUSWIDTH_GET_DATA(BusWidth) Returns the number of data lines to be used for sending and receiving of the user data.

Additional information

The functions of the FS_NOR_HW_TYPE_SPIFI NOR hardware layer and of the FS_NAND_HW_TYPE_QSPI NAND hardware layer that exchange data with the storage device take a parameter that specifies how many data lines have to be used to send different parts of a request and to receive the answer. The value of this parameter is encoded as a 16-bit value and the macros in this section can help extract the bus width value for a specific part of the request and response.

The value is encoded as follows:

Bit range Description
0-3 Number of data lines to be used to transfer the data.
4-7 Number of data lines to be used to transfer the address.
8-11 Number of data lines to be used to transfer the command.
Sample implementation

The sample implementation listed below uses the QUADSPI controller of an ST STM32H743 MCU to interface with a serial NAND flash device. This NAND hardware layer was tested on a SGGER internal test board.

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator.c
Purpose : HW layer for quad and dual serial NAND flash for ST STM32H743.
Literature:
  [1] RM0433 Reference manual STM32H7x3 advanced ARM-based 32-bit MCUs
  [2] STM32H753xI Errata sheet STM32H753xI rev Y device limitations
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/
#include "FS.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#ifndef   FS_NAND_HW_PER_CLK_HZ
  #define FS_NAND_HW_PER_CLK_HZ             240000000     // Clock of Quad-SPI unit
#endif                                      
                                            
#ifndef   FS_NAND_HW_NAND_CLK_HZ            
  #define FS_NAND_HW_NAND_CLK_HZ            48000000      // Frequency of the clock
                                                          // supplied to NAND flash device
#endif

#ifndef   FS_NAND_HW_CYCLES_PER_MS
  #define FS_NAND_HW_CYCLES_PER_MS          150000        // Number of software loops
                                                          // create a 1ms delay
#endif

#ifndef   FS_NAND_HW_USE_OS
  #define FS_NAND_HW_USE_OS                 0             // Enables/disables the interrupt-driven operation.
                                                          // Permitted values:
                                                          //   0 - polling via CPU
                                                          //   1 - event-driven using embOS
                                                          //   2 - event-driven using other RTOS
#endif

/*********************************************************************
*
*       #include section, conditional
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
  #include "stm32h7xx.h"
  #include "FS_OS.h"
#if (FS_NAND_HW_USE_OS == 1)
  #include "RTOS.h"
#endif // FS_NAND_HW_USE_OS == 1
#endif // FS_NAND_HW_USE_OS

/*********************************************************************
*
*       Defines, fixed
*
**********************************************************************
*/

/*********************************************************************
*
*       QSPI registers
*/
#define QUADSPI_BASE_ADDR       0x52005000uL
#define QUADSPI_CR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x00))
#define QUADSPI_DCR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x04))
#define QUADSPI_SR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x08))
#define QUADSPI_FCR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x0C))
#define QUADSPI_DLR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x10))
#define QUADSPI_CCR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x14))
#define QUADSPI_AR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x18))
#define QUADSPI_ABR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x1C))
#define QUADSPI_DR              (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_DR_BYTE         (*(volatile U8  *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_PSMKR           (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x24))
#define QUADSPI_PSMAR           (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x28))
#define QUADSPI_PIR             (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x2C))
#define QUADSPI_LPTR            (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x30))

/*********************************************************************
*
*       Port B registers
*/
#define GPIOB_BASE_ADDR         0x58020400uL
#define GPIOB_MODER             (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x00))
#define GPIOB_OSPEEDR           (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x08))
#define GPIOB_PUPDR             (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x0C))
#define GPIOB_ODR               (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x14))
#define GPIOB_AFRL              (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x20))

/*********************************************************************
*
*       Port F registers
*/
#define GPIOF_BASE_ADDR         0x58021400uL
#define GPIOF_MODER             (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x00))
#define GPIOF_OSPEEDR           (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x08))
#define GPIOF_PUPDR             (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x0C))
#define GPIOF_ODR               (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x14))
#define GPIOF_AFRL              (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x20))
#define GPIOF_AFRH              (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x24))

/*********************************************************************
*
*       Reset and clock control
*/
#define RCC_BASE_ADDR           0x58024400uL
#define RCC_AHB3RSTR            (*(volatile U32*)(RCC_BASE_ADDR + 0x7C))
#define RCC_AHB3ENR             (*(volatile U32*)(RCC_BASE_ADDR + 0xD4))
#define RCC_AHB4ENR             (*(volatile U32*)(RCC_BASE_ADDR + 0xE0))

/*********************************************************************
*
*       Masks for the peripheral enable bits
*/
#define AHB4ENR_GPIOBEN         1
#define AHB4ENR_GPIOFEN         5
#define AHB3ENR_QSPIEN          14

/*********************************************************************
*
*       GPIO bit positions of SPI signals
*/
#define NAND_BK1_NCS_BIT        6   // Port B
#define NAND_CLK_BIT            10  // Port F
#define NAND_BK1_D0_BIT         8   // Port F
#define NAND_BK1_D1_BIT         9   // Port F
#define NAND_BK1_D2_BIT         7   // Port F
#define NAND_BK1_D3_BIT         6   // Port F

/*********************************************************************
*
*       GPIO bits and masks
*/
#define OSPEEDR_HIGH            2uL
#define OSPEEDR_MASK            0x3uL
#define MODER_MASK              0x3uL
#define MODER_ALT               2uL
#define AFR_MASK                0xFuL

/*********************************************************************
*
*       Quad-SPI control register
*/
#define CR_EN_BIT               0
#define CR_ABORT_BIT            1
#define CR_SMIE_BIT             19
#define CR_APMS_BIT             22
#define CR_PRESCALER_BIT        24
#define CR_PRESCALER_MAX        255

/*********************************************************************
*
*       Quad-SPI device configuration register
*/
#define DCR_CKMODE_BIT          0
#define DCR_FSIZE_BIT           16
#define DCR_FSIZE_MAX           0x1FuL

/*********************************************************************
*
*       Quad-SPI status register
*/
#define SR_TEF_BIT              0
#define SR_TCF_BIT              1
#define SR_SMF_BIT              3
#define SR_TOF_BIT              4
#define SR_BUSY_BIT             5
#define SR_FLEVEL_BIT           8
#define SR_FLEVEL_MASK          0x3FuL

/*********************************************************************
*
*       Quad-SPI communication configuration register
*/
#define CCR_INTRUCTION_BIT      0
#define CCR_IMODE_BIT           8
#define CCR_MODE_NONE           0
#define CCR_MODE_SINGLE         1uL
#define CCR_MODE_DUAL           2uL
#define CCR_MODE_QUAD           3uL
#define CCR_ADMODE_BIT          10
#define CCR_ADSIZE_BIT          12
#define CCR_ADSIZE_MASK         0x03uL
#define CCR_ABMODE_BIT          14
#define CCR_ABSIZE_BIT          16
#define CCR_ABSIZE_MASK         0x03uL
#define CCR_DCYC_BIT            18
#define CCR_DMODE_BIT           24
#define CCR_FMODE_BIT           26
#define CCR_FMODE_WRITE         0x0uL
#define CCR_FMODE_READ          0x1uL
#define CCR_FMODE_POLL          0x2uL
#define CCR_FMODE_MMAP          0x3uL
#define CCR_FMODE_MASK          0x3uL
#define CCR_DDRM_BIT            31

/*********************************************************************
*
*       Misc. defines
*/
#define NUM_BYTES_FIFO          32
#define WAIT_TIMEOUT_MS         500
#define WAIT_TIMEOUT_CYCLES     (WAIT_TIMEOUT_MS * FS_NAND_HW_CYCLES_PER_MS)
#define QUADSPI_PRIO            15

/*********************************************************************
*
*       ASSERT_IS_LOCKED
*/
#if FS_SUPPORT_TEST
  #define ASSERT_IS_LOCKED()                  \
    if (_LockCnt != 1) {                      \
      FS_X_PANIC(FS_ERRCODE_INVALID_USAGE);   \
    }
#else
  #define ASSERT_IS_LOCKED()
#endif

/*********************************************************************
*
*       IF_TEST
*/
#if FS_SUPPORT_TEST
  #define IF_TEST(Expr)       Expr
#else
  #define IF_TEST(Expr)
#endif

/*********************************************************************
*
*      Static data
*
**********************************************************************
*/
#if FS_SUPPORT_TEST
  static U8 _LockCnt = 0;      // Just to test if the Lock()/Unlock
                               // function are called correctly.
#endif

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _CalcClockDivider
*/
static U8 _CalcClockDivider(U32 * pFreq_Hz) {
  U8  Div;
  U32 Freq_Hz;
  U32 MaxFreq_Hz;

  Div        = 0;
  MaxFreq_Hz = *pFreq_Hz;
  for (;;) {
    Freq_Hz = FS_NAND_HW_PER_CLK_HZ / (Div + 1);
    if (Freq_Hz <= MaxFreq_Hz) {
      break;
    }
    ++Div;
    if (Div == CR_PRESCALER_MAX) {
      break;
    }
  }
  *pFreq_Hz = Freq_Hz;
  return Div;
}

/*********************************************************************
*
*       _GetMode
*/
static U32 _GetMode(unsigned BusWidth, U32 NumBytes) {
  U32 Mode;

  Mode = CCR_MODE_NONE;
  if (NumBytes) {
    switch (BusWidth) {
    case 1:
      Mode = CCR_MODE_SINGLE;
      break;
    case 2:
      Mode = CCR_MODE_DUAL;
      break;
    case 4:
      Mode = CCR_MODE_QUAD;
      break;
    default:
      break;
    }
  }
  return Mode;
}

/*********************************************************************
*
*       _CalcNumCycles
*
*  Function description
*    Calculates the number of clock cycles required to transfer a specified number of bytes.
*/
static U32 _CalcNumCycles(unsigned BusWidth, U32 NumBytes, int IsDTRMode) {
  U32 NumCycles;

  NumCycles = 0;
  if (NumBytes != 0) {
    NumCycles = NumBytes << 3;        // Assume 8-bits per byte.
    switch (BusWidth) {
    case 2:
      NumCycles >>= 1;
      break;
    case 4:
      NumCycles >>= 2;
      break;
    default:
      break;
    }
    if (IsDTRMode != 0) {
      NumCycles >>= 1;                // The data is sent on both clock edges.
    }
  }
  return NumCycles;
}

/*********************************************************************
*
*       _ClearFlags
*
*  Function description
*    Clears the status flags of QUADSPI peripheral.
*/
static int _ClearFlags(void) {
  U32 TimeOut;
  int r;

  QUADSPI_FCR = 0
              | (1uL << SR_TEF_BIT)
              | (1uL << SR_TCF_BIT)
              | (1uL << SR_SMF_BIT)
              | (1uL << SR_TOF_BIT)
              ;
  //
  // Wait for the flags to be cleared.
  //
  r       = 0;
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & ((1uL << SR_TEF_BIT) |
                       (1uL << SR_TCF_BIT) |
                       (1uL << SR_SMF_BIT) |
                       (1uL << SR_TOF_BIT))) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                    // Error, could not clear flags.
      break;
    }
  }
  return r;
}

#if FS_NAND_HW_USE_OS

/*********************************************************************
*
*       _Cancel
*
*  Function description
*    Interrupts an ongoing data transfer.
*/
static int _Cancel(void) {
  U32 TimeOut;
  int r;

  r       = 0;
  TimeOut = WAIT_TIMEOUT_CYCLES;
  QUADSPI_CR |= 1uL << CR_ABORT_BIT;
  for (;;) {
    if ((QUADSPI_CR & (1uL << CR_ABORT_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                    // Error, could not cancel data transfer.
      break;
    }
  }
  return r;
}

#endif // FS_NAND_HW_USE_OS

/*********************************************************************
*
*       _Init
*
*  Function description
*    Initializes the QSPI hardware.
*/
static int _Init(void) {
  U32 Div;
  U32 Freq_Hz;

  //
  // Enable the clocks of peripherals and reset them.
  //
  RCC_AHB4ENR  |= 0
               | (1uL << AHB4ENR_GPIOBEN)
               | (1uL << AHB4ENR_GPIOFEN)
               ;
  RCC_AHB3ENR  |=   1uL << AHB3ENR_QSPIEN;
  RCC_AHB3RSTR |=   1uL << AHB3ENR_QSPIEN;
  RCC_AHB3RSTR &= ~(1uL << AHB3ENR_QSPIEN);
  //
  // Wait for the unit to exit reset.
  //
  for (;;) {
    if ((RCC_AHB3RSTR & (1uL << AHB3ENR_QSPIEN)) == 0) {
      break;
    }
  }
  //
  // NCS of bank 1 is an output signal and is controlled by the QUADSPI unit.
  //
  GPIOB_MODER   &= ~(MODER_MASK   << (NAND_BK1_NCS_BIT << 1));
  GPIOB_MODER   |=   MODER_ALT    << (NAND_BK1_NCS_BIT << 1);
  GPIOB_AFRL    &= ~(AFR_MASK     << (NAND_BK1_NCS_BIT << 2));
  GPIOB_AFRL    |=   0xAuL        << (NAND_BK1_NCS_BIT << 2);
  GPIOB_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_NCS_BIT << 1));
  GPIOB_OSPEEDR |=   OSPEEDR_HIGH << (NAND_BK1_NCS_BIT << 1);
  //
  // CLK is an output signal controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (NAND_CLK_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (NAND_CLK_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((NAND_CLK_BIT - 8) << 2));
  GPIOF_AFRH    |=   0x9uL        << ((NAND_CLK_BIT - 8) << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_CLK_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (NAND_CLK_BIT << 1);
  //
  // D0 of bank 1 is an input/output signal controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (NAND_BK1_D0_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (NAND_BK1_D0_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((NAND_BK1_D0_BIT - 8) << 2));
  GPIOF_AFRH    |=   0xAuL        << ((NAND_BK1_D0_BIT - 8) << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D0_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (NAND_BK1_D0_BIT << 1);
  //
  // D1 of bank 1 is an input/output signal controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (NAND_BK1_D1_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (NAND_BK1_D1_BIT << 1);
  GPIOF_AFRH    &= ~(AFR_MASK     << ((NAND_BK1_D1_BIT - 8) << 2));
  GPIOF_AFRH    |=   0xAuL        << ((NAND_BK1_D1_BIT - 8) << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D1_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (NAND_BK1_D1_BIT << 1);
  //
  // D2 of bank 1 is an input/output signal and is controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (NAND_BK1_D2_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (NAND_BK1_D2_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (NAND_BK1_D2_BIT << 2));
  GPIOF_AFRL    |=   0x9uL        << (NAND_BK1_D2_BIT << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D2_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (NAND_BK1_D2_BIT << 1);
  //
  // D3 of bank 1 is an output signal and is controlled by the QUADSPI unit.
  //
  GPIOF_MODER   &= ~(MODER_MASK   << (NAND_BK1_D3_BIT << 1));
  GPIOF_MODER   |=   MODER_ALT    << (NAND_BK1_D3_BIT << 1);
  GPIOF_AFRL    &= ~(AFR_MASK     << (NAND_BK1_D3_BIT << 2));
  GPIOF_AFRL    |=   0x9uL        << (NAND_BK1_D3_BIT << 2);
  GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D3_BIT << 1));
  GPIOF_OSPEEDR |=   OSPEEDR_HIGH << (NAND_BK1_D3_BIT << 1);
#if FS_NAND_HW_USE_OS
  //
  // Disable the interrupt and configure the priority.
  //
  NVIC_DisableIRQ(QUADSPI_IRQn);
  NVIC_SetPriority(QUADSPI_IRQn, QUADSPI_PRIO);
#endif // FS_NAND_HW_USE_OS
  //
  // Initialize the Quad-SPI controller.
  //
  Freq_Hz = FS_NAND_HW_NAND_CLK_HZ;
  Div = (U32)_CalcClockDivider(&Freq_Hz);
  QUADSPI_CR  = 0
              | (1uL << CR_EN_BIT)                  // Enable the Quad-SPI unit.
              | (Div << CR_PRESCALER_BIT)
              ;
  QUADSPI_DCR = 0
              | (1uL           << DCR_CKMODE_BIT)   // CLK signal stays HIGH
                                                    // when the NAND flash is not selected.
              | (DCR_FSIZE_MAX << DCR_FSIZE_BIT)    // We set the NAND flash size to maximum
                                                    // since the actual value is not known
                                                    // at this stage.
              ;
#if FS_NAND_HW_USE_OS
  //
  // Clear interrupt flags and enable the interrupt.
  //
  QUADSPI_CR  |= 0
              | (1uL << CR_SMIE_BIT)
              | (1uL << CR_APMS_BIT)
              ;
  QUADSPI_FCR  = 1uL << SR_SMF_BIT;
  NVIC_EnableIRQ(QUADSPI_IRQn);
#endif // FS_NAND_HW_USE_OS
  return (int)Freq_Hz / 1000;
}

/*********************************************************************
*
*       _Control
*
*  Function description
*    Executes a NAND flash command without data transfer.
*/
static int _Control(U8 Cmd, U8 BusWidth) {
  U32 CfgReg;
  U32 CmdMode;
  U32 TimeOut;
  int r;

  //
  // Initialize local variables.
  //
  r       = 0;
  CmdMode = _GetMode(BusWidth, sizeof(Cmd));
  CfgReg  = 0
          | (CCR_FMODE_WRITE << CCR_FMODE_BIT)
          | (CmdMode         << CCR_IMODE_BIT)
          | (Cmd             << CCR_INTRUCTION_BIT)
          ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                                // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // Execute the command.
  //
  QUADSPI_DLR = 0;
  QUADSPI_ABR = 0;
  QUADSPI_CCR = CfgReg;
  //
  // Wait until the command has been completed.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                                                // Error, QUADSPI is not ready.
      break;
    }
  }
Done:
  return r;
}

/*********************************************************************
*
*       _Read
*
*  Function description
*    Transfers data from NAND flash device to MCU.
*/
static int _Read(const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara, 
                 unsigned NumBytesPara, unsigned NumBytesAddr, U8 * pData, 
                 unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
  U32 AddrReg;
  U32 AltReg;
  U32 CfgReg;
  U32 DataMode;
  U32 AddrMode;
  U32 CmdMode;
  U32 DataReg;
  U32 NumCyclesDummy;
  U32 AddrSize;
  U32 NumBytesAvail;
  U32 NumBytes;
  U32 NumBytesDummy;
  U32 TimeOut;
  int r;
  U32 IsDTR;
  U32 Cmd;

  FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u);                                    // This QSPI controller is able to handle only 1-byte commands.
  //
  // Initialize local variables.
  //
  r              = 0;
  AddrReg        = 0;
  AltReg         = 0;
  NumBytesDummy  = NumBytesPara - NumBytesAddr;
  Cmd            = *pCmd;
  //
  // Calculate the transfer mode.
  //
  IsDTR = 0;
  if (   ((Flags & FS_NAND_HW_FLAG_DTR_ADDR) != 0u)
      || ((Flags & FS_NAND_HW_FLAG_DTR_DATA) != 0u)) {
    IsDTR = 1;
  }
  //
  // Calculate the number of data lines to be used for the transfer.
  //
  CmdMode        = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
  AddrMode       = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
  NumCyclesDummy = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesDummy, IsDTR);  // The dummy bytes are sent using the address bus mode.
  DataMode       = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
  //
  // Encode the address.
  //
  if (NumBytesAddr) {
    NumBytes = NumBytesAddr;
    do {
      AddrReg <<= 8;
      AddrReg  |= (U32)(*pPara++);
    } while (--NumBytes);
  }
  AddrSize = 0;
  if (NumBytesAddr) {
    AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
  }
  CfgReg = 0
         | (CCR_FMODE_READ << CCR_FMODE_BIT)
         | (DataMode       << CCR_DMODE_BIT)
         | (NumCyclesDummy << CCR_DCYC_BIT)
         | (IsDTR          << CCR_DDRM_BIT)
         | (AddrSize       << CCR_ADSIZE_BIT)
         | (AddrMode       << CCR_ADMODE_BIT)
         | (CmdMode        << CCR_IMODE_BIT)
         | (Cmd            << CCR_INTRUCTION_BIT)
         ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // Execute the command.
  //
  r = _ClearFlags();
  if (r != 0) {
    goto Done;
  }
  if (NumBytesData) {
    QUADSPI_DLR = NumBytesData - 1;       // 0 means "read 1 byte".
  }
  QUADSPI_ABR = AltReg;
  QUADSPI_CCR = CfgReg;
  if (NumBytesAddr) {
    QUADSPI_AR = AddrReg;
  }
  //
  // Read data from NOR flash.
  //
  if (NumBytesData) {
    do {
      //
      // Wait for the data to be received.
      //
      TimeOut = WAIT_TIMEOUT_CYCLES;
      for (;;) {
        NumBytesAvail = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
        if ((NumBytesAvail >= 4) || (NumBytesAvail >= NumBytesData)) {
          break;
        }
        if (--TimeOut == 0u) {
          r = 1;                          // Error, no data received.
          goto Done;
        }
      }
      //
      // Read data and store it to destination buffer.
      //
      if (NumBytesData < 4) {
        //
        // Read single bytes.
        //
        do {
          *pData++ = QUADSPI_DR_BYTE;
        } while (--NumBytesData);
      } else {
        //
        // Read 4 bytes at a time.
        //
        DataReg = QUADSPI_DR;
        *pData++ = (U8)DataReg;
        *pData++ = (U8)(DataReg >> 8);
        *pData++ = (U8)(DataReg >> 16);
        *pData++ = (U8)(DataReg >> 24);
        NumBytesData -= 4;
      }
    } while (NumBytesData);
  }
  //
  // Wait until the data transfer has been completed.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, transaction not completed.
      break;
    }
  }
Done:
  return r;
}

/*********************************************************************
*
*       _Write
*
*  Function description
*    Transfers data from MCU to NAND flash device.
*/
static int _Write(U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
                  unsigned NumBytesAddr, const U8 * pData, unsigned NumBytesData,
                  U16 BusWidth) {
  U32 AddrReg;
  U32 AltReg;
  U32 CfgReg;
  U32 DataMode;
  U32 AddrMode;
  U32 CmdMode;
  U32 DataReg;
  U32 AddrSize;
  U32 NumCyclesDummy;
  U32 NumBytes;
  U32 NumBytesDummy;
  U32 NumBytesFree;
  U32 TimeOut;
  int r;

  //
  // Initialize local variables.
  //
  r              = 0;
  AddrReg        = 0;
  AltReg         = 0;
  NumBytesDummy  = NumBytesPara - NumBytesAddr;
  CmdMode        = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), sizeof(Cmd));
  AddrMode       = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
  NumCyclesDummy = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesDummy, 0);    // The dummy bytes are sent using the address bus mode.
  DataMode       = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
  //
  // Encode the address.
  //
  if (NumBytesAddr) {
    NumBytes = NumBytesAddr;
    do {
      AddrReg <<= 8;
      AddrReg  |= (U32)(*pPara++);
    } while (--NumBytes);
  }
  AddrSize = 0;
  if (NumBytesAddr) {
    AddrSize = NumBytesAddr - 1;
  }
  CfgReg = 0
         | (CCR_FMODE_WRITE << CCR_FMODE_BIT)
         | (DataMode        << CCR_DMODE_BIT)
         | (NumCyclesDummy  << CCR_DCYC_BIT)
         | (AddrSize        << CCR_ADSIZE_BIT)
         | (AddrMode        << CCR_ADMODE_BIT)
         | (CmdMode         << CCR_IMODE_BIT)
         | (Cmd             << CCR_INTRUCTION_BIT)
         ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // Execute the command.
  //
  r = _ClearFlags();
  if (r != 0) {
    goto Done;
  }
  if (NumBytesData) {
    QUADSPI_DLR = NumBytesData - 1;       // 0 means "read 1 byte".
  }
  QUADSPI_ABR = AltReg;
  QUADSPI_CCR = CfgReg;
  if (NumBytesAddr) {
    QUADSPI_AR = AddrReg;
  }
  //
  // write data to NOR flash.
  //
  if (NumBytesData) {
    do {
      //
      // Wait for free space in FIFO.
      //
      TimeOut = WAIT_TIMEOUT_CYCLES;
      for (;;) {
        NumBytesFree = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
        NumBytesFree = NUM_BYTES_FIFO - NumBytesFree;
        if ((NumBytesFree >= 4) || (NumBytesFree >= NumBytesData)) {
          break;
        }
        if (--TimeOut == 0u) {
          r = 1;                          // Error, no free space in FIFO.
          goto Done;
        }
      }
      //
      // Get the data from source buffer and write it.
      //
      if (NumBytesData < 4) {
        //
        // Write single bytes.
        //
        do {
          QUADSPI_DR_BYTE = *pData++;
        } while (--NumBytesData);
      } else {
        //
        // Write 4 bytes at a time if possible.
        //
        DataReg  = (U32)*pData++;
        DataReg |= (U32)*pData++ << 8;
        DataReg |= (U32)*pData++ << 16;
        DataReg |= (U32)*pData++ << 24;
        NumBytesData -= 4;
        QUADSPI_DR = DataReg;
      }
    } while (NumBytesData);
  }
  //
  // Wait until the data transfer has been completed.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, transfer not completed.
      break;
    }
  }
Done:
  return r;
}

/*********************************************************************
*
*       _Delay
*
*  Function description
*    Blocks the execution for the specified number of milliseconds.
*/
static void _Delay(int ms) {
#if FS_NAND_HW_USE_OS
  if (ms) {
    FS_OS_Delay(ms);
  }
#else
  if (ms) {
    volatile U32 NumCycles;

    do {
      NumCycles = FS_NAND_HW_CYCLES_PER_MS;
      do {
        ;
      } while (--NumCycles);
    } while (--ms);
  }
#endif // FS_NAND_HW_USE_OS
}

#if FS_NAND_HW_USE_OS

/*********************************************************************
*
*       _Poll
*
*  Function description
*    Checks periodically the value of a status flag.
*
*  Parameters
*    Cmd            Code of the command to be sent. Cannot be NULL.
*    pPara          [IN] Command parameters (address and dummy bytes). Can be NULL.
*    NumBytesPara   Total number of address and dummy bytes to be sent. Can be 0.
*    NumBytesAddr   Number of address bytes to be send. Can be 0.
*    BitPos         Position of the bit to be checked.
*    BitValue       Value of the bit to wait for.
*    Delay          Number of clock cycles to wait between two queries.
*    TimeOut_ms     Maximum number of milliseconds to wait for the bit to be set.
*    BusWidth       Number of data lines to be used for the data transfer.
*
*  Return value
*    > 0    Timeout occurred.
*    ==0    OK, bit set to specified value.
*    < 0    Feature not supported.
*/
static int _Poll(U8 Cmd, const U8 * pPara, unsigned NumBytesPara, unsigned NumBytesAddr, U8 BitPos, U8 BitValue, U32 Delay, U32 TimeOut_ms, U16 BusWidth) {
  U32 CfgReg;
  U32 DataMode;
  U32 CmdMode;
  U32 NumBytes;
  U32 NumBytesData;
  U32 DataMask;
  U32 DataMatch;
  U32 AddrReg;
  U32 AltReg;
  U32 NumBytesDummy;
  U32 AddrMode;
  U32 AddrSize;
  U32 NumCyclesDummy;
  U32 TimeOut;
  int r;

  //
  // Initialize local variables.
  //
  r              = 0;
  AddrReg        = 0;
  AltReg         = 0;
  DataMask       = 1uL           << BitPos;
  DataMatch      = (U32)BitValue << BitPos;
  Delay        <<= 4;           // 16 clock cycles are required to transfer 2 bytes.
  NumBytesData   = 1;           // The response consists of only one byte.
  NumBytesDummy  = NumBytesPara - NumBytesAddr;
  //
  // Encode the address.
  //
  if (NumBytesAddr) {
    NumBytes = NumBytesAddr;
    do {
      AddrReg <<= 8;
      AddrReg  |= (U32)(*pPara++);
    } while (--NumBytes);
  }
  //
  // Calculate the number of data lines to be used for the transfer.
  //
  CmdMode        = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), sizeof(Cmd));
  AddrMode       = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
  NumCyclesDummy = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesDummy, 0);    // The dummy bytes are sent using the address bus mode.
  DataMode       = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
  //
  // Calculate the number of bytes in each command phase.
  //
  AddrSize = 0;
  if (NumBytesAddr) {
    AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
  }
  //
  // Configure the operation.
  //
  CfgReg = 0
         | (CCR_FMODE_POLL << CCR_FMODE_BIT)
         | (AddrMode       << CCR_ADMODE_BIT)
         | (AddrSize       << CCR_ADSIZE_BIT)
         | (DataMode       << CCR_DMODE_BIT)
         | (NumCyclesDummy << CCR_DCYC_BIT)
         | (CmdMode        << CCR_IMODE_BIT)
         | (Cmd            << CCR_INTRUCTION_BIT)
         ;
  //
  // Wait until the unit is ready for the new command.
  //
  TimeOut = WAIT_TIMEOUT_CYCLES;
  for (;;) {
    if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
      break;
    }
    if (--TimeOut == 0u) {
      r = 1;                              // Error, QUADSPI is not ready.
      goto Done;
    }
  }
  //
  // Start the poll operation. The end of operation is signaled by interrupt.
  //
  r = _ClearFlags();
  if (r != 0) {
    goto Done;                            // Error, could not clear status flags.
  }
  if (NumBytesData != 0) {
    QUADSPI_DLR = NumBytesData - 1;       // 0 means "read 1 byte".
  }
  QUADSPI_ABR   = AltReg;
  QUADSPI_PSMKR = DataMask;
  QUADSPI_PSMAR = DataMatch;
  QUADSPI_PIR   = Delay;
  QUADSPI_FCR   = 1uL << SR_SMF_BIT;
  QUADSPI_CCR   = CfgReg;
  if (NumBytesAddr != 0u) {
    QUADSPI_AR  = AddrReg;
  }
  r = FS_OS_Wait(TimeOut_ms);
  if (r != 0) {
    //
    // The timeout has expired. Cancel the poll operation.
    //
    (void)_Cancel();
    r = 1;                                // A timeout occurred.
  }
Done:
  return r;
}

#endif // FS_NAND_HW_USE_OS

/*********************************************************************
*
*       Static code (public via callback)
*
**********************************************************************
*/

/*********************************************************************
*
*       _HW_Init
*
*  Function description
*    Initializes the QSPI hardware.
*
*  Parameters
*    Unit           Device index (0-based)
*
*  Return value
*    Frequency of the QSPI clock in kHz.
*/
static int _HW_Init(U8 Unit) {
  int r;

  FS_USE_PARA(Unit);
  r = _Init();
  return r;
}

/*********************************************************************
*
*       _HW_Control
*
*  Function description
*    Executes a NAND flash command without data transfer.
*
*  Parameters
*    Unit           Device index (0-based)
*    Cmd            Code of the command to be sent.
*    BusWidth       Number of data lines to be used for sending
*                   the command code.
*
*  Return value
*    ==0    OK, command sent.
*    !=0    An error occurred.
*/
static int _HW_Control(U8 Unit, U8 Cmd, U8 BusWidth) {
  int r;

  ASSERT_IS_LOCKED();
  FS_USE_PARA(Unit);    // This device has only one HW unit.
  r = _Control(Cmd, BusWidth);
  return r;
}

/*********************************************************************
*
*       _HW_Read
*
*  Function description
*    Transfers data from NAND flash device to MCU.
*
*  Parameters
*    Unit           Device index (0-based)
*    Cmd            Code of the command to be sent.
*    pPara          Additional command parameters (can be NULL).
*    NumBytesPara   Number of additional bytes to be sent after command.
*                   Can be 0 if pPara is NULL.
*    NumBytesAddr   Number of address bytes to be sent.
*                   Can be 0 if pPara is NULL.
*    pData          Data received from the NAND flash device.
*    NumBytesData   Number of bytes to be received from the NAND flash device.
*    BusWidth       Specifies the number of data lines to be used
*                   during the data transfer.
*
*  Return value
*    ==0    OK, data transferred.
*    !=0    An error occurred.
*/
static int _HW_Read(U8 Unit, U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
                    unsigned NumBytesAddr, U8 * pData, unsigned NumBytesData,
                    U16 BusWidth) {
  int r;

  ASSERT_IS_LOCKED();
  FS_USE_PARA(Unit);    // This device has only one HW unit.
  r = _Read(&Cmd, sizeof(Cmd), pPara, NumBytesPara, NumBytesAddr, pData, NumBytesData, BusWidth, 0);
  return r;
}

/*********************************************************************
*
*       _HW_Write
*
*  Function description
*    Transfers data from MCU to NAND flash device.
*
*  Parameters
*    Unit           Device index (0-based)
*    Cmd            Code of the command to be sent.
*    pPara          Additional command parameters (can be NULL).
*    NumBytesPara   Number of additional bytes to be sent after command.
*                   Can be 0 if pPara is NULL.
*    NumBytesAddr   Number of address bytes to be sent.
*                   Can be 0 if pPara is NULL.
*    pData          Data to be sent to NAND flash device.
*    NumBytesData   Number of data bytes to be sent to NAND flash device.
*    BusWidth       Specifies the number of data lines to be used
*                   during the data transfer.
*
*  Return value
*    ==0    OK, data transferred.
*    !=0    An error occurred.
*/
static int _HW_Write(U8 Unit, U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
                     unsigned NumBytesAddr, const U8 * pData, unsigned NumBytesData,
                     U16 BusWidth) {
  int r;

  ASSERT_IS_LOCKED();
  FS_USE_PARA(Unit);    // This device has only one HW unit.
  r = _Write(Cmd, pPara, NumBytesPara, NumBytesAddr, pData, NumBytesData, BusWidth);
  return r;
}

/*********************************************************************
*
*       _HW_Delay
*
*  Function description
*    Blocks the execution for the specified number of milliseconds.
*
*  Parameters
*    Unit           Device index (0-based)
*    ms             Number of milliseconds to wait.
*
*  Additional information
*    This function is mandatory and it has to be implemented by any
*    hardware layer.
*/
static void _HW_Delay(U8 Unit, int ms) {
  FS_USE_PARA(Unit);
  _Delay(ms);
}

/*********************************************************************
*
*       _HW_Poll
*
*  Function description
*    Sends a command repeatedly and checks the response data
*    for a specified condition.
*
*  Parameters
*    Unit           Device index (0-based)
*    Cmd            Code of the command to be sent.
*    pPara          Additional command parameters (can be NULL).
*    NumBytesPara   Number of additional bytes to be sent after command.
*                   Can be 0 if pPara is NULL.
*    BitPos         Position of the bit inside response data that has
*                   to be checked (0-based, with 0 being LSB)
*    BitValue       Bit value to wait for.
*    Delay_ms       Time between two command executions.
*    TimeOut_ms     Maximum time to wait for the bit at BitPos to be set to BitValue.
*    BusWidth       Specifies how many data lines have to be used for sending
*                   the command and parameters and for reading the data.
*
*  Return value
*    > 0    Error, timeout occurred.
*    ==0    OK, bit set to specified value.
*    < 0    Error, feature not supported.
*/
static int _HW_Poll(U8 Unit, U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
                    U8 BitPos, U8 BitValue, U32 Delay_ms, U32 TimeOut_ms, U16 BusWidth) {
  int r;

  ASSERT_IS_LOCKED();
  FS_USE_PARA(Unit);    // This device has only one HW unit.
#if FS_NAND_HW_USE_OS
  r = _Poll(Cmd, pPara, NumBytesPara, NumBytesPara, BitPos, BitValue, Delay_ms, TimeOut_ms, BusWidth);
#else
  FS_USE_PARA(Cmd);
  FS_USE_PARA(pPara);
  FS_USE_PARA(NumBytesPara);
  FS_USE_PARA(BitPos);
  FS_USE_PARA(BitValue);
  FS_USE_PARA(Delay_ms);
  FS_USE_PARA(TimeOut_ms);
  FS_USE_PARA(BusWidth);
  r = -1;                 // Set to indicate that the feature is not supported.
#endif // FS_NAND_HW_USE_OS
  return r;
}

/*********************************************************************
*
*       _HW_ReadEx
*
*  Function description
*    Transfers data from serial NAND flash device to MCU.
*
*  Parameters
*    Unit           Index of the hardware layer (0-based).
*    pCmd           [IN] Code of the command to be sent. Cannot be NULL.
*    NumBytesCmd    Number of bytes in the command code. Cannot be 0.
*    pPara          [IN] Command parameters (address and dummy bytes). Can be NULL.
*    NumBytesPara   Total number of address and dummy bytes to be sent. Can be 0.
*    NumBytesAddr   Number of address bytes to be send. Can be 0.
*    pData          [OUT] Data read from the serial NOR flash device. Can be NULL.
*    NumBytesData   Number of bytes to read from the serial NOR flash device. Can be 0.
*    BusWidth       Number of data lines to be used for the data transfer.
*    Flags          Options for the data exchange.
*
*  Return value
*    ==0      OK, data transferred successfully.
*    !=0      An error occurred.
*/
static int _HW_ReadEx(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara, 
                      unsigned NumBytesPara, unsigned NumBytesAddr, U8 * pData, 
                      unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
  int r;

  ASSERT_IS_LOCKED();
  FS_USE_PARA(Unit);    // This device has only one HW unit.
  r = _Read(pCmd, NumBytesCmd, pPara, NumBytesPara, NumBytesAddr, pData, NumBytesData, BusWidth, Flags);
  return r;
}

/*********************************************************************
*
*       _HW_Lock
*
*  Function description
*    Requests exclusive access to SPI bus.
*
*  Parameters
*    Unit     Device index (0-based)
*
*  Additional information
*    This function is optional and it can be left unimplemented
*    or set to NULL in the structure of the hardware layer below.
*/
static void _HW_Lock(U8 Unit) {
  FS_USE_PARA(Unit);
  IF_TEST(_LockCnt++);
  ASSERT_IS_LOCKED();
}

/*********************************************************************
*
*       _HW_Unlock
*
*  Function description
*    Releases the exclusive access of SPI bus.
*
*  Parameters
*    Unit     Device index (0-based)
*
*  Additional information
*    This function is optional and it can be left unimplemented
*    or set to NULL in the structure of the hardware layer below.
*/
static void _HW_Unlock(U8 Unit) {
  FS_USE_PARA(Unit);
  ASSERT_IS_LOCKED();
  IF_TEST(_LockCnt--);
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

#if FS_NAND_HW_USE_OS

/*********************************************************************
*
*       QUADSPI_IRQHandler
*/
void QUADSPI_IRQHandler(void);
void QUADSPI_IRQHandler(void) {
#if (FS_NAND_HW_USE_OS == 1)
  OS_EnterNestableInterrupt();
#endif // FS_NOR_HW_USE_OS == 1
  QUADSPI_FCR = 1uL << SR_SMF_BIT;    // Prevent other interrupts from occurring.
  FS_OS_Signal();
#if (FS_NAND_HW_USE_OS == 1)
  OS_LeaveNestableInterrupt();
#endif // FS_NAND_HW_USE_OS == 1
}

#endif // FS_NOR_HW_USE_OS

/*********************************************************************
*
*       Public const
*
**********************************************************************
*/

/*********************************************************************
*
*       FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator
*/
const FS_NAND_HW_TYPE_QSPI FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator = {
  _HW_Init,
  _HW_Control,
  _HW_Read,
  _HW_Write,
  _HW_Poll,
  _HW_Delay,
  _HW_Lock,
  _HW_Unlock,
  _HW_ReadEx
};

/*************************** End of file ****************************/
Hardware layer API - FS_NAND_HW_TYPE_SPI

This hardware layer supports any serial NAND flash device with a standard SPI. It is used by the FS_NAND_PHY_SPI physical layer to exchange data with a NAND flash device that supports such an interface. Typically, the implementation of FS_NAND_HW_TYPE_SPI hardware layer makes use of a SPI controller. It is also possible to implement the data exchange via GPIO pins.

The functions of this hardware layer are grouped in the structure of type FS_NAND_HW_TYPE_SPI. The following sections describe these functions in detail.

FS_NAND_HW_TYPE_SPI

Description

NAND hardware layer API for NAND flash devices connected via SPI.

Type definition

typedef struct {
  FS_NAND_HW_TYPE_SPI_INIT       * pfInit;
  FS_NAND_HW_TYPE_SPI_DISABLE_CS * pfDisableCS;
  FS_NAND_HW_TYPE_SPI_ENABLE_CS  * pfEnableCS;
  FS_NAND_HW_TYPE_SPI_DELAY      * pfDelay;
  FS_NAND_HW_TYPE_SPI_READ       * pfRead;
  FS_NAND_HW_TYPE_SPI_WRITE      * pfWrite;
  FS_NAND_HW_TYPE_SPI_LOCK       * pfLock;
  FS_NAND_HW_TYPE_SPI_UNLOCK     * pfUnlock;
} FS_NAND_HW_TYPE_SPI;

Structure members

Member Description
pfInit Initializes the hardware.
pfDisableCS Disables the NAND flash device.
pfEnableCS Enables the NAND flash device.
pfDelay Block the execution for a specified number of milliseconds.
pfRead Transfers a specified number of bytes from NAND flash device to MCU.
pfWrite Transfers a specified number of bytes from MCU to NAND flash device.
pfLock Request exclusive access to SPI bus.
pfUnlock Releases the exclusive access to SPI bus.
FS_NAND_HW_TYPE_SPI_INIT

Description

Initializes the hardware.

Type definition

typedef int FS_NAND_HW_TYPE_SPI_INIT(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Return value

≠ 0 OK, frequency of the SPI clock in kHz.
= 0 An error occurred.

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type. FS_NAND_HW_TYPE_SPI_INIT is the first function of the hardware layer API that is called by a NAND physical layer during the mounting of the file system.

This function has to perform any initialization of the MCU hardware required to access the NAND flash device such as clocks, port pins, SPI controllers, etc.

A serial NAND flash requires that the SPI communication protocol meets the following requirements:

Typically, two SPI modes are supported:

FS_NAND_HW_TYPE_SPI_DISABLE_CS

Description

Disables the NAND flash device.

Type definition

typedef void FS_NAND_HW_TYPE_SPI_DISABLE_CS(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The NAND flash device is disabled by driving the Chip Select (CS) signal to logic-high. The NAND flash device ignores any command or data sent with the CS signal set to logic-high.

FS_NAND_HW_TYPE_SPI_ENABLE_CS

Description

Enables the NAND flash device.

Type definition

typedef void FS_NAND_HW_TYPE_SPI_ENABLE_CS(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The NAND flash device is enabled by driving the Chip Select (CS) signal to logic low state. Typically, the NAND flash device is enabled at the beginning of command and data sequence and disabled at the end of it.

FS_NAND_HW_TYPE_SPI_DELAY

Description

Blocks the execution for the specified number of milliseconds.

Type definition

typedef void FS_NAND_HW_TYPE_SPI_DELAY(U8  Unit,
                                       int ms);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
ms Number of milliseconds to wait.

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The time FS_NAND_HW_TYPE_SPI_DELAY blocks does not have to be accurate. That is the function can block the execution longer that the number of specified milliseconds but no less than that.

FS_NAND_HW_TYPE_SPI_READ

Description

Transfers a specified number of bytes from NAND flash device to MCU.

Type definition

typedef int FS_NAND_HW_TYPE_SPI_READ(U8       Unit,
                                     void   * pData,
                                     unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData Data read from NAND flash device.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The function has to sample the data on the falling edge of the SPI clock.

FS_NAND_HW_TYPE_SPI_WRITE

Description

Transfers a specified number of bytes from MCU to NAND flash device.

Type definition

typedef int FS_NAND_HW_TYPE_SPI_WRITE(      U8       Unit,
                                      const void   * pData,
                                            unsigned NumBytes);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)
pData  in  Data to be written to NAND flash device.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written successfully.
≠ 0 An error occurred.

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. It is mandatory to be implemented by all the NAND hardware layers of this type.

The NAND flash device samples the data on the rising edge of the SPI clock.

FS_NAND_HW_TYPE_SPI_LOCK

Description

Requests exclusive access to SPI bus.

Type definition

typedef void FS_NAND_HW_TYPE_SPI_LOCK(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. The implementation of this function is optional.

The FS_NAND_PHY_SPI physical layer calls this function to indicate that it needs exclusive to access the serial NAND flash device via the SPI bus. It is guaranteed that the FS_NAND_PHY_SPI physical layer does not attempt to exchange any data with the serial NAND flash device via the SPI bus before calling this function first. It is also guaranteed that FS_NAND_HW_TYPE_SPI_LOCK and FS_NAND_HW_TYPE_SPI_UNLOCK are called in pairs. Typically, this function is used for synchronizing the access to SPI bus when the SPI bus is shared between the serial NAND flash and other SPI devices.

A possible implementation would make use of an OS semaphore that is acquired in FS_NAND_HW_TYPE_SPI_LOCK and released in FS_NAND_HW_TYPE_SPI_UNLOCK.

FS_NAND_HW_TYPE_SPI_UNLOCK

Description

Releases the exclusive access of SPI bus.

Type definition

typedef void FS_NAND_HW_TYPE_SPI_UNLOCK(U8 Unit);

Parameters

Parameter Description
Unit Index of the NAND hardware layer instance (0-based)

Additional information

This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware layer API. The implementation of this function is optional.

The FS_NAND_PHY_SPI physical layer calls this function after it no longer needs to access the serial NAND flash device via the SPI bus. It is guaranteed that the FS_NAND_PHY_SPI physical layer does not attempt to exchange any data with the serial NAND flash device via the SPI bus before calling FS_NAND_HW_TYPE_SPI_LOCK. It is also guaranteed that FS_NAND_HW_TYPE_SPI_UNLOCK and FS_NAND_HW_TYPE_SPI_LOCK are called in pairs.

FS_NAND_HW_TYPE_SPI_UNLOCK and FS_NAND_HW_TYPE_SPI_LOCK can be used to synchronize the access to the SPI bus when other devices than the serial NAND flash are connected to it. A possible implementation would make use of an OS semaphore that is acquired FS_NAND_HW_TYPE_SPI_LOCK and released in FS_NAND_HW_TYPE_SPI_UNLOCK.

Test hardware

The SEGGER NAND-Flash EVAL board is an easy to use and cost effective testing tool designed to evaluate the features and the performance of the emFile NAND driver. The NAND driver can be used with emFile or emUSB-Device, in which case the board behaves like a mass storage device (USB drive). Common evaluation boards are usually used to perform these tests but this approach brings several disadvantages. Software and hardware development tools are required to build and load the application into the target system. Moreover, the tests are restricted to the type of NAND flash which is soldered on the board. The NAND-Flash EVAL board was designed to overcome these limitations and provides the user with an affordable alternative. The main feature is that the NAND flash is not directly soldered on the board. A 48-pin TSOP socket is used instead which allows the user to experiment with different types of NAND flashes. This helps finding the right NAND flash for an application and thus reducing costs. A further important feature is that the NAND-Flash EVAL board comes preloaded with a USB-MSD application. When connected to a PC over USB, the board shows up as a removable storage on the host operating system. Performance and functionality tests of NAND flash can thus be performed without the need of an expensive development environment. All current operating systems will recognize the board out of the box.

The NAND-Flash EVAL board comes with a ready to use USB-MSD application in binary form. emFile is provided in object code{c} form together with a start project which can be easily modified to create custom applications. For programming and debugging a JTAG debug probe like J-Link is required. The package also contains the schematics of the board.

NAND-Flash EVAL

Feature list

FAQs

NOR flash driver

General information

emFile supports the use of unmanaged NOR flash devices as data storage. Two drivers for NOR flash devices also known as flash translation layers are provided:

Software structure

The NOR drivers are organized into different layers that contain from top to bottom:

A hardware layer is required only for serial NOR flash devices. Typically, CFI compliant NOR flash device is mapped into the system memory of the MCU and can be accessed directly without a hardware layer. Normally no changes to the physical layer are required. If the physical layer needs to be adapted, a template is provided.

Garbage collection

The driver performs the garbage collection automatically during the write operations. If no empty logical sectors are available to store the data, new empty logical sectors are created by erasing the data of the logical sectors marked as invalid. This involves a NOR physical sector erase operation which, depending on the characteristics of the NOR flash, can potentially take a long time to complete, and therefor reduces the write performance. For applications which require maximum write throughput, the garbage collection can be done in the application. Typically, this operation can be performed when the file system is idle. Two API functions are provided: FS_STORAGE_Clean() and FS_STORAGE_CleanOne(). They can be called directly from the task which is performing the write or from a background task. The FS_STORAGE_Clean() function blocks until all the invalid logical sectors are converted to free logical sectors. A write operation following the call to this function runs at maximum speed. The other function, FS_STORAGE_CleanOne(), converts the invalid sectors of a single physical sector. Depending on the number of invalid logical sectors, several calls to this function are required to clean up the entire storage device.

Fail-safe operation

The operation of emFile NOR driver is fail-safe. This means that the driver performs only atomic operations in order to make sure that the stored data is always valid after a unexpected power failure that interrupts a write operation. If the unexpected power failure interrupts the write operation, then the old version of the modified data is preserved.

The fail-safe operation is only guaranteed if the NOR flash device is able to fully complete the last write operation that it receives from the file system before the unexpected power failure. This means that the supply voltage of the NOR flash device has to remain valid for a sufficiently long time after the MCU enters reset (typically few hundreds of microseconds) to allow the NOR flash device to complete that write operation. The exact timing can be taken from the data sheet of the NOR flash device.

The number of bytes written by the NOR driver in one write operation varies between the value configured via FS_NOR_LINE_SIZE and the page size of the NOR flash device. Not all the data the NOR driver writes to the storage is critical. Non-critical write operations can be interrupted by an unexpected power failure without negatively affecting the fail-safe operation. The critical data is always stored as a write operation containing FS_NOR_LINE_SIZE bytes. This type of write operations have to be completed by the NOR flash device and cannot be interrupted.

The erase operation of a NOR flash sector can be interrupted by an unexpected power failure because the NOR driver is able determine at low-level mount which NOR flash sector was not completely erased. The incompletely erased NOR flash sectors will be erased again when required.

The above requirements for the write operation do not apply for configurations that use the Block Map NOR driver with the CRC verification enabled because in this configuration the file system is able to determine and discard incomplete write operations at low-level mount. However, the retention time of the data written during the interrupted operation can no longer be guaranteed.

Wear leveling

Wear leveling is supported by both NOR drivers. The wear leveling procedure makes sure that the number of erase cycles remains approximately equal for each physical sector. This works by keeping track of the index of the last erased physical sector. When a new erased physical sector is required to store data then the first free physical sector with an index greater than the last one is selected. The index of the physical sector wraps around when the end of the NOR flash device is reached. In addition, the wear leveling procedure keeps a count of the number of times each physical sector has been erased called erase count that is stored on the NOR flash device. The erase count is used to make sure that physical sectors that store data that is rarely modified are also equally erased. For this purpose the wear leveling procedure calculates the difference between the erase counts of the selected physical sector and of the physical sector with the smallest erase count. If the calculated difference is greater than the value specified via FS_NOR_MAX_ERASE_CNT_DIFF or FS_NOR_BM_SetMaxEraseCntDiff() then the physical sector with the smaller erase count is used instead.

Low-level format

Before using a NOR flash device for the first time, the application has to initialize it by performing a low-level format operation on it. Refer to FS_FormatLow() and FS_FormatLLIfRequired() for detailed information about this.

CRC verification

The integrity of the data stored to a NOR flash device using the Block Map NOR driver can be increased by enabling the CRC verification feature. With the CRC verification feature enabled the Block Map NOR driver calculates a checksum of payload and management data that is written to NOR flash device using a CRC (Cyclic Redundancy Check) algorithm. The calculated checksum is stored together with the payload and management data to NOR flash device. Each time the Block Map NOR driver reads some data from the NOR flash device it also calculates the checksum of it using the same algorithm. The calculated checksum is then compared with the checksum read from NOR flash device and if a mismatch occurs an error is reported to the application via the return value of the called API function as well as via the callback registered using FS_NOR_BM_SetOnFatalErrorCallback(). Depending on what data was exactly damaged an error recovery may be possible or not. The application may try to repair the damaged data by running a disk checking operation via FS_CheckDisk(). The CRC verification is disabled by default and has to be enabled at compile time as well as at runtime. FS_NOR_SUPPORT_CRC has to be set to 1 in order to enable the support for CRC verification at compile time. At runtime FS_NOR_BM_EnableCRC() has to be called in FS_X_AddDevices() to activate the CRC verification feature. By default, the Block Map NOR driver uses the internal CRC calculation routines of the file system but the application can register its own CRC calculation routines via FS_NOR_BM_SetCRCHook().

Bit error correction

The integrity of the data stored to a NOR flash device using the Block Map NOR driver can be increased by enabling the bit error correction. With the bit error correction feature enabled the Block Map NOR driver calculates a parity check of payload and management data that is written to NOR flash device using an error correction algorithm. The calculated parity check is stored together with the payload and management data to NOR flash device. Each time the Block Map NOR driver reads some data from the NOR flash device it uses the same error correction algorithm and read parity check to verify if any bit errors occurred and if so to correct them. If the algorithm is not able to correct the bit errors than an error is reported to the application via the return value of the called API function as well as via the callback registered using FS_NOR_BM_SetOnFatalErrorCallback(). Depending on what data was exactly damaged an error recovery may be possible or not. The application may try to repair the damaged data by running a disk checking operation via FS_CheckDisk(). The bit error correction is disabled by default and has to be enabled at compile time as well as at runtime. FS_NOR_SUPPORT_ECC has to be set to 1 in order to enable the support for bit error correction at compile time. At runtime FS_NOR_BM_EnableECC() has to be called in FS_X_AddDevices() to activate the bit error correction feature. By default, the Block Map NOR driver uses an error correction algorithm that is able to correct 1 bit error and to detect 2 bit errors in the management and payload data of the file system but the application can register its own bit error correction routines via FS_NOR_BM_SetECCHook().

Supported hardware

The NOR flash drivers can be used with almost any NOR flash device. This includes NOR flash device with 8-bit and 16-bit parallel interfaces, as well as two 16-bit interfaces in parallel. Serial NOR flash devices are also supported. A NOR flash device has to meet the following requirements:

In order to provide the best write performance, the NOR drivers make use of a NOR flash device feature that permits the same location to be modified multiple times without an erase operation in between, as long as only bits set to 1 are changed to 0. For NOR flash devices that do not support this feature, the NOR drivers have to be compiled with the configuration define FS_NOR_CAN_REWRITE set to 0.

In general, the NOR drivers support almost all serial and parallel NOR flashes which meet the listed requirements. In addition, the NOR drivers can use the internal flash memory of a MCU as storage device.

The following table shows the serial NOR flash devices that were tested by SEGGER or are known to be compatible with a tested device.

Device name Storage capacity Device type Supported extra features
Cypress/Spansion
S25FL032P 32 Mibit SPI extended SPI
S25FL064L 64 Mibit SPI extended SPI
S25FL064P 64 Mibit SPI extended SPI
S25FL127S 128 Mibit SPI extended SPI
S25FL128L 128 Mibit SPI extended SPI
S25FL128S 128 Mibit SPI extended SPI
S25FL129P 128 Mibit SPI extended SPI
S25FL132K 32 Mibit SPI extended SPI
S25FL164K 64 Mibit SPI extended SPI
S25FL256L 256 Mibit SPI extended SPI
S25FL256S 256 Mibit SPI extended SPI
S25FL512S 512 Mibit SPI extended SPI
S25FS128S 128 Mibit SPI extended SPI
S25FS256S 256 Mibit SPI extended SPI
S25FS512S 512 Mibit SPI extended SPI
S26KL512S 512 Mibit HyperBus write buffer
S29GL064N 64 Mibit CFI write buffer
S70FL01GS 1 Gibit SPI extended SPI
S70FL256P 256 Mibit CFI extended SPI
Dialog Semiconductor/Adesto/Atmel
AT25SF128A 128 Mibit SPI extended SPI
AT25SL321 32 Mibit SPI extended SPI
AT25XE041D 4 Mibit SPI extended SPI
AT25XE081D 8 Mibit SPI extended SPI
AT25XE321D 32 Mibit SPI extended SPI
Eon
EN25QH128A 128 Mibit SPI extended SPI
EN25QX64A 64 Mibit SPI extended SPI
GigaDevice
GD25LQ128D 128 Mibit SPI extended SPI
GD25LQ128E 128 Mibit SPI extended SPI
GD25LQ16C 16 Mibit SPI extended SPI
GD25Q127C 128 Mibit SPI extended SPI
GD25Q16B 16 Mibit SPI extended SPI
GD25Q16C 16 Mibit SPI extended SPI
GD25Q256D 256 Mibit SPI extended SPI
GD25Q32C 32 Mibit SPI extended SPI
GD25Q32E 32 Mibit SPI extended SPI
GD25Q64C 64 Mibit SPI extended SPI
GD25Q64E 64 Mibit SPI extended SPI
ISSI
IS25LP01G 1 Gibit SPI extended SPI
IS25LP032D 32 Mibit SPI extended SPI
IS25LP064A 64 Mibit SPI extended SPI
IS25LP128 128 Mibit SPI extended SPI
IS25LP128F 128 Mibit SPI extended SPI
IS25LP256D 256 Mibit SPI extended SPI
IS25LP256E 256 Mibit SPI extended SPI
IS25LP512M 512 Mibit SPI extended SPI
IS25LQ016B 16 Mibit SPI extended SPI
IS25LQ032B 32 Mibit SPI extended SPI
IS25LQ080 8 Mibit SPI extended SPI
IS25LQ080B 8 Mibit SPI extended SPI
IS25WP01G 1 Gibit SPI extended SPI
IS25WP064A 64 Mibit SPI extended SPI
IS25WP256D 256 Mibit SPI extended SPI
Infineon
S25HL512T 512 Mibit SPI extended SPI
S25HS01GT 1 Gibit SPI extended SPI
Macronix
MX25L12835F 128 Mibit SPI extended SPI
MX25L25635F 256 Mibit SPI extended SPI
MX25L25645G 256 Mibit SPI extended SPI
MX25L3233F 32 Mibit SPI extended SPI
MX25L3235E 32 Mibit SPI extended SPI
MX25L51245G 512 Mibit SPI extended SPI
MX25L6433F 64 Mibit SPI extended SPI
MX25L8035E 8 Mibit SPI extended SPI
MX25LM51245G 512 Mibit SPI OPI STR, OPI DTR
MX25R3235F 32 Mibit SPI extended SPI
MX25R6435F 64 Mibit SPI extended SPI
MX25U256 256 Mibit SPI extended SPI
MX25UM51245G 512 Mibit SPI OPI STR, OPI DTR
MX25V1635F 16 Mibit SPI extended SPI
MX66L1G45G 1 Gibit SPI extended SPI
MX66L2G45G 2 Gibit SPI extended SPI
MX66L51235F 512 Mibit SPI extended SPI
MX66U2G45G 2 Gibit SPI extended SPI
Microchip
SST25VF016B 16 Mibit SPI
SST26VF016B 16 Mibit SPI extended SPI
SST26VF032B 32 Mibit SPI extended SPI
SST26VF032BA 32 Mibit SPI extended SPI
SST26VF064B 64 Mibit SPI extended SPI
Micron
M25P128 128 Mibit SPI
M25P16 16 Mibit SPI
M25P32 32 Mibit SPI
M25P40 4 Mibit SPI
M25P64 64 Mibit SPI
M25P80 8 Mibit SPI
M25PX16 16 Mibit SPI
M28F256 256 Kibit CFI
M28W160 16 Mibit CFI
M28W320 32 Mibit CFI
M28W640 64 Mibit CFI
M29F080 8 Mibit CFI
M29W128GL 128 Mibit CFI
M29W160 16 Mibit CFI
M29W320 32 Mibit CFI
M29W640 64 Mibit CFI
M58LW064 64 Mibit CFI
MT25QL01GBB 1 Gibit SPI extended SPI
MT25QL02GC 2 Gibit SPI extended SPI
MT25QL128ABA 128 Mibit SPI extended SPI
MT25QL256ABA 256 Mibit SPI extended SPI
MT25QL512ABB 512 Mibit SPI extended SPI
MT25QU01GAB 1 Gibit SPI extended SPI
MT25QU02GAB 2 Gibit SPI extended SPI
MT25QU128ABA 128 Mibit SPI extended SPI
MT25TL01GHBB 1 Gibit SPI extended SPI
MT28F128 128 Mibit CFI
MT28F320 32 Mibit CFI
MT28F640 64 Mibit CFI
N25Q00AA 1 Gibit SPI extended SPI
N25Q032A 32 Mibit SPI extended SPI
N25Q064 64 Mibit SPI extended SPI
N25Q064A 64 Mibit SPI extended SPI
N25Q128A 128 Mibit SPI extended SPI
N25Q256 256 Mibit SPI extended SPI
N25Q256A 256 Mibit SPI extended SPI
N25Q512A 512 Mibit SPI extended SPI
TE28F128P30B85 128 Mibit CFI
TE28F128P33B85 128 Mibit CFI
TE28F256P30B95 256 Mibit CFI
TE28F256P33B95 256 Mibit CFI
TE28F640P30B85 64 Mibit CFI
TE28F640P33B85 64 Mibit CFI
STMicroelectronics
M95P08 8 Mibit SPI extended SPI
M95P16 16 Mibit SPI extended SPI
M95P32 32 Mibit SPI extended SPI
Winbond
W25Q01JV 1 Gibit SPI extended SPI
W25Q02JV 2 Gibit SPI extended SPI, DTR
W25Q128FW 128 Mibit SPI extended SPI
W25Q128JV 128 Mibit SPI extended SPI
W25Q16DV 16 Mibit SPI extended SPI
W25Q16JV 16 Mibit SPI extended SPI
W25Q256JV 256 Mibit SPI extended SPI
W25Q256JW 256 Mibit SPI extended SPI
W25Q32JV 32 Mibit SPI extended SPI
W25Q512JV 512 Mibit SPI extended SPI, DTR
W25Q64FV 64 Mibit SPI extended SPI
W25Q64FW 64 Mibit SPI extended SPI
W25Q64JV 64 Mibit SPI extended SPI
W25Q80DV 8 Mibit SPI extended SPI
W25Q80EW 8 Mibit SPI extended SPI

Support for devices not available in this list

Most other NOR flash devices are compatible with one of the supported devices. Thus the driver can be used with these devices or may only need a little modification, which can easily be done. Get in touch with us if you have questions about support for devices not in this list.

Using the same NOR flash device for code and data

Most NOR flash device cannot be read out during a program or erase operation. This means that the CPU cannot execute code from the NOR flash device while the NOR flash device is busy performing a program or erase operation. A program crash is almost certain if the CPU tries to execute code in this case.

There are multiple options to solve this problem:

Interfacing with a NOR flash device

The most common setup is a CFI compliant NOR flash device with a 16-bit interface. The picture below shows how this can be realized.

NOR physical interface

In addition to this, emFile supports the use of two CFI compliant NOR flash devices with a 16-bit interface which are connected to the same address bus as illustrated in the picture below.

Dual NOR physical interface

Common flash interface (CFI)

The NOR flash drivers can be used with any CFI-compliant 16-bit device. CFI is an open specification which may be implemented freely by flash memory vendors in their devices. It was developed jointly by Intel, AMD, Sharp, and Fujitsu. The idea behind CFI was the interchangeability of current and future flash memory devices offered by different vendors. If you use only CFI compliant flash memory device, you are able to use one driver for different flash products by reading identifying information out of the flash device itself. The identifying information for the device, such as memory size, byte/word configuration, block configuration, necessary voltages, and timing information, is stored directly on the device. For more technical details about CFI (Common Flash Interface) and SFDP (Serial Flash Discoverable Parameters), check the documents and specifications that are available free of charge at https://www.jedec.org

Sector Map NOR driver

This section describes the NOR driver that was optimized for increased write performance. The Sector Map NOR driver works by mapping single logical sectors to locations on the NOR flash device.

Theory of operation

Differentiating between logical sectors or blocks and physical sectors is essential to understand this section. A logical sector/block s the smallest readable and writable unit of any file system and its usual size is 512 bytes. A physical sector is an array of bytes on the NOR flash device that are erased together (typically between 2 Kbytes - 128 Kbytes). The Sector Map NOR driver is an abstraction layer between these two types of sectors.

Every time a logical sector is being updated, it is marked as invalid and the new content of this sector is written into another area of the flash. The physical address and the order of physical sectors can change with every write access. Hence, a direct relation between the sector number and its physical location cannot exist. The flash driver manages the logical sector numbers by writing it into special headers. To the upper layer, it does not matter were the logical sector is stored or how much flash memory is used as a buffer. All logical sectors (starting with sector 0) always exist and are always available for user access.

Configuring the driver

This section describes how to configure the file system to make use of the Sector Map NOR driver.

Compile time configuration

The Sector Map NOR driver can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The compile time configuration is realized via preprocessor defines that have to be added to the FS_Conf.h file which is the main configuration file of emFile. For detailed information about the configuration of emFile and of the configuration define types, refer to Configuration of emFile The following table lists the configuration defines supported by the Sector Map NOR driver.

Define Default value Type Description
FS_NOR_CAN_REWRITE 1 B Indicates if modifying the same byte on the NOR flash device more than one time is permitted.
FS_NOR_ENABLE_STATS 0 or 1 B Enables or disables the support for statistical counters.
FS_NOR_LINE_SIZE 1 N Number of bytes in a write unit.
FS_NOR_MAX_ERASE_CNT 500000 N Configures the maximum value of a valid erase count.
FS_NOR_MAX_ERASE_CNT_DIFF 5000 N Configures the default maximum difference between erase counts.
FS_NOR_MAX_NUM_SECTOR_SIZES 11 N Configures the maximum number of different sector sizes that the driver supports.
FS_NOR_MIN_SECTOR_SIZE_SHIFT 8 N Configures the minimum size of a supported physical sector size.
FS_NOR_NUM_FREE_SECTORCACHE 100 N Configures the default capacity of the list that stores the indexes of free sectors.
FS_NOR_NUM_UNITS 4 N Maximum number of driver instances.
FS_NOR_OPTIMIZE_DIRTY_CHECK 1 B Enables or disables the optimization for the blank checking of logical sectors.
FS_NOR_OPTIMIZE_HEADER_WRITE 0 B Enables or disables the optimization for the writing of management data.
FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST 1 B Enables or disables the optimization for the physical sector size management.
FS_NOR_READ_BUFFER_FILL_PATTERN 0xFF N Configures a bit pattern to be used for filling the contents of invalid logical sectors.
FS_NOR_SKIP_BLANK_SECTORS 1 B Enables or disables the support for erasing blank physical sectors at low-level format.
FS_NOR_SUPPORT_CLEAN 1 B Enables or disables the support for executing the garbage collection in the application.
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE 0 B Enables or disables the support for configuring at runtime the minimum number of bytes to be written at once.
FS_NOR_VERIFY_WRITE 0 B Reads back and compares the sector data to check if the write operation was successful.
FS_NOR_VERIFY_ERASE 0 B Reads back and compares the sector data to check it the erase operation was successful.
FS_NOR_CAN_REWRITE

For the majority of NOR flash device the same byte can be modified more than once without a erase operation in between while preserving the bits set to 0. That is a byte can be written up to eight times with each write operation setting a different bit in that byte to 0. The Sector Map NOR driver makes use of this feature to make efficient use of the storage space and to improve the performance. FS_NOR_CAN_REWRITE has to be set to 0 for NOR flash devices that permit only one write operation to a byte or a range of bytes between two erase operations of that storage block.

FS_NOR_ENABLE_STATS

This define can be used to enable the support for statistical counters. The statistical counters provide information about the number of operations performed internally by the Sector Map NOR driver that can be useful for debugging. The statistical counters can be queried via FS_NOR_GetStatCounters(). By default FS_NOR_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NOR_LINE_SIZE

FS_NOR_LINE_SIZE specifies the minimum number of bytes the Sector Map NOR driver writes at once. The amount of data written is always a multiple of this value. In addition, FS_NOR_LINE_SIZE specifies the alignment of the written data. That is the offset at which the Sector Map NOR driver writes the data is always a multiple of this value. FS_NOR_LINE_SIZE has to be a power of two value.

FS_NOR_MAX_ERASE_CNT

The Sector Map NOR driver uses the value of FS_NOR_MAX_ERASE_CNT to check the validity of an erase count stored in the header of a physical sector. If the value of the erase count is larger than FS_NOR_MAX_ERASE_CNT then the erase count is considered invalid and is set to the maximum value of all valid erase counts.

FS_NOR_MAX_ERASE_CNT_DIFF

The value of this define is used by the Sector Map NOR driver during the wear leveling procedure to decide which physical sector has to be used for storage. FS_NOR_SetMaxEraseCntDiff() can be used to modify this value at runtime. Refer to Wear Leveling for more information about how this value is used.

FS_NOR_MAX_NUM_SECTOR_SIZES

FS_NOR_MAX_NUM_SECTOR_SIZES can be used to specify how many different physical sector sizes the Sector Map NOR driver is able to use as data storage. If FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST is set to 1 then the supported sector sizes depend on the value of FS_NOR_MIN_SECTOR_SIZE_SHIFT. More exactly the Sector Map NOR driver is able to use as storage any physical sector with a size between 2FS_NOR_MIN_SECTOR_SIZE_SHIFT and 2(FS_NOR_MIN_SECTOR_SIZE_SHIFT + FS_NOR_MAX_NUM_SECTOR_SIZES - 1) that is a power of two value. With FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST set to 0 up to FS_NOR_MAX_NUM_SECTOR_SIZES physical sectors of arbitrary sizes are supported.

FS_NOR_MIN_SECTOR_SIZE_SHIFT

FS_NOR_MIN_SECTOR_SIZE_SHIFT can be used to specify the minimum size of a physical sector that is supported by the Sector Map NOR driver. The physical sector size is specified as a power of two exponent. This configuration define takes effect only when FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST is set to 1. For example, a value of 8 indicates that the minimum size of a physical sector is 28 = 256 bytes.

FS_NOR_NUM_FREE_SECTORCACHE

FS_NOR_NUM_FREE_SECTORCACHE can be used to specify the maximum number of physical sector indexes that an instance of the Sector Map NOR driver can remember as being ready to store data. Each entry of this list occupies 4 bytes. Increasing the capacity of the list can help increase the performance of the write operation at the cost of increased RAM usage.

FS_NOR_NUM_UNITS

This define specifies the maximum number of driver instances of the Sector Map NOR driver the application is allowed create. Four bytes of static RAM are reserved for each instance. If the maximum number of driver instances is smaller than the default then FS_NOR_NUM_UNITS can be set to the to that value in order to reduce the RAM usage.

FS_NOR_OPTIMIZE_DIRTY_CHECK

This define can be used to enable a speed optimization related to the check performed by the the Sector Map NOR driver to determine if a logical sector is blank or not. With FS_NOR_OPTIMIZE_DIRTY_CHECK set to 1 the Sector Map NOR driver remembers which physical sectors were already checked so that the blank checking operation can be skipped. Activating this feature can help improve the write performance at the cost of increased RAM usage. The Sector Map NOR driver requires 1 bit of RAM for each physical sector used as storage.

FS_NOR_OPTIMIZE_HEADER_WRITE

FS_NOR_OPTIMIZE_HEADER_WRITE can be used to specify how the management data is written to storage. The management data is stored at the beginning of each physical and logical sector in an area called header. By default, the size of the physical sector header is 16 bytes and of the logical sector header is 8 bytes. The size of these headers is larger for NOR flash devices that specify a minimum number of bytes that have to be written at once and that are not able to perform incremental write operations. The default behavior of the Sector Map NOR driver, that is when FS_NOR_OPTIMIZE_HEADER_WRITE is set to 0, is to write the entire header every time some of the information stored in it changes. With FS_NOR_OPTIMIZE_HEADER_WRITE set to 1 the Sector Map NOR driver tracks the changes made to a header and writes only the information that actually changed. Reducing the amount of data written to storage can help increase the write performance. The internal flash memory of some MCUs do not allow a second write operation to the same byte with identical data without an erase operation in between. If this type of flash memory is used as storage then it is mandatory to set FS_NOR_OPTIMIZE_HEADER_WRITE to 1.

FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST

The Sector Map NOR driver keeps track of the size of physical sectors it uses as storage. FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST can be used to configure how this list is managed. With FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST set to 1 the Sector Map NOR driver takes advantage of the fact that the size of a physical sector is typically a power of two value to keep the RAM usage to a minimum. If any of the physical sectors used as storage has a size that is not a power of two value then FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST will have to be set to 0. With FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST set to 0 the RAM usage of the Sector Map NOR driver increases by FS_NOR_MAX_NUM_SECTOR_SIZES * 4 per driver instance.

FS_NOR_READ_BUFFER_FILL_PATTERN

The value of FS_NOR_READ_BUFFER_FILL_PATTERN is used by the Sector Map NOR driver to fill the contents of invalid logical sectors that is logical sectors that were not written yet. The contents of all logical sectors is invalid after a low-level format operation. In addition, the contents of a logical sector can be invalidated via FS_STORAGE_FreeSectors().

FS_NOR_SKIP_BLANK_SECTORS

FS_NOR_SKIP_BLANK_SECTORS can be used to enable the support for the optimization that omits the erase of physical sectors that are already blank. This feature has to be explicitly enabled a runtime by calling FS_NOR_BM_SetBlankSectorSkip().

FS_NOR_SUPPORT_CLEAN

This define specifies if the application is allowed to perform a garbage collection operation. If FS_NOR_SUPPORT_CLEAN is set to 1 then the application can perform a garbage collection operation via FS_STORAGE_Clean() and FS_STORAGE_CleanOne(). For more information about the garbage collection refer to Garbage collection. The automatic garbage collection operation performed by the Sector Map NOR driver is not disabled when FS_NOR_SUPPORT_CLEAN is set to 0. If the application does not call either FS_STORAGE_Clean() or FS_STORAGE_CleanOne() then FS_NOR_SUPPORT_CLEAN can be safely set to 0 in order to save ROM space.

FS_NOR_SUPPORT_VARIABLE_LINE_SIZE

FS_NOR_SUPPORT_VARIABLE_LINE_SIZE can be used to enable the runtime configuration of the minimum number of bytes to be written by the Sector Map NOR driver at once. With FS_NOR_SUPPORT_VARIABLE_LINE_SIZE set to 1 the minimum number of bytes to be written at once can be configured via FS_NOR_SetDeviceLineSize() between 1 and FS_NOR_LINE_SIZE. In addition, the ability of the NOR flash device to perform incremental write operations can be configured via FS_NOR_SetDeviceRewriteSupport(). FS_NOR_SUPPORT_VARIABLE_LINE_SIZE is set to 1 when building the NOR Image Creator utility in order to give it the ability to create images for NOR flash devices with different characteristics. Typically, there is no need to modify the default value of FS_NOR_SUPPORT_VARIABLE_LINE_SIZE when building a target application.

FS_NOR_VERIFY_WRITE

This define can be used to activate the write verification of the Sector Map NOR driver. The write verification is performed after each write operation by reading back the modified data from storage and by comparing it with the data requested to be written. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NOR_SetWriteVerification().

Note

Activating the write verification can negatively affect the write performance.

FS_NOR_VERIFY_ERASE

This define can be used to activate the erase verification of the Sector Map NOR driver. The erase verification is performed after each erase operation by reading back the entire data of the erase physical sector from storage and by comparing it with 0xFF. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NOR_SetEraseVerification().

Note

Activating the erase verification can negatively affect the write performance.

Runtime configuration

The driver must be added to the file system by calling FS_AddDevice() with the driver identifier set to the address of FS_NOR_Driver. This function call together with other function calls that configure the driver operation have to be added to FS_X_AddDevices() as demonstrated in the following example. This example shows how to configure the file system to access a NOR flash device connected via SPI.

#include "FS.h"

#define ALLOC_SIZE        0x4000        // Size defined in bytes
#define BYTES_PER_SECTOR  2048

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the NOR flash driver. The first 65536 bytes of the
  // serial NOR flash device are not used by the file system as data storage
  // and can be used by the application for other purposes. The file system
  // uses a total of 1 Mbyte from the serial NOR flash device as storage.
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_ST_M25);
  FS_NOR_Configure(0, 0x00000000, 0x00010000, 0x00100000);
  FS_NOR_SetSectorSize(0, BYTES_PER_SECTOR);
  //
  // Set a larger logical sector size as the default
  // in order to reduce the RAM usage of the NOR driver.
  //
  FS_SetMaxSectorSize(BYTES_PER_SECTOR);
}

The API functions listed in the next table can be used by the application to configure the behavior of the Sector Map NOR driver. The application can call them only at the file system initialization in FS_X_AddDevices().

FunctionDescription
FS_NOR_Configure() Configures an instance of the sector map NOR driver.
FS_NOR_ConfigureReserve() Configures the number of logical sectors to be reserved.
FS_NOR_SetBlankSectorSkip() Configures if the physical sectors which are already blank should be erased during the low-level format operation.
FS_NOR_SetDeviceLineSize() Configures the minimum number of bytes that can be written to NOR flash.
FS_NOR_SetDeviceRewriteSupport() Specifies if the NOR flash device can rewrite the same data if 0s are preserved.
FS_NOR_SetDirtyCheckOptimization() Enables or disables the blank checking of a logical sector before write.
FS_NOR_SetEraseVerification() Enables or disables the checking of the sector erase operation.
FS_NOR_SetPhyType() Configures the type of NOR physical layer.
FS_NOR_SetSectorSize() Configures the number of bytes in a logical sector.
FS_NOR_SetWriteVerification() Enables or disables the checking of the page write operation.
FS_NOR_Configure()

Description

Configures an instance of the sector map NOR driver

Prototype

void FS_NOR_Configure(U8  Unit,
                      U32 BaseAddr,
                      U32 StartAddr,
                      U32 NumBytes);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
BaseAddr Address of the first byte in NOR flash.
StartAddr Address of the first byte the NOR driver is permitted to use as storage.
NumBytes Number of bytes starting from StartAddr available to be used by the NOR driver as storage.

Additional information

This function is mandatory and it has to be called once in FS_X_AddDevices() for each instance of the sector map NOR driver created by the application. Different instances of the NOR driver are identified by the Unit parameter.

BaseAddr is used only for NOR flash devices that are memory mapped. For serial NOR flash devices that are not memory mapped BaseAddr has to be set to 0.

StartAddr has to be greater than or equal to BaseAddr and smaller than the total number of bytes in the NOR flash device. The sector map NOR driver rounds up StartAddr to the start address of the next physical sector in the NOR flash device.

NumBytes is rounded up to a physical sector boundary if the memory range defined by StartAddr and NumBytes is smaller than the capacity of the NOR flash device. If the memory range defined by StartAddr and NumBytes is larger than the capacity of the NOR flash device than NumBytes is rounded down so that the memory range fits into the NOR flash device.

The sector map NOR driver can work with physical sectors of different size. It is required that at least two physical sectors of each sector size are available.

Example

The following sample demonstrates how to configure the file system to work with a single CFI compliant NOR flash device connected via a 16-bit data bus.

#include "FS.h"

#define ALLOC_SIZE 0x2000               // Size defined in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add the NOR driver.
  //
  FS_AddDevice(&FS_NOR_Driver);
  //
  // Set the physical layer type for single CFI compliant
  // NOR flash device with 16-bit data bus interface.
  //
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
  //
  // Configure the range of NOR flash device to be used as storage (2 Mbytes)
  //
  FS_NOR_Configure(0, 0x1000000, 0x1000000, 0x00200000);
}

The next sample demonstrates how to configure the file system to work with two CFI compliant NOR flash devices with each device being connected via a separate 16-bit data bus.

#include "FS.h"

#define ALLOC_SIZE 0x4000               // Size defined in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add the NOR driver.
  //
  FS_AddDevice(&FS_NOR_Driver);
  //
  // Set the physical layer type for two CFI compliant
  // NOR flash devices with 16-bit data bus interface.
  //
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_2x16);
  //
  // Configure the range of NOR flash device to be used as storage (2 Mbytes each)
  //
  FS_NOR_Configure(0, 0x1000000, 0x1000000, 0x00400000);
}

The file system is able to handle two or more NOR flash devices that are not connected in parallel. The next sample shows how this can be realized.

#include "FS.h"

#define ALLOC_SIZE 0x4000               // Size defined in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the first NOR driver. The storage can be accessed
  // using the volume name "nor:0:". The physical layer is set to single
  // CFI compliant NOR flash device with 16-bit interface. The NOR flash
  // device is mapped at address 0x10000000 in the system memory and
  // 2 Mbytes of it are used by the file system as storage.
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(0, 0x1000000, 0x1000000, 0x00200000);
  //
  // Add and configure the second NOR driver. The storage can be accessed
  // using the volume name "nor:1:". The physical layer is set to single
  // CFI compliant NOR flash device with 16-bit interface. The NOR flash
  // device is mapped at address 0x40000000 in the system memory and
  // 4 Mbytes of it are used by the file system as storage.
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(1, 0x4000000, 0x4000000, 0x00400000);
}
FS_NOR_ConfigureReserve()

Description

Configures the number of logical sectors to be reserved.

Prototype

void FS_NOR_ConfigureReserve(U8 Unit,
                             U8 pctToReserve);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
pctToReserve Percent of the total number of logical sectors to reserve.

Additional information

This function is optional. By default, the sector map NOR driver reserves about 10% of the total number of logical sector for future improvements and extensions. FS_NOR_ConfigureReserve() can be used in an application to modify this value. If set to 0 the sector map NOR driver uses all the available logical sectors to store file system data.

The application has to reformat the NOR flash device in order for the modified value to take effect.

FS_NOR_SetBlankSectorSkip()

Description

Configures if the physical sectors which are already blank should be erased during the low-level format operation.

Prototype

void FS_NOR_SetBlankSectorSkip(U8 Unit,
                               U8 OnOff);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 All the physical sectors are erased. ≠0 Physical sectors are not erased if they are blank (default).

Additional information

This function is optional. The blank checking feature is disabled by default and has to be explicitly enabled at compile time by setting FS_NOR_SKIP_BLANK_SECTORS to 1. The feature can then be enabled or disabled at runtime using FS_NOR_SetBlankSectorSkip().

Activating this feature can improve the speed of the low-level format operation when most of the physical sectors of the NOR flash device are already blank which is typically the case with NOR flash devices that ship from factory.

FS_NOR_SetDeviceLineSize()

Description

Configures the minimum number of bytes that can be written to NOR flash.

Prototype

void FS_NOR_SetDeviceLineSize(U8 Unit,
                              U8 ldBytesPerLine);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
ldBytesPerLine Line size in bytes as power of 2 exponent.

Additional information

This function is optional. Typically, the NOR flash have lines smaller than 4 bytes which is the fixed default value configured at compile time. The FS_NOR_SUPPORT_VARIABLE_LINE_SIZE configuration define has to be set to a value different than 0 in order to enable this function.

FS_NOR_SetDeviceRewriteSupport()

Description

Specifies if the NOR flash device can rewrite the same data if 0s are preserved.

Prototype

void FS_NOR_SetDeviceRewriteSupport(U8 Unit,
                                    U8 OnOff);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 Rewrite operations are not performed. ≠0 Rewrite operation are performed (default).

Additional information

This function is optional. Typically, the NOR flash devices are able to rewrite the same data and by default this feature is disabled at compile time. The FS_NOR_SUPPORT_VARIABLE_LINE_SIZE configuration define has to be set to a value different than 0 in order to enable this function, otherwise the function does nothing.

FS_NOR_SetDirtyCheckOptimization()

Description

Enables or disables the blank checking of a logical sector before write.

Prototype

void FS_NOR_SetDirtyCheckOptimization(U8 Unit,
                                      U8 OnOff);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 Dirty check is disabled (default). ≠0 Dirty check is enabled.

Additional information

This function is optional. Per default, the NOR driver checks if the data of the logical sector is blank (all bytes 0xFF) before it writes the data. This is necessary in order to make sure that the NOR driver does not write to partially written logical sectors. Writing to a partially written logical sector can cause a data loss since the write operation can change the value of a bit only from 1 to 0. A partially written logical sector occurs when the write operation is interrupted by an unexpected reset. In this case the status of the logical sector indicates that the logical sector is blank which is not correct. Therefore the logical sector cannot be used for storage and it is marked by the NOR driver as invalid.

Typically, the blank checking runs fast but on some targets it may reduce the write performance. In this cases, this option can be used to skip the blank checking which helps improve the performance. When the optimization is enabled, the blank checking is not longer performed on the logical sectors located on physical sectors that have been erased at least once since the last mount operation. The NOR driver can skip the blank checking for these physical sectors since it knows that they do not contain any partially written logical sectors. The application can remove any partially written logical sectors by performing a clean operation of the entire storage via the FS_STORAGE_Clean() or FS_STORAGE_CleanOne() API functions. The NOR driver requires one bit of RAM storage for each physical sector used as storage.

The FS_NOR_OPTIMIZE_DIRTY_CHECK configuration define has to be set to a value different than 0 in order to enable this function, otherwise the function does nothing.

FS_NOR_SetEraseVerification()

Description

Enables or disables the checking of the sector erase operation.

Prototype

void FS_NOR_SetEraseVerification(U8 Unit,
                                 U8 OnOff);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The erase operation is not checked. ≠0 The erase operation is checked.

Additional information

This function is optional. The result of a sector erase operation is normally checked by evaluating the error bits maintained by the NOR flash device in a internal status register. FS_NOR_SetEraseVerification() can be used to enable additional verification of the sector erase operation that is realized by reading back the contents of the entire erased physical sector and by checking that all the bytes in it are set to 0xFF. Enabling this feature can negatively impact the write performance of sector map NOR driver.

The sector erase verification feature is active only when the sector map NOR driver is compiled with the FS_NOR_VERIFY_ERASE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NOR_SetPhyType()

Description

Configures the type of NOR physical layer.

Prototype

void FS_NOR_SetPhyType(      U8                Unit,
                       const FS_NOR_PHY_TYPE * pPhyType);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
pPhyType  in  NOR physical layer.

Additional information

This function is mandatory and it has to be called once in FS_X_AddDevices() for each instance of the sector map NOR driver created by the application. Different instances of the sector map NOR driver are identified by the Unit parameter.

Permitted values for the pPhyType parameter are:

Identifier Description
FS_NOR_PHY_CFI_1x16 One CFI compliant NOR flash device with 16-bit interface.
FS_NOR_PHY_CFI_2x16 Two CFI compliant NOR flash device with 16-bit interfaces.
FS_NOR_PHY_DSPI This a pseudo physical layer that uses the physical layers FS_NOR_PHY_ST_M25 and FS_NOR_PHY_SFDP
FS_NOR_PHY_SFDP Serial NOR flash devices that support Serial Flash Discoverable Parameters (SFDP)
FS_NOR_PHY_SPIFI Memory mapped serial quad NOR flash devices.
FS_NOR_PHY_ST_M25 Serial NOR flash devices compatible to ST ST25Pxx.
FS_NOR_SetSectorSize()

Description

Configures the number of bytes in a logical sector.

Prototype

void FS_NOR_SetSectorSize(U8  Unit,
                          U16 SectorSize);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
SectorSize Number of bytes in a logical sector.

Additional information

This function is optional. It can be used to modify the size of the logical sector used by the sector map NOR driver. By default the sector map NOR driver uses the logical sector size configured a file system level that is set to 512 bytes at the file system initialization and can be later changed via FS_SetMaxSectorSize(). The NOR flash device has to be reformatted in order for the new logical sector size to take effect.

SectorSize has to be a power of 2 value.

FS_NOR_SetWriteVerification()

Description

Enables or disables the checking of the page write operation.

Prototype

void FS_NOR_SetWriteVerification(U8 Unit,
                                 U8 OnOff);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
OnOff Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked.

Additional information

This function is optional. The result of a page write operation is normally checked by evaluating the error bits maintained by the NOR flash device in a internal status register. FS_NOR_SetWriteVerification() can be used to enable additional verification of the page write operation that is realized by reading back the contents of the written page and by checking that all the bytes are matching the data requested to be written. Enabling this feature can negatively impact the write performance of sector map NOR driver.

The page write verification feature is active only when the sector map NOR driver is compiled with the FS_NOR_VERIFY_WRITE configuration define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL configuration define is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NOR_STAT_COUNTERS

Description

Statistical counters maintained by the Sector Map NOR driver.

Type definition

typedef struct {
  U32  EraseCnt;
  U32  ReadSectorCnt;
  U32  WriteSectorCnt;
  U32  CopySectorCnt;
  U32  ReadCnt;
  U32  ReadByteCnt;
  U32  WriteCnt;
  U32  WriteByteCnt;
} FS_NOR_STAT_COUNTERS;

Structure members

Member Description
EraseCnt Number of sector erase operations.
ReadSectorCnt Number of logical sectors read by the file system.
WriteSectorCnt Number of logical sectors written by the file system.
CopySectorCnt Number of logical sectors copied internally by the driver.
ReadCnt Number of times the driver read data from the NOR flash device.
ReadByteCnt Number of bytes read by the driver from the NOR flash device.
WriteCnt Number of times the driver wrote data to the NOR flash device.
WriteByteCnt Number of bytes written by the driver to the NOR flash device.
Additional sample configurations

The sample configurations below show how to create multiple volumes, logical volumes etc., on a NOR flash device. All configuration steps have to be performed inside the FS_X_AddDevices() function that is called during the initialization of the file system.

Multiple volumes on a single NOR flash device

The following example illustrates how to create multiple volumes on a single NOR flash device. The sample creates two volumes on one NOR flash device.

#include "FS.h"

#define ALLOC_SIZE 0x2000               // Size defined in bytes
//
// Config: 1 NOR flash, where NOR flash size -> 2 MB
//         2 volumes, , where volume 0 size -> 1MB, volume 1 -> 0.5MB
//
#define FLASH_BASE_ADDR             0x80000000
#define FLASH_VOLUME_0_START_ADDR   0x80000000
#define FLASH_VOLUME_0_SIZE         0x00100000  // 1 MByte
#define FLASH_VOLUME_1_START_ADDR   0x80100000
#define FLASH_VOLUME_1_SIZE         0x00080000  // 0.5 MByte

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Volume name: "nor:0:"
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(0, FLASH_BASE_ADDR, FLASH_VOLUME_0_START_ADDR, FLASH_VOLUME_0_SIZE);
  //
  // Volume name: "nor:1:"
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(1, FLASH_BASE_ADDR, FLASH_VOLUME_1_START_ADDR, FLASH_VOLUME_1_SIZE);
}
Multiple volumes on different NOR flash devices

The following example illustrates how to create multiple volumes on multiple NOR flash devices. This sample creates two volume, each one located on different NOR flash device.

#include "FS.h"

#define ALLOC_SIZE 0x2000               // Size defined in bytes
//
// Config:  2 NOR flash devices, where NOR flash 0 size -> 2 MB, NOR flash 1 -> 16MB
//          2 volumes, volume 0 size -> complete NOR 0, volume 1 -> complete NOR 1
//
#define FLASH0_BASE_ADDR            0x80000000
#define FLASH_VOLUME_0_START_ADDR   FLASH0_BASE_ADDR
#define FLASH_VOLUME_0_SIZE         0xFFFFFFFF  // Use the complete flash
#define FLASH1_BASE_ADDR            0x40000000
#define FLASH_VOLUME_1_START_ADDR   FLASH1_BASE_ADDR
#define FLASH_VOLUME_1_SIZE         0xFFFFFFFF  // Use the complete flash

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Volume name: "nor:0:"
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(0, FLASH0_BASE_ADDR, FLASH_VOLUME_0_START_ADDR, FLASH_VOLUME_0_SIZE);
  //
  // Volume name: "nor:1:"
  //
  FS_AddDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(1, FLASH1_BASE_ADDR, FLASH_VOLUME_1_START_ADDR, FLASH_VOLUME_1_SIZE);
}
Volume that stretches over multiple NOR flash devices

The following example illustrates how to create a volume that stretches over two NOR flash devices. This is realized by using the logical volume functionality.

#include "FS.h"

#define ALLOC_SIZE 0x2000               // Size defined in bytes
//
// Config:  2 NOR flash devices, where NOR flash 0 size -> 2 MB, NOR flash 1 -> 16MB
//          1 volume, where volume is NOR flash 0 + NOR flash 1
//
#define FLASH0_BASE_ADDR            0x80000000
#define FLASH_VOLUME_0_START_ADDR   FLASH0_BASE_ADDR
#define FLASH_VOLUME_0_SIZE         0xFFFFFFFF  // Use the complete flash
#define FLASH1_BASE_ADDR            0x40000000
#define FLASH_VOLUME_1_START_ADDR   FLASH1_BASE_ADDR
#define FLASH_VOLUME_1_SIZE         0xFFFFFFFF  // Use the complete flash

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Create physical device 0, this device will not be visible as a volume.
  //
  FS_AddPhysDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(0, FLASH0_BASE_ADDR, FLASH_VOLUME_0_START_ADDR, FLASH_VOLUME_0_SIZE);
  //
  // Create physical device 1, this device will not be visible as a volume
  //
  FS_AddPhysDevice(&FS_NOR_Driver);
  FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
  FS_NOR_Configure(1, FLASH1_BASE_ADDR, FLASH_VOLUME_1_START_ADDR, FLASH_VOLUME_1_SIZE);
  //
  // Now create a logical volume, containing the physical devices. Volume name: "LogVol"
  //
  FS_LOGVOL_Create("LogVol");
  FS_LOGVOL_AddDevice("LogVol", &FS_NOR_Driver, 0, 0, 0);
  FS_LOGVOL_AddDevice("LogVol", &FS_NOR_Driver, 1, 0, 0);
}
Additional driver functions

The functions documented in this section are optional. They can be used to get information about the status of the Sector Map NOR driver or to directly access the data stored on the NOR flash device.

FunctionDescription
FS_NOR_EraseDevice() Erases all the physical sectors configured as storage.
FS_NOR_ErasePhySector() Sets all the bits in a physical sector to 1.
FS_NOR_FormatLow() Performs a low-level format of NOR flash device.
FS_NOR_GetDiskInfo() Returns information about the organization and the management of the NOR flash device.
FS_NOR_GetSectorInfo() Returns information about a specified physical sector.
FS_NOR_GetStatCounters() Returns the values of the statistical counters.
FS_NOR_IsLLFormatted() Checks it the NOR flash is low-level formatted.
FS_NOR_LogSector2PhySectorAddr() Returns the address in memory of a specified logical sector.
FS_NOR_ReadOff() Reads a range of bytes from the NOR flash device.
FS_NOR_ResetStatCounters() Sets the value of the statistical counters to 0.
FS_NOR_WriteOff() Writes data to NOR flash memory.
FS_NOR_EraseDevice()

Description

Erases all the physical sectors configured as storage.

Prototype

int FS_NOR_EraseDevice(U8 Unit);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).

Return value

= 0 Physical sectors erased.
≠ 0 An error occurred.

Additional information

This function is optional. After the call to this function all the bytes in area of the NOR flash device configured as storage are set to 0xFF.

FS_NOR_ErasePhySector()

Description

Sets all the bits in a physical sector to 1.

Prototype

int FS_NOR_ErasePhySector(U8  Unit,
                          U32 PhySectorIndex);

Parameters

Parameter Description
Unit Index of the Block Map NOR driver (0-based).
PhySectorIndex Index of the physical sector to be erased.

Return value

= 0 OK, physical sector erased successfully.
≠ 0 An error occurred.

Additional information

PhySectorIndex is 0-based and is relative to the beginning of the NOR flash area configured via FS_NOR_Configure(). The number of bytes actually erased depends on the size of the physical sector supported by the NOR flash device. Information about a physical sector can be obtained via FS_NOR_GetSectorInfo().

FS_NOR_FormatLow()

Description

Performs a low-level format of NOR flash device.

Prototype

int FS_NOR_FormatLow(U8 Unit);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).

Return value

= 0 OK, NOR flash device has been successfully low-level formated.
≠ 0 An error occurred.

Additional information

This function is optional. FS_NOR_FormatLow() erases the first physical sector and stores the format information in it. The other physical sectors are either erased or invalidated. Per default the physical sectors are invalidated in order to reduce the time it takes for the operation to complete.

FS_NOR_GetDiskInfo()

Description

Returns information about the organization and the management of the NOR flash device.

Prototype

int FS_NOR_GetDiskInfo(U8                 Unit,
                       FS_NOR_DISK_INFO * pDiskInfo);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
pDiskInfo  out  Requested information.

Return value

= 0 OK, information returned.
≠ 0 An error occurred.

Additional information

This function is not required for the functionality of the sector map NOR driver and will typically not be linked in production builds.

Example

#include "FS.h"

void SampleNORGetDiskInfo(void) {
  int              r;
  char             ac[128];
  FS_NOR_DISK_INFO DiskInfo;

  FS_X_Log("Get information about the first Sector Map NOR driver instance\n");
  r = FS_NOR_GetDiskInfo(0, &DiskInfo);
  if (r == 0) {
    SEGGER_snprintf(ac, sizeof(ac), "  Physical sectors: %lu\n", DiskInfo.NumPhysSectors);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Logical sectors : %lu\n", DiskInfo.NumLogSectors);
    FS_X_Log(ac);
    SEGGER_snprintf(ac, sizeof(ac), "  Used sectors:     %lu\n", DiskInfo.NumUsedSectors);
    FS_X_Log(ac);
  }
}
FS_NOR_GetSectorInfo()

Description

Returns information about a specified physical sector.

Prototype

int FS_NOR_GetSectorInfo(U8                   Unit,
                         U32                  PhySectorIndex,
                         FS_NOR_SECTOR_INFO * pSectorInfo);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
PhySectorIndex Index of the physical sector to be queried (0-based).
pSectorInfo  out  Information related to the specified physical sector.

Return value

= 0 OK, information returned successfully.
≠ 0 An error occurred.

Additional information

This function is optional. The application can use it to get information about the usage of a particular physical sector.

PhySectorIndex is relative to the beginning of the region configured as storage via FS_NOR_Configure().

Example

#include "FS.h"

void SampleNORGetDiskInfo(void) {
  char               ac[128];
  FS_NOR_SECTOR_INFO SectorInfo;

  FS_X_Log("Get information about the physical sector 0 of the first Sector Map NOR driver instance\n");
  FS_NOR_GetSectorInfo(0, 0, &SectorInfo);
  SEGGER_snprintf(ac, sizeof(ac), "  Offset:                   %lu\n", SectorInfo.Off);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  Size:                     %lu bytes\n", SectorInfo.Size);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  Erase count:              %lu\n", SectorInfo.EraseCnt);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  Used logical sectors:     %lu\n", SectorInfo.NumUsedSectors);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  Free logical sectors:     %lu\n", SectorInfo.NumFreeSectors);
  FS_X_Log(ac);
  SEGGER_snprintf(ac, sizeof(ac), "  Erasable logical sectors: %lu\n", SectorInfo.NumEraseableSectors);
  FS_X_Log(ac);
}
FS_NOR_GetStatCounters()

Description

Returns the values of the statistical counters.

Prototype

void FS_NOR_GetStatCounters(U8                     Unit,
                            FS_NOR_STAT_COUNTERS * pStat);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
pStat  out  Statistical counter values.

Additional information

This function is optional. The application can use it to get the actual values of the statistical counters maintained by the sector map NOR driver. The statistical counters provide information about the number of internal operations performed by the sector map NOR driver such as sector read and write. All statistical counters are set to 0 when the NOR flash device is low-level mounted. The application can explicitly set them to 0 by using FS_NOR_ResetStatCounters(). A separate set of statistical counters is maintained for each instance of the sector map NOR driver.

The statistical counters are available only when the sector map NOR driver is compiled with the FS_DEBUG_LEVEL configuration define set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL or with the FS_NOR_ENABLE_STATS configuration define set to 1.

FS_NOR_IsLLFormatted()

Description

Checks it the NOR flash is low-level formatted.

Prototype

int FS_NOR_IsLLFormatted(U8 Unit);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).

Return value

≠ 0 The NOR flash device is low-level formatted.
= 0 The NOR flash device is not low-level formatted or an error has occurred.

Additional information

This function is optional. An application should use FS_IsLLFormatted() instead.

FS_NOR_LogSector2PhySectorAddr()

Description

Returns the address in memory of a specified logical sector.

Prototype

void *FS_NOR_LogSector2PhySectorAddr(U8  Unit,
                                     U32 LogSectorIndex);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
LogSectorIndex Index of the logical sector for which the address has to be calculated.

Return value

NULL OK, address of the first byte in the logical sector.
= NULL An error occurred.

Additional information

This function is optional. It can be used only with NOR flash devices that are memory mapped. FS_NOR_LogSector2PhySectorAddr() returns the address in the system memory of the first byte in the specified logical sector.

FS_NOR_ReadOff()

Description

Reads a range of bytes from the NOR flash device.

Prototype

int FS_NOR_ReadOff(U8     Unit,
                   U32    Off,
                   void * pData,
                   U32    NumBytes);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).
Off Offset of the first byte to be read.
pData  out  Read data.
NumBytes Number of bytes to be read.

Return value

= 0 OK, data read.
≠ 0 An error occurred.

Additional information

This function is not required for the functionality of the driver and will typically not be linked in production builds.

Off has to be specified in bytes and is relative to the beginning of the NOR flash area configured via FS_NOR_Configure().

FS_NOR_ResetStatCounters()

Description

Sets the value of the statistical counters to 0.

Prototype

void FS_NOR_ResetStatCounters(U8 Unit);

Parameters

Parameter Description
Unit Index of the sector map NOR driver (0-based).

Additional information

This function is optional. The application can use it to set the statistical counters maintained by the sector map NOR driver to 0. The statistical counters can be read via FS_NOR_GetStatCounters()

FS_NOR_ResetStatCounters() is available only when the sector map NOR driver is compiled with the FS_DEBUG_LEVEL configuration define set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL or with the FS_NOR_ENABLE_STATS configuration define set to 1.

FS_NOR_WriteOff()

Description

Writes data to NOR flash memory.

Prototype

int FS_NOR_WriteOff(      U8     Unit,
                          U32    Off,
                    const void * pData,
                          U32    NumBytes);

Parameters

Parameter Description
Unit Index of the Sector Map NOR driver (0-based).
Off Location where to write the data.
pData  in  Data to be written.
NumBytes Number of bytes to be written.

Return value

= 0 OK, data written successfully.
≠ 0 An error occurred.

Additional information

Off has to be specified in bytes and is relative to the beginning of the NOR flash area configured via FS_NOR_Configure().

FS_NOR_WriteOff() is able to write across page and physical sector boundaries. This function can only change bit values from 1 to 0. The bits can be set to 1 block-wise via FS_NOR_ErasePhySector().

The function takes care of the alignment required when writing to NOR flash devices with line size larger than 1.

FS_NOR_DISK_INFO

Description

Management information maintained by the Sector Map NOR driver.

Type definition

typedef struct {
  U32  NumPhysSectors;
  U32  NumLogSectors;
  U32  NumUsedSectors;
  U16  BytesPerSector;
} FS_NOR_DISK_INFO;

Structure members

Member Description
NumPhysSectors Number of physical sectors available for data storage.
NumLogSectors Number of available logical sectors.
NumUsedSectors Number of logical sectors that store valid data.
BytesPerSector Size of the logical sector used by the driver in bytes.
FS_NOR_SECTOR_INFO

Description

Information about a physical sector maintained by the Sector Map NOR driver.

Type definition

typedef struct {
  U32  Off;
  U32  Size;
  U32  EraseCnt;
  U16  NumUsedSectors;
  U16  NumFreeSectors;
  U16  NumEraseableSectors;
  U8   Type;
} FS_NOR_SECTOR_INFO;

Structure members

Member Description
Off Position of the physical sector relative to the first byte of NOR flash device
Size Size of physical sector in bytes
EraseCnt Number of times the physical sector has been erased
NumUsedSectors Number of logical sectors that contain valid data
NumFreeSectors Number of logical sectors that are empty (i.e. blank)
NumEraseableSectors Number of logical sectors that contain old (i.e. invalid) data.
Type Type of data stored in the physical sector (see FS_NOR_SECTOR_TYPE_…)
Performance and resource usage

This section provides information about the ROM and RAM usage as well as the performance of the Sector Map NOR driver. Each driver instance requires one instance of one NOR physical layer in order to operate. The resource usage of the used NOR physical layer has to be taken into account when calculating the total resource usage of the Sector Map NOR driver. Refer to the section Resource usage for information about the resource usage of the available NOR physical layers.

ROM usage

The ROM usage depends on the compiler options, the compiler version and the used CPU. The memory requirements of the Sector Map NOR driver were measured as described in the section Test procedure.

Usage: 4.0 Kbytes

Static RAM usage

Static RAM usage refers to the amount of RAM required by the Sector Map NOR driver internally for all the driver instances. The number of bytes can be seen in the compiler list file of the FS_NOR_Drv.c file.

Usage: 20 bytes

Dynamic RAM usage

Dynamic RAM usage is the amount of RAM allocated by the driver at runtime. The amount of RAM required depends on the runtime configuration and on the used NOR flash device. The approximate RAM usage of the Sector Map NOR driver can be calculated as follows:

MemAllocated = 500 + (BitsPerEntry * FlashSize / 8) / LogSectorSize
Parameter Description
MemAllocated Number of bytes allocated.
BitsPerEntry Number of bits required to store the offset of the last byte on the storage.
FlashSize Size in bytes of a NOR flash.
LogSectorSize Size in bytes of a file system sector. Typically, 512 bytes or the value set in the call to FS_SetMaxSectorSize().

The following table lists the approximate amount of RAM required for different combinations of NOR flash size and logical sector size:

Flash size (Mbytes) 512 byte sectors 1 Kbyte sectors 2 Kbyte sectors
1 4.6 KBytes 2.5 KBytes 1.5 KBytes
2 8.7 KBytes 4.6 KBytes 2.5 KBytes
4 16.8 KBytes 8.7 KBytes 4.6 KBytes
8 33.2 KBytes 16.8 KBytes 8.7 KBytes

Note

Please note that by increasing the logical sector size the RAM usage of the file system increases too because more memory is required for the sector buffers.

Performance

These performance measurements are in no way complete, but they give an approximation of the length of time required for common operations on various targets. The tests were performed as described in the section Performance. All values are given in Kbytes/second

CPU type NOR flash device Write speed Read speed
ST STR912 (96 MHz) Winbond W25Q32BV (SPI) 75 2625
NXP LPC2478 (57.6 MHz) SST SST39VF201 CFI NOR flash device with 16-bit interface and without support for write buffer 53.5 2560
ST STM32F103 (72 MHz) ST M29W128 CFI NOR flash device 16-bit interface and with support for write buffer 60.4 8000
ST STM32F103 (72 MHz) ST M25P64 SPI NOR flash device 62.8 1125
NXP LPC4357 (204 MHz) Spansion S25FL032P serial NOR flash device interfaced via SPIFI. 185 26947
FAQs

Block Map NOR driver

This section describes the NOR driver which is optimized for reduced RAM usage. It works by mapping blocks of logical sectors to physical sectors of the NOR flash device.

Theory of operation

Differentiating between logical sectors or blocks and physical sectors is essential to understand this section. A logical sector or block is the smallest readable and writable unit of any file system and its usual size is 512 bytes. A physical sector is an array of bytes on the NOR flash device that are erased together (typically between 2 Kbytes - 128 Kbytes). The NOR flash driver is an abstraction layer between these two types of sectors.

The Block Map NOR driver maintains a table that maps ranges of logical sectors, called logical blocks, to physical sectors on the NOR flash device. The number of logical sectors in a logical block depends on how many logical sectors fit in a physical sector. Every time a logical sector is updated, its content is written to a special physical sector called work block. A work block is a kind of temporary storage for the modified data of a logical sector that is later converted into a data block when a new empty work block needs to be allocated.

Configuring the driver

The Block Map NOR driver has to be configured at runtime and optionally at compile time. The following sections described how this can be realized in the application.

Compile time configuration

The Block Map NOR driver can optionally be configured at compile time. Typically, this step can be omitted because reasonable default values are provided that work with most of the applications. The compile time configuration is realized via preprocessor defines that have to be added to the FS_Conf.h file which is the main configuration file of emFile. For detailed information about the configuration of emFile and of the configuration define types, refer to Configuration of emFile The following table lists the configuration defines supported by the Block Map NOR driver.

Define Default value Type Description
FS_NOR_CAN_REWRITE 1 B Specifies if modifying the same byte on the NOR flash device more than one time is permitted.
FS_NOR_CRC_HOOK_DEFAULT &FS_NOR_CRC_SW R Specifies the default routines to be used for the CRC calculation.
FS_NOR_DATA_BUFFER_SIZE 32 N Number of bytes to be reserved for the data buffers used for internal operations.
FS_NOR_ECC_HOOK_DATA_DEFAULT &FS_NOR_ECC_SW_1bit_Data R Specifies the default routines to be used for the ECC calculation of the sector data.
FS_NOR_ECC_HOOK_MAN_DEFAULT &FS_NOR_ECC_SW_1bit_Man R Specifies the default routines to be used for the ECC calculation of the management data.
FS_NOR_ENABLE_STATS 0 or 1 B Enables or disables the support for statistical counters.
FS_NOR_LINE_SIZE 1 N Configures the minimum number of bytes to write at once.
FS_NOR_LOG_SECTOR_RESERVE 4 N Configures additional space to be reserved for the management data of a logical sector.
FS_NOR_MAX_ERASE_CNT 500000 N Configures the maximum value of a valid erase count.
FS_NOR_MAX_ERASE_CNT_DIFF 5000 N Configures the default maximum difference between erase counts.
FS_NOR_NUM_READ_RETRIES 10 N Configures the number of retries in case of a read error.
FS_NOR_NUM_WRITE_RETRIES 10 N Configures the number of retries in case of a write error.
FS_NOR_NUM_UNITS 4 N Configures the maximum number of driver instances.
FS_NOR_OPTIMIZE_EMPTY_CHECK 0 B Enables or disables the optimization for the checking of the physical sector empty status.
FS_NOR_OPTIMIZE_HEADER_WRITE 0 B Enables or disables the optimization for the writing of management data.
FS_NOR_OPTIMIZE_DATA_WRITE 1 B Enables or disables the optimization for the writing of logical sector data.
FS_NOR_PHY_SECTOR_RESERVE 8 N Configures additional space to be reserved for the management data of a physical sector.
FS_NOR_READ_BUFFER_FILL_PATTERN 0xFF N Configures a bit pattern to be used for filling the contents of invalid logical sectors.
FS_NOR_SKIP_BLANK_SECTORS 1 B Enables or disables the support for erasing blank physical sectors at low-level format.
FS_NOR_STRICT_FORMAT_CHECK 0 N Enables or disables additional checks related to the low-level format.
FS_NOR_SUPPORT_CLEAN 1 B Enables or disables the support for executing the garbage collection in the application.
FS_NOR_SUPPORT_CRC 0 B Enables or disables the support for data integrity verification via CRC of payload and management data.
FS_NOR_SUPPORT_ECC 0 B Enables or disables the support for data integrity verification via ECC of payload and management data.
FS_NOR_SUPPORT_FORMAT 1 B Enables or disables the support for low-level formatting.
FS_NOR_SUPPORT_TRIM 1 B Enables or disables the support for marking logical sectors are not being in use.
FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER 0 B Enables or disables the support for configuring at runtime the byte order of management data.
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE 0 B Enables or disables the support for configuring at runtime the minimum number of bytes to be written at once.
FS_NOR_VERIFY_WRITE 0 B Enables or disables the support for checking if the write operation was successful.
FS_NOR_VERIFY_ERASE 0 B Enables or disables the support for checking if the erase operation was successful.
FS_NOR_CAN_REWRITE

For the majority of NOR flash device the same byte can be modified more than once without a erase operation in between while preserving the bits set to 0. That is a byte can be written up to eight times with each write operation setting a different bit in that byte to 0. The Block Map NOR driver makes use of this feature to make efficient use of the storage space and to improve the performance. FS_NOR_CAN_REWRITE has to be set to 0 for NOR flash devices that permit only one write operation to a byte or a range of bytes between two erase operations of that storage block.

FS_NOR_CRC_HOOK_DEFAULT

This define specifies the default routines for the CRC calculation. It can be set to NULL in order to save ROM space if the application registers its own routines via FS_NOR_BM_SetCRCHook()

FS_NOR_DATA_BUFFER_SIZE

This define can be used to specify the size of the buffers used by the Block Map NOR driver for internal operations such as copying the contents of a logical sector or verifying if a physical sector is blank. All these buffers are allocated on the stack therefore increasing the value of FS_NOR_DATA_BUFFER_SIZE increases the stack usage while providing a better performance. FS_NOR_DATA_BUFFER_SIZE has to be a non-zero value multiple of 4. If the file system is built with FS_SUPPORT_EXT_MEM_MANAGER set to 0 then the Block Map NOR driver is using as buffer the available free memory at the time the buffer is required if the number of free bytes is larger than FS_NOR_DATA_BUFFER_SIZE. This means that it is possible to reduce the stack usage by setting FS_NOR_DATA_BUFFER_SIZE to a smaller value than the default and by increasing the size of the memory pool assigned to the file system via FS_AssignMemory() by the amount of memory required for the buffer.

FS_NOR_ECC_HOOK_DATA_DEFAULT

This define specifies the default routines for the ECC calculation of sector data. It can be set to NULL in order to save ROM space if the application registers its own routines via FS_NOR_BM_SetECCHook()

FS_NOR_ECC_HOOK_MAN_DEFAULT

This define specifies the default routines for the ECC calculation of the management data. It can be set to NULL in order to save ROM space if the application registers its own routines via FS_NOR_BM_SetECCHook()

FS_NOR_ENABLE_STATS

This define can be used to enable the support for statistical counters. The statistical counters provide information about the number of operations performed internally by the Block Map NOR driver that can be useful for debugging. The statistical counters can be queried via FS_NOR_BM_GetStatCounters(). By default FS_NOR_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.

FS_NOR_LINE_SIZE

FS_NOR_LINE_SIZE specifies the minimum number of bytes the Block Map NOR driver writes at once. The amount of data written is always a multiple of this value. In addition, FS_NOR_LINE_SIZE specifies the alignment of the written data. That is the offset at which the Block Map NOR driver writes the data is always a multiple of this value. FS_NOR_LINE_SIZE has to be a power of two value.

FS_NOR_LOG_SECTOR_RESERVE

This define can by used to specify the number of additional bytes to be allocated for the management data of a logical sector. The NOR flash device has to be low-level formatted after FS_NOR_LOG_SECTOR_RESERVE is modified. FS_NOR_LOG_SECTOR_RESERVE exists for backward compatibility reasons with older emFile versions. Typically, the default value of FS_NOR_LOG_SECTOR_RESERVE does not have to be modified. FS_NOR_LOG_SECTOR_RESERVE must be a multiple of 4 bytes.

FS_NOR_MAX_ERASE_CNT

The Block Map NOR driver uses the value of FS_NOR_MAX_ERASE_CNT to check the validity of an erase count stored in the header of a physical sector. If the value of the erase count is larger than FS_NOR_MAX_ERASE_CNT then the erase count is considered invalid and is set to the maximum value of all valid erase counts.

FS_NOR_MAX_ERASE_CNT_DIFF

The value of this define is used by the Block Map NOR driver during the wear leveling procedure to decide which physical sector has to be used for storage. FS_NOR_BM_SetMaxEraseCntDiff() can be used to modify this value at runtime. Refer to Wear Leveling for more information about how this value is used.

FS_NOR_NUM_READ_RETRIES

FS_NOR_NUM_READ_RETRIES specifies the maximum number of times the Block Map NOR driver repeats a read operation in case of an error. A read retry is performed each time the read function of the NOR physical layer reports an error or if the CRC feature is activated when the CRC verification fails. NumReadRetries of FS_NOR_BM_STAT_COUNTERS is incremented by 1 on each retry.

FS_NOR_NUM_WRITE_RETRIES

FS_NOR_NUM_WRITE_RETRIES specifies the maximum number of times the Block Map NOR driver repeats a write operation in case of an error. A write retry is performed each time the write function of the NOR physical layer reports an error.

FS_NOR_NUM_UNITS

This define specifies the maximum number of driver instances of the Block Map NOR driver the application is allowed create. Four bytes of static RAM are reserved for each instance. If the maximum number of driver instances is smaller than the default then FS_NOR_NUM_UNITS can be set to the to that value in order to reduce the RAM usage.

FS_NOR_OPTIMIZE_EMPTY_CHECK

This configuration define can be used to enable an optimization that reduces the number of read operations performed by the Block Map NOR driver when it checks if a physical sector can be used to write data to it without being erased first. Setting FS_NOR_OPTIMIZE_EMPTY_CHECK to 1 has effect only if either FS_NOR_SUPPORT_CLEAN or FS_NOR_SKIP_BLANK_SECTORS are set to 1 and the support for fail-safe erase operation is disabled.

FS_NOR_OPTIMIZE_HEADER_WRITE

FS_NOR_OPTIMIZE_HEADER_WRITE can be used to specify how the management data is written to storage. The management data is stored at the beginning of each physical and logical sector in an area called header. By default, the size of the physical sector header is 16 bytes and of the logical sector header is 8 bytes. The size of these headers is larger for NOR flash devices that specify a minimum number of bytes that have to be written at once and that are not able to perform incremental write operations. The default behavior of the Block Map NOR driver, that is when FS_NOR_OPTIMIZE_HEADER_WRITE is set to 0, is to write the entire header every time some of the information stored in it changes. With FS_NOR_OPTIMIZE_HEADER_WRITE set to 1 the Block Map NOR driver tracks the changes made to a header and writes only the information that actually changed. Reducing the amount of data written to storage can help increase the write performance. The internal flash memory of some MCUs do not allow a second write operation to the same byte with identical data without an erase operation in between. If this type of flash memory is used as storage then it is mandatory to set FS_NOR_OPTIMIZE_HEADER_WRITE to 1.

FS_NOR_OPTIMIZE_DATA_WRITE

This configuration define can be used to enable an optimization that can help increase the performance of the write operation. With FS_NOR_OPTIMIZE_DATA_WRITE set to 1 the Block Map NOR driver tries to write the sector data directly to a data block instead of writing it first to a work block. In this way the total number of write operations is reduced, which as a side effect helps extend the lifetime of NOR flash device. Enabling this optimization increases the RAM and ROM usage of the Block Map NOR driver.

FS_NOR_PHY_SECTOR_RESERVE

This define can by used to specify the number of additional bytes to be allocated for the management data of a physical sector. The NOR flash device has to be low-level formatted after FS_NOR_PHY_SECTOR_RESERVE is modified. FS_NOR_PHY_SECTOR_RESERVE exists for backward compatibility reasons with older emFile versions. Typically, the default value of FS_NOR_PHY_SECTOR_RESERVE does not have to be modified. FS_NOR_PHY_SECTOR_RESERVE must be a multiple of 4 bytes.

FS_NOR_READ_BUFFER_FILL_PATTERN

The value of FS_NOR_READ_BUFFER_FILL_PATTERN is used by the Block Map NOR driver to fill the contents of invalid logical sectors that is logical sectors that were not written yet. The contents of all logical sectors is invalid after a low-level format operation. In addition, the contents of a logical sector can be invalidated via FS_STORAGE_FreeSectors().

FS_NOR_SKIP_BLANK_SECTORS

FS_NOR_SKIP_BLANK_SECTORS can be used to enable the support for the optimization that omits the erase of physical sectors that are already blank. This feature has to be explicitly enabled a runtime by calling FS_NOR_BM_SetBlankSectorSkip().

FS_NOR_STRICT_FORMAT_CHECK

FS_NOR_STRICT_FORMAT_CHECK can be used to enable additional checks related to the low-level formatting of the NOR flash device. If FS_NOR_STRICT_FORMAT_CHECK is set to 1 then the Block Map NOR driver checks at low-level mount if the number of logical blocks stored during the last low-level format operation matches the actual number of logical blocks available for storage. The low-level format operation fails if the number of logical blocks is not equal that for example triggers a low-level format operation if the application calls FS_FormatLLIfRequired() This can be useful in a situation where an already low-level formatted NOR partition is enlarged. With FS_NOR_STRICT_FORMAT_CHECK set to 0 the low-level mount operation succeeds and the Block Map NOR driver will not use the additional space as storage. A low-level mount operation fails when an already formatted NOR partition is shrunk irrespective of the value of FS_NOR_STRICT_FORMAT_CHECK.

FS_NOR_SUPPORT_CLEAN

This define specifies if the application is allowed to perform a garbage collection operation. If FS_NOR_SUPPORT_CLEAN is set to 1 then the application can perform a garbage collection operation via FS_STORAGE_Clean() and FS_STORAGE_CleanOne(). For more information about the garbage collection refer to Garbage collection. The automatic garbage collection operation performed by the Block Map NOR driver is not disabled when FS_NOR_SUPPORT_CLEAN is set to 0. If the application does not call either FS_STORAGE_Clean() or FS_STORAGE_CleanOne() then FS_NOR_SUPPORT_CLEAN can be safely set to 0 in order to save ROM space.

FS_NOR_SUPPORT_CRC

FS_NOR_SUPPORT_CRC can be used to enable the support for the CRC verification. This feature has to be enabled at runtime via FS_NOR_BM_EnableCRC(). For more information about the CRC feature refer to CRC verification

FS_NOR_SUPPORT_ECC

FS_NOR_SUPPORT_ECC can be used to enable the support for the ECC verification. This feature has to be enabled at runtime via FS_NOR_BM_EnableECC(). For more information about the ECC feature refer to Bit error correction

FS_NOR_SUPPORT_FORMAT

FS_NOR_SUPPORT_FORMAT can be used to disable the support for the low-level format operation. The ability of the Block Map NOR driver to perform a low-level format operation is not required if the NOR flash device is already formatted for example by storing a file system image via an external utility to it. In such a case FS_NOR_SUPPORT_FORMAT can be set to 0 to reduce the ROM usage.

FS_NOR_SUPPORT_TRIM

FS_NOR_SUPPORT_TRIM can be used to enable or disable the handling of file system operations that inform the Block Map NOR driver about logical sectors that are no longer in use. The Block Map NOR driver can use this information to optimize the internal operation that copies the data from one physical sector to another by not copying the contents of the logical sectors that are marked as being no longer in use. Enabling this feature increases the ROM usage of the Block Map NOR driver.

FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER

This define can be used to specify if the byte order of the management data can be configured at runtime or not. By default, multi-byte management data is stored in the native order of the MCU on which the target application is running. With FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER set to 1 the byte order can be configured at runtime via FS_NOR_BM_SetByteOrderLE() and FS_NOR_BM_SetByteOrderBE(). FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER is set to 1 when building the NOR Image Creator utility in order to give it the ability to create images for a MCU with a different byte ordering than of the host PC. Typically, there is no need to modify the default value of FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER when building a target application.

FS_NOR_SUPPORT_VARIABLE_LINE_SIZE

FS_NOR_SUPPORT_VARIABLE_LINE_SIZE can be used to enable the runtime configuration of the minimum number of bytes to be written by the Block Map NOR driver at once. With FS_NOR_SUPPORT_VARIABLE_LINE_SIZE set to 1 the minimum number of bytes to be written at once can be configured via FS_NOR_BM_SetDeviceLineSize() between 1 and FS_NOR_LINE_SIZE. In addition, the ability of the NOR flash device to perform incremental write operations can be configured via FS_NOR_BM_SetDeviceRewriteSupport(). FS_NOR_SUPPORT_VARIABLE_LINE_SIZE is set to 1 when building the NOR Image Creator utility in order to give it the ability to create images for NOR flash devices with different characteristics. Typically, there is no need to modify the default value of FS_NOR_SUPPORT_VARIABLE_LINE_SIZE when building a target application.

FS_NOR_VERIFY_WRITE

This define can be used to activate the write verification of the Block Map NOR driver. The write verification is performed after each write operation by reading back the modified data from storage and by comparing it with the data requested to be written. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NOR_BM_SetWriteVerification().

Note

Activating the write verification can negatively affect the write performance.

FS_NOR_VERIFY_ERASE

This define can be used to activate the erase verification of the Block Map NOR driver. The erase verification is performed after each erase operation by reading back the entire data of the erase physical sector from storage and by comparing it with 0xFF. An error is reported if a difference is detected. This feature has to be enabled at runtime by calling FS_NOR_BM_SetEraseVerification().

Note

Activating the erase verification can negatively affect the write performance.

Runtime configuration

The driver must be added to the file system by calling FS_AddDevice() with the driver identifier set to the address of FS_NOR_BM_Driver. This function call together with other function calls that configure the driver operation have to be added to FS_X_AddDevices() as demonstrated in the following example. This example shows how to configure the file system to access a NOR flash device connected via SPI.

#include "FS.h"

#define ALLOC_SIZE 0x4000               // Size defined in bytes

static U32 _aMemBlock[ALLOC_SIZE / 4];  // Memory pool used for
                                        // semi-dynamic allocation.

/*********************************************************************
*
*       FS_X_AddDevices
*
*  Function description
*    This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
  //
  // Give the file system memory to work with.
  //
  FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
  //
  // Add and configure the NOR flash driver. The first 65536 bytes of the
  // serial NOR flash device are not used by the file system as data storage
  // and can be used by the application for other purposes. The file system
  // uses a total of 1 Mbyte from the serial NOR flash device as storage.
  //
  FS_AddDevice