cancel
Showing results for 
Search instead for 
Did you mean: 

QSPI + FatFS + USB mass storage

Posted on March 21, 2018 at 15:12

Hello there,

I am trying to connect 3 sub-systems:

  • qspi flash memory
  • FatFS
  • USB mass storage device

I have successfully written low level drivers for qspi and have connected it with FatFS middleware. I can read and write file and all- this is working.

Now I need to connect the FatFS layer with USB mass storage layer. I am working with the examples found in CubeMx as well as this:

https://community.st.com/thread/44445-using-fatfs-to-access-sd-card-and-usb-mass-storage-device#comments

My problem is that I quite do not understand how the usb mass storage part reaches for files in the FatFs. I thought at the beginning, that the function pointer for USB mass storage lib would be something like: list files, open file, read file, get file time stamp etc... Now I see that there are function pointers for reading and writing some kind of blocks, which have nothing to do with files in my opinion (at least I see no connection yet):

int8_t STORAGE_Init(uint8_t lun);

int8_t STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size);

int8_t STORAGE_IsReady(uint8_t lun);

int8_t STORAGE_IsWriteProtected(uint8_t lun);

int8_t STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);

int8_t STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);

int8_t STORAGE_GetMaxLun(void);

USBD_StorageTypeDef USBD_DISK_fops = {

STORAGE_Init,

STORAGE_GetCapacity,

STORAGE_IsReady,

STORAGE_IsWriteProtected,

STORAGE_Read,

STORAGE_Write,

STORAGE_GetMaxLun,

(int8_t *)STORAGE_Inquirydata,

};

How to translate data from files like language that FatFS is speaking to the language that USB mass storage API will understand? How are FatFs sectors related to USB mass storage blocks?

I would appreciate all help.

#qspi #usb-mass-storage #fatfs

Note: this post was migrated and contained many threaded conversations, some content may be missing.
11 REPLIES 11
Posted on March 21, 2018 at 16:04

The underlying media is a block storage system. The ability to store an arbitrary block of data, and then recover that same data at some point in the future.

The FAT File System defines the use of those blocks, the content and structure contained within them.

https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system

 

https://en.wikipedia.org/wiki/File_Allocation_Table

 

The DISKIO layer of the FatFS implementation reads and writes the blocks/sectors on the media. The typical sector size dating back to the CPM and DOS days is 512 bytes. At the time it was an optimal mix of data length vs bit error/detection, and headers, gaps, etc.

Other types of file system include NTFS and UDF

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 21, 2018 at 16:23

Hi

Turvey.Clive

‌ thanks for answer,

I do get the block access idea- in my system 512 bytes is also the block size. The part I dont understand is how to connect FAT filesystem on my device with the USB mass storage link. There are no functions like open file, close file, read file or write file. All there is for the user is to write blocks of data and read them, without any division on files.

So my question is, if I am to write a connection code between FatFS and USB mass storage, how can I overcome this? I understand the concept of file system, i dont understand how to deliver it to the USB mass storage part.

For example: Imagine I have already created 3 files and wrote something to them. They reside in my file system. On the FatFs interface part I do not know where exactly they are in the filesystem and how are they distributed in the memory. I access them through f_open, f_read etc. The USB mass storage on the other hand requires block addresses and sizes. How to connect this?

Posted on March 21, 2018 at 16:42

ST's method is to have a 'wedge' DISKIO implementation for FATFS that vectors the block IO calls to the specific storage layer/drive being used. So you have a structure of function pointers, one goes to SDIO/SDMMC, another to USBSTOR/MSC, QSPI, NOR/NAND, etc.

/**

  * @brief  Gets Disk Status

  * @param  pdrv: Physical drive number (0..)

  * @retval DSTATUS: Operation status

  */

DSTATUS disk_status (

    BYTE pdrv        /* Physical drive number to identify the drive */

)

{

  DSTATUS stat;

  stat = disk.drv[pdrv]->disk_status(disk.lun[pdrv]);

  return stat;

}

/**

  * @brief  Initializes a Drive

  * @param  pdrv: Physical drive number (0..)

  * @retval DSTATUS: Operation status

  */

DSTATUS disk_initialize (

    BYTE pdrv                /* Physical drive nmuber to identify the drive */

)

{

  DSTATUS stat = RES_OK;

  if(disk.is_initialized[pdrv] == 0)

  {

    disk.is_initialized[pdrv] = 1;

    stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);

  }

  return stat;

}

/**

  * @brief  Reads Sector(s)

  * @param  pdrv: Physical drive number (0..)

  * @param  *buff: Data buffer to store read data

  * @param  sector: Sector address (LBA)

  * @param  count: Number of sectors to read (1..128)

  * @retval DRESULT: Operation result

  */

DRESULT disk_read (

    BYTE pdrv,        /* Physical drive nmuber to identify the drive */

    BYTE *buff,        /* Data buffer to store read data */

    DWORD sector,            /* Sector address in LBA */

    UINT count        /* Number of sectors to read */

)

{

  DRESULT res;

  res = disk.drv[pdrv]->disk_read(disk.lun[pdrv], buff, sector, count);

  return res;

}

The MSC implementation has to provide a number of SCSI/ATAPI-MMC type commands (READ, WRITE, TEST-UNIT-READY, GET CAPACITY, INQUIRY, etc), as your Windows/Linux system sends IO requests to the media, and implements the FAT, NTFS, UDF etc with File System drivers on the host, NOT on the flash stick or external hard drive.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 21, 2018 at 16:46

See also Application\FatFs directories for your board/chip, or close target

Here the F7 being an OTG host to a MSC/USBSTOR type device plugged into the board

STM32Cube_FW_F7_V1.9.0\Projects\STM32F767ZI-Nucleo\Applications\FatFs\FatFs_USBDisk\readme.txt

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 23, 2018 at 05:47

Thank you for answer,

Ok now I think I get the idea... Please confirm either this is right or wrong. I thought the design for this would look like this:

0690X0000060ADJQA2.png

Where as it has to work like this:

0690X0000060ADTQA2.png

The USB mass storage cannot use the FatFs file system, since it already has its own file system. The FatFs mapping has to be 100% covered with the maping done by the windows or linux computer connected through USB. Is that correct?

Posted on March 23, 2018 at 16:50

At the moment I am using FAT16 filesystem on the MCU (formated with FatFS). I have created the needed links for the USB mass storage system. My problem is that at the moment after I connect the USB the PC asks me either I wasnt to format the driveas it cannot read it. I wonder where could the incomparability come from. This is my readinf function:

/**

  * @brief  Reads data from the medium.

  * @param  lun: unused

  * @param  buf: pointer to data buffer

  * @param  blkAddr: Logical block address

  * @param  noOfBlocks: Blocks number

  * @retval Status (0: Ok / -1: Error)

  */

int8_t usbds_read(uint8_t lun, uint8_t* buf, uint32_t blkAddr, uint16_t noOfBlocks)

{

    (void)lun;

    assert_param(buf);

    const uint32_t len = noOfBlocks * fat_getClusterSize();

    if (HAL_OK != qspi_readData(blkAddr, buf, len))

        return USBDS_RET_ERR;

    return USBDS_RET_OK;

}

The qspi_readData function takes as parameters: direct flash address in bytes, data buffer, amount of bytes. Do I understand correctly that blkAddr should be the qspi address, or should it be a 'block address', which is a multiplication of block size? I would appreciate further help.

Posted on March 23, 2018 at 18:00

In the general sense the logic needs to equate too

AddressWithinQSPI = blkAddr * BLK_SIZE;

LengthInBytes = noOfBlocks * BLK_SIZE;

AddressInSTM32 = 0x90000000 + AddressWithinQSPI ;

If you have it memory mapped, then memcpy() would be efficient, though might not play well with Erase/Write operations.

Don't think it is working with clusters, Blocks != Clusters (except for small media), Blocks = Sectors, fat_getClusterSize() is likely to get to be 8KB or 32KB, etc depending on size of media, and not appropriate here. Cluster management should be occurring deeper in FatFs, and noOfBlock likely peak at the cluster size.

The QSPI pages can be smaller than 512 bytes, often 256 bytes in devices I've seen. On write you'd need to pre-erase the pages you expect to write, and then write the new data.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 23, 2018 at 18:03

Yes, and only one of these should have control otherwise you will get coherency issues and damage, as Windows will cache content and write with no regard to what FatFs might be doing.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 23, 2018 at 18:20

Turvey.Clive

‌ thank you for answer,

As for the qspi and flash part- I have everything covered (erasing before writing to non formatted memory sectors etc). As for this example you can assume that the function qspi_readData(blkAddr, buf, len) and qspi_writeData(blkAddr, buf, len) work as it was reading/ writing to ram memory. They are also thread safe (I am not using memory mapped btw).

Now before connecting the device to the PC host using USB, I have internally created a FAT16 filesystem and created a file there (using FatFS). After connecting the PC asks for formatting the device, as it doesnt recognize any file system. For the FatFs there are 2 kind of 'blocks': sectors and clusters. Sector in my case is 512 B. Cluster consists of couple sectors (not sure how many, but I can check). Now I do not know what should be the block size (in read function) for the USB device. Should it be somehow connected to sectors and clusters of FatFS? How is it connected?

Also, the USB read function requires the block address. Should it be the direct flash address, or the address / blockSize? So ihe address 1024 would be blockAddress = 3?