STM32G0xx HAL和LL库Flash读写擦除操作

例程说明

  1. STM32G0xx在对Flash操作时,有时会出现HardFault异常、或者出现擦除、写入失败的情况,故有此记录。
  2. STM32G0xx LL库官方没有提供Flash相关的操作需要自己写,可借鉴HAL库。

宏定义说明


#define XMEM_ALIGN_SIZE(size , align)                                        (((size) + (align) - 1) / (align))

/* 获取成员m在结构体t中的偏移位置 */
#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解锁与加锁

/* Unlock the FLASH control register access */
static u8 ubFLASH_Unlock(void)
{
    u8 sta = 0;

    if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
    {
        /* Authorize the FLASH Registers access */
        WRITE_REG(FLASH->KEYR, FLASH_KEY1);
        WRITE_REG(FLASH->KEYR, FLASH_KEY2);

        /* verify Flash is unlock */
        if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
        {
            sta = 1;
        }
    }

    return sta;	
}


/* Lock the FLASH control register access */
static u8 ubFLASH_Lock(void)
{
    u8 sta = 1;

    /* Set the LOCK Bit to lock the FLASH Registers access */
    SET_BIT(FLASH->CR, FLASH_CR_LOCK);

    /* verify Flash is locked */
    if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00u)
    {
        sta = 0;
    }

    return sta;
}

Flash选项字节解锁与加锁

/* Unlock the FLASH Option Bytes Registers access */
static u8 ubFLASH_OB_Unlock(void)
{
    u8 sta = 1;

    if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00U)
    {
        /* Authorizes the Option Byte register programming */
        WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
        WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);

        /* verify option bytes are unlocked */
        if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0x00U)
        {
            sta = 0;
        }
    }

    return sta;
}


/* Lock the FLASH Option Bytes Registers access */
static u8 ubFLASH_OB_Lock(void)
{
    u8 sta = 1;

    /* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
    SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);

    /* verify option bytes are locked */
    if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00u)
    {
        sta = 0;
    }

    return sta;
}

Flash擦除页

/* Gets the page of a given address */
static u32 ulGetPage(u32 startAddr)
{
    return ((startAddr - FLASH_BASE) / FLASH_PAGE_SIZE);
}


/* Erase the specified FLASH memory page */
static u8 ubFLASH_PageErase(u32 page)
{
    u32 tmp  = 0;
    u32 time = 0;
    u8  res  = 0;

    /* Get configuration register, then clear page number */
    tmp = (FLASH->CR & ~FLASH_CR_PNB);

    /* Set page number, Page Erase bit & Start bit */
    FLASH->CR = (tmp | (FLASH_CR_STRT | (page <<  FLASH_CR_PNB_Pos) | FLASH_CR_PER));

    /* wait for BSY1 in order to be sure that flash operation is ended before allowing prefetch in flash */
    while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
    {
        if ((++time) > FLASH_OPT_OVERTIMER)
        {
            res = 1;
            break;
        }
    }

    /* If operation is completed or interrupted, disable the Page Erase Bit */
    CLEAR_BIT(FLASH->CR, FLASH_CR_PER);

    return res;
}

Flash忙等待

/* Wait for a FLASH operation to complete */
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)
    /* check flash errors */
    error = (FLASH->SR & FLASH_FLAG_SR_ERROR);

    /* Clear SR register */
    FLASH->SR = FLASH_FLAG_SR_CLEAR;
#endif
    

#if ( USE_STM32G0_HAL_LIB_ENABLE > 0)
    /* check flash errors */
    error = (FLASH->SR & FLASH_SR_ERRORS);

    /* Clear SR register */
    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双字写入

/* Program double-word (64-bit) at a specified address */
/* Must EN PG bit before and DIS PG bit after */
static u8 ubFLASH_Program_DoubleWord(u32 addr, u64 data)
{
    u32 time = 0;

	
    /* Wait for last operation to be completed */
    while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
    {
        if ((++time) > FLASH_OPT_OVERTIMER)
        {
            return 1;
        }
    }
	
	/* Set PG bit */
	SET_BIT(FLASH->CR, FLASH_CR_PG);

    /* Program first word */
    *(u32 *)addr = (u32)data;

    /* Barrier to ensure programming is performed in 2 steps, in right order
    (independently of compiler optimization behavior) */
    __ISB();

    /* Program second word */
    *(u32 *)(addr + 4U) = (u32)(data >> 32U);

    /* Wait for last operation to be completed */
    while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
    {
        if ((++time) > FLASH_OPT_OVERTIMER)
        {
            return 2;
        }
    }

    return 0;
}

Flash LL库双字写

/* Program double-word(64-bit) at a specified address */
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库双字写

/* Program double-word(64-bit) at a specified address */
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双字读

/* Read double-word (64-bit) at a specified address */
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;       /* x轴陀螺仪校准值 */
    s16 yGyroCaliVal;       /* y轴陀螺仪校准值 */
    s16 zGyroCaliVal;       /* z轴陀螺仪校准值 */


    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)
//        if (ubHAL_Flash_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();
	
//	vShow_ProductInfo();
}

测试情况

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...

在这里插入图片描述

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值