FreeRTOS+FAT + USB Mass Storage Device Class

swichu91 wrote on Thursday, February 22, 2018:

Hello,

I have project which implements FreeRTOS+FAT and USB Host configured as MSC Class. The goal is to transfer files from PC to devboard’s FAT inside RAM. The problems is, when I am creating or updating existing files from PC I see that correct data are transfered to RAM but FAT itself won’t notice those changes, for example upon opening modified file or creating new one invoking ff_fopen will return NULL or will show old file size. After some code scavenging I found that this is happening due to page buffering/caching. I’ve managed to solve this problem by setting IO_MANAGER_CACHE_SIZE to minimal value (2). This seemed to resolve problem but I am not sure if it’s correct way to disable/limit? buffering or is this only working by accident.

Could you confirm this or propose different workaround ?

Thanks in advance
Mateusz

rtel wrote on Saturday, February 24, 2018:

Does this help? https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Embedded_File_System_Configuration.html#ffconfigCACHE_WRITE_THROUGH

heinbali01 wrote on Sunday, February 25, 2018:

Hi Mateusz, does your embedded device also make changes to the same FAT partition?
The two ways of access are really incompatible, both the PC and the embedded device have a FAT driver, and both have low-level access.
And even if +FAT has read-only access, the partition might not always be stable.
USB has low-level SCSI access to the partition. At certain moments (during updates), the drive will contain incomplete or inconsistent information. Normally, a FAT driver will lock a directory and it will lock the File Allocation Table. But in your situation, these locks are useless.

Can’t you unmount the drive as long as USB is active, and remount it as soon as USB disconnects?

Using 2 cache buffers would be very inefficient when using an SD-card. Your partition is stored in RAM, so you will notice less that there is extra copying.

swichu91 wrote on Sunday, February 25, 2018:

Hi Hein,

Thank you for response.

I am familiar with what you wrote. Basically I am looking for a way to sync/update +FAT after host/PC actions. I developed system such way that there is no concurrent access to device’s FAT. Is there any way to request +FAT synchronization(refetch/flush cache buffers ?). I am thinking that I could send such request after USB write etc. That way I could configure +FAT to use more cache buffers

I am afraid that unmounting/mounting +FAT is not possible as user will have to unplug device after each file update etc.

Temporarily I am using ramdisk but in future application will use eMMC which is practically the SD card so as you said, using 2 cache buffers will be inefficient.

Richard

I’ve already set ffconfigCACHE_WRITE_THROUGH to 1 but it didn’t help :frowning:

Any ideas ?

heinbali01 wrote on Sunday, February 25, 2018:

If you can avoid that the two drivers work simultaneously on the same partition, there might be a way.

I suppose that you’ve seen where +FAT flushes the cache:

FF_Error_t FF_FlushCache( FF_IOManager_t *pxIOManager );

Here below is a sketch for a function that will invalidate all buffers:

FF_Error_t FF_InvalidateCache( FF_IOManager_t *pxIOManager )
{
BaseType_t xIndex;
FF_Error_t xError;

    if( pxIOManager == NULL )
    {
        xError = FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
    }
    else
    {
        xError = FF_ERR_NONE;

        FF_PendSemaphore( pxIOManager->pvSemaphore );
        {
            for( xIndex = 0; xIndex < pxIOManager->usCacheSize; xIndex++ )
            {
                /* If a buffers has no users and if it has been modified... */
                if( ( pxIOManager->pxBuffers[ xIndex ].usNumHandles != 0 ) ||
                    ( pxIOManager->pxBuffers[ xIndex ].bModified == pdTRUE ) )
                {
                    /* Can not flush all caches. */
                    xError++;
                }
                else
                {
                    /* Mark the buffer as invalid so that it won't be used again. */
                    pxIOManager->pxBuffers[ xIndex ].bValid = pdFALSE;
                }
            }
        }

        FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
    }

    /* Function successful if it returns 0. */
    return xError;
}    /* FF_FlushCache() */
/*-----------------------------------------------------------*/

Now before USB becomes active, you can call both functions:

    FF_FlushCache( pxIOManager );
    if( FF_InvalidateCache( pxIOManager ) != 0 )
    {
        /* Not all buffers could be invalidated. */
    }

Note that there is more caching:

#define ffconfigHASH_CACHE 1 /* Enable HASH to speed up file creation. */
#define ffconfigPATH_CACHE 1 /* Enables a simply Path Caching mechanism
                              * that increases performance of repeated
                              * operations. */

You could try to switch them off, in case they’re enabled.

Hein

swichu91 wrote on Tuesday, February 27, 2018:

Hein,

Small update, I’ve managed to solve this issue using snippet that you uploaded :slight_smile: I would like to thank you very much for help. As always your responses are 100% valid and quick as possible :slight_smile:

Best regards
Mateusz

heinbali01 wrote on Wednesday, February 28, 2018:

Good to hear, thanks.
Now you can use a normal cache size again to make it run more efficiently.
I think that 4 KB ( 8 sectors ) is a good size.
Regards, Hein