查阅了很多网络文章,尤其是参考作者“ 茶话MCU”写的《STM32L4系列内部FLASH双字编程示例》
困扰很久的问题,终于实现了。
以下是一些文章、参考书的记录, 最后是代码(最后的读、写函数 其参数传递/使用时, 也是要求8字节对齐的)。
stm32F103
可编程flash区,以页为单位,每页1K,共128页, 擦写次数>1万次;
写入以16位“半字”为最小单位,擦除以页为单位;
先解锁,清标志,擦除,写,上锁;
进行flash操作时,必须打开内部HSI;
stm32G030
用时 \/
64-bit program 85~125us;
32 Double word program X ms
page(2k) program X ms
bank(64k) program X s
page(2k) erase 40ms
Mass erase X ms
擦写次数 仅>= 1K次!!! 需考虑坏页情况;
写数据时,一般建议关闭所有中断!
stm32g030 双字写时,不仅要求是双字形式, 而且要求8字节对齐。 否则进入硬件错误!
stm32G030 测试成功的程序:
#define Address_Const (0x800F000)
uint64_t *Address;
uint64_t Data64_To_Prog[] = {0x0023456789abcdef,0x1123456789abcdef,
0x2223456789abcdef,0x3323456789abcdef,
0x4423456789abcdef,0x5523456789abcdef,};
void test_flash(void)
{
FLASH_EraseInitTypeDef FlashEraseInit;
uint32_t ulPageError = 0;
Address = (uint64_t *)(Address_Const);
FlashEraseInit.TypeErase = TYPEERASE_PAGES; //擦除类型-page擦除
FlashEraseInit.Page = FLASH_PAGE_NB - 2;
FlashEraseInit.NbPages = 1;
if(*Address == 0x0023456789abcdef){
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
HAL_FLASHEx_Erase(&FlashEraseInit,&ulPageError);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(uint32_t)(uint64_t *)(Address),Data64_To_Prog[0]);
Address = (uint64_t *)(Address_Const + 8);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(uint32_t)(uint64_t *)(Address),Data64_To_Prog[1]);
Address = (uint64_t *)(Address_Const + 16);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(uint32_t)(uint64_t *)(Address),Data64_To_Prog[2]);
HAL_FLASH_Lock();
}
}
***********************************以下是读 写 擦程序**********************************
UINT8 ucMCU_FlashRead_WithAddr(UINT32 FlashAddr,UINT8 *pDesAddr, UINT16 uiDataLen)
{
UINT8 ucErrSta,ucByteAlign;
UINT16 uiCnt;
UINT64 *ps;
UINT64 pd;
ucErrSta = FLASH_OK;
if(1024 == FlashAddr){
FlashAddr = 0x800F000;
}
else{
FlashAddr = 0x800F800;
}
__disable_irq();
for(uiCnt = 0; uiCnt < uiDataLen; uiCnt += 8){
ps = (UINT64 *)(FlashAddr + uiCnt);
pd = *ps;
for(ucByteAlign = 0; ucByteAlign < 8; ucByteAlign++){
pDesAddr[ucByteAlign + uiCnt * 8] = (UINT8)((pd >> (ucByteAlign * 8)) & 0xff);
}
}
__enable_irq();
return (ucErrSta);
}
UINT8 ucMCU_FlashWrite_WithAddr(UINT32 FlashAddr, UINT8 *pSrcAddr, UINT16 uiDataLen)
{
UINT8 ucErrSta,ucByteAlign;
UINT16 uiLen;
UINT64 ps,tmp;
ucErrSta = FLASH_OK;
if(1024 == FlashAddr){
FlashAddr = 0x800F000;
}
else{
FlashAddr = 0x800F800;
}
__disable_irq();
HAL_FLASH_Unlock(); //解锁
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);//清标志位
uiLen = 0;
while(uiLen < uiDataLen) //写数据
{
ps = 0;
for(ucByteAlign = 0; ucByteAlign < 8; ucByteAlign++){
tmp = (UINT64)(pSrcAddr[ucByteAlign + uiLen]);
ps += (tmp << (ucByteAlign * 8));
}
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,FlashAddr, ps) != HAL_OK)
{
ucErrSta = FLASH_ERR_WRITE;
break;
}
FlashAddr += 8;
uiLen += 8;
}
HAL_FLASH_Lock(); //上锁
__enable_irq();
return (ucErrSta);
}
UINT8 ucMCU_FlashErase_WithAddr(UINT16 PageAddr)
{
UINT8 ucErrSta;
UINT8 ucpage;
FLASH_EraseInitTypeDef FlashEraseInit;
uint32_t ulPageError = 0;
ucErrSta = FLASH_OK;
if(1 == PageAddr){
ucpage = 30;
}
else{
ucpage = 31;
}
__disable_irq();
HAL_FLASH_Unlock(); //解锁
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);//清标志位
FlashEraseInit.TypeErase = TYPEERASE_PAGES; //擦除类型-page擦除
FlashEraseInit.Page = ucpage;
FlashEraseInit.NbPages = 1;
if(HAL_FLASHEx_Erase(&FlashEraseInit,&ulPageError) != HAL_OK)
{
ucErrSta = FLASH_ERR_ERASE;
}
else{
ucErrSta = FLASH_OK;
}
HAL_FLASH_Lock(); //上锁
__enable_irq();
return (ucErrSta);
}