以下是STM32F4系列HAL库里的flash擦除函数。该函数下有一条语句是如果扇区号大于11,需要加4偏移值。
从字面上理解,意思是如果我要擦除23扇区,则需要加4,就变成了擦除27扇区。其实这样理解是不对的。先看一下STM32F429的2Mbytes的flash空间,它被分成bank1和bank2,各1Mbytes。
/* Base address of the Flash sectors */
/* STM32F429各个扇区的基地址 */
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000)//16 Kbyte
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000)//16 Kbyte
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000)//16 Kbyte
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000)//16 Kbyte
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000)//64 Kbytes
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000)//128 Kbytes
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000)
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000)
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000)
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000)
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000)
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000)//128 Kbytes
#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000)//16 Kbyte
#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000)//16 Kbyte
#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000)//16 Kbyte
#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) //16 Kbyte
#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000)//64 Kbytes
#define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000)
#define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000)
#define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000)
#define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000)
#define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000)
#define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000)
#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) //128 Kbytes
每一个地址对应的扇区可以通过函数STMFLASH_GetFlashSector(addr)获得。
//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~23,即addr所在的扇区
uint8_t STMFLASH_GetFlashSector(uint32_t addr)
{
if(addr<ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;
else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;
else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;
else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10;
else if(addr<ADDR_FLASH_SECTOR_12)return FLASH_SECTOR_11;
else if(addr<ADDR_FLASH_SECTOR_13)return FLASH_SECTOR_12;
else if(addr<ADDR_FLASH_SECTOR_14)return FLASH_SECTOR_13;
else if(addr<ADDR_FLASH_SECTOR_15)return FLASH_SECTOR_14;
else if(addr<ADDR_FLASH_SECTOR_16)return FLASH_SECTOR_15;
else if(addr<ADDR_FLASH_SECTOR_17)return FLASH_SECTOR_16;
else if(addr<ADDR_FLASH_SECTOR_18)return FLASH_SECTOR_17;
else if(addr<ADDR_FLASH_SECTOR_19)return FLASH_SECTOR_18;
else if(addr<ADDR_FLASH_SECTOR_20)return FLASH_SECTOR_19;
else if(addr<ADDR_FLASH_SECTOR_21)return FLASH_SECTOR_20;
else if(addr<ADDR_FLASH_SECTOR_22)return FLASH_SECTOR_21;
else if(addr<ADDR_FLASH_SECTOR_23)return FLASH_SECTOR_22;
return FLASH_SECTOR_23;
}
再看看手册上对FLASH_CR寄存器的说明,确实12-15被not allowed了。从12扇区开始,都需要跳过4个扇区号,也就有了前面库函数里的扇区+4操作。
那为什么要对扇区进行+4操作?猜测原因在于要兼顾到其他产品使用的双BANK应用模式。
如果此处不进行+4操作,则会出现擦除的扇区和写入读出的扇区不一致,导致读出数据不是写入的数据。下面是库函数原型。
/**
* @brief Erase the specified FLASH memory sector
* @param Sector FLASH sector to erase
* The value of this parameter depend on device used within the same series
* @param VoltageRange The device voltage range which defines the erase parallelism.
* This parameter can be one of the following values:
* @arg FLASH_VOLTAGE_RANGE_1: when the device voltage range is 1.8V to 2.1V,
* the operation will be done by byte (8-bit)
* @arg FLASH_VOLTAGE_RANGE_2: when the device voltage range is 2.1V to 2.7V,
* the operation will be done by half word (16-bit)
* @arg FLASH_VOLTAGE_RANGE_3: when the device voltage range is 2.7V to 3.6V,
* the operation will be done by word (32-bit)
* @arg FLASH_VOLTAGE_RANGE_4: when the device voltage range is 2.7V to 3.6V + External Vpp,
* the operation will be done by double word (64-bit)
*
* @retval None
*/
void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)
{
uint32_t tmp_psize = 0U;
/* Check the parameters */
assert_param(IS_FLASH_SECTOR(Sector));
assert_param(IS_VOLTAGERANGE(VoltageRange));
if(VoltageRange == FLASH_VOLTAGE_RANGE_1)
{
tmp_psize = FLASH_PSIZE_BYTE;
}
else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)
{
tmp_psize = FLASH_PSIZE_HALF_WORD;
}
else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)
{
tmp_psize = FLASH_PSIZE_WORD;
}
else
{
tmp_psize = FLASH_PSIZE_DOUBLE_WORD;
}
/* Need to add offset of 4 when sector higher than FLASH_SECTOR_11 */
if(Sector > FLASH_SECTOR_11)
{
Sector += 4U;
}
/* If the previous operation is completed, proceed to erase the sector */
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
FLASH->CR |= tmp_psize;
CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);
FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos);
FLASH->CR |= FLASH_CR_STRT;
}