FLASH内部结构
Table 5. Flash module organization (STM32F40x and STM32F41x)
Block Name Block base addresses Size
Main memory
Sector 0 0x0800 0000 - 0x0800 3FFF 16 Kbytes
Sector 1 0x0800 4000 - 0x0800 7FFF 16 Kbytes
Sector 2 0x0800 8000 - 0x0800 BFFF 16 Kbytes
Sector 3 0x0800 C000 - 0x0800 FFFF 16 Kbytes
Sector 4 0x0801 0000 - 0x0801 FFFF 64 Kbytes
Sector 5 0x0802 0000 - 0x0803 FFFF 128 Kbytes
Sector 6 0x0804 0000 - 0x0805 FFFF 128 Kbytes
.............................
Sector 11 0x080E 0000 - 0x080F FFFF 128 Kbytes
System memory 0x1FFF 0000 - 0x1FFF 77FF 30 Kbytes
OTP area 0x1FFF 7800 - 0x1FFF 7A0F 528 bytes
Option bytes 0x1FFF C000 - 0x1FFF C00F 16 bytes
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
uint32_t n,ii;
uint32_t Address = 0;
if(blk_addr < BLOCK1_VA_ADDR)
{
Address = BLOCK1_PY_ADDR;
}
else if(blk_addr < BLOCK2_VA_ADDR)
{
Address = BLOCK2_PY_ADDR;
blk_addr -= BLOCK1_VA_ADDR;
}
else if(blk_addr < BLOCK3_VA_ADDR)
{
Address = BLOCK3_PY_ADDR;
blk_addr -= BLOCK2_VA_ADDR;
}
else if(blk_addr < BLOCK4_VA_ADDR)
{
Address = BLOCK4_PY_ADDR;
blk_addr -= BLOCK3_VA_ADDR;
}
else
{
return (USBD_FAIL);
}
for(n = 0;n < blk_len;n++)
{
for(ii = 0;ii<STORAGE_BLK_SIZ;ii++)
{
buf[ii] = (*(__IO uint8_t*)(Address + ((n + blk_addr) * STORAGE_BLK_SIZ) + ii));
}
}
return (USBD_OK);
/* USER CODE END 6 */
}
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
uint32_t n,ii,index,erase_flag = 0;
uint32_t Address = 0, FLASH_SECTOR = 5, SectorError = 0;
// 地址转换
if(blk_addr < BLOCK1_VA_ADDR)
{
Address = BLOCK1_PY_ADDR;
FLASH_SECTOR = 5;
}
else if(blk_addr < BLOCK2_VA_ADDR)
{
Address = BLOCK2_PY_ADDR;
blk_addr -= BLOCK1_VA_ADDR;
FLASH_SECTOR = 6;
}
else if(blk_addr < BLOCK3_VA_ADDR)
{
Address = BLOCK3_PY_ADDR;
blk_addr -= BLOCK2_VA_ADDR;
FLASH_SECTOR = 7;
}
else if(blk_addr < BLOCK4_VA_ADDR)
{
Address = BLOCK4_PY_ADDR;
blk_addr -= BLOCK3_VA_ADDR;
FLASH_SECTOR = 8;
}
else
{
return (USBD_FAIL);
}
// 判断是否是可用块
index = 0;
erase_flag = 0;
for(n = 0;n < blk_len;n++)
{
for(ii = 0;ii<STORAGE_BLK_SIZ;ii++)
{
RAM_DISK[index] = (*(__IO uint8_t*)(Address + ((n + blk_addr) * STORAGE_BLK_SIZ) + ii));
if(RAM_DISK[index] != 0xff)
{
erase_flag = 1;
break;
}
index++;
}
}
// 如果已经使用,全部读出来后,擦除
HAL_FLASH_Unlock();
if(erase_flag)
{
// 读出来
for(n = 0;n < (32 * 1024); ++n)
{
RAM_DISK[n] = (*(__IO uint8_t*)(Address + n));
}
// 擦除
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR;
EraseInitStruct.NbSectors = 1;
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
{
return (USBD_FAIL);
}
// 修改数据
for(n = 0;n < blk_len;n++)
{
for(ii = 0;ii<STORAGE_BLK_SIZ;ii++)
{
RAM_DISK[(blk_addr + n) * STORAGE_BLK_SIZ + ii] = buf[n * STORAGE_BLK_SIZ + ii];
}
}
// 回写
for(n = 0;n < (32 * 1024); ++n)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, Address + n, RAM_DISK[n]) != HAL_OK)
{
return (USBD_FAIL);
}
}
}
else
{
// 写入
for(n = 0;n < blk_len;n++)
{
for(ii = 0;ii<STORAGE_BLK_SIZ;ii++)
{
HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, Address + ((n + blk_addr) * STORAGE_BLK_SIZ) + ii, buf[n * STORAGE_BLK_SIZ + ii]);
}
}
}
HAL_FLASH_Lock();
return (USBD_OK);
/* USER CODE END 7 */
}
本例使用Sector 5/6/7/8共4 Sector,每Sector 会用前面32K,这样一共就能模拟128K的U盘,每个block为512B,逻辑上共256 Block。
在读的时候,直接根据blk_add判断使用的哪些block,然后对应到物理地址Sector,然后直接读取,这部分没问题。
在写的时候,当写入(写入包括FAT表部分和DATA部分)时,先判断blk_add和blk_len,把blk_add*512B*blk_len的数据读出来,判断是否全为0XFF,如果全部为0XFF,则直接写。否则已经使用,需要擦除再写。
那么问题来了:
当所要写入的区域需要擦除的时候,此时因为每个Sector只使用前面32K,所以得先把原有的32K读到SRAM,然后把128K的Sector擦除,在读出来的32K数据中,改写需要写入的数据,然后再把32K回写到Sector中。那么,FAT表得改写,数据也得改写,而且FAT表和数据不一定在同一Sector中,此时就需要多次擦除,这不但效率慢(擦除过程需要时间),而且操作频繁,FLASH是有寿命的。
所以,这种方法是不可取的,本人接触不久,水平有限,暂时没有想到什么好方法,还请各路大神指点迷津。