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);
}
}
signed long
. Only a matter of time until you get bugs caused by this. One solution is to never write "magic numbers" in your code, which you shouldn't be doing anyway. \$\endgroup\$