zoukankan      html  css  js  c++  java
  • 【RTThread】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压缩,这里也必须选上。

     

  • 相关阅读:
    给Windows组件添加图标
    C#文件和文件夹操作
    WinForm TreeView 右键菜单
    VC++ New 操作符
    Ext与Jquery的整合
    PowerDesign报表操作
    SQLServer自动建表存储过程
    Visual Studio 2008简体中文正式版下载地址
    WinForm遍历控件
    发布时用直接用源文件部署
  • 原文地址:https://www.cnblogs.com/Raowz/p/13276647.html
Copyright © 2011-2022 走看看