【RT-Thread】Bootloader與OTA升級


今天開始寫日志總結順便再復習一下。

軟件:RT-Thread Studio

硬件:正點原子探索者開發板 芯片 STM32F407ZG

 

(一)BOOTLOADER:

相比較引導Linux使用的Uboot而言,RTThread使用的bootloader 系統引導程序稍微簡單一點。

 RTThread 官方BOOTLOADER生成地址:http://iot.rt-thread.com

貼一下生成步驟

 

 

使用STM32 ST-LINK Utility軟件將收到的rtboot_f4.bin燒入到板子的flash

 

 驗證一下bootloader,由於此時app分區還沒有對應的app程序,所以會卡住:

 

(二)APP

1.使用RTThread Studio新建F4工程;

2.可以使用有線或者無線將開發板聯網。這里使用的時ESP8266接入wifi連入互聯網。

3.添加FAL分區表,使APP對應的分區和bootloader分區一致,否則在使用OTA升級時下載的分區不對,重啟時,bootloader無法獲取到新的的固件。

4.添加OTA軟件包

5.修改APP的中斷向量表存放地址以及APP開始地址。

實現上述四個步驟即可完成開發板的OTA升級功能。

使能ESP8266:

在board.h中添加對UART3的定義,是能UART3

 至此,esp8266已經可以工作。

 

FAL對ON_CHIP_FLASH進行分區:

打開BSP_USING_ON_CHIP_FLASH與HAL_FLASH_MODULE_ENABLED宏

 

 定義FAL分區表,創建fal_cfg.h,內容如下

/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2020-06-13     rwz       the first version
 */
#ifndef DRIVERS_INCLUDE_FAL_CFG_C_
#define DRIVERS_INCLUDE_FAL_CFG_C_

/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2020-06-11     rwz       the first version
 */

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtthread.h>
#include <board.h>

#define FLASH_SIZE_GRANULARITY_16K   (4 * 16 * 1024)
#define FLASH_SIZE_GRANULARITY_64K   (64 * 1024)
#define FLASH_SIZE_GRANULARITY_128K  (7 * 128 * 1024)

#define STM32_FLASH_START_ADRESS_16K  STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_64K  (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
#define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)

extern const struct fal_flash_dev stm32_onchip_flash_16k;
extern const struct fal_flash_dev stm32_onchip_flash_64k;
extern const struct fal_flash_dev stm32_onchip_flash_128k;
/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &stm32_onchip_flash_128k,                                        \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG

/* partition table */
#define FAL_PART_TABLE                                                                                                     \
{                                                                                                                          \
    {FAL_PART_MAGIC_WROD, "app", "onchip_flash_128k",  0 , 256*1024 , 0}, \
    {FAL_PART_MAGIC_WROD, "download","onchip_flash_128k", 256*1024 ,256*1024, 0}, \
    {FAL_PART_MAGIC_WROD, "factory","onchip_flash_128k", 512*1024,256*1024, 0}, \
}

#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */


#endif /* DRIVERS_INCLUDE_FAL_CFG_C_ */

 

修改中斷向量表位置

#define RT_APP_PART_ADDR 0x8020000

static int ota_app_vtor_reconfig(void)
{
    #define NVIC_VTOR_MASK   0x3FFFFF80
    /* Set the Vector Table base location by user application firmware definition */
    SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK;

    return 0;
}
INIT_BOARD_EXPORT(ota_app_vtor_reconfig);

修改程序鏈接腳本中ROM的起始地址

 在main函數中調用fal_init()對設置的分區表進行初始化;

int main(void)
{
    int count = 1;
  fal_init(); while (count++)
    {
       // LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

 編譯程序,下載到開發板試運行一下FAL分區表是否正確。

 根據結果可以看到程序已經成功的加載運行,對應的分區表也是對的。剩下的問題就是類似tftp的功能,把對應的升級固件獲取到,然后寫入到對應的downloaderFLASH分區就可以了,

我是直接使用的RT-Thread對應的ota軟件包(因為懶)。

打開RT-Thread Settings,添加ota-downloader軟件包,設置如下:

編譯下載到開發板進行http_ota升級,發現下載到一定位置會下載失敗,如圖所示。

 

在不斷的摸索和問度娘下,發現在http_ota_fw_download函數里出現了問題。原函數如下,大概分為以下幾步:

1.創建session

2.get連接webserver

3.獲取文件大小

4.擦除分區對應的大小

5.接收文件寫入FLASH

可能是因為擦除FLASH十分耗時,導致web連接失敗的情況。

static int http_ota_fw_download(const char* uri)
{
    int ret = 0, resp_status;
    int file_size = 0, length, total_length = 0;
    rt_uint8_t *buffer_read = RT_NULL;
    struct webclient_session* session = RT_NULL;
    const struct fal_partition * dl_part = RT_NULL;

    /* create webclient session and set header response size */
    session = webclient_session_create(GET_HEADER_BUFSZ);
    if (!session)
    {
        LOG_E("open uri failed.");
        ret = -RT_ERROR;
        goto __exit;
    }

    /* send GET request by default header */
    if ((resp_status = webclient_get(session, uri)) != 200)
    {
        LOG_E("webclient GET request failed, response(%d) error.", resp_status);
        ret = -RT_ERROR;
        goto __exit;
    }

    file_size = webclient_content_length_get(session);
    rt_kprintf("http file_size:%d\n",file_size);

    if (file_size == 0)
    {
        LOG_E("Request file size is 0!");
        ret = -RT_ERROR;
        goto __exit;
    }
    else if (file_size < 0)
    {
        LOG_E("webclient GET request type is chunked.");
        ret = -RT_ERROR;
        goto __exit;
    }

    /* Get download partition information and erase download partition data */
    if ((dl_part = fal_partition_find("download")) == RT_NULL)
    {
        LOG_E("Firmware download failed! Partition (%s) find error!", "download");
        ret = -RT_ERROR;
        goto __exit;
    }

    LOG_I("Start erase flash (%s) partition!", dl_part->name);

    if (fal_partition_erase(dl_part, 0, file_size) < 0)
    {
        LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
        ret = -RT_ERROR;
        goto __exit;
    }
    LOG_I("Erase flash (%s) partition success!", dl_part->name);

    buffer_read = web_malloc(HTTP_OTA_BUFF_LEN);
    if (buffer_read == RT_NULL)
    {
        LOG_E("No memory for http ota!");
        ret = -RT_ERROR;
        goto __exit;
    }
    memset(buffer_read, 0x00, HTTP_OTA_BUFF_LEN);

    LOG_I("OTA file size is (%d)", file_size);

    do
    {
        length = webclient_read(session, buffer_read, file_size - total_length > HTTP_OTA_BUFF_LEN ?
                            HTTP_OTA_BUFF_LEN : file_size - total_length);   
        if (length > 0)
        {
            /* Write the data to the corresponding partition address */
            if (fal_partition_write(dl_part, total_length, buffer_read, length) < 0)
            {
                LOG_E("Firmware download failed! Partition (%s) write data error!", dl_part->name);
                ret = -RT_ERROR;
                goto __exit;
            }
            total_length += length;

            print_progress(total_length, file_size);
        }
        else
        {
            LOG_E("Exit: server return err (%d)!", length);
            ret = -RT_ERROR;
            goto __exit;
        }

    } while(total_length != file_size);

    ret = RT_EOK;

    if (total_length == file_size)
    {
        if (session != RT_NULL)
            webclient_close(session);
        if (buffer_read != RT_NULL)
            web_free(buffer_read);

        LOG_I("Download firmware to flash success.");
        LOG_I("System now will restart...");

        rt_thread_delay(rt_tick_from_millisecond(5));

        /* Reset the device, Start new firmware */
        extern void rt_hw_cpu_reset(void);
        rt_hw_cpu_reset();
    }

__exit:
    if (session != RT_NULL)
        webclient_close(session);
    if (buffer_read != RT_NULL)
        web_free(buffer_read);

    return ret;
}

最終的解決是在連接之前可以針對整個download分區進行擦除,然后在進行web連接,或者先l連接獲取文件大小--->斷開連接--->進行擦除--->再次 連接--->獲取文件大小進行比對--->傳輸文件寫入FLASH。

再次嘗試結果:

注意:固件打包器中的選項跟BOOTLOADER選項必須一致。BOOTLOADER我選擇了GZIP壓縮,這里也必須選上。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM