本来想用做个OTA的功能,但在调试过程中发现,片内的flash扇区擦除不生效。无论怎么擦,读出的数据始终不为0xff。
后来,看了用户手册和HC32的库的代码,才发现问题。
以下是用户手册的扇区擦除步骤:
以下为官方库的扇区擦除源码:
en_result_t Flash_SectorErase(uint32_t u32SectorAddr)
{
en_result_t enResult = Ok;
volatile uint32_t u32TimeOut = FLASH_TIMEOUT_ERASE;
if (FLASH_END_ADDR < u32SectorAddr)
{
enResult = ErrorInvalidParameter;
return (enResult);
}
//busy?
u32TimeOut = FLASH_TIMEOUT_ERASE;
while (TRUE == M0P_FLASH->CR_f.BUSY)
{
if(0 == u32TimeOut--)
{
return ErrorTimeout;
}
}
//Flash 解锁
Flash_UnlockAll();
//set OP
u32TimeOut = FLASH_TIMEOUT_ERASE;
while(SectorErase != M0P_FLASH->CR_f.OP)
{
if(u32TimeOut--)
{
FLASH_BYPASS();
M0P_FLASH->CR_f.OP = SectorErase;
}
else
{
return ErrorTimeout;
}
}
//write data
*((volatile uint8_t*)u32SectorAddr) = 0;
//busy?
u32TimeOut = FLASH_TIMEOUT_ERASE;
while (TRUE == M0P_FLASH->CR_f.BUSY)
{
if(0 == u32TimeOut--)
{
return ErrorTimeout;
}
}
//Flash 加锁
Flash_LockAll();
return (enResult);
}
可以从以上看出,源码中的flash解锁的步骤写在了Step1之前,而用户手册中则是flash解锁的步骤是在Step6才执行。因此我们修改代码如下:
en_result_t Flash_SectorErase(uint32_t u32SectorAddr)
{
en_result_t enResult = Ok;
volatile uint32_t u32TimeOut = FLASH_TIMEOUT_ERASE;
if (FLASH_END_ADDR < u32SectorAddr)
{
enResult = ErrorInvalidParameter;
return (enResult);
}
//busy?
u32TimeOut = FLASH_TIMEOUT_ERASE;
while (TRUE == M0P_FLASH->CR_f.BUSY)
{
if(0 == u32TimeOut--)
{
return ErrorTimeout;
}
}
// //Flash 解锁
// Flash_UnlockAll();
//set OP
u32TimeOut = FLASH_TIMEOUT_ERASE;
while(SectorErase != M0P_FLASH->CR_f.OP)
{
if(u32TimeOut--)
{
FLASH_BYPASS();
M0P_FLASH->CR_f.OP = SectorErase;
}
else
{
return ErrorTimeout;
}
}
//Flash 解锁
Flash_UnlockAll();
//write data
*((volatile uint8_t*)u32SectorAddr) = 0;
//busy?
u32TimeOut = FLASH_TIMEOUT_ERASE;
while (TRUE == M0P_FLASH->CR_f.BUSY)
{
if(0 == u32TimeOut--)
{
return ErrorTimeout;
}
}
//Flash 加锁
Flash_LockAll();
return (enResult);
}
修改代码后,测试一遍。测试方法,可以通过往该扇区地址写入0,再擦除,再读出数据是否0xff的方式来判断是否生效。
关于华大HC32L的flash这块还需要注意手册提到的以下几点:
1.对 FLASH 进行页擦除和写的代码所在的地址必须小于 32768。
2.需要根据HCLK时钟的频率大小配置擦写参数
3.HCLK的频率大于24MHz时,需要配置读等待周期。
4.擦写时需关闭中断