FreeRTOS+FAT ramdisk creation on Nucleo-L476RG

sachingole wrote on Sunday, June 04, 2017:

Hi All,

I have Nucleo-L476RG development board, I am able to run FreeRTOS 8.2.3 version on it.
LED blinking code works good as expected.

I have integrated FreeRTOS v8.2.3 + FAT inside my source, build is sucessful.

For one of my use case I need ramdisk file system with few KB size.

This board processor has 128KB SRAM and 1MB flash(code size),

Currently I am trying to create ramdisk with size 75KB, I am getting following error.

FF_Format: Secs 142 Rsvd 1 Hidden 8 Root 32 Data 109
FF_Format: Can not make a FAT16 (tried 16) with 142 sectors

Can any help me to resolve following queries :-

1. Is it posible to create ramdisk with this much low size like 50KB or 75KB ?
2. any suggestion to create ramdisk with this much low SRAM.
3. Any significance form numbers from above error.

Reason to create ramdisk, one of my use case need file system and for this board there is no any another way to get memory like SD card or increase memory.

Thanks in advance for reply.

Best regards,
Sachin

heinbali01 wrote on Sunday, June 04, 2017:

Sachin, sure it is possible to have a very small volume.

You have to overrule the MS standards though, which define the minimum amount of clusters for FAT16 ( or FAT32 ).

#ifdef ffconfigMIN_CLUSTERS_FAT32
    #define MIN_CLUSTER_COUNT_FAT32        ffconfigMIN_CLUSTERS_FAT32
#else
    #define MIN_CLUSTER_COUNT_FAT32        ( 65525 )
#endif

#ifdef ffconfigMIN_CLUSTERS_FAT16
    #define MIN_CLUSTERS_FAT16            ffconfigMIN_CLUSTERS_FAT16
#else
    #define MIN_CLUSTERS_FAT16            ( 4085 + 1 )
#endif

Have a try with FAT16 and define ffconfigMIN_CLUSTERS_FAT16 very low:

    #define ffconfigMIN_CLUSTERS_FAT16    32

Within ff_ramdisk.c you might want to decrease ramHIDDEN_SECTOR_COUNT, I think that zero should work.

Also, for FAT16, you will have a root directory which can contain up to 512 entries. Not sure if you need that many?

    ucFATType = FF_T_FAT16;
    iFAT32RootClusters = 0;
    ulFATReservedSectors = 1u;
    iFAT16RootSectors = 32; /* to get 512 dir entries */

You could make iFAT16RootSectors lower, and ulFATReservedSectors as zero.

Please report back, good luck!

sachingole wrote on Sunday, June 04, 2017:

Thank you Hein, This reply motivated me to try further and get it done. Thanks once again.

Changes which I have done :-

  1. I have declared below line in ff_format.c
#define ffconfigMIN_CLUSTERS_FAT16    32
  1. I have declared below line in ff_ramdisk.c
#define ramHIDDEN_SECTOR_COUNT		0
  1. I have done below changes in ff_ramdisk.c
		ucFATType = FF_T_FAT16;
		iFAT32RootClusters = 0;
		ulFATReservedSectors = 0;
		iFAT16RootSectors = 8;

With above changes, Looks like partition creation is successful. Please see below logs :-

ffconfigMIN_CLUSTERS_FAT16 = 32

FF_Format: Secs 150 Rsvd 0 Hidden 0 Root 8 Data 142
FF_Format: SecCluster 1 DatSec 140 DataClus 140 ulClusterBeginLBA 2
FF_Format: Clearing entire FAT (2 x 1 sectors):
FF_Format: Clearing done
FF_Format: Clearing root directory at 00000002: 8 sectors
FF_RAMDiskInit: FF_Format:
FF_PartitionSearch: [F8,FF] No signature (00 00), no PBR neither
FF_RAMDiskInit: FF_Mount:
Reading FAT and calculating Free Space
pxIOManager->xPartition.ucType = 0

Then looks like it failed in function

	FF_RAMDiskShowPartition( pxRAMDisk );

Then flow goes to function and looks like
pxIOManager->xPartition.ucType = 0 so it goes in case
default:
pcTypeName = “UNKOWN”;
break;

Note : pxIOManager->xPartition.ucType value printed above.

When debugged further looks like it is going further function is

		FF_GetFreeSize( pxIOManager, &xError );

Further debugging take to next fuction

pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );

control is getting blocked inside this function, It doesnt come out of this. Any suggestion what could be missing.

sachingole wrote on Sunday, June 04, 2017:

Further debugging inside FF_CountFreeClusters( pxIOManager, &xError ); function, control gets blocked in below line :-

		FF_LockFAT( pxIOManager );

From below code snippet.

BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;

	if( xTakeLock )
	{
		FF_LockFAT( pxIOManager );
	}

Please could help to verify and suggest workaround, seems like variable lock synchronisation issue.

heinbali01 wrote on Monday, June 05, 2017:

Sachin, could you try with again with ulFATReservedSectors = 1 again?

About the lock synchronisation: is the kernel running when you create/mount the RAM-disk? That is necessary because the locking mechanism uses event groups.

I know there was a locking-related issue with FF_IncreaseFreeClusters().

Here is a patch for ‘ff_ioman.c’, around line 1703 :

     if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
     {
+        BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;

-        FF_LockFAT( pxIOManager );
+        if( xTakeLock )
+        {
+            FF_LockFAT( pxIOManager );
+        }
         {
             /* Find the an available cluster. */
             pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
         }
-        FF_UnlockFAT( pxIOManager );
+        if( xTakeLock )
+        {
+            FF_UnlockFAT( pxIOManager );
+        }
         if( FF_isERR( xError ) )
         {
             break;
         }
     }
     

Regards

sachingole wrote on Monday, June 05, 2017:

Thanks Hein for reply.

I have tried following changes, seems still we have some issue.

  1. I have done below changes in ff_ramdisk.c
		ulFATReservedSectors = 1u;
  1. above mentioned patch added in ff_ioman.c

Following are logs :-

FF_Partition:
ffconfigMIN_CLUSTERS_FAT16 = 32
FF_Format: Secs 150 Rsvd 1 Hidden 0 Root 8 Data 141
FF_Format: SecCluster 1 DatSec 139 DataClus 139 ulClusterBeginLBA 3
FF_Format: Clearing entire FAT (2 x 1 sectors):
FF_Format: Clearing done
FF_Format: Clearing root directory at 00000003: 8 sectors
FF_RAMDiskInit: FF_Format:
FF_Part: no partitions, try as PBR

sachingole wrote on Monday, June 05, 2017:

After debugging further I can see that I got stuck in following function.

FF_Error_t FF_Mount( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )

Stuck at below line

pxPartition->ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );

Which is inside these locks, seems again similar to above lock synchronisation issue.

			FF_LockFAT( pxIOManager );
			{
				/* The parameter 'pdFALSE' means: do not claim the free cluster found. */
				pxPartition->ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
			}
			FF_UnlockFAT( pxIOManager );

sachingole wrote on Monday, June 05, 2017:

After debugging inside this function.

uint32_t FF_FindFreeCluster( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, BaseType_t xDoClaim )

Control stuck at line no 1102 inside file ff_fat.c which is as below

		FF_LockFAT( pxIOManager );

heinbali01 wrote on Monday, June 05, 2017:

  1. Are you calling FF_Mount()directly or do you use FF_RAMDiskInit()?
  2. Is your scheduler running when you create the RAM-disk?

sachingole wrote on Monday, June 05, 2017:

Hi Hein,

  1. I have below function flow, FF_RAMDiskInit() internally calls FF_Mount()
	/* Create the RAM disk used by the FTP and HTTP servers. */
	prvCreateDiskAndExampleFiles();

Inside this it is calling

	/* Create the RAM disk. */
	pxRAMDisk = FF_RAMDiskInit( mainRAM_DISK_NAME, ucRAMDisk, mainRAM_DISK_SECTORS, mainIO_MANAGER_CACHE_SIZE );

Inside this it calls

			xError = prvPartitionAndFormatDisk( pxDisk );

Then it comes to

				/* Mount the partition. */
				xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
  1. scheduler is started after function prvCreateDiskAndExampleFiles() like below
	prvCreateDiskAndExampleFiles();

	LoggingPrintf("ramdisk creation successful\n");

	BSP_LED_On(LED2);

	xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );

	if( xQueue != NULL )
	{
		xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
    }
		/* Start the tasks and timer running. */
		vTaskStartScheduler();

heinbali01 wrote on Monday, June 05, 2017:

Could you call prvCreateDiskAndExampleFiles() after the scheduler has started, from the first task that becomes active, eg. from your prvQueueSendTask()?

sachingole wrote on Monday, June 05, 2017:

Hi Hein,

I have moved these calls in prvQueueSendTask like below

static void prvQueueSendTask( void *pvParameters )
{
	TickType_t xNextWakeTime;
	const unsigned long ulValueToSend = 100UL;

	/* Remove compiler warning about unused parameter. */
	( void ) pvParameters;

	/* Initialise xNextWakeTime - this only needs to be done once. */
	xNextWakeTime = xTaskGetTickCount();

	/* Create the RAM disk used by the FTP and HTTP servers. */
	prvCreateDiskAndExampleFiles();

	LoggingPrintf("ramdisk creation successful\n");

	BSP_LED_On(LED2);

Still it didnt help, please see logs below :-

Init boot is done                           
FF_Partition:
ffconfigMIN_CLUSTERS_FAT16 = 32                              
FF_Format: Secs 150 Rsvd 1 Hidden 0 Root 8 Data 141

Seems like this it stuck inside FF_RAMDiskInit()

sachingole wrote on Monday, June 05, 2017:

Following is function flow, how it reaches to infinite loop :-

main.c line no. 180

pxRAMDisk = FF_RAMDiskInit( mainRAM_DISK_NAME, ucRAMDisk, mainRAM_DISK_SECTORS, mainIO_MANAGER_CACHE_SIZE );

ff_ramdisk.c line no 183

xError = prvPartitionAndFormatDisk( pxDisk );

ff_ramdisk.c line no 368

xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE );

ff_format.c line no. 337

pucSectorBuffer = ( uint8_t * ) ffconfigMALLOC( 512 );

heap_4.c line no. 151

void *pvPortMalloc( size_t xWantedSize )

heap_4.c line no. 280

( void ) xTaskResumeAll();

list.c line no. 1698

( void ) uxListRemove( &( pxTCB->xEventListItem ) );

list.c line no. 216

List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

line no. 134

	b	Infinite_Loop

Also I have tried to decrese ram disk from 75KB to 50KB like below :-

define mainRAM_DISK_SECTORS			( ( 50UL * 1024UL ) / mainRAM_DISK_SECTOR_SIZE ) /* 50K bytes. */

Please see function flow, and help me to debug further to find problem.

heinbali01 wrote on Monday, June 05, 2017:

Can you increase the size of the stack for the task that uses +FAT?
Now it is only configMINIMAL_STACK_SIZE, which won’t be enough.
Can you give it 512 words?

sachingole wrote on Monday, June 05, 2017:

Hi Hein,

Thanks a lot for your valueable time and prompt responses. Finally things started working and I am able to create ramdisk with size 50KB.

Following are logs :-

Init boot is done
FF_Partition:
ffconfigMIN_CLUSTERS_FAT16 = 32
FF_Format: Secs 100 Rsvd 1 Hidden 0 Root 8 Data 91
FF_Format: SecCluster 1 DatSec 89 
DataClus 89 ulClusterBeginLBA 3
FF_Format: Clearing entire FAT (2 x 1 sectors):
FF_Format: Clearing done
FF_Format: Clearing root directory at 00000003: 8 sectors
FF_RAMDiskInit: FF_Format:
FF_Part: no partitions, try as PBR
FF_RAMDiskInit:
FF_Mount:
FF_FS_Add: Table full '/ram' (max = 1)
Reading FAT and calculating Free Space
pxIOManager->xPartition.ucType = 11
Partition Nr          0
Type 11 (FAT16)
VolLabel       'MY NAME    F'
TotalSectors        100
SecsPerCluster        1                                                       
Size                  0 MB
FreeSize              0 MB ( 100 perc free )

I have 3 task creation code, some either one combination works. Is is it because of memory constraints.

Either this task works

		xTaskCreate( prvRamDiskTask, "RAMDISKTASK", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RAMDISK_TASK_PRIORITY, NULL );

Or following 2 task works

		xTaskCreate( prvQueueReceiveTask, "Rx", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
		xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
  1. If I have both then it doesnt work.

Also I can see following issues in test code.
2. In file CreateAndVerifyExampleFiles.c inside function prvCreateDemoFileUsing_ff_fputc
configASSERT( strcmp( pcRAMBuffer, pcFileName ) == 0 );
This fails because
pcRAMBuffer = /SUB1/SUB2
and pcFileName = //SUB1/SUB2

  1. Looks like ff_truncate() fails,
	pxFile = ff_truncate( pcTestFileName, 1000L );
	ff_fclose( pxFile );
	ff_stat( pcTestFileName, &xStat );
	configASSERT( xStat.st_size == 1000L );

I can see that xStat.st_size is 0

  1. I have observed that prvTest_ff_findfirst_ff_findnext_ff_findclose() inside this funtion it iterate using ff_findnext( pxFindStruct ) but it returns reaiming 7 but it doesnt return “…”
    Following is expected to return
    const char *pcExpectedRootFiles[] =
{
	".",
	"..",
	"SUB1",
	"root001.txt",
	"root002.txt",
	"root003.txt",
	"root004.txt",
	"root005.txt"
};