USBX MSC + LVLX, USBD_STORAGE_Write and USBD_STORAGE_Read

RemiNao 20 Reputation points
2025-10-15T16:04:36.8833333+00:00

ello,  I am trying to set up an external flash memory (MX25V1635F) on a Nucleo-U575ZI-Q using SPI.

  • I managed to simulate a disk using RAM memory, Windows formats it perfectly, which leads me to believe that my USBX configuration is correct.
  • I also tested my LevelX functions for reading and writing to my NOR flash, and they seem to be working correctly, which leads me to believe that the LevelX configuration is correct.
  • I disabled all my FileX functions (format, open, read, and write) because it seems that Windows (USB Host) takes over the formatting. (Btw, if FileX can't be used, how can I write a formatted file to my flash memory?).

 

My problem: when I leave the USBD_STORAGE_Write and USBD_STORAGE_Read functions empty, Windows can see the size of my disk and offers to format it (without success):

RemiNao_0-1760366801083

And when I implement these two functions (based on the only example I found online using the Levelx functions lx_nor_flash_sector_write and lx_nor_flash_sector_read: LINK), Windows can no longer read my disk volume or offer to format it. I think my functions are not defined correctly : 

/**
  * @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(media_status);
  while(number_blocks--)
      {
 //         status =  fx_media_read(&nor_flash_disk,lba,data_pointer);
          status = lx_nor_flash_sector_read(&nor_flash,lba,data_pointer);
          data_pointer+=SECTOR_SIZE_LOGICAL;//512
          lba++;
          if (status != FX_SUCCESS) {
        	  Error_Handler();
          }
      }
//
//  for (UINT block = 0; block < number_blocks; block++)
//      {
//          //status =  fx_media_read(&nor_flash_disk,lba,data_pointer);
//          status = lx_nor_flash_sector_read(&nor_flash, lba + block, data_pointer);
//          data_pointer += SECTOR_SIZE_LOGICAL;//512
//          if(status != UX_SUCCESS)
//          {
//              break;
//          }
//      }

  /* 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(media_status);
  while(number_blocks--)
     {
//         status =  fx_media_write(&nor_flash_disk,lba,data_pointer);
         status = lx_nor_flash_sector_write(&nor_flash,lba,data_pointer);
         data_pointer+=SECTOR_SIZE_LOGICAL;//512
         lba++;
         if(status != FX_SUCCESS)
         {
        	 Error_Handler();
         }
     }
//  for (UINT block = 0; block < number_blocks; block++)
//     {
//         //status = fx_media_write(&nor_flash_disk, lba + block, data_pointer);
//	       status = lx_nor_flash_sector_write(&nor_flash, lba + block, data_pointer);
//         data_pointer += SECTOR_SIZE_LOGICAL;//512
//         if(status != UX_SUCCESS)
//         {
//             break;
//         }
//     }
  /* USER CODE END USBD_STORAGE_Write */

  return status;
}

For your information, here is the information from my storage instance when I do:

lx_nor_flash_open(&nor_flash, "NOR_FLASH_DISK", lx_stm32_nor_custom_driver_initialize);

RemiNao_0-1760540469454.png

Does LX_NOR_SECTOR_SIZE correspond to the size of a physical sector? Mine are 4096 bytes (or 1024 words). And will this value define the size of the logical sectors? I have the impression that the logical sectors need to be 512 bytes.

RemiNao_1-1760540539835.png

Can you help me? thanks

Azure RTOS
Azure RTOS
An Azure embedded development suite including a small but powerful operating system for resource-constrained devices.
{count} votes

Answer accepted by question author
  1. Nikhil Jha (Accenture International Limited) 4,230 Reputation points Microsoft External Staff Moderator
    2025-10-22T09:47:41.7133333+00:00

    Hello RemiNao,

    From your detailed post, code, and debug information. I have isolated the problem. Your tests with the RAM disk (proving USBX is correct) and standalone LevelX (proving your driver is correct) are perfect. The issue is, as you suspect, in the integration.

    This symptom points directly to a fundamental mismatch between your USBX and LevelX configurations, which is causing a classic buffer overflow.

    Possible cause you are facing is of Sector Size Mismatch:

    • USBX MSC Config: Your USBD_STORAGE_GetMediaBlocklength function correctly tells Windows that your disk's logical block (sector) size is 512 bytes. This is the standard for USB mass storage.
    • LevelX Config: Your debug screenshot of the nor_flash struct shows lx_nor_flash_sector_size: 4096. This means you have configured LevelX to use a 4096-byte logical sector.

    These two systems are not speaking the same language. Windows is asking for blocks of 512 bytes, but LevelX is reading and writing blocks of 4096 bytes.

    Workaround I would recommend:
    You must configure LevelX to use the same 512-byte logical sector size that USBX is using. The physical sector size of your flash (4096 bytes) is different, and LevelX's entire purpose is to manage this translation.

    You need to do this in your lx_stm32_nor_custom_driver_initialize function, which you pass to _lx_nor_flash_open. In that function, you must define the driver parameters.

    You need to set:

    • Physical Sector Size: The erase-block size of your flash. This should be 4096.
    • Logical Sector Size: The block size you want to expose. This must be 512 to match USBX.

    LevelX also requires an internal "scratch" buffer equal to the size of at least one physical sector (4096 bytes) to perform its read-modify-erase-write wear-leveling operations. You must also allocate and provide this buffer during initialization.

    Once LevelX is configured with a 512-byte logical sector, your USBD_STORAGE_Read and USBD_STORAGE_Write loops will work perfectly, as lx_nor_flash_sector_read will correctly read/write one 512-byte block at a time.

    Answering your other question "if FileX can't be used, how can I write a formatted file to my flash memory?"

    When used as a USB Mass Storage device, the Host (Windows) is the master. It controls the file system (FAT, exFAT, etc.).

    Your device's only job is to provide raw block-level access via USBD_STORAGE_Read and USBD_STORAGE_Write. You cannot (and must not) use FileX on the device at the same time, as the two file systems would instantly corrupt each other. If you need to pre-load the disk with a file, you will have to:

    1. Implement your FileX code first.
    2. In a "first boot" routine, open the media with FileX, format it, create a file, write to it, and close the media.
    3. Then, un-initialize FileX and start the USBX MSC class, handing over control to the host.

    Please accept the answer and upvote for visibility to other community members.

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.