加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

RT-thread應(yīng)用講解——通過U盤升級(jí)程序固件

04/03 13:11
3602
閱讀需 15 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

我前面介紹過RT-thread的一種OTA方案,可以通過串口或者網(wǎng)絡(luò)進(jìn)行遠(yuǎn)程升級(jí),那今天在原來的這套方案的基礎(chǔ)上做一些修改,實(shí)現(xiàn)U盤升級(jí)。

相比于串口和網(wǎng)絡(luò),U盤升級(jí)在某些方面有很大的優(yōu)勢(shì),首先它不需要網(wǎng)絡(luò),對(duì)于那些不具備上網(wǎng)功能的設(shè)備來說很方便,其次它不需要連接數(shù)據(jù)線,在距離上有優(yōu)勢(shì),說到這,可能有人會(huì)說,u盤要插到設(shè)備上才能用,距離怎么就有優(yōu)勢(shì)了呢?

是的,U盤升級(jí)確實(shí)需要有人到設(shè)備這邊手動(dòng)操作,但是因?yàn)閁盤是很通用的設(shè)備,即使是非研發(fā)人員也可以操作,不需要燒錄器,也不需要安裝一些驅(qū)動(dòng)和軟件,只需要找一個(gè)U盤把升級(jí)固件放進(jìn)去,然后插到設(shè)備上升級(jí)即可。

比如有個(gè)客戶安裝了我們的設(shè)備,但是后來軟件要進(jìn)行升級(jí)優(yōu)化,如果這個(gè)設(shè)備是支持U盤升級(jí)的那么我就可以把升級(jí)的固件發(fā)給客戶,讓他自己用一個(gè)U盤來升級(jí)設(shè)備,這樣一來,我們就不需要跑到現(xiàn)場(chǎng)去燒錄固件了。

好了,廢話不多說,馬上開整。

一、掛載U盤

使用U盤升級(jí),第一步要先把U盤的讀寫調(diào)試好,關(guān)于U盤的使用,可以看下我之前的博客,有很詳細(xì)的介紹,這里就不多說了。

RT-thread應(yīng)用講解——U盤(usb host)

二、使能OTA

要想遠(yuǎn)程升級(jí),那肯定先得有OTA的功能,關(guān)于OTA的使用我在前面的博客里面也詳細(xì)介紹過了,不知道的同學(xué)可以先去看下。

RT-thread應(yīng)用講解——OTA

OTA部分只要要完成bootloader的制作和app的制作即可。這兩部分都調(diào)試好了之后就可以加入U(xiǎn)盤升級(jí)的代碼。

三、U盤升級(jí)代碼

前面把U盤的掛載和OTA都調(diào)試好了之后就可以使用U盤來進(jìn)行OTA了。

示例代碼如下:

#include <rtthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <finsh.h>
#include <fal.h>
#include <dfs_posix.h>

#define DBG_SECTION_NAME          "ota_usb"

#define DBG_LEVEL                 DBG_LOG

#define DBG_COLOR
#include <rtdbg.h>

/* 固件版本號(hào) */
#define APP_VERSION               "1.0.0"

/* 固件名稱 */
#define USBH_UPDATE_FN            "/rtthread.rbl"

/* 固件下載分區(qū)名稱 */
#define DEFAULT_DOWNLOAD_PART     "download"

static char* recv_partition = DEFAULT_DOWNLOAD_PART;

rt_sem_t ota_sem = RT_NULL;

static void print_progress(size_t cur_size, size_t total_size)
{
    static unsigned char progress_sign[100 + 1];
    uint8_t i, per = cur_size * 100 / total_size;

    if (per > 100)
    {
        per = 100;
    }

    for (i = 0; i < 100; i++)
    {
        if (i < per)
        {
            progress_sign[i] = '=';
        }
        else if (per == i)
        {
            progress_sign[i] = '>';
        }
        else
        {
            progress_sign[i] = ' ';
        }
    }

    progress_sign[sizeof(progress_sign) - 1] = '?';

    LOG_I("?33[2A");
    LOG_I("Download: [%s] %d%%", progress_sign, per);
}

static int ota_usb_download_entry(void* parameter)
{
    DIR *dirp;
    static size_t update_file_total_size, update_file_cur_size;
    static const struct fal_partition * dl_part = RT_NULL;
    static int fd;
    static rt_uint8_t buf[1024];
    static rt_err_t result;
    struct stat file;

    rt_kprintf("The current version of APP firmware is %sn", APP_VERSION);	

    while(1)
    {
        result = rt_sem_take(ota_sem, RT_WAITING_FOREVER);
        if(result == RT_EOK)
        {
            rt_kprintf("Default save firmware on download partition.n");

            rt_kprintf("Warning: usb has started! This operator will not recovery.n");

            /* 查詢固件大小 */
            result = stat(USBH_UPDATE_FN, &file);
            if(result == RT_EOK)
            {
                LOG_D(""USBH_UPDATE_FN" file size is : %dn", file.st_size);
            }
            else
            {
                LOG_E(""USBH_UPDATE_FN" file not fonud.");
                goto __exit;
            }
            if(file.st_size <= 0)
            {
                LOG_E(""USBH_UPDATE_FN" file is empty.");
                goto __exit;
            }
                
            /* 獲取"download"分區(qū)信息并清除分區(qū)數(shù)據(jù) */
            if ((dl_part = fal_partition_find(recv_partition)) == RT_NULL)
            {
                LOG_E("Firmware download failed! Partition (%s) find error!", recv_partition);
                goto __exit;
            }
            if (file.st_size > dl_part->len)
            {
                LOG_E("Firmware is too large! File size (%d), '%s' partition size (%d)", file.st_size, recv_partition, dl_part->len);
            }
            if (fal_partition_erase(dl_part, 0, file.st_size) < 0)
            {
                LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
            }

            /* 以只讀模式打開固件 */
            fd = open(USBH_UPDATE_FN, O_RDONLY);
            if (fd >= 0)
            {
                do
                {
                    /* 讀取u盤的固件,一次讀1024字節(jié) */
                    update_file_cur_size = read(fd, buf, sizeof(buf));

                    /* 把固件寫入片外flash的download分區(qū)  */
                    if (fal_partition_write(dl_part, update_file_total_size, buf, update_file_cur_size) < 0)
                    {
                        LOG_E("Firmware download failed! Partition (%s) write data error!", dl_part->name);
                        close(fd);
                        goto __exit;
                    }

                    update_file_total_size += update_file_cur_size;

                    print_progress(update_file_total_size, file.st_size);
                } 
                while (update_file_total_size != file.st_size);
                
                close(fd);
            }
            else
            {
                LOG_E("check: open file for read failedn");
                goto __exit;
            }

            rt_kprintf("Download firmware to flash success.n");
            rt_kprintf("System now will restart...rn");

            /* wait some time for terminal response finish */
            rt_thread_delay(rt_tick_from_millisecond(200));

            /* Reset the device, Start new firmware */
            extern void rt_hw_cpu_reset(void);
            rt_hw_cpu_reset();
            /* wait some time for terminal response finish */
            rt_thread_delay(rt_tick_from_millisecond(200));

        __exit:
            LOG_E("download rtthread.rbl file failed");
        }
    }
}

void ota_usb_init(void)
{
    fal_init();

    ota_sem = rt_sem_create("otasem", 0, RT_IPC_FLAG_FIFO);
    
    rt_thread_t thread1 = rt_thread_create("ota_usb", ota_usb_download_entry, RT_NULL, 4096, 26, 10);
    if (thread1 != RT_NULL)
    {
        rt_thread_startup(thread1);
    }
}
INIT_APP_EXPORT(ota_usb_init);

static rt_uint8_t ota_usb_start(void)
{
    rt_sem_release(ota_sem);

    return RT_EOK;
}
MSH_CMD_EXPORT(ota_usb_start, OTA start);

四、運(yùn)行測(cè)試

先做好一個(gè)要升級(jí)的固件(rtthread.rbl)放到U盤里,插入U(xiǎn)盤之后,查看U盤是否有該文件。

在這里插入圖片描述

通過調(diào)用命令開始升級(jí)。

提示:用命令只是為了方便調(diào)試,實(shí)際使用可以通過實(shí)體按鍵或屏幕按鍵來觸發(fā)升級(jí)。

在這里插入圖片描述

至此,整個(gè)升級(jí)的流程就走完了。

五、結(jié)束語(yǔ)

好了,關(guān)于U盤升級(jí)的介紹就到這里,整個(gè)流程看著挺復(fù)雜,但是知道原理之后回頭再看,其實(shí)結(jié)構(gòu)還是很清晰的,如果還有什么問題,歡迎在評(píng)論區(qū)留言。如果這篇文章能夠幫到你,就給我點(diǎn)個(gè)贊吧,如果想了解更多RT-thread和單片機(jī)的內(nèi)容,可以關(guān)注一下博主,后續(xù)我還會(huì)繼續(xù)分享更多的經(jīng)驗(yàn)給大家。

教程相關(guān)源碼:https://download.csdn.net/download/ShenZhen_zixian/12880749

RT-thread相關(guān)教程匯總:https://blog.csdn.net/ShenZhen_zixian/article/details/120563891

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
FTE8510K1LTN 1 Finisar Corporation Transceiver
$159.17 查看
NX5032GA-8.000M-STD-CSU-1 1 Nihon Dempa Kogyo Co Ltd Parallel - Fundamental Quartz Crystal, 8MHz Nom, ROHS COMPLIANT PACKAGE-2
暫無數(shù)據(jù) 查看
SN74LVC1G14DBVRE4 1 Texas Instruments Single 1.65-V to 5.5-V inverter with Schmitt-Trigger inputs 5-SOT-23 -40 to 125

ECAD模型

下載ECAD模型
$0.42 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜