【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压缩,这里也必须选上。

 

 

 

 

posted @ 2020-07-22 22:51  一半丶  阅读(5131)  评论(1编辑  收藏  举报