首先我们都知道我们的代码是保存在FLASH里的,FLASH的数据掉电不会消失,所以我们也可以将FLASH当作eeprom来用,这里以H743为例,743有两个1M的bank,每个bank有8个128k的扇区,我们需要注意的是每个扇区写之前都是要先擦除的,这也是为什么750不能用FLASH当做eeprom来用,一般750会额外外挂一个外扩的FLASH芯片,比如w25q之类的,因为750只有一块扇区,首先我们看一下743的扇区:
/* FLASH 扇区的起始地址,分2个bank,每个bank 1MB */
/* BANK1 */
#define BANK1_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Bank1扇区0起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_1 ((uint32_t)0x08020000) /* Bank1扇区1起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_2 ((uint32_t)0x08040000) /* Bank1扇区2起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_3 ((uint32_t)0x08060000) /* Bank1扇区3起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_4 ((uint32_t)0x08080000) /* Bank1扇区4起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_5 ((uint32_t)0x080A0000) /* Bank1扇区5起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_6 ((uint32_t)0x080C0000) /* Bank1扇区6起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_7 ((uint32_t)0x080E0000) /* Bank1扇区7起始地址, 128 Kbytes */
/* BNAK2 */
#define BANK2_FLASH_SECTOR_0 ((uint32_t)0x08100000) /* Bank2扇区0起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_1 ((uint32_t)0x08120000) /* Bank2扇区1起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_2 ((uint32_t)0x08140000) /* Bank2扇区2起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_3 ((uint32_t)0x08160000) /* Bank2扇区3起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_4 ((uint32_t)0x08180000) /* Bank2扇区4起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_5 ((uint32_t)0x081A0000) /* Bank2扇区5起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_6 ((uint32_t)0x081C0000) /* Bank2扇区6起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_7 ((uint32_t)0x081E0000) /* Bank2扇区7起始地址, 128 Kbytes */
另外还需要注意一点就是对FLASH的操作地址必须是4字节对齐的,也就是说必须是4的倍数,不然会出问题:
//从指定地址读取一个字
uint32_t flash_read_word(uint32_t pAddr)
{
return *(uint32_t *)pAddr;
}
//从指定地址读出指定长度的数据
void flash_read(uint32_t pAddr, uint32_t *pBuf, uint32_t pLength)
{
for (int i = 0; i < pLength; i++)
{
pBuf[i] = flash_read_word(pAddr);
pAddr += 4;
}
}
//获取某个地址所在的扇区
uint8_t flash_get_flash_sector(uint32_t pAddr)
{
if (pAddr < BANK1_FLASH_SECTOR_1)return 0;
else if (pAddr < BANK1_FLASH_SECTOR_2)return 1;
else if (pAddr < BANK1_FLASH_SECTOR_3)return 2;
else if (pAddr < BANK1_FLASH_SECTOR_4)return 3;
else if (pAddr < BANK1_FLASH_SECTOR_5)return 4;
else if (pAddr < BANK1_FLASH_SECTOR_6)return 5;
else if (pAddr < BANK1_FLASH_SECTOR_7)return 6;
else if (pAddr < BANK2_FLASH_SECTOR_0)return 7;
else if (pAddr < BANK2_FLASH_SECTOR_1)return 8;
else if (pAddr < BANK2_FLASH_SECTOR_2)return 9;
else if (pAddr < BANK2_FLASH_SECTOR_3)return 10;
else if (pAddr < BANK2_FLASH_SECTOR_4)return 11;
else if (pAddr < BANK2_FLASH_SECTOR_5)return 12;
else if (pAddr < BANK2_FLASH_SECTOR_6)return 13;
else if (pAddr < BANK2_FLASH_SECTOR_7)return 14;
return 15;
}
//从指定地址写入指定长度数据
void flash_write(uint32_t pAddr, uint32_t *pbuf, uint32_t length)
{
FLASH_EraseInitTypeDef FlashEraseInit;
HAL_StatusTypeDef FlashStatus = HAL_OK;
uint32_t SectorError = 0;
uint32_t addrx = 0;
uint32_t endaddr = 0;
if (pAddr < 0x08000000 || pAddr % 32 || pAddr > (0x081FFFFF))
{
return;
}
HAL_FLASH_Unlock();
addrx = pAddr;
endaddr = pAddr + length * 4;
if (addrx < 0x081FFFFF)
{
while (addrx < endaddr)
{
if (flash_read_word(addrx) != 0XFFFFFFFF)
{
if (addrx < 0x08100000) {
FlashEraseInit.Banks = FLASH_BANK_1;
FlashEraseInit.Sector = flash_get_flash_sector(addrx);
}
else {
FlashEraseInit.Banks = FLASH_BANK_2;
FlashEraseInit.Sector = (flash_get_flash_sector(addrx) - 8);
}
FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
FlashEraseInit.NbSectors = 1;
FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3; /* 电压范围,VCC=2.7~3.6V之间!! */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1);
// __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGSERR | FLASH_FLAG_WRPERR);
if (HAL_FLASHEx_Erase(&FlashEraseInit, &SectorError) != HAL_OK)
{
break; /* 发生错误了 */
}
//SCB_CleanInvalidateDCache(); /* 清除无效的D-Cache */
}
else
{
addrx += 4;
}
FLASH_WaitForLastOperation(FLASH_WAITETIME, FLASH_BANK_1); /* 等待上次操作完成 */
}
}
FlashStatus = FLASH_WaitForLastOperation(FLASH_WAITETIME, FLASH_BANK_1); /* 等待上次操作完成 */
if (FlashStatus == HAL_OK)
{
while (pAddr < endaddr) /* 写数据 */
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, pAddr, (uint64_t)pbuf) != HAL_OK) /* 写入数据 */
{
break; /* 写入异常 */
}
pAddr += 32;
pbuf += 8;
}
}
HAL_FLASH_Lock(); /* 上锁 */
}