I'm on Arduino Uno (SAMD21 architecture) and I'm using FatFs to have a FAT file system. I also use Adafruit SPIFlash library to enable low-level read/write on the flash memory (so I call its APIs in the FatFs->diskio.cpp file).
The memory chip is Winbond W25Q64JVSM.
I've noticed an issue when I've started to fill a file with data from a for loop (simplified code):
char buff[32];
for (unsigned int i = 0; i < 399; ++i)
{
memset(buff, 0, sizeof(buff)); // erase the buffer
snprintf(buff, sizeof(buff), "%d,", i); // fill it
f_write(file, buff, strlen(buff), &wr); // write the string into file
}
f_sync(file);
When I go reading the file, I expect it to be filled with a single line containing:
0,1,2,3,4,5,.....,398,
Instead, the line always stops at a certain point, precisely "153,".
I can say that:
- f_write never returns errors
- If I query the size of the file, it returns the expected size of bytes
- I did not experience this issue when writing shorter lines of just 5/10 chars.
- For the previous point, I was thinking about a sync issue and I need to wait for an actual write operation to end, but I think I'm doing it correctly in the "diskio.cpp" file, see below.
Following relevant parts of my code:
#define MAX_FREQ 10000000 // SAMD21 SPI chip max speed = 12MHz
#define SECTOR_SIZE 4096
#define PAGE_SIZE 256
#define BLOCK_SIZE 1
#define CHIP_SELECT 3
FatFs->diskio.cpp
static Adafruit_FlashTransport_SPI _flashTransport(CHIP_SELECT, SPI);
static Adafruit_SPIFlash _flash(&_flashTransport);
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
_flashTransport.setClockSpeed(MAX_FREQ, MAX_FREQ);
if (_flash.begin()) return RES_OK;
else return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
BYTE * b = buff;
if(_flash.readBlocks(sector, b, count)) return RES_OK;
else return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
BYTE * b = (BYTE*) buff;
if (_flash.writeBlocks(sector, buff, count)) return RES_OK;
else return RES_ERROR;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = RES_ERROR;
switch( cmd )
{
case CTRL_SYNC : // Make sure that data has been written
_flash.syncBlocks(); // <<--- this should prevent any sync issue with writing (?)
res = RES_OK;
break;
case GET_SECTOR_COUNT :
*(LBA_t*)buff = _flash.size() / SECTOR_SIZE;
res = RES_OK;
break;
case GET_SECTOR_SIZE :
*(WORD*)buff = SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE :
*(DWORD*)buff = BLOCK_SIZE;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
return res;
}
The flash memory was initialized this way (already checked for bad return codes):
BYTE work[SECTOR_SIZE];
MKFS_PARM p = {FM_FAT, 1, 0, 0, SECTOR_SIZE};
f_mkfs("", &p, work, sizeof work);
f_mount(&fs, "", 1);
Am I missing something?
(This question is also on StackOverflow: https://stackoverflow.com/questions/74265635/fatfs-f-write-stops-working-after-writing-some-data)