Electrical – STM32 Mass Storage with 8K allocation unit size

cmicrocontrollerstm32usb

I have an MSC/CDC Composite Device project that works with 4K allocation unit size for the mass storage. I am trying to convert this to use 8K allocation units instead, but the format does not complete successfully.

The flash memory is a QSPI flash (Cypress) with 32 4K sectors at the beginning, and 510 64K sectors afterwards. I want to use the 64K sectors because there are more of them. Unfortunately, I do not have 64K of RAM on the MCU (this is an STM32L443CCU) to cache the entire sector while I substitute new data. As such I have been using the 4K sectors as a backup area.

I cannot change the flash IC, or the microcontroller, so I have to use what I've got. If I use the 4K allocation unit size for mass storage, it works fine (it's slow, but it works). It cannot complete the format for the 8K allocation unit size.

Below are my functions for reading and writing, I would appreciate someone taking a fresh look over them to see if I missed something.

I have also updated the MSC_MEDIA_PACKET define to be 8192. I increased the heap and stack in the startup file, but I haven't seen any change in behaviour when doing that. Is there anything else I am forgetting?

Some defines first:

#define STORAGE_BLK_SIZ          8192
#define FLASH_MEMORY_PAGE_SIZE   256

The read function:

int8_t STORAGE_Read_FS (uint8_t lun,
                    uint8_t *buf,
                    uint32_t blk_addr,
                    uint16_t blk_len)
{ 
   uint32_t pages_to_read = STORAGE_BLK_SIZ * blk_len / FLASH_MEMORY_PAGE_SIZE;
   uint8_t err_code;
   uint32_t converted_block_addr = blk_addr * STORAGE_BLK_SIZ + 0x20000; // 0x20000 is where the 64K sectors start in flash

   if (converted_block_addr > 0x2000000)
   {
      // Outta memory :(
      return USBD_FAIL;
   }
   for (uint32_t i = 0; i < pages_to_read; i++)
   {
      err_code = flashMemory_ReadPage((converted_block_addr + i * FLASH_MEMORY_PAGE_SIZE), &buf[i * FLASH_MEMORY_PAGE_SIZE]);
      if (err_code != HAL_OK)
      {
         return (USBD_FAIL);
      }
   }
   return (USBD_OK);
}

The write function:

int8_t STORAGE_Write_FS (uint8_t lun,
                         uint8_t *buf,
                         uint32_t blk_addr,
                         uint16_t blk_len)
{

   // 1. Convert address to match the start of 64K sectors 
   uint32_t converted_block_addr = blk_addr * STORAGE_BLK_SIZ + 0x20000;
   if (converted_block_addr > 0x2000000)
   {
      // Outta memory :(
      return USBD_FAIL;
   }
   // 2. Figure out 64k sector that this address falls into
   uint32_t start_64k_sector = (uint32_t)(converted_block_addr / 0x10000) * 0x10000;
   // 3. Erase 4K sectors (starting at address 0x0) we need to store the 64K backup
   for (uint8_t i = 0; i < (65536/4096); i++)
   {
      flashMemory_EraseSector(i * 4096);
   }
   // 4. Copy 64k sector, one 256 byte page at a time, and store in the 4K sectors
   uint32_t page_64k_sector_addr = start_64k_sector;
   uint8_t buffer[256] = {0};
   for (uint16_t i = 0; i < 256; i++)
   {
      flashMemory_ReadPage(page_64k_sector_addr, buffer);
      flashMemory_WritePage(i * 256, buffer, 256);
      page_64k_sector_addr += 256;
   }
   // 5. Erase 64K sector
   flashMemory_Erase64KSector(start_64k_sector);
   // 6. Find location of data in 64k sector
   uint8_t data_loc_64k_sector = (converted_block_addr - start_64k_sector)/STORAGE_BLK_SIZ;
   // 7. a) Restore old data from 4K sectors, up until the point of new data
   for (uint16_t i = 0; i < data_loc_64k_sector; i++)
   {
      for (uint16_t j = 0; j < (STORAGE_BLK_SIZ/256); j++)
      {
         flashMemory_ReadPage(i * STORAGE_BLK_SIZ + j * 256, buffer);
         flashMemory_WritePage(start_64k_sector + i * STORAGE_BLK_SIZ + j * 256, buffer, 256);
      }
   }
   // 7. b) Write new data
   for (uint16_t j = 0; j < (STORAGE_BLK_SIZ/256); j++)
   {
      flashMemory_WritePage(start_64k_sector + data_loc_64k_sector * STORAGE_BLK_SIZ + j * 256, &buf[j * 256], 256);
   }
   // 7. c) Write all remaining old data after new data
   for (uint16_t i = (data_loc_64k_sector + 1); i < (65536/STORAGE_BLK_SIZ); i++)
   {
      for (uint16_t j = 0; j < (STORAGE_BLK_SIZ/256); j++)
      {
         flashMemory_ReadPage(i * STORAGE_BLK_SIZ + j * 256, buffer);
         flashMemory_WritePage(start_64k_sector + i * STORAGE_BLK_SIZ + j * 256, buffer, 256);
      }
   }

Best Answer

The issue was in the Storage_WriteFS function call, I was not using blk_len at all, so it would only write one block out of all of the supplied data.