精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

固件升級的設計

CHANBAEK ? 來源:小陳學不停 ? 作者:小陳學不停 ? 2023-05-17 16:17 ? 次閱讀

1 固件升級
在一些項目交期比較急的情況下,可以先把基本功能做出來,加入固件升級的功能,后續即使發現重大BUG,也不用返廠更新固件,只需要把加密固件發給客戶自行更新,也可以使用物聯網的方式進行遠程固件升級。

2 FLASH劃分
2.1 內部FLASH
STM32F103ZET6為例,內部FLASH的扇區大小是2KB

2.2 外部FLASH
整個FLASH作為FAT32使用,以W25Q128為例,有16MB的空間

3 生成加密文件
3.1 加密算法
用的是tinycrypt中的aes加密算法修改IV和KEY的定義
#define TEST_TINY_AES_IV
"0123456789ABCDEF"
#define TEST_TINY_AES_KEY
"0123456789ABCDEF0123456789ABCDEF"
在使用前選擇是作為加密還是解密
tinycrypt_enc_init();
tinycrypt_dec_init();

3.2 壓縮算法
用的是quicklz壓縮算法,壓縮率比較低,154KB的固件壓縮之后是118KB

3.3 app再加工
keil編譯出app固件后,使用外部應用程序來對app進行壓縮,再進行加密,再為整個固件增加CRC32校驗,外部程序在linux平臺下同樣適用,只需要在目標主機上編譯生成目標文件即可。

3.3.1 參數檢查
主要有FLASH總大小、FLASH扇區大小、bootloader大小、bootloader輸入文件名、app輸入文件名、輸出app+crc文件名、輸出app加密壓縮后的文件名等

if (argc == 13)
    {
        combine_file.size_total = atoi(argv[1]);
        combine_file.size_sector = atoi(argv[2]);
        combine_file.size_bootloader = atoi(argv[3]);
        combine_file.check_type = atoi(argv[4]);


        sprintf(combine_file.fn_bootloader,"%s",argv[5]);
        sprintf(combine_file.fn_app_in,"%s",argv[6]);
        sprintf(combine_file.fn_app_out,"%s",argv[7]);
        sprintf(combine_file.fn_app_mask,"_upfw_app.bin",argv[7]);
        sprintf(combine_file.fn_product,"%s",argv[8]);


        get_debug_switch = atoi(argv[9]);


        combine_file.size_app_max = atoi(argv[10]);
        combine_file.flash_base = atoi(argv[11]);
        sprintf(combine_file.fn_user,"%s",argv[12]);
    }

3.3.2 文件讀取和加工

FILE *p_bootloader_file_source=NULL;
    FILE *p_app_file_source=NULL;
    FILE *p_app_file_out=NULL;
    FILE *p_app_file_out_mask=NULL;
    FILE *p_product_file_out=NULL;
    FILE *p_user_file_out=NULL;


    p_bootloader_file_source = fopen(combine_file.fn_bootloader,"rb+");


    if (!p_bootloader_file_source)
    {
        if (get_debug_switch > 0)
        {
            printf("read bootloader file error=%s\\r\\n",combine_file.fn_bootloader);
        }


        goto error;
    }


    p_app_file_source = fopen(combine_file.fn_app_in,"rb+");


    if (!p_app_file_source)
    {
        if (get_debug_switch > 0)
        {
            printf("p_app_file_source error=%d\\r\\n",p_app_file_source);
        }


        goto error;
    }


    //讀取bootloader文件


    fseek(p_bootloader_file_source, 0, SEEK_END);


    uint32_t get_bootloader_file_size = ftell(p_bootloader_file_source);


    if (get_debug_switch > 0)
    {
        printf("bootloader file size=%d\\r\\n",get_bootloader_file_size);
    }


    if ((0 == get_bootloader_file_size) || (get_bootloader_file_size > combine_file.size_total))
    {
        if (get_debug_switch > 0)
        {
           printf("bootloader file size invalid=%d\\r\\n",get_bootloader_file_size);
        }


        goto error;
    }


    fseek(p_bootloader_file_source, 0L, SEEK_SET);


    uint8_t *bootloader_data_buffer = (uint8_t *)malloc(sizeof(uint8_t)*get_bootloader_file_size);


    if (!bootloader_data_buffer)
    {
        if (get_debug_switch > 0)
        {
            printf("bootloader buffer malloc error\\r\\n");
        }


        goto error;
    }


    fread(bootloader_data_buffer,1,get_bootloader_file_size,p_bootloader_file_source);


    //讀取APP來源文件
    fseek(p_app_file_source, 0, SEEK_END);


    uint32_t get_app_file_size = ftell(p_app_file_source);


    if (get_debug_switch > 0)
    {
        printf("file size[app]=%d\\r\\n",get_app_file_size);


        printf("file size[app + crc]=%d\\r\\n",get_app_file_size+4);
    }


    if ((0 == get_app_file_size) || (get_app_file_size > (combine_file.size_app_max-8)))
    {
        if (get_debug_switch > 0)
        {
           printf("app file size invalid\\r\\n");
        }


        goto error;
    }


    fseek(p_app_file_source, 0L, SEEK_SET);


    uint8_t *app_data_buffer = (uint8_t *)malloc(sizeof(uint8_t)*get_app_file_size);


    if (!app_data_buffer)
    {
        if (get_debug_switch > 0)
        {
           printf("app buffer malloc error\\r\\n");
        }


        goto error;
    }


    fread(app_data_buffer,1,get_app_file_size,p_app_file_source);


    //把app內容進行校驗生成帶校驗的app文件
    uint32_t get_crc_value = crc32_customized(CONFIG_CRC32_POLY,CONFIG_CRC32_INIT_VALUE,CONFIG_CRC32_OUT_XOR,app_data_buffer,get_app_file_size);


    if (get_debug_switch > 0)
    {
        printf("get_crc_value = %x\\r\\n",get_crc_value);
    }


    //緩存大小是 bootloader+sector+app
    //新建一個bootloader大小+sector+app大小的緩存
    //生產用的文件需要帶CRC校驗和字節大小,客戶用的APP文件只包含CRC校驗沒有大小,大小在升級的時候自動加上去
    //后續再優化APPSIZE和APPCRC的存儲位置,節省FLASH空間


    uint32_t size_product = combine_file.size_bootloader+combine_file.size_parameter+get_app_file_size;


    uint8_t *product_data_buffer = (uint8_t *)malloc(sizeof(uint8_t)*(size_product));


    if (get_debug_switch > 0)
    {
        printf("product file size = %d\\r\\n",size_product);
    }


    if (!product_data_buffer)
    {
        if (get_debug_switch > 0)
        {
            printf("bootloader buffer malloc error\\r\\n");
        }


        goto error;
    }


    //填充0xff
    printf("fill 0xff\\n");
    memset(product_data_buffer,0xff,size_product);


    printf("write bootloader\\n");


    //寫入 bootloader
    memcpy(product_data_buffer,bootloader_data_buffer,get_bootloader_file_size);


    //加入 CRC和SIZE信息
    memcpy(&product_data_buffer[combine_file.size_bootloader],&get_app_file_size,4);




    printf("write app\\n");


    //寫入app
    memcpy(&product_data_buffer[combine_file.size_bootloader+combine_file.size_parameter],app_data_buffer,get_app_file_size);


    if (get_debug_switch > 0)
    {
        printf("app at=[%08x]\\r\\n",combine_file.flash_base+combine_file.size_bootloader+combine_file.size_parameter);
    }


    //輸出 app_out


    p_app_file_out = fopen(combine_file.fn_app_out,"wb+");


    if (!p_app_file_out)
    {
        if (get_debug_switch > 0)
        {
           printf("write app crc file error\\r\\n");
        }


        goto error;
    }


    fwrite(app_data_buffer,1,get_app_file_size,p_app_file_out);


    //輸出 加密后的文件
    uint8_t *app_mask_data_buffer = 0;


    printf("combine_file.check_type=[%d]\\r\\n",combine_file.check_type);


    p_app_file_out_mask = fopen(combine_file.fn_app_mask,"wb+");


    if (!p_app_file_out_mask)
    {
        if (get_debug_switch > 0)
        {
           printf("write app mask file error\\r\\n");
        }


        goto error;
    }

3.3.3 文件加密和壓縮處理

if (T_CRYPT == combine_file.check_type)
    {
        int res = 0;
        uint8_t *set_data_out = 0;


        tinycrypt_enc_init();


        uint8_t *buffer_out_temp = (uint8_t *) malloc(sizeof(uint8_t)*get_app_file_size);


        if (!buffer_out_temp)
        {
            printf("buffer_out_temp malloc error \\r\\n");
        }


        uint32_t size_out = 0;


        if (quicklz_compress_buffer(buffer_out_temp,app_data_buffer,get_app_file_size,&size_out) >= 0)
        {
            if (!size_out)
            {
                printf("size_out error \\r\\n");
                goto error;
            }


            set_data_out = (uint8_t *) malloc(sizeof(uint8_t)*size_out);


            if (!set_data_out)
            {
                printf("set_data_out malloc error \\r\\n");
                res = -1;
                goto error;
            }


            memset(buffer_data,0,COMPRESS_BUFFER_SIZE);


            aes_en_buffer(set_data_out,buffer_out_temp,size_out);
            fwrite(set_data_out,1,size_out,p_app_file_out_mask);
            uint32_t aes_crc32  =crc32_customized(CONFIG_CRC32_POLY,CONFIG_CRC32_INIT_VALUE,CONFIG_CRC32_OUT_XOR,set_data_out,size_out);


            if (get_debug_switch > 0)
            {
                printf("aes_crc32 mask = %x\\r\\n",aes_crc32);
            }


            fwrite(&aes_crc32,1,4,p_app_file_out_mask);
        }


        if (buffer_out_temp)
        {
            free(buffer_out_temp);
        }


        if (set_data_out)
        {
            free(set_data_out);
        }
}

3.4 bootloader的設計
在啟動后掛載文件系統,檢查是否存在xxx.bin的文件,如果存在則檢查文件是否合法,合法就進入解密和解壓縮階段,最后把文件的crc和size寫入flash,復位跳轉到app對應的地址上運行

int result = dfs_elm_mount(&g_fat,0,0);


        PRINTF_APP_MAIN("result=%d\\r\\n",result);

        //if (0 == check_boot(CONFIG_UBOOT_WAITING_TIME_S))
        {
            uint8_t get_firmware_name[32]={0};


            if (check_firmware_file(get_firmware_name))
            {
                PRINTF_APP_MAIN("find the firmware file name=%s\\r\\n",get_firmware_name);


                FRESULT res = f_open(&_update_file,get_firmware_name,FA_OPEN_EXISTING|FA_READ);

                uint32_t get_crc_result = 0;


                PRINTF_APP_MAIN("res=%d\\r\\n",res);


                if (FR_OK == res)
                {
                    uint32_t read_bytes = 0;
                    uint32_t total_bytes = _update_file.fsize-4;
                    uint32_t left_bytes = total_bytes;
                    uint32_t read_actual_bytes = 0;
                    uint32_t index_read = 0;


                    PRINTF_APP_MAIN("update_file.fsize=%d\\r\\n",_update_file.fsize);
                    PRINTF_APP_MAIN("total_bytes=%d\\r\\n",total_bytes);
                    /**/
                    if (total_bytes <= CONFIG_FLASH_APP_SIZE)
                    {
                        volatile uint32_t check_crypt_crc = 0;

                        hardware_crc32_short_start();

                        while (left_bytes > 0)
                        {
                            if (left_bytes > CONFIG_FLASH_SECTOR_SIZE)
                            {
                                read_bytes = CONFIG_FLASH_SECTOR_SIZE;
                            }
                            else
                            {
                                read_bytes = left_bytes;
                            }


                            FRESULT read_res = f_read(&_update_file,read_file,read_bytes,&read_actual_bytes);


                            if (0 == read_actual_bytes)
                            {
                                break;
                            }


                            check_crypt_crc = hardware_crc32_short(read_file,read_actual_bytes);

                            left_bytes = left_bytes - read_actual_bytes;
                        }


                        check_crypt_crc &= 0xFFFFFFFF;


                        (check_crypt_crc ^= 0x00000000);

                        PRINTF_APP_MAIN("check_crypt_crc=%x\\r\\n",check_crypt_crc);


                        FRESULT read_last_res = f_read(&_update_file,read_file,4,&read_actual_bytes);


                        if (FR_OK == read_last_res)
                        {
                            uint32_t source_crc = 0;
                            memcpy(&source_crc,read_file,4);

                            f_close(&_update_file);


                            memset(read_file,0,CONFIG_FLASH_SECTOR_SIZE);

                            PRINTF_APP_MAIN("source_crc=%x\\r\\n",source_crc);

                            if (check_crypt_crc == source_crc)
                            {
                                res = f_open(&_update_file,get_firmware_name,FA_READ);

                                if (FR_OK == res)  
                                {
                                    PRINTF_APP_MAIN("crypt_decode_part\\r\\n");

                                    if (crypt_decode_part(&_update_file,CONFIG_FLASH_APP_ADDRESS,&get_crc_result,&total_bytes) >= 0)
                                    {
                                        f_close(&_update_file);
                                        PRINTF_APP_MAIN("crypt_decode_part after\\r\\n");
                                        PRINTF_APP_MAIN("total_bytes=%d\\r\\n",total_bytes);
                                        PRINTF_APP_MAIN("get_crc_result=%x\\r\\n",get_crc_result);

                                        uint8_t set_data_buffer[20];

                                        set_data_buffer[0] = (uint8_t)(total_bytes);
                                        set_data_buffer[1] = (uint8_t)(total_bytes>>8);
                                        set_data_buffer[2] = (uint8_t)(total_bytes>>16);
                                        set_data_buffer[3] = (uint8_t)(total_bytes>>24);

                                        set_data_buffer[4] = (uint8_t)(get_crc_result);
                                        set_data_buffer[5] = (uint8_t)(get_crc_result>>8);
                                        set_data_buffer[6] = (uint8_t)(get_crc_result>>16);
                                        set_data_buffer[7] = (uint8_t)(get_crc_result>>24);        

                                        memset(&set_data_buffer[8],0xff,12);

                                        uint8_t idx_check=0;

                                        PRINTF_APP_MAIN("app info[");

                                        for (idx_check=0; idx_check<20; idx_check++)
                                        {
                                            PRINTF_APP_MAIN("%02x ",set_data_buffer[idx_check]);

                                            if(idx_check==3)
                                            {
                                                PRINTF_APP_MAIN("| ");
                                            }
                                        }

                                        PRINTF_APP_MAIN("]\\n");

                                        g_flash_write_bytes(CONFIG_FLASH_APP_SIZE_ADDRESS,set_data_buffer,LENGTH_OF_ARRAY(set_data_buffer));

                                        f_unlink(get_firmware_name);

                                        hw_cpu_reset(); 
                                    }
                                }
                            }
                        }
                    }
                }
            }
            //else
            {
                int res_umount = dfs_elm_unmount(&g_fat);


                PRINTF_APP_MAIN("res_umount=%d\\r\\n",res_umount);

                PRINTF_APP_MAIN("without update file then check app format\\r\\n"); 
                uint32_t get_app_size = flash_read_word(CONFIG_FLASH_APP_SIZE_ADDRESS);
                uint32_t get_app_crc = flash_read_word(CONFIG_FLASH_APP_CRC_ADDRESS);

                PRINTF_APP_MAIN("get_app_size=%d\\r\\n",get_app_size);
                PRINTF_APP_MAIN("get_app_crc=%x\\r\\n",get_app_crc);

                memset(read_file,0,CONFIG_FLASH_SECTOR_SIZE);

                if ((get_app_size > 0) && (get_app_size<= CONFIG_FLASH_APP_SIZE))
                {
                    uint32_t read_bytes,data_offset,calc_crc_val = 0;
                    uint32_t left_bytes = get_app_size;
                    uint32_t flash_addr_index = CONFIG_FLASH_APP_ADDRESS;


                    PRINTF_APP_MAIN("left_bytes=%d\\r\\n",left_bytes);

                    calc_crc_val = crc32_customized(CONFIG_CRC32_POLY,CONFIG_CRC32_INIT_VALUE,CONFIG_CRC32_OUT_XOR,CONFIG_FLASH_APP_ADDRESS,get_app_size);

                    PRINTF_APP_MAIN("calc_crc_val=%x\\r\\n",calc_crc_val);


                    if (get_app_crc == calc_crc_val)
                    {
                        PRINTF_APP_MAIN("run app\\r\\n");


                        iap_load_app(CONFIG_FLASH_APP_ADDRESS);
                    }
                }
            }

可以加個后門,比如上電后某個腳為某個電平停留在bootloader階段,進行OTA響應。
3.5 在KEIL上的應用
3.5.1 準備資源
編寫腳本文件另存為
firmware_update.bat

@echo off
set /a CONFIG_DEBUG_SWITCH=1
set /a CONFIG_FLASH_BASE=0x08000000
set /a CONFIG_FLASH_SECTOR_SIZE=(2*1024)
set /a CONFIG_FLASH_TOTAL_SIZE=(512*1024)
set /a CONFIG_BOOTLOADER_SIZE=(40*1024)
set /a CONFIG_APP_MAX_SIZE=(235*1024)
set /a CONFIG_CHECK_TYPE=3
set CONFIG_FN_BOOTLOADER=bootloader.bin
set CONFIG_FN_APP_SOURCE=app_.bin
set CONFIG_FN_APP_OUT=_upfw_.bin
set CONFIG_FN_PRODUCT=product_.bin
set CONFIG_FN_USER=sys.bin


::call clean.bat
copy %CONFIG_FN_BOOTLOADER% .\\bin
copy data_crypt.exe .\\bin
copy %CONFIG_FN_USER% .\\bin
cd bin/
data_crypt %CONFIG_FLASH_TOTAL_SIZE% %CONFIG_FLASH_SECTOR_SIZE% %CONFIG_BOOTLOADER_SIZE% %CONFIG_CHECK_TYPE% %CONFIG_FN_BOOTLOADER% %CONFIG_FN_APP_SOURCE% %CONFIG_FN_APP_OUT% %CONFIG_FN_PRODUCT% %CONFIG_DEBUG_SWITCH% %CONFIG_APP_MAX_SIZE% %CONFIG_FLASH_BASE% %CONFIG_FN_USER%
start %~dp0\\bin

3.5.2 Bootloader的KEIL配置
在keil的User 標簽中添加AfterBuild/Rebuild腳本
$K\\ARM\\ARMCC\\bin\\fromelf.exe --bin --output=bin@L.bin ! L
將bootloader.bin存放到mdk項目文件目錄下
3.5.3 APP的KEIL配置

3.5.4 編譯后生成以下目標文件

upfw_app.bin是壓縮和加密后的文件
app
.bin是未加工的應用程序
product_.bin是用于量產時的燒錄文件

4 應用場景
4.1 通過電腦升級固件
枚舉成大容量存儲設備,通過USB線連接到電腦后會枚舉出一個U盤,把_upfw_app.bin復制到U盤根目錄下后重啟即可

可以參考這篇文章做一個USB大容量存儲設備STM32大容量存儲設備

4.2 通過U盤升級
工作在USB主機模式下,
把_upfw_app.bin復制到一個U盤根目錄下,插入U盤后,主機識別到U盤根目錄下的文件,拷貝到文件系統,復位重啟即可

4.3 通過離線燒錄器燒錄
在量產時可以使用合并好的未加密的product_.bin

4.4 OTA升級
可通過ymodem協議把加密文件傳輸到文件系統根目錄下,再重啟即可,
可以參考涂鴉智能的串口協議的設計,可以參考rtthread自帶的ymodem例子,也可以參考小米用到的xmodem來設計自己的OTA

5 總結
加入OTA后,分配給APP的FLASH大小可能會少很多,把運用在實際項目上的經驗復盤到自己的開發板上,總結好理論經驗,多做幾次實際操作,按照這樣的方法,應該可以內化吸收,把經驗轉換成我們內在的東西,再刻意地運用在新的項目上。
做任何事應該都有方法,賺錢有方法,工作有方法,幫助他人有方法,教育孩子有方法,努力是沒有用的,有了正確的方法和方向的努力才有用。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FlaSh
    +關注

    關注

    10

    文章

    1621

    瀏覽量

    147745
  • 物聯網
    +關注

    關注

    2903

    文章

    44262

    瀏覽量

    371213
  • STM32
    +關注

    關注

    2266

    文章

    10871

    瀏覽量

    354786
  • 固件
    +關注

    關注

    10

    文章

    550

    瀏覽量

    22966
  • 固件升級
    +關注

    關注

    0

    文章

    34

    瀏覽量

    12096
收藏 人收藏

    評論

    相關推薦

    Ethernet遠程固件升級

    本實驗工程實現了Ethernet遠程固件升級, 通過編譯下載工程到STM32F769 Flash bank1并執行,能夠實現從遠程服務器下載程序到Flash bank2中做固件升級,并
    發表于 09-11 06:00

    昂達vx979+固件升級

    昂達vx979固件升級   本固件為出廠時的初始固件,非升級版本。 更新固件
    發表于 12-24 10:30 ?122次下載

    mp3固件升級工具下載

    mp3固件升級工具下載
    發表于 01-05 11:20 ?24次下載
    mp3<b class='flag-5'>固件</b><b class='flag-5'>升級</b>工具下載

    mp3固件升級軟件下載

    mp3固件升級軟件下載
    發表于 01-05 11:20 ?1508次下載
    mp3<b class='flag-5'>固件</b><b class='flag-5'>升級</b>軟件下載

    mp3固件升級程序

    mp3固件升級程序
    發表于 01-14 12:38 ?7次下載
    mp3<b class='flag-5'>固件</b><b class='flag-5'>升級</b>程序

    魅族固件升級教程

    魅族固件升級教程
    發表于 12-14 14:55 ?8次下載

    什么是MP3固件升級

    什么是MP3固件升級 1、 什么是固件,固件的概念   固件(FirmWare)的詞典里的解釋是具有軟件功能的硬件
    發表于 02-02 11:43 ?1058次閱讀

    USB設備固件升級_cn

    STM2T之USB設備固件升級_cn,很好的stm32資料,快來學習吧,免費的哦。
    發表于 04-25 17:40 ?17次下載

    NOR閃存提升OTA固件升級能力

    NOR閃存提升OTA固件升級能力
    的頭像 發表于 07-02 15:33 ?3166次閱讀

    MCU固件升級的閃存劃分方法分享

    現在在MCU上實現固件升級(OTA)功能變得越來越普遍,今天我們就來探討一下MCU固件升級(OTA)的幾種閃存(Flash)劃分方式。
    的頭像 發表于 11-10 16:28 ?4905次閱讀

    固件升級和軟件升級區別

    固件升級,指的是對音樂播放機等便攜式機器的內嵌固件進行升級。可以完善機器功能、增強機器穩定性、修補機器漏洞。
    的頭像 發表于 11-30 14:07 ?1.8w次閱讀

    西數SSD固件升級工具

    西數SSD固件升級工具,電腦本地固件升級,無需轉接板。
    發表于 08-28 11:13 ?1次下載

    如何對物聯設備進行遠程固件升級?

    當有新功能或需要修復bug,而設備已經生產出來,在渠道或客戶手中時,那么遠程固件升級就很重要了。ZLG物聯網云平臺支持遠程固件升級,本文將詳解固件
    的頭像 發表于 11-01 13:14 ?1436次閱讀

    STM32WB系列的固件升級服務

    STM32WB系列的固件升級服務
    發表于 11-21 08:11 ?4次下載
    STM32WB系列的<b class='flag-5'>固件</b><b class='flag-5'>升級</b>服務

    多路手機固件升級工具設計

    電子發燒友網站提供《多路手機固件升級工具設計.pdf》資料免費下載
    發表于 11-08 11:18 ?0次下載
    多路手機<b class='flag-5'>固件</b><b class='flag-5'>升級</b>工具設計