0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

寫flash意外斷電的處理方法

冬至子 ? 來源:小陳學(xué)不停 ? 作者:小陳學(xué)不停 ? 2023-07-21 16:33 ? 次閱讀

1 寫flash意外斷電
在寫flash時突然斷電可能會造成數(shù)據(jù)丟失,為了避免這種情況發(fā)生,我們可以加一層數(shù)據(jù)保護(hù),在上電時檢查數(shù)據(jù)是否正確,如果不正確則使用備份的數(shù)據(jù)

2 內(nèi)部flash還是以STM32F103ZET6為例可在ST官網(wǎng)下載文檔:PM0075
(STM32F10xxx Flash memory microcontrollers)

圖片

FLASH的最小擦除單位是扇區(qū),扇區(qū)大小為2K

3 實現(xiàn)數(shù)據(jù)恢復(fù)
3.1 實現(xiàn)原理
-在保存數(shù)據(jù)時,對當(dāng)前數(shù)據(jù)進(jìn)行CRC校驗,把校驗結(jié)果一起寫入FLASH,同時再拷貝一份作為備份數(shù)據(jù)
-在上電加載參數(shù)時,對當(dāng)前數(shù)據(jù)進(jìn)行CRC校驗,對比校驗結(jié)果是否正確,如果不正確則使用備份數(shù)據(jù),正確則不處理
3.1.1 測試數(shù)據(jù)
假設(shè)需要存儲的數(shù)據(jù)是這樣的:

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

利用影子變量,每隔一定時間來檢查參數(shù)是否發(fā)生變化,如果變化了就把最新的數(shù)據(jù)寫入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中的數(shù)據(jù)應(yīng)該是這個樣子的:

圖片

3.2 實現(xiàn)代碼
3.2.1 需要被存儲的數(shù)據(jù)相關(guān)定義

#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結(jié)果相同

#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 上電加載參數(shù),檢查數(shù)據(jù)是否出錯,出錯則使用備份數(shù)據(jù)

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 總結(jié)
這個方法不適合存儲的數(shù)據(jù)超過一個扇區(qū)大小,還需要根據(jù)實際情況來調(diào)整寫入和加載參數(shù)的方式
我們雖不能保證自己的軟件完全沒有BUG,但可以先寫一份軟件測試用例,將需要測試的每一個功能列成TODOLIST,再按照這個清單去自測,這樣就能在自測試發(fā)現(xiàn)并及時修正錯誤,反復(fù)測試多次后,我們再把軟件提交給測試可能會更好一些,工作中遇到困難是讓我們進(jìn)步的,是提醒我們該優(yōu)化自己的工作方法了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 存儲器
    +關(guān)注

    關(guān)注

    38

    文章

    7440

    瀏覽量

    163530
  • CRC校驗
    +關(guān)注

    關(guān)注

    0

    文章

    84

    瀏覽量

    15176
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1265

    瀏覽量

    39854
  • Flash單片機(jī)
    +關(guān)注

    關(guān)注

    0

    文章

    111

    瀏覽量

    9379
  • STM32F103ZET6
    +關(guān)注

    關(guān)注

    9

    文章

    67

    瀏覽量

    21069
收藏 人收藏

    評論

    相關(guān)推薦

    STM32燒失敗錯誤的處理方法

    STM32燒失敗錯誤:Contents mismatch at: 08000000H (Flash=FFH Required=00H)
    的頭像 發(fā)表于 06-21 08:55 ?1.3w次閱讀
    STM32燒<b class='flag-5'>寫</b>失敗錯誤的<b class='flag-5'>處理</b><b class='flag-5'>方法</b>

    flash,要不要加個判斷?

    flash,要不要加個判斷?”這是我一個朋友的提問。
    的頭像 發(fā)表于 11-21 10:07 ?658次閱讀
    <b class='flag-5'>寫</b><b class='flag-5'>flash</b>,要不要加個判斷?

    *** Flash 成功燒 斷電不運(yùn)行

    dsp *** 編寫的串口程序,用ccs4.1.2 成功調(diào)通,燒寫過程沒有問題,但是斷電后程序沒有正常運(yùn)行。燒后進(jìn)行了復(fù)位,也沒有反應(yīng)
    發(fā)表于 03-01 16:02

    28035燒FLash出現(xiàn)錯誤

    之前燒寫過很多次,也沒事,今天燒FLash的時候突然出現(xiàn)這個問題:Flash API Error #24:The Erase operation failed the pre-compaction step
    發(fā)表于 11-09 14:21

    基于CCS的DSP片外Flash直接燒設(shè)計

    基于CCS的DSP片外Flash直接燒設(shè)計 自加載后DSP能夠正常運(yùn)行,關(guān)鍵是Flash中原程序代碼的正確燒。CCS編譯生成的.out格式文件不能直接用于
    發(fā)表于 10-04 09:41 ?3281次閱讀
    基于CCS的DSP片外<b class='flag-5'>Flash</b>直接燒<b class='flag-5'>寫</b>設(shè)計

    JTAG接口在線燒Flash的實現(xiàn)

    本文闡述了一種針對TMS320VC5509A DSP 簡單有效的Flash方法, 并提出了程序自舉引導(dǎo)的實現(xiàn)方法??梢杂行У亟鉀Q程序代碼存儲問題和DSP 脫機(jī)自舉問題.
    發(fā)表于 09-16 14:43 ?1.6w次閱讀
    JTAG接口在線燒<b class='flag-5'>寫</b><b class='flag-5'>Flash</b>的實現(xiàn)

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

    Xilinx的JTAG電纜可以通過FPGA“直接”燒SPI/BPI。很多對xilinx開發(fā)環(huán)境不熟悉的用戶,如果第一次接觸這種燒模式可能會有疑惑,F(xiàn)PGA是如何做到JTAG和Flash之間的橋接
    發(fā)表于 02-08 02:40 ?8020次閱讀
    FPGA配置– 使用JTAG是如何燒<b class='flag-5'>寫</b>SPI/BPI <b class='flag-5'>Flash</b>的?

    使用JTAG燒Nand Flash實驗解析

    4.4 實驗內(nèi)容使用JTAG燒Nand Flash 1.實驗?zāi)康?通過使用JTAG燒Flash的實驗,了解嵌入式硬件環(huán)境,熟悉JTAG的使用,為今后的進(jìn)一步學(xué)習(xí)打下良好的基礎(chǔ)。本書
    發(fā)表于 10-18 17:03 ?6次下載
    使用JTAG燒<b class='flag-5'>寫</b>Nand <b class='flag-5'>Flash</b>實驗解析

    基于DSP虹膜識別系統(tǒng)中Flash方法的研究

    基于DSP虹膜識別系統(tǒng)中Flash方法的研究
    發(fā)表于 10-19 14:41 ?2次下載
    基于DSP虹膜識別系統(tǒng)中<b class='flag-5'>Flash</b>燒<b class='flag-5'>寫</b><b class='flag-5'>方法</b>的研究

    CCS的DSP片外Flash直接燒設(shè)計

    CCS的DSP片外Flash直接燒設(shè)計
    發(fā)表于 10-20 08:29 ?3次下載
    CCS的DSP片外<b class='flag-5'>Flash</b>直接燒<b class='flag-5'>寫</b>設(shè)計

    如何采用DATA進(jìn)行Flash的在線燒

    自加載后DSP能夠正常運(yùn)行,關(guān)鍵是Flash中原程序代碼的正確燒。CCS編譯生成的.out格式文件不能直接用于Flash,在TI公司給出的技術(shù)文檔閉中,首先將.out文件利用其H
    的頭像 發(fā)表于 02-06 08:51 ?3563次閱讀
    如何采用DATA進(jìn)行<b class='flag-5'>Flash</b>的在線燒<b class='flag-5'>寫</b>

    NOR Flash,Flash鎖死怎么辦 詳解NOR Flash方法

    上面的代碼中第4個操縱周期中的ADDR是從ARM處理器的角度來看的BYTE地址, 由于在執(zhí)行操縱的時候,用戶??粗付ǖ氖菑?ARM 的角度看到的地址,這樣會更方便和更直觀。
    的頭像 發(fā)表于 09-19 09:21 ?1.3w次閱讀

    HCC推出故障安全 防止意外復(fù)位或斷電的exFAT解決方案

    HCC推出故障安全,防止意外復(fù)位或斷電的exFAT解決方案
    的頭像 發(fā)表于 02-25 16:11 ?2179次閱讀

    可供用戶修改的FLASH驅(qū)動介紹

    為方便客戶針對 S698 芯片外接不同種類的 FLASH 進(jìn)行在線編程。V8mon 的 FLASH 燒提供源碼可以進(jìn)行用戶自行修改。FLASH
    發(fā)表于 06-08 14:39 ?0次下載
    可供用戶修改的<b class='flag-5'>FLASH</b>燒<b class='flag-5'>寫</b>驅(qū)動介紹

    stm32 flash數(shù)據(jù)怎么存儲的

    stm32 flash數(shù)據(jù)怎么存儲的? STM32是一款廣泛應(yīng)用于嵌入式系統(tǒng)開發(fā)的微控制器,它的Flash存儲器是其中一個重要的組成部分。在本文中,我將詳細(xì)介紹STM32 Flash
    的頭像 發(fā)表于 01-31 15:46 ?2213次閱讀