因为片内FLASH有使用寿命,我们写了个函数:
1、如果目标地址已经写过,先擦除再写
2、如果目标地址没有写过,直接写到目标地址
RetType_t Flash_AdvantageWrite(uint32_t address, uint16_t * buf, uint32_t bytenum)
{
uint8_t needErase = 0;
HAL_StatusTypeDef status = HAL_OK;
uint16_t *addp = NULL;
uint32_t tadd = (address-address%FLASHPAGESIZE);
int i;
uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0;
uint32_t PAGEError = 0;
FLASH_EraseInitTypeDef EraseInitStruct;
uint64_t data_64_A = 0,data_64_B = 0,data_64_C = 0,data_64_D = 0;
uint32_t startCheckAddr, endCheckAddr;
uint16_t byteNum;
Voice_WaitEnd();
FeedDog();
_say_("FlashWrite:address=0x%x,bytenum=%d\r\n", address, bytenum);
if ((address%FLASHPAGESIZE+bytenum) > FLASHPAGESIZE)
{
_say_("Exceed limit:address=0x%x,bytenum=0x%x\r\n", address, bytenum);
return RET_EXCEED_LIMIT;
}
memset(g_flagpagebuf, 0xff, FLASHPAGESIZE);
//判断需要写的区域是否已经写过,并更新标志位
startCheckAddr = address - address % 8;
endCheckAddr = address + bytenum;
if (endCheckAddr % 8 != 0)
{
endCheckAddr += 8 - (endCheckAddr % 8);
}
for (i = startCheckAddr; i < endCheckAddr; i += 2)
{
addp = (uint16_t *)i;
if (*addp != FLASH_DEFAULT_HALFWORD)
{
needErase = 1;
_say_("Writed,need to erase!\r\n");
break;
}
}
// 如果需要写的区域已经被写过,需要把数据全部读出,更新后重新写入
if (needErase == 1)
{
addp = (uint16_t *)(address-address%FLASHPAGESIZE);// 当前页首地址
_memcpy(g_flagpagebuf,addp,FLASHPAGESIZE);//读出数据到g_flagpagebuf
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
/* Get the 1st page to erase */
FirstPage = GetPage(address);
/* Get the number of pages to erase from 1st page */
NbOfPages = 1;
/* Get the bank */
BankNumber = GetBank(address);
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Banks = BankNumber;
EraseInitStruct.Page = FirstPage;
EraseInitStruct.NbPages = NbOfPages;
status = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
if (status != HAL_OK)
{
HAL_FLASH_Lock();
_say_("Fail to Erase!\r\n");
return RET_ERASE_FLASH_ERROR;
}
memcpy(g_flagpagebuf+(address%FLASHPAGESIZE)/2,buf,bytenum);// 更新buf数据
// 将数据写回
for (i = 0; i < FLASHPAGESIZE/8; tadd += 8, i++)
{
data_64_A = g_flagpagebuf[i*4+0];
data_64_B = g_flagpagebuf[i*4+1];
data_64_C = g_flagpagebuf[i*4+2];
data_64_D = g_flagpagebuf[i*4+3];
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, tadd, data_64_A+(data_64_B<<16)+(data_64_C<<32)+(data_64_D<<48));
if (status != HAL_OK)
{
_say_("FLASH program fail(page),status=%d,i=%d\r\n", status, i);
break;
}
}
}
else // 如果需要写的区域没有被写过,直接将数据写入
{
/*必须保证address是2字节的倍数*/
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
//SET_BIT(FLASH->CR, 1 << 27);
memcpy(g_flagpagebuf+(address%8)/2,buf,bytenum);
tadd = address - address % 8;
byteNum = bytenum + address % 8;
if (byteNum % 8 != 0)
{
byteNum += 8 - (byteNum % 8);
}
_say_("tadd=0x%x, byteNum=%d\r\n", tadd, byteNum);
for (i = 0; i < byteNum/8; tadd += 8, i++)
{
data_64_A = g_flagpagebuf[i*4+0];
data_64_B = g_flagpagebuf[i*4+1];
data_64_C = g_flagpagebuf[i*4+2];
data_64_D = g_flagpagebuf[i*4+3];
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, tadd, data_64_A+(data_64_B<<16)+(data_64_C<<32)+(data_64_D<<48));
if (status != HAL_OK)
{
uint32_t data1, data2;
_say_("Program %d Dword fail,status=%d\r\n", i, status);
data1 = *(uint32_t*)tadd;
data2 = *(uint32_t*)(tadd+4);
_say_("data1=0x%X,data2=0x%X\r\n", data1, data2);
break;
}
}
}
HAL_FLASH_Lock();
FeedDog();
return (status != HAL_OK) ? RET_WRITE_FLASH_ERROR : RET_OK;
}
先对整个页进行擦除,然后进行读写操作,测试中发现:
1、对于已经写过数据的先擦除再写没问题
2、对没有写过的写数据时有时会出错。
出错的地方在FLASH_WaitForLastOperation中,
error = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
状态寄存器被置上了FLASH_SR_PEMPTY
请问各位大大什么情况下状态寄存器会被置上这个值? |
|