FreeRTOS+FAT FF_Mount() fails IOMAN_INVALID_FORMAT

I am modifying the FF_RAMDiskInit, prvReadRAM and prvWriteRAM function to write directly to my 16MB NOR Flash directly (I have tested my drivers and wrote the routines to access my flash in blocks of data). Here is the result out of my console when I try to get the drive to mount from FF_Mount via the FF_RAMDiskInit (which I have not renamed yet).
FF_Partition: NONE
FF_Format: Secs 32760 Rsvd 1 Hidden 8 Root 32 Data 32727
FF_Format: SecCluster 1 DatSec 32473 DataClus 32473 pxSet->ulClusterBeginLBA 263
FF_Format: Clearing entire FAT (2 x 127 sectors):
FF_Format: Clearing done
FF_Format: Clearing root directory at 00000107: 32 sectors
FF_RAMDiskInit: FF_Format: NONE
FF_RAMDiskInit: FF_Mount: IOMAN_INVALID_FORMAT

I have some years of experience with FreeRTOS+FAT but not in a “raw data” situation like this. Any help or pointers you might have would be appreciated.

I would be curious to see how you altered ff_ramdisk.c, can you post the code?

Can you tell which type of flash it is? Especially I would like to know the erase- and the program-sizes.

Hello Hein,

This is the code I modified, although my first attempt was a little different. 
I changed it so that if the mount failed that it would format then mount so that it does not format every time. 
Obviously I have taken out the ram portion of the code that initializes the ram and removed the pointer that was passed in.  
I also include the read and write function that are now writing to my NAND flash (16MB).  
The intent is for a mostly read-only drive except for web and firmware updates (no logging) so I am not too concerned with wear leveling my flash.  

My main() call is at the bottom with the defines. 
I did not pre-erase sectors as they are done in 4096 byte blocks.  
It did not seem to be a problem when writing to the flash in my testing.  
The read and write code assumes 512 byte blocks.  
I don't know if that is correct or not as there is no length passed into the read and write functions.

Any help or hints you could provide would be much appreciated.
Thanks,
Joel.

/* This is the prototype of the function used to initialise the RAM disk driver.
 * Other media drivers do not have to have the same prototype.
 *
 * In this example:
 + pcName is the name to give the disk within FreeRTOS+FAT's virtual file system.
 + pucDataBuffer is the start of the RAM to use as the disk. (removed)
 + ulSectorCount is effectively the size of the disk, each sector is 512 bytes.
 + xIOManagerCacheSize is the size of the IO manager's cache, which must be a
 + multiple of the sector size, and at least twice as big as the sector size.
 */
FF_Disk_t * FF_RAMDiskInit( char * pcName,
                            uint32_t ulSectorCount,
                            size_t xIOManagerCacheSize )
{
    FF_Error_t xError;
    FF_Disk_t * pxDisk = NULL;
    FF_CreationParameters_t xParameters;

    /* Check the validity of the xIOManagerCacheSize parameter. */
    configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 );
    configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) );

    /* Attempt to allocated the FF_Disk_t structure. */
    pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) );

    if( pxDisk != NULL )
    {
        /* Start with every member of the structure set to zero. */
        memset( pxDisk, '\0', sizeof( FF_Disk_t ) );

        /* Clear the entire space. */
        /* The signature is used by the disk read and disk write functions to
         * ensure the disk being accessed is a RAM disk. */
        pxDisk->ulSignature = ramSIGNATURE;

        /* The number of sectors is recorded for bounds checking in the read and
         * write functions. */
        pxDisk->ulNumberOfSectors = ulSectorCount;

        /* Create the IO manager that will be used to control the RAM disk. */
        memset( &xParameters, '\0', sizeof( xParameters ) );
        xParameters.pucCacheMemory = NULL;
        xParameters.ulMemorySize = xIOManagerCacheSize;
        xParameters.ulSectorSize = ramSECTOR_SIZE;
        xParameters.fnWriteBlocks = prvWriteRAM;
        xParameters.fnReadBlocks = prvReadRAM;
        xParameters.pxDisk = pxDisk;

        /* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE.
         * In this case the semaphore is only used to protect FAT data
         * structures. */
        xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex();
        xParameters.xBlockDeviceIsReentrant = pdFALSE;

        pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError );

        if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
        {
            /* Record that the RAM disk has been initialised. */
            pxDisk->xStatus.bIsInitialised = pdTRUE;

            /* Record the partition number the FF_Disk_t structure is, then
                * attempt to mount the partition. */
            pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER;

            /* Mount the partition. */
            xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
            FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );

			if( FF_isERR( xError ) == pdTRUE )
	        {
				xError = prvPartitionAndFormatDisk( pxDisk );
			}
			else
			{
				goto InitializeDisk;
			}	

            if( FF_isERR( xError ) == pdFALSE )
            {
                /* Mount the partition. */
                xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
                FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
            }

InitializeDisk:
            if( FF_isERR( xError ) == pdFALSE )
            {
                /* The partition mounted successfully, add it to the virtual
                 * file system - where it will appear as a directory off the file
                 * system's root directory. */
                FF_FS_Add( pcName, pxDisk );
            }
        }
        else
        {
            FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) );

            /* The disk structure was allocated, but the disk's IO manager could
             * not be allocated, so free the disk again. */
            FF_RAMDiskDelete( pxDisk );
            pxDisk = NULL;
        }
    }
    else
    {
        FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" );
    }

    return pxDisk;
}

static int32_t prvReadRAM( uint8_t * pucDestination,
                           uint32_t ulSectorNumber,
                           uint32_t ulSectorCount,
                           FF_Disk_t * pxDisk )
{
    int32_t lReturn;
	uint32_t ulReadAddress;
	uint16_t usCount;

    if( pxDisk != NULL )
    {
        if( pxDisk->ulSignature != ramSIGNATURE )
        {
            /* The disk structure is not valid because it doesn't contain a
             * magic number written to the disk when it was created. */
            lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
        }
        else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
        {
            /* The disk has not been initialized. */
            lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
        }
        else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
        {
            /* The start sector is not within the bounds of the disk. */
            lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
        }
        else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
        {
            /* The end sector is not within the bounds of the disk. */
            lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
        }
        else
        {
			uint8_t *ptr = pucDestination;
			/* calculate the address of flash to start writing to. */
			ulReadAddress = ( ramSECTOR_SIZE * ulSectorNumber );
			
			for( usCount = 0; usCount < ulSectorCount; usCount++ )
			{
				if ( ReadQSPI( ptr, ulReadAddress + (usCount * ramSECTOR_SIZE), ramSECTOR_SIZE ) )
				{
					lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
					break;
				}
				ptr += ramSECTOR_SIZE;
			}
			lReturn = FF_ERR_NONE;
        }
    }
    else
    {
        lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
    }

    return lReturn;
}
/*-----------------------------------------------------------*/

static int32_t prvWriteRAM( uint8_t * pucSource,
                            uint32_t ulSectorNumber,
                            uint32_t ulSectorCount,
                            FF_Disk_t * pxDisk )
{
    int32_t lReturn = FF_ERR_NONE;
	uint32_t ulWriteAddress;
	uint16_t usCount;

    if( pxDisk != NULL )
    {
        if( pxDisk->ulSignature != ramSIGNATURE )
        {
            /* The disk structure is not valid because it doesn't contain a
             * magic number written to the disk when it was created. */
            lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
        }
        else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
        {
            /* The disk has not been initialized. */
            lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
        }
        else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
        {
            /* The start sector is not within the bounds of the disk. */
            lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
        }
        else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
        {
            /* The end sector is not within the bounds of the disk. */
            lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
        }
        else
        {
			uint8_t *ptr = pucSource;

			/* calculate the address of flash to start writing to. */
			ulWriteAddress = ( ramSECTOR_SIZE * ulSectorNumber );
			
			for( usCount = 0; usCount < ulSectorCount; usCount++ )
			{
				if ( WriteQSPI( ptr, ulWriteAddress + (usCount * ramSECTOR_SIZE), ramSECTOR_SIZE ) )
				{
					lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
					break;
				}
				ptr += ramSECTOR_SIZE;
				
			}
			lReturn = FF_ERR_NONE;
        }
    }
    else
    {
        lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
    }

    return lReturn;
}

#define FLASH_DISK_SIZE		0x1000000
#define FLASH_SECTOR_SIZE	512
#define FLASH_SECTOR_COUNT  FLASH_DISK_SIZE / FLASH_SECTOR_SIZE
#define FLASH_CACHE_SIZE	4096

        
	/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
	gFF_Disk_t = FF_RAMDiskInit( 
								"system_disk",
								FLASH_SECTOR_COUNT,
								FLASH_CACHE_SIZE );

Hello Hein,

I resolved my issue. I was not writing to the flash chip properly with the correct page size, and I was not pre-erasing the sectors as they were written. Since I have not seen multiple sectors written when the code is running, I just asserted that the sector size was always 1. Here is my code in case it helps someone else. It need more error checking but it does not need to be fast.
I am now able to mount the drive and write and read back a file.

/*-----------------------------------------------------------*/
static int32_t prvWriteRAM( uint8_t * pucSource,
                            uint32_t ulSectorNumber,
                            uint32_t ulSectorCount,
                            FF_Disk_t * pxDisk )
{
    int32_t lReturn = FF_ERR_NONE;
	uint32_t ulWriteAddress;
	uint16_t usCount;

	ASSERT( ulSectorCount == 1 );

    if( pxDisk != NULL )
    {
        if( pxDisk->ulSignature != ramSIGNATURE )
        {
            /* The disk structure is not valid because it doesn't contain a
             * magic number written to the disk when it was created. */
            lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
        }
        else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
        {
            /* The disk has not been initialized. */
            lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
        }
        else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
        {
            /* The start sector is not within the bounds of the disk. */
            lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
        }
        else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
        {
            /* The end sector is not within the bounds of the disk. */
            lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
        }
        else
        {
			#define ERASE_SECTOR_SIZE 0x1000        // flash erase sector size MUST ERASE BEFORE WRITE!!!!
			#define FLASH_PAGE_WRITE_SIZE 0x100     // flash page write size 256 bytes at a time.
			
			uint8_t u8Buffer[ ERASE_SECTOR_SIZE ];
			uint8_t *bufptr = u8Buffer;
			uint32_t ulEraseWriteSectorAddress;
			uint32_t ulWriteOffset;
			uint32_t ulWritePageAddress;
			
			// calculate the address of flash to to write the new sector to
			ulWriteAddress = ( ramSECTOR_SIZE * ulSectorNumber );

			// get the appropriate erase sector which is 4096 aligned 
			ulEraseWriteSectorAddress = ( ulWriteAddress / ERASE_SECTOR_SIZE ) * ERASE_SECTOR_SIZE;
			
			// read the 4096 sector block into memory so we can erase it, update it then write it back to flash.
			ReadQSPI( u8Buffer, ulEraseWriteSectorAddress, ERASE_SECTOR_SIZE );
			
			// erase the erase sector on the flash
			EraseQSPI( ulEraseWriteSectorAddress, ERASE_SECTOR_SIZE );
			
			// get the difference of the address
			ulWriteOffset = ulWriteAddress - ulEraseWriteSectorAddress; 			

			// offset into the internal buffer
			bufptr += ulWriteOffset;

			// copy the disk sector into the buffer
			memcpy( bufptr, pucSource, ramSECTOR_SIZE );			
			
			// reset the buffer to the sector buffer
			bufptr = u8Buffer;
			
			// initialize the write page address back to the beginning of the erased sector address
			ulWritePageAddress = ulEraseWriteSectorAddress;
			
			// write the erased and modified sector back to flash
			for( usCount = 0; usCount < ERASE_SECTOR_SIZE / FLASH_PAGE_WRITE_SIZE; usCount++ )				
			{
				// write the flash 256 bytes at a time back to the erased sector
				if ( WriteQSPI( bufptr, ulWritePageAddress , FLASH_PAGE_WRITE_SIZE ) )
				{
					lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
					break;
				}
				bufptr += FLASH_PAGE_WRITE_SIZE;
				ulWritePageAddress += FLASH_PAGE_WRITE_SIZE;
			}
			lReturn = FF_ERR_NONE;
        }
    }
    else
    {
        lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
    }

    return lReturn;
}

Good to hear, and thanks for reporting back.

ASSERT( ulSectorCount == 1 );

That depends on the write actions that you do. As soon as you write at least 2 sectors at a time, the data will be passed unbuffered to prvWriteRAM().
But what is the actual value of ERASE_SECTOR_SIZE and FLASH_PAGE_WRITE_SIZE?
The sector size of FAT must be at least 512 bytes, but you may define it larger, a multiple of 512 bytes.

Hello Hein,

As I tested writing larger files, I realized that I need to handle more that one block at a time (hit the ASSERT() of course). So a little more code is needed. Here are the sizes. I am tempted to just make my ramSECTOR_SIZE 4096 but I think that will waste a lot of space with small files which I will have a few for my web server app.

#define ERASE_SECTOR_SIZE 0x1000        // 4096 flash erase sector size MUST ERASE BEFORE WRITE!!!!
#define FLASH_PAGE_WRITE_SIZE 0x100     // flash page write size 256 bytes at a time.

Hi Joel, with the latest version of FreeRTOS+FAT it is possible to use sectors larger than 512 bytes.

When the sector size becomes 4096 bytes, it is indeed a waste of space, but it is also a lot easier and more efficient for you: each disk sector has its own erase area.

It is possible to continue with a sector size of 512 bytes, but a lot of extra programming will be needed. Read 4 KB, erase the area, write back the modified contents.

Mind you that before erasing or writing, it is good to check if anything has changed. Just to safe unnecessary writes. Reading from flash is relatively very fast compared to writing.

Good luck!

Hello Hein,

I just wanted to say thank you for your help. You gave me just the right hints to get my flash driver at least working. Below is my ultimate solution if it helps anyone. It is only suitable for occasionally writing but reading often since there is no wear leveling. I left the names the same just to make sense in the thread but I will be renaming functions and defines in my project after this. From this driver I was able to make a functional (if very slow) FTP server and HTTP server from the demo code provided in the FreeRTOS\FreeRTOS-Plus\Demo\Common\Demo_IP_Protocols directory.

Cheers!

#define EraseQSPI( addr, len ) SPI_NOR_FLASH_0->interface->erase(SPI_NOR_FLASH_0, addr, len )
#define WriteQSPI( buf, addr, len ) SPI_NOR_FLASH_0->interface->write(SPI_NOR_FLASH_0, buf, addr, len )
#define ReadQSPI( buf, addr, len ) SPI_NOR_FLASH_0->interface->read(SPI_NOR_FLASH_0, buf, addr, len )

#ifdef DEBUG
//	#define FLASH_DRIVE_WRITE_DEBUG
#endif // DEBUG	

/*-----------------------------------------------------------*/
static int32_t prvWriteRAM( uint8_t * pucSource,
                            uint32_t ulSectorNumber,
                            uint32_t ulSectorCount,
                            FF_Disk_t * pxDisk )
{
    int32_t lReturn = FF_ERR_NONE;

	// create the flash read/write buffer
	uint8_t *pu8FlashSectorBuf = NULL;

	if( pxDisk == NULL )
    {
			lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
			goto EXIT;
	}

    if( pxDisk->ulSignature != ramSIGNATURE )
    {
        /* The disk structure is not valid because it doesn't contain a
            * magic number written to the disk when it was created. */
        lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
		goto EXIT;
	}
    
	if( pxDisk->xStatus.bIsInitialised == pdFALSE )
    {
        /* The disk has not been initialized. */
        lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
		goto EXIT;
    }

	if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
    {
        /* The start sector is not within the bounds of the disk. */
        lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
		goto EXIT;
    }
	if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
    {
        /* The end sector is not within the bounds of the disk. */
        lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
		goto EXIT;
    }
    // Erase/Write sector size for the flash
	#define ERASE_SECTOR_SIZE 0x1000        // flash erase sector size 4096 MUST ERASE BEFORE WRITE!!!!
	// Flash page write size for when the data is ready to write
    #define FLASH_PAGE_WRITE_SIZE 0x100     // flash page write size 256 bytes at a time.
	
    // The number of page writes needed to write the Erase/Write sector back to flash
    #define PAGE_WRITES_PER_ERASE_SECTOR	ERASE_SECTOR_SIZE / FLASH_PAGE_WRITE_SIZE 
	// The number of 512 byte disk sectors per flash Erase/Write sector
    #define DISK_SECTORS_PER_ERASE_SECTOR   ERASE_SECTOR_SIZE / ramSECTOR_SIZE			
			
	// where in flash do we want to start reading and erasing sectors on 4096 byte boundaries
    // when the erase/write sector is complete this is where we will write it back
	uint32_t ulFlashEraseWriteAddress = ( ( ramSECTOR_SIZE * ulSectorNumber ) / ERASE_SECTOR_SIZE ) * ERASE_SECTOR_SIZE;
			
	// what is the current 512 byte disk sector number we are working with
	uint32_t ulCurrDiskSectorNumber = ulSectorNumber;  // initialize to the sector number passed in to start
	
	// how many sectors are left
	uint32_t ulCurrDiskSectorsLeft = ulSectorCount;
	
	// calculate disk sector at the start of the erased block
	uint32_t ulErasedSectorStart;
	
	// local position in the current flash sector buffer
	uint8_t *pu8FlashWriteBufPtr;
	
	// source buffer pointer
	uint8_t *pu8SourceBufPtr; 
	
	// internal sectorCount
	uint32_t sectorCount, usCount;
	

#ifdef FLASH_DRIVE_WRITE_DEBUG
	if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
	{
		vTaskSuspendAll();
		FF_PRINTF( "\n ulSectorNumber %u, ulSectorCount %u \n", ulSectorNumber, ulSectorCount );
	}
#endif // FLASH_DRIVE_WRITE_DEBUG

	// allocate a buffer to read and write the 4096 byte read/erase/write data
	pu8FlashSectorBuf =  pvPortMalloc( ERASE_SECTOR_SIZE );
	
	if( !pu8FlashSectorBuf )	
	{
			/* The end sector is not within the bounds of the disk. */
		lReturn = ( FF_ERR_NOT_ENOUGH_MEMORY | FF_ERRFLAG );
		goto EXIT;
	}
	
	// initialize the the source pointer
	pu8SourceBufPtr = pucSource;
		
	while( 1 ) 
	{
		// calculate disk sector at the start of the erased block
		ulErasedSectorStart = ulFlashEraseWriteAddress / ramSECTOR_SIZE;
		
		// reset the buffer pointer to the start of the read/write buffer
		pu8FlashWriteBufPtr = pu8FlashSectorBuf;
				
#ifdef FLASH_DRIVE_WRITE_DEBUG
		if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
			printf( "\nulFlashEraseWriteAddress %X",  ulFlashEraseWriteAddress );
#endif // FLASH_DRIVE_WRITE_DEBUG
		
		// read the 4096 byte block into memory so we can erase it, update it and then write it back to flash.
		if( ReadQSPI( pu8FlashSectorBuf, ulFlashEraseWriteAddress, ERASE_SECTOR_SIZE ) )
        {
            lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
            break;
        }
		// erase the sector on the flash
		if( EraseQSPI( ulFlashEraseWriteAddress, ERASE_SECTOR_SIZE ) )
        {
            lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
            break;
        }
		
		// initialize the destination pointer
		pu8FlashWriteBufPtr = pu8FlashSectorBuf;
		
		// calculate disk sector at the start of the start of the erased block
		sectorCount = ulErasedSectorStart;
		
#ifdef FLASH_DRIVE_WRITE_DEBUG
		if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
			printf( "\nulCurrDiskSectorsLeft %u, ulErasedSectorStart %u", ulCurrDiskSectorsLeft, ulErasedSectorStart );
#endif // FLASH_DRIVE_WRITE_DEBUG
		
		// write any new data to the the write buffer
        for( usCount = 0; usCount < DISK_SECTORS_PER_ERASE_SECTOR; usCount++ ) // do not want to overrun the read/write buffer
		{
			// if the sector submitted is in the middle if the erase block
			// we need to leave the start of the read block intact and 
			// move past it before starting the write to the block
			if( sectorCount < ulCurrDiskSectorNumber ) // if we are not into the buffer far enough to start writing to it.
			{

#ifdef FLASH_DRIVE_WRITE_DEBUG
				if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
					printf( "\n skipping: sectorCount %u > ulCurrDiskSectorNumber %u", sectorCount, ulCurrDiskSectorNumber );
#endif // FLASH_DRIVE_WRITE_DEBUG
				
				// move on to the next sector
				sectorCount++;
				pu8FlashWriteBufPtr += ramSECTOR_SIZE;
				continue;
			}
		
#ifdef FLASH_DRIVE_WRITE_DEBUG
			if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
				printf( "\ncopying: ulCurrDiskSectorNumber %u from %x to %x (512)", ulCurrDiskSectorNumber, (uint32_t)pu8SourceBufPtr, pu8FlashWriteBufPtr  );
#endif // FLASH_DRIVE_WRITE_DEBUG

			// copy the sector into the buffer
			memcpy( pu8FlashWriteBufPtr, pu8SourceBufPtr, ramSECTOR_SIZE );
			
			// are there any sectors left to process?
			ulCurrDiskSectorsLeft--;
			if( !ulCurrDiskSectorsLeft )
				break;

			// next disk sector.
			ulCurrDiskSectorNumber++;
			sectorCount++;
			
			// move to the next sector in the buffer
			pu8FlashWriteBufPtr += ramSECTOR_SIZE;
			pu8SourceBufPtr += ramSECTOR_SIZE;
		}		

		// reset the buffer pointer so we can read it out 256 bytes at a time and write it to flash
		pu8FlashWriteBufPtr = pu8FlashSectorBuf;
		
		// write the erased and modified sector back to flash
       for( usCount = 0; usCount < PAGE_WRITES_PER_ERASE_SECTOR; usCount++ )				
		{

#ifdef FLASH_DRIVE_WRITE_DEBUG
			if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
				printf( "\npu8FlashWriteBufPtr %x, ulFlashEraseWriteAddress %x", (uint32_t)pu8FlashWriteBufPtr, (uint32_t)ulFlashEraseWriteAddress );
#endif // FLASH_DRIVE_WRITE_DEBUG

			// write the flash 256 bytes at a time back to the erased sector
			if ( WriteQSPI( pu8FlashWriteBufPtr, ulFlashEraseWriteAddress, FLASH_PAGE_WRITE_SIZE ) )
			{
				lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
				break;
			}
			pu8FlashWriteBufPtr += FLASH_PAGE_WRITE_SIZE;
			ulFlashEraseWriteAddress += FLASH_PAGE_WRITE_SIZE;
		}
	
		
		if( lReturn ) // if we got an error in the write loop then get out
			break;

		// if there are no sectors left to write then get out
        if( !ulCurrDiskSectorsLeft )
			break;
	
		// move on to the next erase sector if there are more sectors to process
	} // end while( 1 )

EXIT:

#ifdef FLASH_DRIVE_WRITE_DEBUG
 	if( ulSectorCount > DISK_SECTORS_PER_ERASE_SECTOR )
	{
		printf( "\nSector Writes Complete! lReturn %u \n\n", lReturn );
		xTaskResumeAll();
	}
#endif // FLASH_DRIVE_WRITE_DEBUG	

	if( pu8FlashSectorBuf ) 
		vPortFree( pu8FlashSectorBuf );

    return lReturn;
}

Thank you for taking time to report back.