今天开始写日志总结顺便再复习一下。
软件: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压缩,这里也必须选上。