如何使用stm32内部Flash

  • 该功能可以实现数据掉电不丢失

1.准备数据

定义一个用户数据结构体,其中的数据要求掉电不丢失,可以在结构体中继续拓展需要存的数据类型。

typedef struct user_data{
	data1_t data1;
	data2_t data2;
	...
	datan_ta datan;
}user_data_t;
//定义变量保存用户数据
user_data_t user_data;

2.选择内存中的保存位置

确定数据保存在内存中的地址

//G0B0 flash大小 0x0800 0000-0x0807 FFFF 
//size : 0x7ffff + 0x0001 --> 1000 0000 0000 0000 0000 = 2^19 = 512K

//定义一个用于存储用户数据的地址
#define     USER_DATA_ADDRESS      (0x0807D000UL)  

3.写入数据

将全局变量 DataFlash 中的数据同步到 Flash 中的指定地址

int32_t DataSyncFlash(void)
{
    int32_t ret = 0;

    ret = coreFlashWrite((void*)USER_DATA_ADDRESS, (void*)&user_data_t, sizeof(user_data_t));
    return ret;
}

4.读取数据

开机首先将FLASH中的数据读到声明的变量中

void DataReadFlash(void)
{
    const volatile user_data_t* rawPtr = (const volatile user_data_t*)USER_DATA_ADDRESS;

    if (DataIsActive())
    {
        memcpy(&user_data, (void*)rawPtr, sizeof(user_data_t));
    }
}

5. 驱动函数

//定义一个缓冲区用于存放要写入FLASH的数据 注意字节对齐 why? 优化内存访问
__align(8) static uint8_t flashWriteBuf[2048];

1.1 coreFlashAcquireWriteBuffer

uint8_t* coreFlashAcquireWriteBuffer(void)
{
    return flashWriteBuf;
}

1.2 getPage

static uint32_t getPage(uint32_t addr)
{
    uint32_t page = 0;

    /* Bank 1 */
    page = (addr - FLASH_BASE) / FLASH_PAGE_SIZE;

    return page;
}

页面号被计算为地址相对于基地址 FLASH_BASE 的偏移量除以页面大小 FLASH_PAGE_SIZE

1.3 coreFlashWrite

int32_t coreFlashWrite(void* dstAddr, const void* srcAddr, const uint32_t size)
{
    //初始化FLASH_EraseInitTypeDef
    FLASH_EraseInitTypeDef eraseInitStruct = {0x00};

    int32_t ret = ERR_FLASHOP_OK;  // 返回值

    //1.判断入参正确
    if (!srcAddr || !dstAddr || 0 == size)
    {
        return ERR_FLASHOP_PARAM_INVAL;
    }
    if (0 != ((uint32_t)srcAddr & 0x00000007))
    {
        return ERR_FLASHOP_SRCADDR_UNALIGN;
    }
    if (0 != ((uint32_t)dstAddr & 0x00000007))
    {
        return ERR_FLASHOP_DSTADDR_UNALIGN;
    }

    //2.写数据之前 要先擦除数据
    //获取要擦除的第一页
    firstPage = getPage((uint32_t)dstAddr);
    //计算从第一页开始的 要擦除的页数
    nbOfPages = size / FLASH_PAGE_SIZE + (size % FLASH_PAGE_SIZE ? 1 : 0);
    //擦除数据初始化
    eraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    eraseInitStruct.Page        = firstPage;  // 擦除起始页
    eraseInitStruct.NbPages     = nbOfPages;  // 擦除页数

    HAL_FLASH_Unlock();  // Flash解锁
    __disable_irq();  // 擦除前需要关闭中断
    if (HAL_FLASHEx_Erase(&eraseInitStruct, &pageError) != HAL_OK)
    {
        __enable_irq();
        ret = -ERR_FLASHOP_FAIL_ERASE;
        goto exit;
    }
    __enable_irq();

    //3.开始写入Flash
    flashAddress = (uint32_t)dstAddr;
    nWriteAll = size;

    while (nHasWrite < nWriteAll)
    {
        // 以64位为单位写入数据
        srcDW = *(uint64_t*)((uint32_t)srcAddr + nHasWrite);
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flashAddress, srcDW) == HAL_OK)
        {
            flashAddress += 8;
            nHasWrite += 8;
        }
        else
        {
            ret = ERR_FLASHOP_FAIL_PROG;
            goto exit;
        }
    }

exit:
    HAL_FLASH_Lock();  // Flash加锁
    return ret;
}
  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值