0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

写flash意外断电的处理方法

冬至子 来源:小陈学不停 作者:小陈学不停 2023-07-21 16:33 次阅读

1 写flash意外断电
在写flash时突然断电可能会造成数据丢失,为了避免这种情况发生,我们可以加一层数据保护,在上电时检查数据是否正确,如果不正确则使用备份的数据

2 内部flash还是以STM32F103ZET6为例可在ST官网下载文档:PM0075
(STM32F10xxx Flash memory microcontrollers)

图片

FLASH的最小擦除单位是扇区,扇区大小为2K

3 实现数据恢复
3.1 实现原理
-在保存数据时,对当前数据进行CRC校验,把校验结果一起写入FLASH,同时再拷贝一份作为备份数据
-在上电加载参数时,对当前数据进行CRC校验,对比校验结果是否正确,如果不正确则使用备份数据,正确则不处理
3.1.1 测试数据
假设需要存储的数据是这样的:

typedef struct
{
  uint32_t times_clean;
  uint32_t times_error;
  uint8_t name[8];
  uint32_t crc32;
}test_data_t;

利用影子变量,每隔一定时间来检查参数是否发生变化,如果变化了就把最新的数据写入FLASH

if  (0  !=  rt_memcmp(&test_data,&test_data_shadow,sizeof(test_data_t)))
{
    uint32_t get_crc = crc32_customized(&test_data_shadow,sizeof(test_data_t)-4);
    test_data_shadow.crc32 = get_crc;         
    stm32_flash_erase(CONFIG_ADDRESS_TEST_DATA,sizeof(test_data_t)*2);
    stm32_flash_write(CONFIG_ADDRESS_TEST_DATA,&test_data_shadow,sizeof(test_data_t));         
    stm32_flash_write(CONFIG_ADDRESS_TEST_DATA+sizeof(test_data_t),&test_data_shadow,sizeof(test_data_t));   
    rt_memcpy(&test_data,&test_data_shadow,sizeof(test_data_t));
}

此时FLASH中的数据应该是这个样子的:

图片

3.2 实现代码
3.2.1 需要被存储的数据相关定义

#define CONFIG_ADDRESS_TEST_DATA        0x0807F800


#define CONFIG_HEAT_PARAMETER_DEFAULT   
{                                       
    .times_clean = 0,                   
    .times_error = 0,                   
    .name = "test",                     
};
test_data_t test_data =  CONFIG_HEAT_PARAMETER_DEFAULT;
test_data_t test_data_shadow = CONFIG_HEAT_PARAMETER_DEFAULT;
test_data_t test_data_bak = CONFIG_HEAT_PARAMETER_DEFAULT;

3.2.2 CRC32校验API,与STM32的硬件CRC结果相同

#define CONFIG_CRC32_POLY              0x04C11DB7
#define CONFIG_CRC32_INIT_VALUE        0xFFFFFFFF
#define CONFIG_CRC32_OUT_XOR          0x00000000 


uint32_t crc32_stm32_hardware(uint8_t *source,uint32_t length)
{
    uint32_t crc_value = CONFIG_CRC32_INIT_VALUE;


    for  (int i =0; i < length; i++)
    {
        for  (int j = 0; j < 8; j++)
        {
            uint8_t get_bit_value = ((source[i] > > (7 - j) & 1) == 1);
            uint8_t get_value = ((crc_value > > 31 & 1) == 1);
            crc_value < <= 1;
            if  (get_value ^ get_bit_value)
            {
                crc_value ^= CONFIG_CRC32_POLY;
            }
        }
    }


    crc_value &= 0xFFFFFFFF;


    return (crc_value ^= CONFIG_CRC32_OUT_XOR);
}

3.2.3 上电加载参数,检查数据是否出错,出错则使用备份数据

void g_check_data(void)
{
    stm32_flash_read(CONFIG_ADDRESS_TEST_DATA,&test_data_shadow,sizeof(test_data_t));
    stm32_flash_read(CONFIG_ADDRESS_TEST_DATA+sizeof(test_data_t),&test_data_bak,sizeof(test_data_t));
    uint32_t crc_value_cal = crc32_stm32_hardware(&test_data_shadow,sizeof(test_data_t)-4);


    rt_kprintf("crc_value_cal[%x], crc_old[%x]rn",crc_value_cal,test_data_shadow.crc32);

    if  (crc_value_cal != test_data_shadow.crc32)
    {
        rt_kprintf("test data is invalidrn");

        rt_memcpy(&test_data_shadow,&test_data_bak,sizeof(test_data_t)-4);

        uint32_t crc_value_bak = crc32_stm32_hardware(&test_data_bak,sizeof(test_data_t)-4);

        test_data_shadow.crc32 = crc_value_bak;

        rt_memcpy(&test_data_shadow,&test_data_bak,sizeof(test_data_t)-4);
    }

    rt_memcpy(&test_data,&test_data_shadow,sizeof(test_data_t)); 
}

3.2.4 完整的测试代码

int main(void)
{
    uint32_t get_crc_first = crc32_stm32_hardware(&test_data_shadow,sizeof(test_data_t)-4);

    test_data_shadow.crc32 = get_crc_first;
    test_data.crc32 = get_crc_first;

    g_check_data();

    while (1)
    {
         if (0 != rt_memcmp(&test_data,&test_data_shadow,sizeof(test_data_t)))
         {
             uint32_t get_crc = crc32_stm32_hardware(&test_data_shadow,sizeof(test_data_t)-4);

             test_data_shadow.crc32 = get_crc;

             rt_base_t level;

             level = rt_hw_interrupt_disable();

             stm32_flash_erase(CONFIG_ADDRESS_TEST_DATA,sizeof(test_data_t)*2);

             stm32_flash_write(CONFIG_ADDRESS_TEST_DATA,&test_data_shadow,sizeof(test_data_t));

             stm32_flash_write(CONFIG_ADDRESS_TEST_DATA+sizeof(test_data_t),&test_data_shadow,sizeof(test_data_t));

             rt_hw_interrupt_enable(level);

             rt_memcpy(&test_data,&test_data_shadow,sizeof(test_data_t));
         }
         
         rt_thread_mdelay(1000);
    }
}


int cmd_flash_protect_test(int argc, char **argv)
{
    if (2 == argc)
    {
        uint32_t get_type = atoi(argv[1]);


        if (0 == get_type)
        {
            g_check_data();
        }
        else if (1 == get_type)
        {
            test_data_shadow.times_clean++;
        }
    }

    return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_flash_protect_test,flash_protect,flash_protect [val]);

4 测试效果

| /
RT -     Thread Operating System
 / |      4.1.1 build Jul  1 2023 21:37:26
 2006 - 2022 Copyright by RT-Thread team
crc_value_cal[95663ff9], crc_old[95663ff9]
msh / >flash_protect 1
msh / >need write flash crc[ba0600aa]
old_data: times_clean:[6] times_error:[0] name[test] crc:[95663ff9] old_data end
new_data: times_clean:[7] times_error:[0] name[test] crc:[ba0600aa] new_data end
msh / >flash_protect 0
crc_value_cal[ba0600aa], crc_old[ba0600aa]

5 总结
这个方法不适合存储的数据超过一个扇区大小,还需要根据实际情况来调整写入和加载参数的方式
我们虽不能保证自己的软件完全没有BUG,但可以先写一份软件测试用例,将需要测试的每一个功能列成TODOLIST,再按照这个清单去自测,这样就能在自测试发现并及时修正错误,反复测试多次后,我们再把软件提交给测试可能会更好一些,工作中遇到困难是让我们进步的,是提醒我们该优化自己的工作方法了。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7538

    浏览量

    164530
  • CRC校验
    +关注

    关注

    0

    文章

    84

    浏览量

    15295
  • RT-Thread
    +关注

    关注

    31

    文章

    1312

    浏览量

    40565
  • Flash单片机
    +关注

    关注

    0

    文章

    111

    浏览量

    9482
  • STM32F103ZET6
    +关注

    关注

    9

    文章

    67

    浏览量

    21254
收藏 人收藏

    相关推荐

    STM32烧失败错误的处理方法

    STM32烧失败错误:Contents mismatch at: 08000000H (Flash=FFH Required=00H)
    的头像 发表于 06-21 08:55 1.4w次阅读
    STM32烧<b class='flag-5'>写</b>失败错误的<b class='flag-5'>处理</b><b class='flag-5'>方法</b>

    flash,要不要加个判断?

    flash,要不要加个判断?”这是我一个朋友的提问。
    的头像 发表于 11-21 10:07 767次阅读
    <b class='flag-5'>写</b><b class='flag-5'>flash</b>,要不要加个判断?

    *** Flash 成功烧 断电不运行

    dsp *** 编写的串口程序,用ccs4.1.2 成功调通,烧写过程没有问题,但是断电后程序没有正常运行。烧后进行了复位,也没有反应
    发表于 03-01 16:02

    28035烧FLash出现错误

    之前烧写过很多次,也没事,今天烧FLash的时候突然出现这个问题:Flash API Error #24:The Erase operation failed the pre-compaction step
    发表于 11-09 14:21

    基于CCS的DSP片外Flash直接烧设计

    基于CCS的DSP片外Flash直接烧设计 自加载后DSP能够正常运行,关键是Flash中原程序代码的正确烧。CCS编译生成的.out格式文件不能直接用于
    发表于 10-04 09:41 3413次阅读
    基于CCS的DSP片外<b class='flag-5'>Flash</b>直接烧<b class='flag-5'>写</b>设计

    JTAG接口在线烧Flash的实现

    本文阐述了一种针对TMS320VC5509A DSP 简单有效的Flash方法, 并提出了程序自举引导的实现方法。可以有效地解决程序代码存储问题和DSP 脱机自举问题.
    发表于 09-16 14:43 1.6w次阅读
    JTAG接口在线烧<b class='flag-5'>写</b><b class='flag-5'>Flash</b>的实现

    FPGA配置– 使用JTAG是如何烧SPI/BPI Flash的?

    Xilinx的JTAG电缆可以通过FPGA“直接”烧SPI/BPI。很多对xilinx开发环境不熟悉的用户,如果第一次接触这种烧模式可能会有疑惑,FPGA是如何做到JTAG和Flash之间的桥接
    发表于 02-08 02:40 8827次阅读
    FPGA配置– 使用JTAG是如何烧<b class='flag-5'>写</b>SPI/BPI <b class='flag-5'>Flash</b>的?

    使用JTAG烧Nand Flash实验解析

    4.4 实验内容使用JTAG烧Nand Flash 1.实验目的 通过使用JTAG烧Flash的实验,了解嵌入式硬件环境,熟悉JTAG的使用,为今后的进一步学习打下良好的基础。本书
    发表于 10-18 17:03 6次下载
    使用JTAG烧<b class='flag-5'>写</b>Nand <b class='flag-5'>Flash</b>实验解析

    基于DSP虹膜识别系统中Flash方法的研究

    基于DSP虹膜识别系统中Flash方法的研究
    发表于 10-19 14:41 2次下载
    基于DSP虹膜识别系统中<b class='flag-5'>Flash</b>烧<b class='flag-5'>写</b><b class='flag-5'>方法</b>的研究

    CCS的DSP片外Flash直接烧设计

    CCS的DSP片外Flash直接烧设计
    发表于 10-20 08:29 3次下载
    CCS的DSP片外<b class='flag-5'>Flash</b>直接烧<b class='flag-5'>写</b>设计

    如何采用DATA进行Flash的在线烧

    自加载后DSP能够正常运行,关键是Flash中原程序代码的正确烧。CCS编译生成的.out格式文件不能直接用于Flash,在TI公司给出的技术文档闭中,首先将.out文件利用其H
    的头像 发表于 02-06 08:51 3752次阅读
    如何采用DATA进行<b class='flag-5'>Flash</b>的在线烧<b class='flag-5'>写</b>

    NOR Flash,Flash锁死怎么办 详解NOR Flash方法

    上面的代码中第4个操纵周期中的ADDR是从ARM处理器的角度来看的BYTE地址, 由于在执行操纵的时候,用户希看指定的是从 ARM 的角度看到的地址,这样会更方便和更直观。
    的头像 发表于 09-19 09:21 1.3w次阅读

    HCC推出故障安全 防止意外复位或断电的exFAT解决方案

    HCC推出故障安全,防止意外复位或断电的exFAT解决方案
    的头像 发表于 02-25 16:11 2307次阅读

    可供用户修改的FLASH驱动介绍

    为方便客户针对 S698 芯片外接不同种类的 FLASH 进行在线编程。V8mon 的 FLASH 烧提供源码可以进行用户自行修改。FLASH
    发表于 06-08 14:39 0次下载
    可供用户修改的<b class='flag-5'>FLASH</b>烧<b class='flag-5'>写</b>驱动介绍

    stm32 flash数据怎么存储的

    stm32 flash数据怎么存储的  STM32是一款广泛应用于嵌入式系统开发的微控制器,它的Flash存储器是其中一个重要的组成部分。在本文中,我将详细介绍STM32 Flash
    的头像 发表于 01-31 15:46 2561次阅读