cancel
Showing results for 
Search instead for 
Did you mean: 

USBX MSC + FileX + NAND Flash - Windows I/O

Pepils
Associate II

Hello,

I am building and application with a STM32U575 and a 4Gb NAND Flash. What I am trying to achieve now is to upload files from my PC through USB and then used these file within the STM32 using FileX.

I already managed to set up FileX and LevelX to create and manipulate files within the MCU. Then I managed to get a USBX MSC device to appead in windows, with correct capacity, name etc..
Finally I tried to implement the read/write functions in ux_device_msc.c by using the FileX function fx_media_read and fx_media_write. And not I have some issues in the wrinting method.

If I implement the read function "USBD_STORAGE_Read" only, leaving the write function empty, everyting works fine. I am able to find and read my files from windows.


From the moment I implement the USBD_STORAGE_Write function, nothing works anymore. In this configuration, the USB MSC apprears in windows with a capacity of 0 octets and windows stalls if I try to access it. After some digging, I found out that windows tries to write at block 0, which is prevented by the fx_media_write function.

What am I doing wrong here?

Thank you in advance for your help.

1 ACCEPTED SOLUTION

Accepted Solutions
MWB_CHa
ST Employee

Hi @Pepils 

Your use case is interesting although we never tested it.

First, you must use the LevelX, otherwise you risk to damage your memory part. (ie. USB Host will try to write multiple times to block0 and it will be worn). (It is probable that you already damaged sector 0, so I advise that you first check it with a simple read/write example using FileX/LevelX).

Of course you can't use FileX, since Windows will manage the file system directly. (as @Pavel A.  explained, you can't have two file system owners on the same memory in the same time).

The other point of vigilance would be checking the timings: Windows (and more generally USB Host MSC) has some strict timing values for read/write operations. While using NAND (with its LevelX wear leveling algos) leads to variable access timing depending on the status of the sectors and usage rate of the NAND memory.

I hope it helps.

View solution in original post

5 REPLIES 5
Pavel A.
Evangelist III

When Windows tries to write block 0, what is the data? Does it look reasonable?

Do you implement synchronization of  writes from Windows over the MSC interface and writes by FileX?

Hi @Pavel A. ,

Thank you for your answer.

Yes, the block zero that windows tries to write seems legit. I attached the contents of block 0 read and then the windows attempt to block zero write.

And yes, I implement the hole thing in the MSC interface. Please find below my implementation of the USBD_STORAGE_Read and USBD_STORAGE_Write functions:

/**
  * @brief  USBD_STORAGE_Read
  *         This function is invoked to read from media.
  * @param  storage_instance : Pointer to the storage class instance.
  * @param  lun: Logical unit number is the command is directed to.
  * @param  data_pointer: Address of the buffer to be used for reading or writing.
  * @param  number_blocks: number of sectors to read/write.
  * @param  lba: Logical block address is the sector address to read.
  * @param  media_status: should be filled out exactly like the media status
  *                       callback return value.
  * @retval status
  */
UINT USBD_STORAGE_Read(VOID *storage_instance, ULONG lun, UCHAR *data_pointer,
                       ULONG number_blocks, ULONG lba, ULONG *media_status)
{
  UINT status = UX_SUCCESS;

  /* USER CODE BEGIN USBD_STORAGE_Read */
  UX_PARAMETER_NOT_USED(storage_instance);
  UX_PARAMETER_NOT_USED(lun);
  UX_PARAMETER_NOT_USED(media_status);
  
  ULONG i;
  for(i=0; i < number_blocks; i++)
  {
    /* Check if the media has been red successfully */
    if (fx_media_read( &nand_flash_disk, lba, data_pointer) != FX_SUCCESS)
    {
      Error_Handler();
    }
    data_pointer += nand_flash_disk.fx_media_bytes_per_sector;
  }
  /* USER CODE END USBD_STORAGE_Read */

  return status;
}

/**
  * @brief  USBD_STORAGE_Write
  *         This function is invoked to write in media.
  * @param  storage_instance : Pointer to the storage class instance.
  * @param  lun: Logical unit number is the command is directed to.
  * @param  data_pointer: Address of the buffer to be used for reading or writing.
  * @param  number_blocks: number of sectors to read/write.
  * @param  lba: Logical block address is the sector address to read.
  * @param  media_status: should be filled out exactly like the media status
  *                       callback return value.
  * @retval status
  */
UINT USBD_STORAGE_Write(VOID *storage_instance, ULONG lun, UCHAR *data_pointer,
                        ULONG number_blocks, ULONG lba, ULONG *media_status)
{
  UINT status = UX_SUCCESS;

  /* USER CODE BEGIN USBD_STORAGE_Write */
  UX_PARAMETER_NOT_USED(storage_instance);
  UX_PARAMETER_NOT_USED(lun);
  UX_PARAMETER_NOT_USED(media_status);

  ULONG i;
  for(i=0; i < number_blocks; i++)
  {
    /* Check if the media has been red successfully */
    if (fx_media_write( &nand_flash_disk, lba, data_pointer) != FX_SUCCESS)
    {
      Error_Handler();
    }
    data_pointer += nand_flash_disk.fx_media_bytes_per_sector;
  }
  /* USER CODE END USBD_STORAGE_Write */

  return status;
}

 

I read somewhere that the MSC interface should access the storage media directly without passing by FileX. Thus using the QSPI interface in my case. However, the NAND flash need a lot of management already handled by LevelX. Maybe should I use the LevelX api instead of the FileX api? I did not find a way to instantiate the LevelX driver thought.

Thank you again for your help.

Pavel A.
Evangelist III

The NAND flash is a "dumb" storage, it only can have one master at any time. Consider what happens if your program and the host decide to write concurrently. The host side has its own view of the storage, it may have a cache... It looks like the FileX has a minimal safeguard from its POV. Extra flash layers such as LevelX won't change this.

MWB_CHa
ST Employee

Hi @Pepils 

Your use case is interesting although we never tested it.

First, you must use the LevelX, otherwise you risk to damage your memory part. (ie. USB Host will try to write multiple times to block0 and it will be worn). (It is probable that you already damaged sector 0, so I advise that you first check it with a simple read/write example using FileX/LevelX).

Of course you can't use FileX, since Windows will manage the file system directly. (as @Pavel A.  explained, you can't have two file system owners on the same memory in the same time).

The other point of vigilance would be checking the timings: Windows (and more generally USB Host MSC) has some strict timing values for read/write operations. While using NAND (with its LevelX wear leveling algos) leads to variable access timing depending on the status of the sectors and usage rate of the NAND memory.

I hope it helps.

Pepils
Associate II

Hi @MWB_CHa ,

Thank you for your answer and explanations. I supposed that the fx_media_xxx functions were designed to address this somehow. Apparently this is not the case.

I changed my code to use LevelX functions instead. This seems to work better. But I had other problems which prevented to make it work as it should (hardware ECC and spare bytes constrains of the Flash not compatible with LevelX).

Finally, I changed for a NOR flash and everythings worked like a charm in a matter of hours (with LevelX API).

Thank you again.