STM32G0xx HAL和LL库Flash读写擦除操作
例程说明
- STM32G0xx在对Flash操作时,有时会出现HardFault异常、或者出现擦除、写入失败的情况,故有此记录。
- STM32G0xx LL库官方没有提供Flash相关的操作需要自己写,可借鉴HAL库。
宏定义说明
#define XMEM_ALIGN_SIZE(size , align) (((size) + (align) - 1) / (align))
#define XOFS(t , m) ((u32)(&(((t *)0)->m)))
#define SYSTEM_ARG_STORE_START_ADDRE (0x0800F800UL)
#define FLASH_OPT_OVERTIMER (0x1FFFF)
#define FLASH_OPT_TRY_COUNT (5)
Flash解锁与加锁
static u8 ubFLASH_Unlock(void)
{
u8 sta = 0;
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
{
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
{
sta = 1;
}
}
return sta;
}
static u8 ubFLASH_Lock(void)
{
u8 sta = 1;
SET_BIT(FLASH->CR, FLASH_CR_LOCK);
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00u)
{
sta = 0;
}
return sta;
}
Flash选项字节解锁与加锁
static u8 ubFLASH_OB_Unlock(void)
{
u8 sta = 1;
if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00U)
{
WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);
if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0x00U)
{
sta = 0;
}
}
return sta;
}
static u8 ubFLASH_OB_Lock(void)
{
u8 sta = 1;
SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);
if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00u)
{
sta = 0;
}
return sta;
}
Flash擦除页
static u32 ulGetPage(u32 startAddr)
{
return ((startAddr - FLASH_BASE) / FLASH_PAGE_SIZE);
}
static u8 ubFLASH_PageErase(u32 page)
{
u32 tmp = 0;
u32 time = 0;
u8 res = 0;
tmp = (FLASH->CR & ~FLASH_CR_PNB);
FLASH->CR = (tmp | (FLASH_CR_STRT | (page << FLASH_CR_PNB_Pos) | FLASH_CR_PER));
while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
{
if ((++time) > FLASH_OPT_OVERTIMER)
{
res = 1;
break;
}
}
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
return res;
}
Flash忙等待
static u8 ubFlash_WaitFor_Operate(u32 timeOut)
{
u32 timer = 0;
u32 error = 0;
while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
{
if ((++timer) >= timeOut)
{
return 1;
}
}
#if ( USE_STM32G0_LL_LIB_ENABLE > 0)
error = (FLASH->SR & FLASH_FLAG_SR_ERROR);
FLASH->SR = FLASH_FLAG_SR_CLEAR;
#endif
#if ( USE_STM32G0_HAL_LIB_ENABLE > 0)
error = (FLASH->SR & FLASH_SR_ERRORS);
FLASH->SR = FLASH_SR_CLEAR;
#endif
if (error != 0x00U)
{
return 2;
}
timer = 0;
while ((FLASH->SR & FLASH_SR_CFGBSY) != 0x00U)
{
if ((++timer) > timeOut)
{
return 3;
}
}
return 0;
}
Flash双字写入
static u8 ubFLASH_Program_DoubleWord(u32 addr, u64 data)
{
u32 time = 0;
while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
{
if ((++time) > FLASH_OPT_OVERTIMER)
{
return 1;
}
}
SET_BIT(FLASH->CR, FLASH_CR_PG);
*(u32 *)addr = (u32)data;
__ISB();
*(u32 *)(addr + 4U) = (u32)(data >> 32U);
while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
{
if ((++time) > FLASH_OPT_OVERTIMER)
{
return 2;
}
}
return 0;
}
Flash LL库双字写
u8 ubFlash_Write_DoubleWord(u32 startAddr, u64 * pDat, u16 len)
{
u32 page = 0, time = 0;
u8 tryCount = 0, res = 0;
u16 i = 0;
FLASH_UNLOCK:
if (ubFLASH_Unlock())
{
if ((++tryCount) < FLASH_OPT_TRY_COUNT)
{
res = ubFlash_WaitFor_Operate(FLASH_OPT_OVERTIMER);
dprintf("Wait For Operate %s...%d\r\n", (res ? "Fail" : "OK"), res);
goto FLASH_UNLOCK;
}
else
{
dprintf("Flash Unlock Fail...\r\n");
return 1;
}
}
page = ulGetPage(startAddr);
tryCount = 0;
FLASH_ERASE:
if(ubFLASH_PageErase(page))
{
if ((++tryCount) < FLASH_OPT_TRY_COUNT)
{
res = ubFlash_WaitFor_Operate(FLASH_OPT_OVERTIMER);
dprintf("Wait For Operate %s...%d\r\n", (res ? "Fail" : "OK"), res);
goto FLASH_ERASE;
}
else
{
ubFLASH_Lock();
dprintf("Flash Erase Fail...\r\n");
return 2;
}
}
tryCount = 0;
for (i = 0; i < len; ++i)
{
while(tryCount < FLASH_OPT_TRY_COUNT)
{
if(ubFLASH_Program_DoubleWord(startAddr , pDat[i]))
{
res = ubFlash_WaitFor_Operate(FLASH_OPT_OVERTIMER);
dprintf("Wait For Operate %s...%d\r\n", (res ? "Fail" : "OK"), res);
tryCount++;
}
else
{
startAddr += 8;
tryCount = 0;
break;
}
}
if (tryCount)
{
ubFLASH_Lock();
dprintf("Write Flash Fail...\r\n");
return 3;
}
}
ubFLASH_Lock();
dprintf("Write Flash OK...\r\n");
return 0;
}
Flash HAL库双字写
u8 ubHAL_Flash_Write_DoubleWord(u32 startAddr, u64 * pDat, u16 len)
{
FLASH_EraseInitTypeDef EraseInitStruct = {0};
u32 pageError = 0;
u8 i = 0, tryCount = 0;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Page = ulGetPage(startAddr);
EraseInitStruct.NbPages = 1 ;
EraseInitStruct.Banks = FLASH_BANK_1 ;
FLASH_UNLOCK_TRY:
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY) != 0x00U)
{
*(u32 *)(startAddr + 600) = 0x123123;
FLASH->SR = FLASH_SR_CLEAR;
}
if(HAL_FLASH_Unlock() != HAL_OK)
{
if ((++tryCount) < FLASH_OPT_TRY_COUNT)
{
FLASH_WaitForLastOperation(50);
goto FLASH_UNLOCK_TRY;
}
else
{
dprintf("Flash Unlock Fail...\r\n");
return 1;
}
}
tryCount = 0;
FLASH_ERASE_TRY:
HAL_FLASHEx_Erase(&EraseInitStruct, &pageError);
if(pageError != 0xFFFFFFFF)
{
if ((++tryCount) < FLASH_OPT_TRY_COUNT)
{
FLASH_WaitForLastOperation(50);
goto FLASH_ERASE_TRY;
}
else
{
HAL_FLASH_Lock();
dprintf("Flash Erase Fail...\r\n");
return 2;
}
}
tryCount = 0;
for (i = 0; i < len; ++i)
{
while(tryCount < FLASH_OPT_TRY_COUNT)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, startAddr, pDat[i]) == HAL_OK)
{
startAddr += 8;
tryCount = 0;
break;
}
else
{
FLASH_WaitForLastOperation(50);
tryCount++;
}
}
if (tryCount)
{
HAL_FLASH_Lock();
dprintf("Write Flash Fail...\r\n");
return 3;
}
}
dprintf("Write Flash OK...\r\n");
HAL_FLASH_Lock();
return 0;
}
Flash双字读
void vFlash_Read_DoubleWord(u32 startAddr, u64 * pDat, u16 len)
{
u16 i = 0;
for(i = 0; i < len; ++i)
{
*pDat++ = *(volatile u64 *)(startAddr + (i << 3));
}
}
Flash读写擦除测试
typedef struct
{
eBatteryCap eBatCap;
eMeasUnit eUnit;
u8 LowBatFlg;
u8 MeasType;
u16 MeasMaxRange;
}GlobalParamStore, * GlobalParamStore_t;
typedef struct
{
u8 AngleDemarFlg;
s16 AngleDemarVal;
u8 GyroCaliFlg;
s16 xGyroCaliVal;
s16 yGyroCaliVal;
s16 zGyroCaliVal;
u8 DistDemarFlg;
u8 ZeroDistDemarVal;
u16 FarDistDemarVal;
}DemarParamStore, * DemarParamStore_t, * pDemarParamStore;
typedef struct
{
xSuperProductInfo ProInfo;
GlobalParamStore SysPar;
DemarParamStore DemarPar;
u8 ubRes[1];
u8 ubCRC8;
}SystemParamStore, * SystemParamStore_t;
SystemParamStore SystemParam = {0};
void vSave_System_Parameter(void)
{
u16 len = 0;
len = XMEM_ALIGN_SIZE(sizeof(SystemParamStore) , 8);
if (len > (FLASH_PAGE_SIZE >> 3))
{
dprintf("System Param Over Flash Page Size...\r\n");
}
else
{
vSynWrite_System_Parameter();
SystemParam.ubCRC8 = ubCheckSum_CRC8((void *)(&SystemParam), XOFS(SystemParamStore , ubCRC8));
dprintf("SystemParam CRC8...%X\r\n", SystemParam.ubCRC8);
if (ubFlash_Write_DoubleWord(SYSTEM_ARG_STORE_START_ADDRE, (u64 *)&SystemParam, len) != 0x00U)
{
dprintf("Save Param Fail...\r\n");
}
else
{
dprintf("Save Param OK...\r\n");
}
}
}
void vRead_System_Parameter(void)
{
u16 len = 0;
u8 crc8 = 0;
AppProInfo = &SystemParam.ProInfo;
len = XMEM_ALIGN_SIZE(sizeof(SystemParamStore) , 8);
dprintf("SystemParamStore Size:%d %d\r\n", sizeof(SystemParamStore), len);
if (len > (FLASH_PAGE_SIZE >> 3))
{
len = (FLASH_PAGE_SIZE >> 3);
dprintf("System Param Over Flash Page Size...\r\n");
}
#if 1
vFlash_Read_DoubleWord(SYSTEM_ARG_STORE_START_ADDRE, (u64 *)&SystemParam, len);
crc8 = ubCheckSum_CRC8((void *)(&SystemParam), XOFS(SystemParamStore , ubCRC8));
if(crc8 != SystemParam.ubCRC8)
{
Restore_Default_SystemParam();
dprintf("Restore Default Param...%X %X\r\n", crc8, SystemParam.ubCRC8);
}
else
{
dprintf("Read System Param OK...\r\n");
}
#endif
AppProInfo->DevInfo.SWVer.MajorVer = DEV_INFO_SOFT_MAJOR_VER;
AppProInfo->DevInfo.SWVer.MinorVer = DEV_INFO_SOFT_MINOR_VER;
vSynRead_System_Parameter();
}
测试情况
Init UART OK..
Vref: 3298mV
SystemParamStore Size:88 11
Read System Param OK...
******************** System Parameter ********************
Meas Masx Range: 20000dm
Angle Demar : 0 ==> 0
Dist Demar : 0 ==> 0
Meas Type : 6
Meas Unit : 1
Gryo Cali : 0 ==> 0 0 0
**********************************************************
Gyro Type MPU6887 ID 0x0F
Set Meas Type: 6
Shutdown OverTime: 20s
Bat Sat : 0
Set Meas Type: 2
Set Meas Type: 9
Set Meas Type: 3
Set Meas Type: 5
Set Meas Type: 7
Set Meas Type: 8
SystemParam CRC8...E7
Write Flash OK...
Save Param OK...
Overtime Shutdown...
Init UART OK..
Vref: 3302mV
SystemParamStore Size:88 11
Read System Param OK...
******************** System Parameter ********************
Meas Max Range: 20000dm
Angle Demar : 0 ==> 0
Dist Demar : 0 ==> 0
Meas Type : 8
Meas Unit : 1
Gryo Cali : 0 ==> 0 0 0
**********************************************************
Gyro Type MPU6887 ID 0x0F
Set Meas Type: 8
Shutdown OverTime: 20s
Bat Sat : 0
SystemParam CRC8...E7
Write Flash OK...
Save Param OK...
Overtime Shutdown...
|