问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32F103 内部片上flash读写操作实现掉电保存数据(附代码)

创作时间:
作者:
@小白创作中心

STM32F103 内部片上flash读写操作实现掉电保存数据(附代码)

引用
CSDN
1.
https://m.blog.csdn.net/DongJayYet/article/details/138610783

在许多嵌入式项目中,需要实现参数的掉电保存功能,即在设备重启后能够自动恢复之前设置的参数。对于数据量较小的情况,可以利用微控制器内部的Flash存储器来实现这一功能。本文将以STM32F103芯片为例,详细介绍如何通过编程实现内部Flash的读写操作,从而实现参数的掉电保存。

一、准备工作

在开始编写代码之前,需要对STM32F103芯片的内部Flash有基本的了解,包括其大小、地址范围等信息。这些信息可以在芯片的数据手册中找到。以STM32F103C8为例,其内部Flash的大小为64KB,每一页的大小为1KB。

为了确认可用的Flash空间,可以使用STM32Cube IDE的Build Analyzer工具进行查看。如下图所示,可以看到还有10几KB的Flash空间可以使用。

二、代码设计

A. 读操作

读取Flash中的数据需要使用以下函数:

uint32_t flash_read(uint32_t address, uint8_t* pdata, uint32_t size)
{
    uint32_t read_index = 0;
    uint8_t value;
    uint32_t start_addr;
    uint32_t end_addr;
    if (!pdata || size < 1)
    {
        return 0; // FLASH_PARAM_ERROR;
    }
    start_addr = address;
    end_addr = start_addr + size;
    if (start_addr < FLASH_USER_START_ADDR || end_addr > FLASH_USER_END_ADDR)
    {
        return 0; // FLASH_ADDR_ERROR;
    }
    read_index = 0;
    while (read_index < size)
    {
        value = *(__IO uint8_t*)start_addr;
        start_addr = start_addr + 1;
        *(pdata + read_index) = value;
        read_index++;
    }
    return read_index;
}

B. 擦除操作

在写入数据之前,需要先对目标区域进行擦除。擦除操作使用以下函数:

FLASH_ERROR_CODE_E flash_erase(uint32_t start_addr, uint32_t end_addr)
{
    static FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t PageError = 0;
    if ((start_addr > end_addr) || (start_addr < FLASH_USER_START_ADDR) || (end_addr > FLASH_USER_END_ADDR))
    {
        return FLASH_ADDR_ERROR;
    }
    /* Unlock the Flash to enable the flash control register access */
    HAL_FLASH_Unlock();
    /* Fill EraseInit structure */
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.PageAddress = start_addr;
    EraseInitStruct.NbPages = (end_addr - start_addr + (FLASH_PAGE_SIZE - 1)) / FLASH_PAGE_SIZE;
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
    {
        HAL_FLASH_Lock();
        return FLASH_ERASE_ERROR;
    }
    /* Lock the Flash to disable the flash control register access */
    HAL_FLASH_Lock();
    return FLASH_SUCCESS;
}

C. 写操作

写入数据到Flash中使用以下函数:

FLASH_ERROR_CODE_E flash_write(uint32_t address, const uint8_t* pdata, uint32_t size)
{
    HAL_StatusTypeDef result = HAL_ERROR;
    uint32_t end_addr = 0;
    uint32_t start_addr;
    uint32_t word_num;
    uint8_t half_word_num;
    uint8_t byte_num;
    uint32_t write_index = 0;
    if ((!pdata) || (size < 1))
    {
        return FLASH_PARAM_ERROR;
    }
    word_num = (size >> 2); // size/4
    half_word_num = (size % 4) >> 1; // (size%4)>>1
    byte_num = (size % 2); // size % 2
    start_addr = address;
    end_addr = (start_addr + size);
    if (start_addr < FLASH_USER_START_ADDR || end_addr > FLASH_USER_END_ADDR)
    {
        return FLASH_ADDR_ERROR;
    }
    /* Unlock the Flash to enable the flash control register access */
    HAL_FLASH_Unlock();
    write_index = 0;
    while (write_index < word_num)
    {
        result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, start_addr, BUILD_UINT32(*(pdata), *(pdata + 1), *(pdata + 2), *(pdata + 3)));
        if (HAL_OK == result)
        {
            start_addr = start_addr + 4;
            pdata = pdata + 4;
            write_index++;
        }
        else
        {
            return FLASH_WRITE_WORD_ERROR;
        }
    }
    write_index = 0;
    while (write_index < half_word_num)
    {
        result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, start_addr, BUILD_UINT16(*(pdata), *(pdata + 1)));
        if (HAL_OK == result)
        {
            start_addr = start_addr + 2;
            pdata = pdata + 2;
            write_index++;
        }
        else
        {
            return FLASH_WRITE_HALF_WORD_ERROR;
        }
    }
    write_index = 0;
    while (write_index < byte_num)
    {
        result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, start_addr, BUILD_UINT16(*(pdata), 0xFFFF));
        if (HAL_OK == result)
        {
            start_addr = start_addr + 2;
            pdata = pdata + 2;
            write_index++;
        }
        else
        {
            return FLASH_WRITE_BYTE_ERROR;
        }
    }
    /* Lock the Flash to disable the flash control register access */
    HAL_FLASH_Lock();
    return FLASH_SUCCESS;
}

以上代码参考:stm32f0_flash/STM32/STM32F0/STM32F0_CUBE_FLASH at master · GreatWall51/stm32f0_flash · GitHub

三、结果验证

可以在STM32CubeIDE的debug模式下,通过memory窗口输入地址来查看写入的数据是否正确。

四、注意事项

  1. 写Flash时,需注意先要擦除;
  2. 地址要输入正确;
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号