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;
}