How to format USB drive with TexFAT programmatically

We are using a USB drive which is formatted as FAT32 to log run-time data. The idea is to preserve the lifetime of the internal flash memory within the Colibri module by logging data to USB instead. We use both T20 and iMX6 modules with WinCE 7.

But we are seeing occasional file system corruption on the USB drive, the symptoms are files which disappear and folders which can no longer be written to and cannot be deleted even if they are empty. I am exploring using TexFAT instead to benefit from the transaction safety in case of the power failing while writing. I just learned about TexFAT this week even though it is a very old piece of technology. I was encouraged to learn that the internal flash in the Colibri is formatted using TexFAT.

I can format USB drives using the interactive Storage Manager in WinCE using a mouse and a display. If I format the drive as TexFAT then I can confirm that TexFAT is active by calling CeGetVolumeInfo() and confirming that the flag CE_VOLUME_TRANSACTION_SAFE is set for that volume.

My question is, how can I format using TexFAT from code in my application? What I want to do in code is something like this:

  1. Check if USB drive uses FAT32, exFAT or TexFAT
  2. Reformat it as TexFAT if needed

Here are a few references:
Transaction-Safe FAT File System - Wikipedia
Issue SD Card Corruption - Technical Support - Toradex Community
Getting USB mass storage to work on T20 using USB on-the-go - Technical Support - Toradex Community
Non Volatile Memory Storage using C# - Technical Support - Toradex Community

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

Did you like my answer? :+1: :-1:


Hello! Thank you for your clear and detailed description of your scenario.

Based on your requirements and the available documentation, here is guidance on checking the file system type of a USB drive and formatting it as TexFAT programmatically on your Colibri T20 and iMX6 running Windows CE 7.

1. Check the File System Type Programmatically

You can use the CeGetVolumeInfo() API to determine the current file system and to check if the CE_VOLUME_TRANSACTION_SAFE flag is set. This lets you identify whether the volume is formatted as TFAT (TexFAT).

Example Logic:

CE_VOLUME_INFO volInfo;
if (CeGetVolumeInfo(L"\\USB Disk", CE_VOLUME_INFO_LEVEL, &volInfo, sizeof(volInfo))) {
    if (volInfo.dwFlags & CE_VOLUME_TRANSACTION_SAFE) {
        // TexFAT or TFAT is active
    } else {
        // Regular FAT
    }
}

2. Programmatically Format the USB Drive as TexFAT

To format a volume programmatically, you would use the Storage Manager APIs:

However, the key to enabling TFAT is to set the proper flag when calling FormatPartition(). The documentation in the knowledge base highlights that while code samples are not provided, the process from the Storage Manager UI involves selecting the TFAT option, which must be mapped to the flag value in your function call.

Basic flow for formatting:

  1. Use FindFirstStore() / FindFirstPartition() to enumerate and identify your USB storage/partition.
  2. Use DismountPartition() as needed.
  3. Call FormatPartition() with the appropriate parameters and with the TFAT flag enabled.

Pseudocode Outline

// Open handle to storage manager
HANDLE hStore = OpenStore(storeName);
// Get partition info
HANDLE hPart = OpenPartition(hStore, partitionName);
// Unmount (dismount) partition before formatting
DismountPartition(hPart);
// Set TFAT flag and format
DWORD formatFlags = FORMAT_SKIP_CONFIRMATION | FORMAT_ENABLE_TFAT;
BOOL bResult = FormatPartition(hPart, formatFlags, NULL);
// Mount partition again
MountPartition(hPart);

Notes:

  • The actual value for FORMAT_ENABLE_TFAT may need to be defined. If not available in your header files, you may want to refer to platform-specific defines or Microsoft/ODM documentation.
  • Make sure to check your device’s documentation for the correct store and partition names for your USB device.

3. Additional References

4. Important Considerations

  • Backup Important Data: Formatting a drive will erase all data on it.
  • User Confirmation: For production systems, consider providing a way for the user to confirm the formatting action.

5. Example Discussion

Here’s a relevant discussion thread you might find helpful:
Issue SD Card Corruption - Toradex Community


In summary:

  • Use CeGetVolumeInfo() to detect TFAT.
  • Use the Storage Manager APIs (OpenStore, OpenPartition, FormatPartition with flag for TFAT) to format partitions programmatically.
  • The process is similar for both T20 and iMX6 running WinCE 7.

If you need a more detailed sample code, let me know and I can help structure it further.

Best regards,
Toradex AI Assistant.

@ToradexAI that is close to what I am looking for. But the FormatPartition() and FormatPartitionEx() functions do not have a parameter for flags, they are defined in storemgr.h like this:

BOOL   WINAPI FormatPartition(HANDLE hPartition);
BOOL   WINAPI FormatPartitionEx(HANDLE hPartition, BYTE bPartType, BOOL bAuto);

What I am looking for is how to pass a parameter into the FormatPartition() function to specify that TFAT or TexFAT should be used.

Thanks for your response.

Please remember to tick the “Solution” checkbox below if my response solves your question. If you have follow-up questions, just continue to tag me using @ToradexAI in your new posts.

Did you like my answer? :+1: :-1:


Hello! Thank you for this clarification and for providing the exact function signatures.

You are correct: on Windows CE for Toradex modules (like T20 and iMX6), the FormatPartition() and FormatPartitionEx() APIs do not offer a parameter to select TFAT (TexFAT) directly at runtime. The choice of whether to enable TFAT is actually controlled through device registry settings before the format takes place—not by passing a flag during the format operation.

Here’s how TFAT is typically enabled for external storage devices like USB drives in Windows CE:

How TFAT Formatting Is Controlled

  • For Internal Flash:
    The StorageManager profile in the registry determines if TFAT is used. (See Toradex Flash File System documentation)
  • For External Storage (USB, SD):
    To format as TFAT from code, you need to adjust the StorageManager profile for that volume in the registry so that when you subsequently call FormatPartition(), the file system will be formatted as TFAT.

What to Do in Code

  1. Update Registry Settings Programmatically
    Before you call FormatPartition() on your USB drive, update the relevant StorageManager registry profile (for the USB device) to enable TFAT formatting.

  2. Reboot or Unmount/Remount (if required)
    Sometimes, Windows CE requires a reboot or remount of the device for the new registry settings to take effect.

  3. Call FormatPartition()
    When formatting, the StorageManager will see the registry and choose TFAT. There is no direct runtime parameter to FormatPartition() for this.

Example: Setting Registry for TFAT

You will need to set certain registry keys under:

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\USBHD]

Or similar, depending on your device. You would set:

  • "MountFlags"=dword:00000002 (this flag enables TFAT)
  • "FormatTFAT"=dword:1

(Exact names/values may vary by platform; see the Toradex Flash File System documentation for precise details.)

After updating the relevant keys, calling FormatPartition() on the USB volume will use TFAT.

Interactive UI vs. Programmatic Approach

The Storage Manager interactive UI allows you to pick the TFAT option. Programmatically, you must set the registry in advance so the StorageManager framework chooses TFAT for you.


Summary

  • You cannot pass a flag to FormatPartition()/FormatPartitionEx() to explicitly request TFAT.
  • Set the appropriate registry keys for the USB drive profile to enable TFAT formatting.
  • After registry setup, call FormatPartition() as usual.

For more about the registry keys and profile details:

Let me know if you need a registry code example or have questions about which registry keys to use for your specific device.

Best regards,
Toradex AI Assistant.

@ToradexAI at first I tried using the default registry settings. A simplified version of my code is:

HANDLE hStore = OpenStore(storeName);
HANDLE hPartitionSearch = FindFirstPartition(hStore, &partInfo);
HANDLE hPartition = OpenPartition(hStore, partInfo.szPartitionName);
DismountPartition(hPartition);
FormatPartition(hPartition);
MountPartition(hPartition);
CloseHandle(hPartition)
FindClosePartition(hPartitionSearch);
CloseHandle(hStore);

The call to DismountPartition() returns TRUE and I see the USB HD folder disappear from the Colibri file system, which is reassurig as it means I do have the handle to the correct partition.

The call to FormatPartition() also returns TRUE, but the call to MountPartition() returns FALSE and the USB HD folder does not reappear in my system.

If I open the Storage Manager on the device I can see that the partition in the USB drive is unmounted. If I press the button to mount it I get the error message, “Unable to mount partition”. If I reformat the drive in the Storage Manager then I am able to mount it correctly.

I also tried using FormatPartitionEx() but saw the same results. I tried copying the values of the registry entries for FormatExFat, FormatTFat and Dll from [HKLM\StorageManager\Profiles\BootMMC\FATFS] to [HKLM\StorageManager\Profiles\USBHDProfile\FATFS] but saw the same result. I performed this test on a Colibri iMX6.

Could you try FormatVolume() with _FORMAT_OPTIONS flag set to FATUTIL_FORMAT_TFAT ?

Please double check if your OS image supports TexFAT. Have you tried to format USB stick or an SD card to TexFAT using StorageManager applet?

As for registry settings please check this article.

Hi @alex.tx, thanks for replying.

I am able to format the USB drive with TexFAT using the StorageManager applet. When I do that I am then able to use CeGetVolumeInfo() in my code and confirm that the CE_VOLUME_TRANSACTION_SAFE flag is set. This makes me think that my OS image does support TexFAT. I am using version 1.8 of the CE7 image for iMX6.

The link you sent for FormatVolume() sounds promising but the header file formatdisk.h does not seem to be part of the BSP and so I can’t compile my code if I try to use that function.

Reading the links you sent me did make me think of a few more things to try which did allow me to get this to work! I was doing this before, but MountPartition() was failing:

HANDLE hStore = OpenStore(storeName);
HANDLE hPartitionSearch = FindFirstPartition(hStore, &partInfo);
HANDLE hPartition = OpenPartition(hStore, partInfo.szPartitionName);
DismountPartition(hPartition);
FormatPartition(hPartition);
MountPartition(hPartition);

I realized that what I need to do is this instead:

HANDLE hStore = OpenStore(storeName);
DismountStore(hStore);
FormatStore(hStore);
CreatePartition(hStore, ...);

When I did it that way the new partition is automatically mounted and appears in the file system. I also figured out that I was able to specify TexFAT by adding registry entries to [HKLM\SYSTEM\StorageManager\FATFS].

Here is the full code which checks to see if TexFAT is enabled and if it is not enabled then it reformats using TexFAT, in case someone else finds this discussion in the future and needs the same thing. After doing this the CE_VOLUME_TRANSACTION_SAFE is set and if I insert the USB drive into my PC I can see that file system was changed from FAT32 to exFAT. So I think this is working.

// Call CeGetVolumeInfo() to see if the CE_VOLUME_TRANSACTION_SAFE flag is set
// If the flag is set then USB drive is already using either the TFAT or TexFAT file system
CE_VOLUME_INFO ceVolumeInfo;
memset(&ceVolumeInfo, 0, sizeof(CE_VOLUME_INFO));
ceVolumeInfo.cbSize = sizeof(CE_VOLUME_INFO);
BOOL success = CeGetVolumeInfo(L"\\USB HD", CeVolumeInfoLevelStandard, &ceVolumeInfo);
BOOL transactionSafe = FALSE;
if (success)
{
    transactionSafe = ceVolumeInfo.dwFlags & CE_VOLUME_TRANSACTION_SAFE;
    if (!transactionSafe)
    {
        // Change the file system to TexFAT by reformatting the USB drive
        STOREINFO storeInfo;
        memset(&storeInfo, 0, sizeof(STOREINFO));
        storeInfo.cbSize = sizeof(STOREINFO);
        HANDLE hStoreSearch = FindFirstStore(&storeInfo);
        if (hStoreSearch != INVALID_HANDLE_VALUE)
        {
            BOOL success;
            do
            {
                if (storeInfo.dwDeviceType & STORAGE_DEVICE_TYPE_USB)
                {
                    HANDLE hStore = OpenStore(storeInfo.szDeviceName);
                    if (hStore != INVALID_HANDLE_VALUE)
                    {
                        if (DismountStore(hStore))
                        {
                            // Specify that we want TexFAT by setting two registry keys
                            HKEY hKey;
                            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\StorageManager\\FATFS", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
                            {
                                DWORD data = 1;
                                DWORD size = sizeof(DWORD);
                                if ((RegSetValueEx(hKey, L"FormatExFat", NULL, REG_DWORD, (byte*)&data, size) == ERROR_SUCCESS) &&
                                    (RegSetValueEx(hKey, L"FormatTFat", NULL, REG_DWORD, (byte*)&data, size) == ERROR_SUCCESS))
                                {   
                                    if (FormatStore(hStore))
                                    {
                                        // If I use CreatePartition() then the new partition appears in the WinCE Storage Manager as type 0x0B, which is FAT32
                                        // But using CHKDSK on Windows 11 I can see that the drive is actually using exFAT
                                        // Using CreatePartitionEx() allows me to specify the partition type as 0x07, which is exFAT
                                        // This makes the partition look correct in Storage Manager but does not seem to have any other effect
                                        // I cannot find a #define for the partition type in the BSP
                                        if (CreatePartitionEx(hStore, L"MyPart", 0x07, storeInfo.snNumSectors))
                                        {
                                            printf("Success!\n");
                                        }
                                    }
                                }
                                RegCloseKey(hKey);
                            }
                        }
                        CloseHandle(hStore);
                    }
                }
                success = FindNextStore(hStoreSearch, &storeInfo);
            } while (success);
            FindCloseStore(hStoreSearch); 
        }
    }
}

Thank you for the update. I’m glad to hear that your issue has been resolved

@alex.tx I measured the performance of my USB drive with FAT32, exFAT and TexFAT. The results are interesting and a bit surprising. The USB drive has 8GB of capacity and I used a 4K allocation unit size with all three formats.

The first test uses a single 15 MB file. I see the same performance for reading and writing that file with all three formats. I can read at 20.0 MB/sec and write at 4.3 MB/sec. That’s a good result.

The second test uses a set of 2000 small files (A few bytes each) spread across about 800 folders. I saw these results for writing the set of files:

FAT32 write 34 files per second
exFAT write 26 files per second (22% slower than FAT32)
TexFAT write 16 files per second (52% slower than FAT32)

It seems reasonable that writing many files to TexFAT will take longer due to the transaction protection overhead.

The surprising result was for reading the set of 2000 files:

FAT32 read 611 files per second
exFAT read 83 files per second (86% slower than FAT32)
TexFAT read 91 files per second (85% slower than FAT32)

The difference between exFAT and TexFAT is probably not statistically significant. But reading lots of small files from FAT32 is way faster. I would have expected the read performance to be more similar as the transaction protection shouldn’t cause an overhead. Maybe it’s slow due to having to read a journal rather than just read the raw data?

Does it make sense to you that reading small files is much slower with exFAT than wth FAT32?

How did you perform the testing? The exFAT/TexFAT file systems support a ‘Last Accessed’ timestamp, so even read access may result in writes. According to what I found online, on Windows, the ‘Last Accessed’ timestamp on exFAT may only change when a file is modified (e.g., edited or saved), or when using tools like Windows Explorer that trigger such updates. I’m not sure if this behavior also applies to Windows CE.

I used the code below to recursively copy a set of files and folders between the USB drive and the RAM drive. There is some variability in the result so I run the test five times and average the results. It takes nearly 4 minutes for this test to write 3400 small files to USB using TexFAT, and about 30 seconds to read 3400 files from USB.

SYSTEMTIME t1, t2;
INT32 fileCount = 0;
GetSystemTime(&t1);
CopyFiles(L"\\USB HD\\CopyTest", L"\\Temp\\CopyTest", &fileCount);
GetSystemTime(&t2);
INT64 dt = CMyTime::Subtract(t2, t1);
float fileRate = fileCount / dt;

void CopyFiles(const CString &sourcePath, const CString &destinationPath, INT32 *count)
{
    WIN32_FIND_DATA fileData;   // Data structure describes the file found
    HANDLE hSearch;             // Search handle returned by FindFirstFile
    BOOL moreFiles = true;
    CreateDirectory(destinationPath, NULL);
    (*count)++;
    hSearch = FindFirstFile(sourcePath + L"/*.*", &fileData);
    if (hSearch != INVALID_HANDLE_VALUE)
    {
        while (moreFiles)
        {
            // Don't recursively search into the . and .. folders
            INT32 length = wcslen(fileData.cFileName);
            WCHAR* lastChar = fileData.cFileName + length - 1;
            if (*lastChar != L'.')
            {
                CString sourceFilePath = sourcePath + L"/" + fileData.cFileName;
                CString destinationFilePath = destinationPath + + L"/" + fileData.cFileName;
                if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    CopyFiles(sourceFilePath, destinationFilePath, count);
                }
                else
                {
                    CopyFile(sourceFilePath, destinationFilePath, FALSE);
                    (*count)++;
                }
            }
            moreFiles = FindNextFile(hSearch, &fileData);
        }
        FindClose(hSearch);
    }
}