Search code examples
c++embeddedstm32stm32f4fatfs

FatFS - Cannot format drive, FR_MKFS_ABORTED


I am implementing a file system on SPI flash memory using a w25qxx chip and an STM32F4xx on STM32CubeIDE. I have successfully created the basic i/o for the w25 over SPI, being able to write and read sectors at a time.

In my user_diskio.c I have implemented all of the needed i/o methods and have verified that they are properly linked and being called.

in my main.cpp I go to format the drive using f_mkfs(), then get the free space, and finally open and close a file. However, f_mkfs() keeps returning FR_MKFS_ABORTED. (FF_MAX_SS is set to 16384)

  fresult = FR_NO_FILESYSTEM;
  if (fresult == FR_NO_FILESYSTEM)
  {
      BYTE work[FF_MAX_SS]; // Formats the drive if it has yet to be formatted
      fresult = f_mkfs("0:", FM_ANY, 0, work, sizeof work);
  }

  f_getfree("", &fre_clust, &pfs);

  total = (uint32_t)((pfs->n_fatent - 2) * pfs->csize * 0.5);
  free_space = (uint32_t)(fre_clust * pfs->csize * 0.5);

  fresult = f_open(&fil, "file67.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
  f_puts("This data is from the FILE1.txt. And it was written using ...f_puts... ", &fil);
  fresult = f_close(&fil);

  fresult = f_open(&fil, "file67.txt", FA_READ);
  f_gets(buffer, f_size(&fil), &fil);
  f_close(&fil);

Upon investigating my ff.c, it seems that the code is halting on line 5617:

if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */

n_clst is calculated a few lines up before some conditional logic, on line 5594:

n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;

Here is what the debugger reads the variables going in as:

enter image description here

This results in n_clst being set to 4294935040, as it is unsigned, though the actual result of doing the calculations would be -32256 if the variable was signed. As you can imagine, this does not seem to be an accurate calculation.

The device I am using has 16M-bit (2MB) of storage organized in 512 sectors of 4kb in size. The minimum erasable block size is 32kb. If you would need more info on the flash chip I am using, page 5 of this pdf outlines all of the specs.

This is what my USER_ioctl() looks like:

DRESULT USER_ioctl (
    BYTE pdrv,      /* Physical drive nmuber (0..) */
    BYTE cmd,       /* Control code */
    void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
    UINT* result = (UINT*)buff;
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);

    switch (cmd) {
        case GET_SECTOR_COUNT:
            result[0] = 512; // Sector and block sizes of
            return RES_OK;
        case GET_SECTOR_SIZE:
            result[0] = 4096;
            return RES_OK;
        case GET_BLOCK_SIZE:
            result[0] = 32768;
            return RES_OK;

    }
    return RES_ERROR;
  /* USER CODE END IOCTL */
}

I have tried monkeying around with the parameters to f_mkfs(), swapping FM_ANY out for FM_FAT, FM_FAT32, and FM_EXFAT (along with enabling exFat in my ffconf.h. I have also tried using several values for au rather than the default. For a deeper documentation on the f_mkfs() method I am using, check here, there are a few variations of this method floating around out there.


Solution

  • Here:

    fresult = f_mkfs("0:", FM_ANY, 0, work, sizeof work);
    

    The second argument is not valid. It should be a pointer to a MKFS_PARM structure or NULL for default options, as described at http://elm-chan.org/fsw/ff/doc/mkfs.html.

    You should have something like:

    MKFS_PARM fmt_opt = {FM_ANY, 0, 0, 0, 0};
    fresult = f_mkfs("0:", &fmt_opt, 0, work, sizeof work);
    

    except that it is unlikely for your media (SPI flash) that the default option are appropriate - the filesystem cannot obtain formatting parameters from the media as it would for SD card for example. You have to provide the necessary formatting information.

    Given your erase block size I would guess:

     MKFS_PARM fmt_opt = {FM_ANY, 0, 32768, 0, 0};
    

    but to be clear I have never used the ELM FatFS (which STM32Cube incorporates) with SPI flash - there may be additional issues. I also do not use STM32CubeMX - it is possible I suppose that the version has a different interface, but I would recommend using the latest code from ELM rather than ST's possibly fossilised version.

    Another consideration is that FatFs is not particularly suitable for your media due to wear-levelling issues. Also ELM FatFs has not journalling or check/repair function, so is not power fail safe. That is particularly important for non-removable media that you cannot easily back-up or repair.

    You might consider a file system specifically designed for SPI NOR flash such as SPIFFS, or the power-fail safe LittleFS. Here is an example of LittleFS in STM32: https://uimeter.com/2018-04-12-Try-LittleFS-on-STM32-and-SPI-Flash/